Few topics generate more heated debate in engineering teams than branching strategy. GitFlow has been the default for so long that questioning it feels heretical. But the data from the DORA research program and the daily practice of high-performing engineering teams points clearly in one direction.

Let’s settle the debate.

GitFlow: The Strategy

GitFlow, introduced by Vincent Driessen in 2010, defines a strict branching model:

main         ───────────────────────────────────────→
               ↑release              ↑hotfix
develop      ───────────────────────────────────→
               ↑feature-a    ↑feature-b
feature/a    ──────────────→
feature/b              ──────────────────────────→
  • main: production-ready code only
  • develop: integration branch for next release
  • feature/*: one per feature, branched from develop
  • release/*: release preparation branch
  • hotfix/*: emergency fixes on main

It was designed for projects with scheduled releases and versioned software — open source libraries, mobile apps with app store releases, on-premise enterprise software.

GitFlow Problems

Long-lived branches create merge hell: a feature branch open for two weeks diverges significantly from develop. Merging becomes a multi-hour ordeal.

Integration is deferred: developers only discover integration issues when merging, not while building. The longer the branch lives, the worse the merge conflict.

Slow feedback loops: code in a feature branch isn’t tested against other features until merge. Bugs compound.

Overhead: maintaining develop, release, and hotfix branches adds complexity with little benefit for teams doing continuous delivery.

Trunk-Based Development

In Trunk-Based Development (TBD), everyone commits to a single shared branch (usually main) at least once a day. Feature branches exist but live for hours to days, never weeks.

main  ──●──●──●──●──●──●──●──●──●──→
         ↑A  ↑B  ↑A  ↑C  ↑B  ↑A

Every commit to main goes through CI. Features are hidden behind feature flags while they’re being built. Production releases are a subset of main, not a branch merge.

Why TBD Works

Continuous integration is real: when you commit to main daily, integration issues surface immediately while they’re small, not after two weeks when they’re catastrophic.

Smaller, safer changes: daily commits force you to break work into smaller increments. Smaller changes are easier to review, test, and roll back.

Feature flags replace branches: incomplete features are hidden at the application layer, not the git layer. The code is deployed; the feature isn’t visible.

Faster feedback: your code runs against production CI immediately. You know within minutes if something broke.

The Numbers

The DORA research (now part of Google Cloud’s DevOps Research and Assessment) consistently shows:

Elite performers deploy multiple times per day, have change failure rates below 5%, and restore service in under one hour. They overwhelmingly use trunk-based development.

Low performers deploy once a month or less, with failure rates above 15%. They overwhelmingly use long-lived feature branches.

GitFlow isn’t disqualifying, but it tends to enable the behaviors that correlate with low performance: batching changes, deferring integration, and treating deployment as a risk rather than a routine.

Making the Switch

Step 1: Shorten branch lifetimes

Don’t delete GitFlow overnight. Start by enforcing a rule: no branch older than 2 days. Branches that can’t merge in 2 days need to be broken into smaller pieces.

Step 2: Add feature flags

Feature flags are what make TBD safe. Introduce them for any significant feature that takes more than a day to build.

if (featureFlags.isEnabled('new-search')) {
  return newSearch(query);
}
return legacySearch(query);

Step 3: Invest in CI

TBD only works with fast, reliable CI. A 30-minute CI pipeline makes daily commits painful. Get it under 10 minutes, ideally under 5.

Step 4: Move to short-lived branches

Replace long-lived feature branches with short-lived ones (< 2 days). Use them for code review, then merge and delete.

# Short-lived branch workflow
git checkout -b feature/add-search-filter
# ... make changes, get review ...
git checkout main
git merge feature/add-search-filter
git branch -d feature/add-search-filter
git push

When GitFlow Still Makes Sense

TBD is the right choice for teams doing continuous delivery or deployment. But GitFlow still makes sense in specific scenarios:

  • Versioned open source libraries: you maintain v1.x, v2.x, and v3.x simultaneously, each with their own release branches and hotfix process
  • App store releases: iOS/Android apps are reviewed and released on Apple/Google’s schedule, not yours
  • Highly regulated industries: where a change must go through a formal approval process before release

If your deployment model doesn’t allow continuous delivery, GitFlow’s release management structure has genuine value.

Summary

GitFlowTrunk-Based Dev
Branch lifetimeWeeks–monthsHours–days
Integration pointMerge to developDaily commits to main
Incomplete featuresFeature branchesFeature flags
Release cadenceScheduledContinuous
Merge conflictsFrequent, largeRare, small
DORA correlationLow performersElite performers
Best forVersioned softwareContinuous delivery

Key Takeaways

  • GitFlow was designed for scheduled releases and versioned software — not continuous delivery
  • Trunk-Based Development correlates with elite engineering performance per DORA research
  • Feature flags replace long-lived feature branches as the way to hide incomplete work
  • The switch requires fast CI, a feature flag system, and a culture of small commits
  • GitFlow still makes sense for versioned open source or app-store-constrained releases