Branching Strategy for Teams That Actually Ship

Software Delivery git, release

Trunk-based, GitHub flow, GitFlow, release branches: which one fits which team size, with the lead-time numbers that decide it instead of opinion.

  • By Orzed Team
  • 7 min read
Key takeaways
  • Trunk-based suits teams shipping at least daily. Below that frequency it adds friction without payback.
  • GitHub flow is the right default for most product teams: short-lived branches, single main, deploy on merge.
  • GitFlow is the right answer for shipped-binaries (mobile, desktop, embedded) and almost no one else.
  • Release branches are a parking lot for risk. Use them when you must, retire them as fast as you can.

The branching strategy debate is one of those engineering decisions that gets argued in the abstract by people who have never actually felt the pain of either side. We have inherited every shape of git history on client engagements: trunk repositories with thirty engineers committing to main hourly, GitFlow setups with six concurrent release branches, GitHub flow with feature branches that quietly aged into long-running forks. None of those are wrong in principle. All of them are wrong for at least one team that adopted them.

This piece is the practical version of the trade-off. The numbers we measure when we walk into an engineering team that wants to fix its branching, and the strategy that those numbers usually pick.

The four real options

The actual branching models in use across teams that ship software:

Trunk-based development. A single branch (main or trunk). Engineers commit directly or through very short-lived PRs (under a day). Incomplete work is hidden behind feature flags. Deploys happen many times a day from main.

GitHub flow. A single long-lived branch (main). Feature branches are short (one to five days), opened with a PR, reviewed, merged, deployed. No release branches, no develop branch.

GitFlow. Long-lived main plus long-lived develop, plus release branches and hotfix branches. Originally designed for shipped software with versioned releases. Heavy ceremony.

Release branches off trunk. A simpler variant of GitFlow: trunk is the source of truth, but release-vX branches are cut from trunk for staging, hardening, then promoted to production. Useful for shipped binaries.

The wrong question is “which is best.” The right questions are “what cadence does your team ship at, and what is the cost of an incident.”

The numbers that pick the strategy

We measure four things on every engineering team before we recommend a branching change:

MetricWhat it tells you
Deploy frequencyHow often the team puts a change in front of users
Median PR lifetimeHow long work sits between first commit and merge
Change failure rateWhat percent of deploys cause an incident or rollback
Mean time to recoveryHow long it takes to recover from a deploy-related incident

These four come from the DORA research and remain the cleanest framing we have found for branching decisions. The matrix below is what the numbers usually say:

Deploy frequencyMedian PR lifetimeRecommended strategy
Multiple per dayUnder 4 hoursTrunk-based with feature flags
Daily to weekly1 to 5 daysGitHub flow
Weekly to monthly5 to 14 daysRelease branches off trunk
Less than monthlyOver 14 daysGitFlow (only if shipping binaries)

The mismatches are the source of most pain. A team deploying weekly with trunk-based discipline ends up with feature flags they never clean up. A team deploying multiple times per day with GitFlow spends hours per week on merge management that yields no value. Pick the strategy that fits your cadence, then change cadence and strategy together if you need to.

When trunk-based actually works

Trunk-based is the highest-output branching model when its prerequisites are present. Those prerequisites are non-negotiable:

  • Every commit to main must be deployable. The build is green, the tests pass, the artefact ships.
  • Every incomplete feature must be hidden behind a flag. The flag system has to work, with per-environment toggles and per-user overrides.
  • Code review must happen quickly (under four hours for non-trivial changes) or before-merge entirely.
  • The deploy pipeline must take less than fifteen minutes. Slower than that and engineers stop shipping multiple times per day.

When all four are present, trunk-based is what a healthy SaaS engineering team looks like. We see it work consistently in teams of five to fifty engineers running first-party SaaS with strong CI.

When one of the four is missing, trunk-based produces incidents. Half-finished features ship behind flags that nobody flips. PRs sit unreviewed for days. Builds take an hour and the team batches up commits to amortise. Each of these is a known failure mode and each gets attributed to “trunk-based does not work for our team,” when the actual issue is the missing prerequisite.

The honest test for whether your team can adopt trunk-based: can you ship a small, harmless change to production today, in under two hours, with code review, with no fear? If yes, trunk-based fits. If not, fix the pipeline first.

When GitHub flow is the default

GitHub flow is the most common shape across teams shipping a typical SaaS or web product. The branching is small (one main, short-lived feature branches), the ceremony is low (PR, review, merge, deploy) and the failure modes are easy to spot (PRs over a week old, feature branches that never merge).

The tells that GitHub flow is fitting badly:

  • Feature branches consistently age past a week. The work was scoped wrong, or the team is not splitting into smaller shippable pieces. The branching model is not the bug here; the work-shaping is.
  • Merge conflicts dominate the engineering rhythm. Either the team is over-touching the same files (a code architecture issue), or branches are too long-lived (back to scope).
  • Production incidents trace to “this got merged but did not get tested with X.” The CI is incomplete; GitHub flow assumes CI catches integration issues at PR time.

For a team of three to thirty engineers shipping daily to weekly, GitHub flow is the right default. Switching from it is usually a sign that something else (deploy pipeline, scope discipline) needs fixing first, not that the branching is wrong.

When release branches earn their keep

Release branches off trunk are the right answer for two cases. The first is shipped binaries: a mobile app submitted to a store, an embedded firmware blob, a desktop installer. The store or distribution channel enforces a versioned release; trunk cannot deploy itself there.

The second is regulated environments where a frozen branch is required for audit. We have seen this in healthcare and in financial services: the auditor needs to point at a specific commit and say “this is what was running on production on date X.” A trunk-only model with continuous deploy makes this answer “everything between commits A and B”; a release branch makes it “commit C, here is the diff.”

Release branches in any other case are a parking lot for risk. Code that is not in trunk is code that is not being integrated, and integration debt grows quietly until the merge becomes unmanageable. The right discipline is to keep release branches as short-lived as the constraint allows: cut at code freeze, harden for a week, promote, delete.

When GitFlow is the answer (and when it is not)

GitFlow was designed for a specific era: shipped binaries, fixed-version releases, multi-month cycles. It still fits in those contexts: long-lived develop branch as integration target, release branches for hardening, hotfix branches for patches. The ceremony is heavy because the cost of a bad release is heavy.

For a team shipping a SaaS product weekly, GitFlow is almost always wrong. The develop branch becomes a place where work goes to die between releases, the merges from release back to develop create periodic conflict storms, and the hotfix branches accumulate because the slow normal-flow path makes urgent fixes feel exceptional.

We have walked into exactly two engagements where GitFlow was the right answer and we kept it. Both were shipping firmware to physical devices on quarterly release cycles. Every other GitFlow team we have advised, we have helped migrate off.

The migration that matters most

The single migration we find ourselves doing repeatedly: a team shipping daily but using GitFlow because someone set it up three years ago when the team shipped quarterly. The branching model never updated when the cadence did, and the team is paying weekly for ceremony designed for quarterly releases.

The migration is mechanical: collapse develop into main, retire long-lived release branches, switch to feature branches off main, keep hotfix as a process not a branch shape. The cultural part is harder: the team needs to internalise that there is no “release” to harden anymore, the deploy is the release.

For a team that has been on GitFlow for years, the cultural shift takes a quarter. The mechanical shift takes a day. Both are easier than the team imagines, because the friction they have been absorbing is invisible until it stops.

What never matters as much as the team thinks

Branching naming conventions. PR template length. Whether merges are squashed or rebased. The colour of the GitHub Actions badge. These get debated as if they were branching strategy. They are paint colour, not architecture. Pick a defensible answer, write it down once, and stop talking about it.

The branching model is one of the small number of decisions where getting it wrong costs the team an hour every day forever, and getting it right buys back time the team did not realise they were spending. Pick by the numbers, revisit when the cadence changes, ignore the religious arguments.

Frequently asked

Questions teams ask

Is trunk-based development always the most modern choice?

No. Trunk-based requires either a feature flag system or the discipline to merge only completable work. Teams without either constraint will accidentally ship half-finished features to production and conclude trunk-based does not work, when the issue is that they skipped the prerequisites.

How long should a feature branch live?

Under five working days for product teams, under one day for trunk-based. Branches over two weeks accumulate merge debt that costs more to resolve than the branch itself was worth. Track the median PR age and treat outliers as a signal that the work was scoped wrong, not that the branching model is wrong.

Do we need release branches if we use feature flags?

Almost never. Feature flags decouple deploy from release, which removes the original argument for release branches. Keep release branches only when you ship binaries that cannot be flag-gated (mobile app store builds, firmware), or when a regulator explicitly requires a frozen branch for audit.