# Branching strategy decision matrix

Pick a branching model by answering the questions that actually decide it, not by preference.
Derived from the lesson [Choosing a branching strategy](https://moderngitacademy.com/workflows/branching/choosing-a-branching-strategy/).

*Modern Git Engineering Toolkit — Free Edition. https://moderngitacademy.com/*

## The five questions

| # | Question | Pushes towards |
|---|---|---|
| 1 | How often do you ship to users? | Daily or more → **trunk-based**. Weekly → **GitHub Flow**. Less often, in versions → **release branches** |
| 2 | How many versions are in use at once? | One → trunk-based / GitHub Flow. Several supported → **release branches** (or Git Flow) |
| 3 | Can you undo a bad change in minutes? | Yes → trunk-based is safe. No → gate with review and a **release branch** |
| 4 | How good are your automated tests, really? | Strong → trunk-based. Weak → you need review gates; **feature branches with required checks** |
| 5 | What must happen before code reaches production? | Nothing beyond CI → trunk-based. Sign-off, staging, compliance → **release branches** or environments |

## The models at a glance

| | Trunk-based | GitHub Flow | Release branches | Git Flow |
|---|---|---|---|---|
| Long-lived branches | `main` only | `main` only | `main` + `release/*` | `main`, `develop`, `release/*`, `hotfix/*` |
| Feature branch lifetime | Hours to a day | Days | Days | Days to weeks |
| Requires strong CI | **Strongly** | Yes | Helpful | Helpful |
| Requires feature flags | Often | Sometimes | Rarely | Rarely |
| Supports several live versions | No | No | **Yes** | Yes |
| Process overhead | Low | Low | Medium | **High** |
| Fits continuous deployment | **Best** | Well | Poorly | Poorly |
| Fits packaged / versioned software | Poorly | Poorly | **Best** | Well |

## Worked decisions

**SaaS web service, deploys several times a day, one version, strong tests, fast rollback.**
→ Trunk-based, squash merges, feature flags for anything multi-day.

**Mobile app, store releases every two weeks, must patch the previous release.**
→ GitHub Flow for day-to-day plus `release/x.y` branches cut at code freeze; hotfixes land on the
release branch and are merged forward.

**Library with semantic versions, three supported majors.**
→ Release branches per supported major; `main` is the next release. Git Flow's `develop` branch
adds nothing here.

**Team with weak tests inheriting a legacy system.**
→ Feature branches with required review and checks, short-lived; invest in tests before moving
towards trunk-based. Choosing trunk-based first would ship the weak tests' failures to users.

## The merge-method half of the decision

| Merge method | Produces | Choose when |
|---|---|---|
| Merge commit | Full branch history in the graph | You want to see that a branch existed and what it contained |
| Squash | One commit per pull request | Short branches; you want a bisectable, revertable `main` |
| Rebase and merge | Linear history, each commit kept | Commits are individually meaningful and reviewed as such |

Squash and long-lived branches do not mix: a three-week branch squashed is a commit nobody can
review or bisect. Lesson: [Squash merging](https://moderngitacademy.com/workflows/merging/squash-merging/).

## Combinations that work

- Trunk-based + squash + feature flags
- GitHub Flow + squash + required checks
- Release branches + merge commits on `main`, cherry-pick or merge-forward for fixes

## Combinations to avoid

- Git Flow for a service that deploys continuously (the `develop`/`main` split is pure overhead)
- Trunk-based without CI you trust (you have removed the gate that catches what tests miss)
- Rebase-and-merge with required signed commits (the rebase produces unsigned commits; the rule blocks the merge)
