Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXIX · Branching StrategiesPolicy

The team-policy decision — choosing, documenting, enforcing, and changing the branching strategy

Advanced⏱ ~24 mingit

What you'll learn

  • Articulate the decision framework: release cadence, deployment model, team size, regulatory constraints
  • Document the chosen strategy in CONTRIBUTING.md with explicit branches, lifetimes, merge verbs, and force-push rules
  • Enforce the strategy via server-side branch protection and CI checks
  • Migrate from one strategy to another when the team's situation changes

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

Choosing a branching strategy is one of the most consequential decisions an infrastructure team makes. The choice determines how integration happens, how promotion happens, how the audit trail is structured, and how the GitOps controller is configured.

The choice must be made explicitly, documented, enforced via branch protection and CI, and revisited when the team’s situation changes.

The decision framework

Four inputs drive the decision:

  • Release cadence. Quarterly needs named versions; continuous needs always-deployable trunk. Primary driver.
  • Deployment model. Manual deploys allow human-action promotion. A GitOps controller cannot split its view.
  • Team size. Three engineers can coordinate without ceremony; thirty need more ceremony.
  • Regulatory constraints. Regulated industries may need named versions with audit trails.
flowchart LR
    A["release cadence"] --> D["strategy choice"]
    B["deployment model"] --> D
    C["team size"] --> D
    E["regulatory constraints"] --> D
    D --> R1["trunk-based"]
    D --> R2["trunk + release branches"]
    D --> R3["GitFlow"]
    D --> R4["environment branches (rare)"]

Choosing the strategy

The mapping from inputs to strategies:

  • Continuous deployment, small team, no regulation → Trunk-based. The default.
  • Continuous deployment, large team → Trunk-based with sub-team branches.
  • Scheduled releases with manual QA → GitFlow. Cadence drives the choice.
  • LTS support for named versions → Trunk + release branches.
  • Multi-tenant or regional divergence → Environment branches (rare).

Documenting the strategy

The strategy is documented in CONTRIBUTING.md. Specify: (1) branches with role and lifetime; (2) merge verbs per integration; (3) force-push rules; (4) configuration that enforces; (5) exception process.

cat >> CONTRIBUTING.md <<'EOF'
## Branching strategy

Trunk-based with release branches for LTS.

- `main` — Always deployable. Controller reads this.
- `feature/<ticket>` — Short-lived (hours). Cut from `main`.
- `release/v<major>.<minor>` — Long-lived.

Merge verbs: feature branches rebase onto `main`, merge with `--no-ff`.
Release branches cherry-pick from `main`; merge back with `--no-ff`.

Force-push: `main` no; feature branches `--force-with-lease` before review.

Config: `merge.ff = false` on `main` and `release/*`;
`pull.rebase = true` and `branch.autosetuprebase = local`.

Exceptions documented in PR description.
EOF

Enforcing the strategy

Three levels: documentation (CONTRIBUTING.md records the policy), branch protection (server-side enforcement of structural rules), and CI checks (behavioural rules: feature branches merge within 24 hours, release branches not more than 30 commits behind).

flowchart LR
    A["CONTRIBUTING.md"] --> D["policy"]
    B["branch protection"] --> D
    C["CI checks"] --> D
    D --> E["enforced policy"]

Each layer is necessary; none alone is sufficient.

Changing the strategy

The team’s situation changes over time. When inputs change, the strategy must change too. The migration: (1) adopt the new strategy going forward; (2) do not rewrite existing history — preserve OIDs, signed tags, artifact pins; (3) audit the policy quarterly.

cat >> CONTRIBUTING.md <<'EOF'

## Migration to trunk-based (effective <date>)

Migrating from GitFlow to trunk-based; `develop` is archived.
EOF

git branch -d develop
git push origin --delete develop

Production discipline

  1. Choose the strategy explicitly. Driven by cadence, deployment model, team size, regulation.
  2. Document in CONTRIBUTING.md. Branches, merge verbs, force-push rules, configuration, exceptions.
  3. Enforce via branch protection and CI checks.
  4. Audit the policy quarterly. A policy two years old may have drifted.
  5. Migrate forward when inputs change. History is preserved.

Cross-course references

  • CI/CD Pipeline Patterns - Part VII (PipelineGovernance) covers pipeline governance.
  • GitOps with Argo CD - Part VIII (MultiCluster) covers multi-cluster patterns.
  • Ansible for Production Sysadmins - Part XXXVII (RepoArch) covers repo architecture.

Quiz

Knowledge check · 4 questions

  1. Q1. A team deploys continuously via a GitOps controller, has twelve engineers, and operates in an unregulated industry. Which strategy is the correct default?

  2. Q2. A team that has chosen trunk-based development does not need to justify the choice in CONTRIBUTING.md; the strategy is the conventional default.

  3. Q3. Name the four inputs to the branching-strategy decision.

  4. Q4. Diagnose a team whose branching strategy has drifted from what CONTRIBUTING.md prescribes.

    A team adopted trunk-based two years ago. Branch protection on `main` is configured: no direct pushes, PR required, linear history. CI runs in eight minutes. Recently, the team has been creating long-lived feature branches (some live for two weeks), rebasing repeatedly, force-pushing. 30% of recent PRs were force-pushed after review started, breaking CI cache keys for downstream consumers.

Passing score: 75%. Answers are checked in this browser.