

- Description
- Une branche qui se divise en deux, prise dans un manchon de glace sur fond de ciel bleu.
- Source
- Velatrix · original page
- Licence
- CC0 Public domain
Branching Strategies
Understand why we branch, and what a branch that lives too long costs.
In brief
- Understand why we branch, and what a branch that lives too long costs.
- Know the reference strategies: trunk-based, GitFlow, GitHub Flow, GitLab Flow, release branches, branches by product version.
- Know how to apply this to the TFVC world (Main/Dev/Release, merges, baseless) and to release snapshots.
- Use feature toggles to decouple merging and delivery.
- Choose a strategy for a SQL/BI project, with /5 ratings by context.
Level: 🟢→🔴
Why branch#
🟢 Novice level
A branch isolates a development line: you work on an evolution without disturbing stable code. We branch for three reasons: isolate work in progress (feature, fix), stabilize (prepare a version while development continues), maintain (fix a version already delivered). A project without branches works on a single trunk; an over-branched project spends its time merging.
The cost of a branch#
🟢 Novice level
Branching is free; merging is not. The cost of a merge grows with how long branches diverge and the number of files touched on both sides. Two effects:
- Textual conflicts: same lines modified.
- Semantic conflicts: code merges without conflict but no longer works (column renamed on the SQL side, new use of the old column on the report side). These are the most expensive, because no tool flags them.
A 3-day feature branch accumulating 12 modified files on an active trunk merges in 15 to 30 minutes. The same branch left for 6 weeks takes several hours, with regression risk. The relationship is not linear—that is the key message.
Rule of thumb: integrate into trunk at least once a day or every two days; any branch older than one week must be justified.
Trunk-based development#
🟡 Practical level
Principle: everyone integrates into a single trunk (main), through very short branches (hours to 1-2 days) or directly. Unfinished features are hidden by feature toggles. A release branch is cut only to stabilize/maintain.
Prerequisites: fast and reliable CI, automated tests, lightweight review (or pair programming), discipline around small commits. In delivery performance literature (DORA research, Accelerate), this practice is the one most associated with better delivery metrics.
Strengths: minimal merges, true continuous integration, visibility. Limits: requires test maturity; difficult with deliveries in separate packages with long maintenance without release branches; uncomfortable when trunk cannot break (no reliable CI).
GitFlow#
🟡 Practical level
Model published by Vincent Driessen in 2010: permanent branches master (production, labeled main in the diagram) and develop (integration), temporary branches feature/*, release/*, hotfix/*.
main ──●────────────────●─────────●── (tags v1.0, v1.1)
\ / /
release \ ●──●──● /
\ / /
develop ──●───●──●──●──●───●──●──●────
\ / \ /
feature ●─● ●──●──●
Strengths: clear framework for planned versions at a slow pace, parallel maintenance of multiple versions. Limits: heavy (two permanent branches, multiple merges), delays integration, discouraged by its own author for continuously delivered applications (note added by the author to his article in 2020). Still relevant for versioned products delivered as packages.
GitHub Flow#
🟡 Practical level
Very simple: main is always deployable; you create a short branch, open a pull request, review, test, merge, deploy. No develop, no release branches. Suited to an application in continuous deployment and a small to mid-sized team. Insufficient when you must maintain multiple versions installed at customers.
GitLab Flow#
🟡 Practical level
Variant: environment branches (staging, production) or release branches (release/9.1) downstream from main. Changes go from main downstream only (“upstream first”: fix first on main, then backport). A compromise between GitHub Flow simplicity and the need for maintained versions. Often the best starting point for a product team.
Release branches#
🟡 Practical level
A release branch (release/9.1) is cut when the version is “almost ready.” On it: only fixes (no new features). Meanwhile, main continues toward the next version. Golden rule: fix on the oldest affected branch, merge forward (or “upstream first” then backport via cherry-pick with -x if models diverge).
Cycle: main → release/9.1 (cut) → hardening, fixes → tag v9.1.0 → later fixes 9.1.1, 9.1.2 on the same branch → end of support.
Branches by product version#
🟡 Practical level
For a product delivered to customers who stay on different versions (typically 8.0, 8.1, 9.0, 9.1…), each maintained version has its own branch (or folder), with a long lifespan. Two variants:
| Variant | Principle | Advantage | Disadvantage |
|---|---|---|---|
| Live maintenance branches | release/9.0, release/9.1 receive fixes; merge forward |
One source of truth per version, continuous history | Cascading merges (9.0 → 9.1 → main), risk of omission |
| Frozen “snapshots” | At each delivery, a copy of the tree is archived (folder Releases/9.1/); changes enter only through explicit fixes |
Simple reproduction of a version, zero surprises | Duplication; fixes copied manually; silent drift between snapshots |
The “snapshots in folders” model is common in TFVC (branches are folders there). Its flaw: no merge relationship between folders if they were copied instead of branched; each multi-version fix then becomes a manual hand cherry-pick operation (or baseless merge), with no trace of what has already been propagated. Remedy: keep the branch relationship (declared TFVC branches or Git branches), and maintain a fix propagation matrix (which defect fixed in which versions).
A fix for a KPI calculation is discovered in 9.1. It must reach 9.0, 8.1, and main. With Git branches: commit on release/8.1, merge to 9.0, 9.1, main: one single commit, tracked. With copied folders: four manual edits, four risks of omission or divergence, four acceptance testing runs.
Minimum propagation matrix (to keep in the ticket or release page):
| Defect | 8.1 | 9.0 | 9.1 | main |
|---|---|---|---|---|
| #A — coverage calculation | ✅ CS/commit | ✅ | ✅ | ✅ |
| #B — multilingual label | n/a | ✅ | ✅ | ✅ |
| #C — customer join | ❌ not applicable (different model) | ✅ | ✅ | ✅ |
Mark explicitly “not applicable” with the reason; a defect absent from a version must be a choice, not an oversight.
TFVC and standard branches#
🟡 Practical level
The historical Microsoft guide (Branching and Merging Guide, Visual Studio ALM Rangers) describes models: Main Only (single trunk); development isolation (Main + Dev); feature isolation (Main + Feature); release isolation (Main + Release); maintenance and release isolation (Servicing + Release). The “code promotion” model is no longer recommended there. In short:
$/Projet
Main (stable integration)
Dev (current development)
Feature-ABC (short branch)
Releases
R9.0 R9.1 (maintenance)
Rules of the standard model:
- Upstream/downstream flow: Dev → Main (RI, reverse integration), Main → Dev (FI, forward integration). A lateral merge (R9.0 → R9.1) is not allowed without passing through Main, except baseless.
- Integrate often into Dev to reduce drift; reintegrate in tested batches into Main.
- Release branches created from Main at freeze time; fixes on the release then merged into Main (reverse integration) to avoid regressions.
- Baseless merges (
tf merge /baseless): outside branch relationship; reserved for special cases (see 03). Each baseless merge is a roll of the dice on conflicts.
/5 ratings of the TFVC “Main + Releases” structure for a product maintained across 4 versions (team of 5-15):
| Criterion | Rating | Rationale |
|---|---|---|
| Version isolation | 5/5 | Separate folder, folder-level permissions |
| Fix propagation | 2/5 | Manual merges, baseless if copied |
| Readability | 4/5 | Visible folder tree |
| Cost of a new release | 3/5 | Simple server-side branch, but growing surface area |
| Back-merge and traceability | 3/5 | Hierarchy visualization in Visual Studio |
Feature toggles#
🔴 Expert level
A feature toggle (feature flag) allows you to merge unfinished code without activating it. It decouples deployment and go-live. Types: release toggle (short term, hides a feature in progress), ops toggle (disable in an emergency), experiment toggle (A/B), permission toggle (by client).
Data/BI application:
- Parameter
_Parameterin the database that activates a new calculation or a new join; the same procedure contains both paths, selected by parameter (tested on both sides); remove the old path and the parameter once validated. - DAX measures in parallel (old/new) with switching via field parameter or calculation group, without deleting the old one (client reports remain linked to the existing one).
- Hidden report pages for a feature in acceptance testing (reminder: “hidden” is not “inaccessible”).
Cost: toggle debt (dead code, test combinatorics). Each toggle has a removal date and an owner.
Symptom: no one knows anymore which parameters are active for which client; cause: toggles never removed. Remedy: toggle registry, quarterly review, scheduled removal.
Strategies for SQL and BI#
🔴 Expert level
Specifics that change the answer:
- Deployment is not code: a database schema carries state (data, existing tables); two branches that modify the same table produce conflicting migrations even if the files do not touch. See 06.
- Reports are coupled to the model: a column renamed in SQL breaks the semantic layer and reports. Branch in vertical slices (SQL + model + report together) in a monorepo, or coordinate PRs.
- BI files merge poorly (
.pbix): PBIP/TMDL format to enable merging (see 06). - Multiple versions installed at client sites: maintenance branches or snapshots; installation kits by version.
- Business acceptance testing: validation on numbers requires environments; the “release” branch must have its test environment.
- Partial continuous integration: you cannot always fully rebuild the whole datamart on every commit; plan a partial load test (sample) on each PR and full rebuild at release (CI/CD for Data: Databases, Datamarts, Pipelines, and Reports).
General recommendation for a 5 to 30-person team on a datamart + BI with maintained versions: “lightweight” trunk-based (short branches, PRs) + release branches per maintained version + fix first on the oldest affected branch and merge forward + signed tags + propagation matrix.
Ratings by context#
🔴 Expert level
Ratings /5; criterion: fit of the strategy to each context (see RATING). Reading: a low rating is not a flaw, it is a poor match.
| Strategy | Team 3-5, single product continuously | Team 10-30, maintained versions (kits) | Data/BI project, coupled reports | Team new to VCS | High audit requirement |
|---|---|---|---|---|---|
| Trunk-based | 5/5 | 3/5 | 3/5 (if partial CI) | 2/5 | 3/5 |
| GitHub Flow | 5/5 | 2/5 | 3/5 | 5/5 | 3/5 |
| GitLab Flow (release branches) | 4/5 | 5/5 | 4/5 | 3/5 | 4/5 |
| GitFlow | 2/5 | 4/5 | 3/5 | 2/5 | 4/5 |
| Folder snapshots (without branch relationship) | 2/5 | 2/5 | 2/5 | 4/5 | 3/5 |
| TFVC Main/Dev/Release | 3/5 | 4/5 | 3/5 | 4/5 | 4/5 |
Conventions and protections#
🟡 Practical level
- Naming:
feature/<ticket>-<subject>,fix/<ticket>-<subject>,release/<version>,hotfix/<version>-<subject>. - Protections:
mainandrelease/*forbid force-push and deletion; mandatory PR with at least one reviewer; validation build; link to a work item; comment resolution. - Merge: squash for short feature branch, merge commit to preserve release topology, rebase for linear history. Choose one convention per branch type and document it.
- Versioning: semantic versioning
MAJOR.MINOR.PATCH; annotated (signed) tag per delivery; release branch deleted only at end of support. - Lifespan: automatic deletion of merged feature branches.
Pitfalls#
🔴 Expert level
- ⚠️ Pitfall — Eternal “Dev” branch: the integration branch drifts from trunk; each reintegration becomes a project. Remedy: merge often, or remove Dev.
- ⚠️ Pitfall — Cherry-pick without trace: the same fix exists under four IDs; later merges flag it again as a conflict. Remedy:
-x, propagation matrix, upstream-first fix. - ⚠️ Pitfall — “Open” release branch: features get slipped into it. Remedy: “fixes only” policy, PR enforcement.
- ⚠️ Pitfall — Unseen semantic merge: tests green, numbers wrong. Remedy: acceptance testing on three business totals before tagging.
- ⚠️ Pitfall — Wrong tool for the problem: GitFlow for a 4-person team in continuous deployment; GitHub Flow for 4 maintained versions.
- ⚠️ Pitfall —
Releases/folder copied manually: see above, no merge relationship.
AI helps draft conventions, generate scripts for branch protection (platform API), suggest the propagation matrix from history, and spot divergences between branches (git cherry). Guardrails: it does not know your support policy; the decision to backport or not remains human; verify destructive commands. See AI in Planning and Version Control Tools.
See also#
- Git In Depth · TFVC In Depth · Git vs TFVC: Compare, Migrate, and Coexist · VCS and SQL / BI
- Matrix: version control and branching
- CI/CD · CI/CD for Data: Databases, Datamarts, Pipelines, and Reports
- Glossary
✻ Written by Claude Sonnet 5.5