ManagementAll levels

Git Branching Strategy

A Git branching strategy is the agreement on how a team splits its work into branches and rejoins them. The choice looks like a matter of taste and is not: the variable that predicts pain is how long a branch lives before it merges, and every model is a position on that number plus a rule for where releases and fixes come from. The page opens with six models on one screen and the five questions that choose between them, then covers branch lifetime, where each model came from and what its authors said later, release branches and the way a fix travels, what makes short branches possible, merge versus rebase versus squash, and where it degrades.

What matters
Branch lifetime
DORA finding
≤ 3 active branches, merged daily
A fix is made
On main first, then cherry-picked

Six models on one screen — and the questions that choose

Most people who look up branching strategies want the comparison and a way to choose. Here are the six models you will meet, compared on the four things that actually differ between them: which branches live long, where a release comes from, where a fix is made first, and how long an ordinary branch lives.

ModelLong-lived branchesA release comes fromA fix is made first onAn ordinary branch livesFits
1. Trunk-basedmain onlymain, or a tag on itmainHours, under a dayOne live version; fast tests that are trusted
2. Trunk with release branches — Google, Microsoft’s Release Flowmain; a branch per release, never merged backThe release branchmain, then cherry-picked to the release branchHours to a day or twoScheduled deploys; two versions live during a rollout
3. GitHub Flowmain onlymain — GitHub itself deploys the branch before merging itA short branch off mainA day or a fewMost product teams, with review on every change
4. GitLab Flowmain, plus a branch per environment or per supported versionThe downstream branchmain, then downA day or a fewEnvironments that must lag one another
5. GitFlowmain and develop; release and hotfix branchesA release branch off develop, merged into mainA hotfix branch off main, merged into main and developWeeksInstalled software with several supported versions
6. Maintainer trees — LinuxEach subsystem maintainer’s tree; linux-next merges them all dailyThe mainline, after a two-week merge windowThe subsystem tree, then mainline, then the stable kernelsOne release cycle, two to three monthsThousands of contributors and a hierarchy of maintainers

The table compares; the questions below choose. Answer them in order, and stop at the first answer that rules a model out. Later sections cite them by number.

  1. 1.How many versions are live at once?

    1. One — model 1 or 3; release branches would only add cherry-picks
    2. Two, briefly, while a rollout is in progress — model 2
    3. Several, for months, each one patched — model 2 or 5, and price the back-porting first
  2. 2.Can `main` be deployed at any moment?

    1. Yes: tests run in minutes and people believe them — model 1 is open to you
    2. No — fix the tests before changing the model; a longer branch hides an unreliable main, it does not cure it
  3. 3.How long does a pull request wait for its first review?

    1. Hours — branches can be short in any model
    2. A day or more — branches will be long in every model, whatever its diagram says
  4. 4.Must environments lag one another?

    1. No — deploy from main
    2. Yes — promote one tested build through the environments; a branch per environment, model 4, is the fallback when a build cannot be promoted
  5. 5.Is a release approved by someone outside the team — a store review, a certification?

    1. No — release from main or from a tag
    2. Yes — cut a release branch at the point of approval, and make every fix on main first

Branch lifetime is the whole story

A branch is a bet that the rest of the codebase will not change in a way that conflicts with your work. That bet is cheap for a day and expensive for a month, because conflict risk grows with both the size of your change and the number of changes everyone else lands while you are away.

All three models are drawn to the same scale, so the only difference visible is how far a branch travels before rejoining main. Trunk-based rejoins within a day, GitHub Flow within a few days, GitFlow after weeks — and conflict risk grows with that distance.

The trap is that the cost is invisible while it accrues. A branch open for three weeks feels productive every one of those days; the price arrives all at once at merge, as a conflict resolution nobody estimated and a regression nobody predicted. The arithmetic for a team of eight that merges about fifteen changes a day into main shows how fast it grows.

Branch open forLanded on main meanwhileWhat the merge feels like
Four hours≈ 3 changesA rebase that applies cleanly
Two days≈ 30 changesA conflict or two, resolved by an author who still remembers both sides
Two weeks≈ 150 changesA merge that needs its own review, and a regression found after it
Two months≈ 600 changesA project of its own; often rewritten rather than merged

Jez Humble turned that into a three-question test, which Martin Fowler published in January 2017. Does every member of the team push to a shared mainline at least daily? Does every such commit trigger an automated build and tests? When the build breaks, is it usually green again within ten minutes? A team that answers no to the first is not doing continuous integration, whatever its pipeline is called.

’s research of 2016 and 2017 put numbers on it. Teams with higher delivery performance had three or fewer active branches in the application’s repository, merged branches to trunk at least once a day, and had no code freezes and no integration phases. The obstacles DORA lists are the ones this page returns to: review processes that need several approvals, asynchronous reviews that leave branches waiting, and tests that are not run before a commit.

Where each model came from — and what its authors said later

Branching models are usually taught as timeless patterns. Each was written by a particular team for a particular situation, and three of the authors later said in writing where their model stops fitting. Six episodes, in order.

Linux, 2005 and 2008 — many branches, merged every day

Linus Torvalds wrote Git in April 2005 for the Linux kernel, and the kernel’s process is the oldest model here. Each subsystem has a maintainer with their own tree. A release cycle opens with a merge window of about two weeks, in which Torvalds pulls the maintainers’ trees into the mainline. After it only fixes are accepted. come about once a week, normally up to -rc6 to -rc9, and a new kernel ships every two to three months with about 13,000 changesets.

Trees that live for months would be integration hell on their own. What prevents it is linux-next, which Stephen Rothwell started in February 2008. Every working day it merges all the subsystem trees together, builds the result and publishes it, so conflicts between trees surface weeks before the merge window. The lesson is the one this page keeps returning to: what matters is not how many branches exist, but how often they meet.

GitFlow, 2010 — and its author’s note of 2020

Vincent Driessen published “A successful Git branching model” on 5 January 2010. It has two permanent branches: main (then master), which always reflects production, and develop, where finished work is integrated. Feature branches leave develop and return to it. A release branch leaves develop while a release is prepared and merges into both main and develop. A hotfix branch leaves main and merges into both — or into the release branch, if one exists at the time. Every merge uses --no-ff, so each feature stays visible as a group of commits.

On 5 March 2020 Driessen added a note of reflection to the top of the post. In short, it says the model was written for explicitly versioned software, that continuously delivered web applications had become the common case, and that for those he would suggest a simpler workflow such as GitHub Flow. The model was never wrong. It answered the question of a team shipping version 2.4 while still supporting 2.3 — and most teams that adopted it did not have that question.

GitHub Flow, 2011 — and then deploying before merging

Scott Chacon described GitHub’s own process on 31 August 2011, in reaction to GitFlow being more than most teams need. It has six rules. Anything in main is deployable. New work goes on a descriptively named branch off main. Push that branch to the server regularly. Open a pull request when you want feedback or think the work is ready. Merge only after someone has reviewed it. Deploy immediately after merging. GitHub then deployed about two dozen times on a typical day.

By 2015 GitHub had swapped the last two rules for its own site. Aman Gupta described it in June 2015: new code is deployed from the pull request’s branch, and merged only once it has been confirmed in production. If a branch deploy goes bad, the rollback is to deploy main again — which is always good, because nothing reaches it unproven. Microsoft’s documentation names the cost: every pull request waits in a deployment queue, which becomes the bottleneck once hundreds of pull requests land a day.

GitLab Flow, 2014 — and leaving the documentation in 2023

Sytse Sijbrandij, GitLab’s co-founder, proposed GitLab Flow on 29 September 2014 for teams that GitHub Flow does not fit because a deployment is not a merge. It adds downstream branches — one per environment, such as and production, or one per supported version. Commits flow only downstream, so every line is tested in each environment before it reaches the next. For fixes it states the rule this page recommends, which GitLab called “upstream first” and credited to Google and Red Hat: merge into main, then cherry-pick into the release branch.

In 2023 GitLab took the GitLab Flow page out of its product documentation: in version 16.0 it became a general introduction to Git workflows, and from 16.4 it redirects to a blog post. The idea survives, but environment branches have a weakness the original did not dwell on. The build deployed to production is not the build that was tested in staging; it is a fresh build of a merge. That is why question 4.2 prefers promoting one tested build from environment to environment, on a single branch.

Google, 2016 — one trunk for 25,000 engineers

In July 2016 Rachel Potvin and Josh Levenberg described Google’s repository in Communications of the ACM: one repository of about two billion lines of code and 35 million commits, used by more than 25,000 engineers. Development on branches is unusual there and not well supported. New and old code paths live side by side behind conditional flags. Releases are cut as branches from a chosen revision, and fixes are made on mainline and then cherry-picked into the release branch. It is the strongest evidence that trunk-based development scales: the tooling had to be built for it, but the branching model did not change with size.

Microsoft, 2018 — Release Flow

Edward Thomson described the Azure DevOps team’s model in April 2018 and named it Release Flow. Developers work on short topic branches merged into main through pull requests, and the busiest repositories take more than 200 pull requests a day. main is never deployed directly. At the end of each three-week sprint a release branch is cut — at sprint 129 it is releases/M129 — and that branch is deployed. Release branches never merge back into main.

A hotfix starts on main, always, and is then cherry-picked into the release branch from the pull request page. Microsoft’s documentation gives the reason in a sentence worth pinning to a wall: fixing the release branch without bringing the change to main means the bug recurs at the next deployment, and it is easy to forget main in the stress of an outage. During a ring-by-ring rollout two release branches are in production at once, so a fix made in that window goes into both.

Release branches — and which way a fix travels

A release branch exists for one reason: to let main move on while one version is stabilised, shipped and patched. Everything else about it follows from one decision — where a fix is made first. The two answers produce very different failures.

The same bug, fixed in two orders. Made on main first and cherry-picked to the release branch, the fix is in every release cut afterwards. Made on the release branch first, it depends on a merge back that is easy to forget during an incident — and when it is forgotten, the next release ships the bug again.
PathHow it worksWhat goes wrongWho uses it
Upstream firstFix on main with a test, then cherry-pick into each release branchA fix that does not apply cleanly to an older branch needs rework thereGoogle, Microsoft’s Release Flow, GitLab Flow, the Linux stable kernels
Release first, merge backFix on the release or hotfix branch, then merge it into main and developThe merge back is forgotten under pressure, and the bug returns in the next releaseGitFlow

Upstream first has one honest exception. Sometimes a bug cannot be reproduced on main, because the code there has moved on. Then the fix is made on the release branch, and the reason it never reached main is written down, because main does not need it. Everything else goes to main first.

The price of supported versions

Every supported version is a branch that a security fix must be applied to separately, tested against separately and released separately. That work is the real cost of release branches, and no diagram of a model shows it. Count it before agreeing to support one more version.

Supported versionsOne urgent security fix means
1One change, one pipeline run, one release
2One fix, one cherry-pick, two test runs, two releases
4One fix and three cherry-picks — at least one will not apply cleanly to code two years older — then four test runs and four releases

That is why projects that support several versions publish exactly how many and for how long. Node.js, Java and the Linux kernel all name their lines and their end dates. A team with three customers on three versions has the same problem without the policy, and usually finds out during an incident.

What makes short branches possible

Teams rarely choose long branches on purpose. They end up with them because something makes merging early impossible, and the model gets the blame for the symptom. Four things are usually the actual cause, and question 3 asks about the first.

Review latency and change size

If a pull request waits a day and a half for a reviewer, nobody opens small ones — the round-trip cost is fixed, so the rational move is to put more into each. That makes reviews larger, which makes them slower, which makes batching more attractive. The loop reinforces itself, and it is the most common reason a team cannot get branch lifetime down.

Slow review and big pull requests feed each other. When a review takes a day and a half, the rational move is to put more into each pull request; bigger pull requests are started later and take longer; and the wait grows. Two team rules break the loop — a review turnaround measured in hours, and a size at which a reviewer may ask for a split.

The best published data on what fast review looks like comes from Google. Its 2018 study of about nine million reviewed changes found a median wait for first feedback of under an hour for small changes and about five hours for very large ones, and a median of under four hours for the whole review. Fewer than a quarter of reviews had more than one approver. Speed and size are one finding, not two.

The fixes are unglamorous: a stated expectation for review turnaround, measured in hours; a size at which a reviewer may ask for a split; and pairing or ensemble work for changes that would otherwise be too big to review at all. Trunk-based development does not skip review. It moves it, either into pairing in real time or into a review fast enough not to bend the workflow around itself.

Unfinished work behind a flag

A branch often stays open simply because the feature is not finished, and nobody wants half a feature in main. A answers that: the code merges every day and stays switched off until it is complete. The cost is the flag itself, which must be removed once the feature is fully on — the release planning page covers the four kinds of flag and how long each should live.

Big changes without big branches

The usual objection to short branches is the large refactor — replacing a payment provider, swapping an , restructuring a module. Branch by abstraction answers it; Paul Hammant named the technique in April 2007. Introduce an interface in front of the thing being replaced. Move callers onto the interface, one merge at a time. Build the new implementation behind it, switch over, then delete the old one. Every step is a small change that can be merged on its own, and the codebase can be released at each of them.

Keeping main green when many people merge

Short branches raise a new problem. Two pull requests can each pass their checks and still break main together, because neither was tested with the other. Graydon Hoare, the creator of Rust, called the answer the “not rocket science rule”: automatically keep a repository of code that always passes all its tests, by testing each change merged with the current main before it lands. A merge queue does exactly that. GitHub’s became generally available in July 2023, and GitLab calls the same thing merge trains.

Merge, rebase or squash

This argument consumes more team energy than it deserves. All three land the same code on main; what differs is the history left behind, and what that history can still tell you a year later.

Merge, rebase and squash put identical code on main and leave different histories. A merge commit keeps both lines exactly as they happened; a rebase replays the commits in a straight line with new IDs; a squash leaves one commit per branch. None of them changes delivery outcomes, so pick one, write it down, and never rewrite a branch someone else has built on.
WayMain’s history afterwardsKeepsLosesSafe when
Merge commitBoth lines, joined by a merge commitExactly what happened, and whenReadability on a busy repositoryAlways
Rebase, then fast-forwardA straight line, the branch’s commits on topEvery commit, rewrittenThe original commit IDs, and the base each was written againstThe branch is yours alone
SquashOne commit per branchOne change per unit of work, easy to revertThe intermediate stepsBranches are short and each is one idea

None of the three measurably affects delivery outcomes: pick one, write it down and stop discussing it. One practical difference is worth knowing. git bisect finds the commit that broke something by halving the history, and it works best when every commit on main builds and passes. Squash merges and a merge queue both guarantee that. A rebase of twenty work-in-progress commits does not.

What does matter is a rule most teams agree on without arguing: never rewrite history on a branch someone else has based work on. Rewriting your own branch before review is fine. If you must force-push it afterwards, use git push --force-with-lease, which refuses when someone else has pushed in the meantime. Rewriting a shared branch breaks everyone who built on it, and unlike the aesthetic question, that is not a matter of preference.

How this shows up in real delivery — and where it degrades

Branching strategy is where team process meets engineering practice, and it exposes gaps in the latter mercilessly. A team cannot move to short-lived branches if its test suite takes forty minutes and is , because nobody will merge six times a day into a signal they do not trust. The branching model is usually a symptom; the test suite is usually the cause.

Where it degrades

  • A feature branch open for a month, so the merge is a project of its own.
  • GitFlow adopted for a web app with one live version, adding ceremony that serves nothing — its author said so in 2020.
  • A develop branch in front of main, so every change is integrated twice.
  • A branch per developer, which turns integration into a periodic negotiation.
  • A hotfix applied to the release branch and never merged back, so it returns as a bug.
  • Environment branches that rebuild the code for each environment, so production runs a build nobody tested.
  • Release branches kept alive long after their version left production.
  • Short branches without feature flags, so half-built work is either merged broken or held back.
  • Rewriting history on a shared branch, which breaks everyone who had based work on it.

When to use it

Use it when

  • Choosing trunk-based when exactly one version runs in production and tests are fast and trustworthy.
  • Choosing GitHub Flow as a sane default for a product team that reviews every change.
  • Adding release branches, fixed upstream first, when deploys are scheduled or a store or a certifier approves each release.
  • Choosing GitFlow when several released versions must be supported and patched in parallel.
  • Pairing short branches with feature flags so unfinished work can merge safely.

Avoid it when

  • Moving to trunk-based while the test suite is slow or flaky — fix that first.
  • Adopting GitFlow because it is familiar rather than because you ship versions.
  • Adding branch types to solve a review or ownership problem — that is a process fix, not a Git one.
  • Supporting more released versions than the back-porting effort can actually carry.
  • Changing the model without changing what made the old one painful.

Sources and method

What this page stands on

  • 17 sources
  • Checked October 12, 2026

Researched with Claude. Finding and cross-checking the primary sources was done with Claude (Anthropic). Selection, writing and fact-checking: the Anatomy of IT Product editors.

Found this useful?

Share it with someone who is working on the same problem.