Git, CI/CD & GitOpsXXIX · Branching StrategiesPolicy
The team-policy decision — choosing, documenting, enforcing, and changing the branching strategy
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
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
- Choose the strategy explicitly. Driven by cadence, deployment model, team size, regulation.
- Document in
CONTRIBUTING.md. Branches, merge verbs, force-push rules, configuration, exceptions. - Enforce via branch protection and CI checks.
- Audit the policy quarterly. A policy two years old may have drifted.
- 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
Q1. A team deploys continuously via a GitOps controller, has twelve engineers, and operates in an unregulated industry. Which strategy is the correct default?
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.
Q3. Name the four inputs to the branching-strategy decision.
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.