Skip to content

Branching Strategies

Status: 🟢 Active  |  Owner: Engineering Enablement  |  Last Reviewed: 2025-Q4


Default: Trunk-Based Development

Trunk-Based Development (TBD) is the required branching strategy for all active product teams. Developers integrate small changes directly into the main branch (trunk) frequently — at least daily. This is the strategy most strongly correlated with high delivery performance in the DORA research.

Core Rules

  • main is always deployable. The CI pipeline must be fully green before any change is merged. A broken main is the team's highest priority to fix.
  • Feature branches are short-lived: target < 1 day, maximum 2 days. Long-lived branches cause integration pain, merge conflicts, and delayed feedback.
  • Incomplete features use feature flags to merge into trunk without exposing to users. Code ships; features activate on a schedule.
  • No long-lived auxiliary branches: No develop, staging, integration, or release branches. All these patterns introduce delay and complexity without benefit.

Branch Naming Convention

<type>/<jira-ticket>-<short-description>

Examples:
  feat/PROJ-1234-add-discount-codes
  fix/PROJ-5678-correct-vat-calculation
  chore/PROJ-9012-upgrade-spring-boot-3-2
  docs/PROJ-3456-update-api-readme
  refactor/PROJ-7890-extract-pricing-service

Allowed types: - feat — new feature - fix — bug fix - chore — maintenance, dependency updates, config changes - docs — documentation only - refactor — code restructuring without behaviour change - test — adding or updating tests - perf — performance improvement

Merge Strategy

All branches merge to main via Squash and Merge — producing one clean commit per feature branch. This keeps the main history readable and each commit deployable.

Exception: Large refactors with multiple coherent commits that tell a story may use Rebase and Merge if the commit history adds value.

Merge commits are prohibited on main.


Feature Flags for Incomplete Work

When a feature takes more than a day to complete, the correct approach is to merge the partial implementation behind a feature flag — not to keep the branch alive.

# Feature flag check — implementation ships continuously; feature activates on schedule
if feature_flags.is_enabled("new-checkout-flow", user_id=request.user_id):
    return new_checkout_controller.handle(request)
else:
    return legacy_checkout_controller.handle(request)

Approved feature flag tools: - LaunchDarkly (primary) - AWS AppConfig (approved for AWS-native services) - Simple database/config flags (approved for simple boolean flags with infrequent changes)

Feature flags must be: - Logged when evaluated (log.debug("Feature flag 'x' evaluated: {}", result)). - Removed within 30 days of the feature being fully rolled out. Stale flags are technical debt. - Tracked as Jira tickets for their eventual removal.


Release Branching (Regulated Products Only)

For products with formal release cycles or regulatory change control requirements, a controlled release branching model is permitted with explicit Architecture Team approval.

Permitted Release Model

main ──────────────────────────────────────►
         │                    │
         └─ release/2025.3 ──►└─ release/2025.4
              (hotfixes only)     (hotfixes only)

Rules: - Feature development still happens on short-lived branches from main. - Release branches are cut from main at a designated stabilisation point. - Only hotfixes go onto release branches — never new features. - Hotfixes applied to a release branch must be cherry-picked back to main immediately. - Release branches are read-only after the release ships (no new commits; create the next release branch for the next cycle).


Protected Branch Configuration

Required branch protection rules on main (enforced in GitHub/GitLab):

Rule Setting
Require pull request before merging ✅ Enabled
Required approvals Minimum 1 (2 for critical services)
Dismiss stale approvals on new push ✅ Enabled
Require status checks to pass ✅ Enabled (CI pipeline, SonarQube)
Require branches to be up to date ✅ Enabled
Restrict who can push directly Only admins (never engineers)
Require signed commits ✅ Enabled

Branch Hygiene

  • Delete branches after merge. GitHub/GitLab is configured to auto-delete merged branches. No exceptions — stale branches create confusion.
  • Rebase before merge to resolve conflicts. Never merge main into your branch (merging creates a noisy history). Always git rebase origin/main.
  • Branches older than 3 days without a merged PR will be flagged in the weekly #engineering digest.

When Not to Use TBD

TBD is not appropriate for:

  • Open source or external contribution workflows — use fork + PR model.
  • Emergency hotfixes to a release branch — apply directly to the release branch, then cherry-pick to main.

References


Last reviewed: 2025-Q4  |  Owner: Engineering Enablement