The branching strategy debate is loudly opinionated in both directions. GitFlow advocates point to clean release management and isolated feature development. Trunk-based development advocates point to the evidence that short-lived branches correlate with higher engineering performance. Both sides are often talking past each other.
The useful question is not “which is better” but “which fits our context” — and the context includes team size, release cadence, engineering practices, and the nature of the software being delivered.
GitFlow: Structured Release Management
GitFlow (introduced by Vincent Driessen in 2010) organizes branches around releases:
main ──────────────────────────────────→ (production)
↑ ↑
release/1.2 ──┤ │
merge merge
feature/X ────────┤
feature/Y ───────────────────────┤
hotfix/Z ──────────────────────────┤
Key branches:
main: production-ready codedevelop: integration branch for featuresfeature/*: individual features, branched from developrelease/*: release preparation, branched from develophotfix/*: emergency fixes, branched from main
What GitFlow solves: managing multiple release lines simultaneously, coordinating large teams, supporting explicit release cycles with QA gates.
Where GitFlow struggles: long-lived feature branches that diverge significantly from develop, merge conflicts that grow with branch age, “integration hell” when multiple features merge around the same time, deployment frequency limited by release cycle.
Trunk-Based Development: Continuous Integration
Trunk-based development (TBD) means all engineers integrate into the main branch (trunk) continuously — multiple times per day. Feature branches are allowed but must be short-lived (hours to days, not weeks).
main ────────────────────────────────────────→ (continuously deployable)
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
commits from all engineers, multiple per day
Short-lived feature branches merge quickly:
main ─────────────────────────────────────→
↑ ↑
feature ─┤ ─┤
(hours) (hours)
What TBD solves: integration problems surface when they’re small (daily changes vs multi-week branches), deployment pipeline always runs against near-current code, encourages small incremental changes.
Where TBD struggles: requires feature flags to deploy code before it’s complete, requires high CI/CD maturity, can be uncomfortable for teams that prefer explicit handoffs between integration and release.
The Real Difference: Integration Frequency
The fundamental difference between these strategies is when integration happens — and therefore when integration problems surface.
With GitFlow and long-lived branches:
- Integration happens at branch merge time (days or weeks after branching)
- Integration problems are large (big diff to resolve)
- Problems surface late (sometimes the day before a release)
With trunk-based development:
- Integration happens daily (or more often)
- Integration problems are small (small diff to resolve)
- Problems surface immediately
The DORA (DevOps Research and Assessment) research across thousands of teams consistently shows that trunk-based development with frequent integration correlates with higher deployment frequency, lower change failure rate, and faster time to restore. This is correlation, not causation, but the mechanism is plausible: small, frequent integrations reduce batch size and therefore blast radius.
Feature Flags: The Enabler of TBD
The most common objection to trunk-based development: “we can’t merge incomplete features into main.”
Feature flags resolve this. You commit code that’s behind a flag:
if (featureFlags.isEnabled("new-checkout-v2", user)) {
return newCheckoutService.process(request);
}
return legacyCheckoutService.process(request);
The code is deployed to production but the feature is disabled. You enable it progressively:
- Enabled for internal users (smoke testing)
- Enabled for 1% of users (canary)
- Enabled for 10%, 50%, 100% (gradual rollout)
- Legacy code removed, flag deleted
Feature flag systems: LaunchDarkly, Unleash, Split.io, or a simple database-backed implementation.
The discipline this requires: flags must be cleaned up. A codebase with 200 stale feature flags is harder to understand than one with long-lived branches. Treat flag removal as normal engineering work, not an afterthought.
Release Management
GitFlow’s release branches address a specific problem: preparing a release takes time (QA, documentation, final bugfixes) while feature development continues. The release branch isolates this work.
Trunk-based development handles this with release trains (release from a specific commit) or release branches that are short-lived and quickly merged back:
main ─────────────────────────────────────────→
↓
release/1.2 ─────────────┐
(branch for a few days) → tag → merge back to main
For software with explicit versioned releases (libraries, mobile apps, enterprise software), some form of release branch is often necessary regardless of branching strategy. The discipline difference is: release branches should be short-lived, and the main branch should always be deployable.
Team Size and Coordination
GitFlow is often preferred by larger teams because it provides explicit coordination points. The develop branch is where integration happens; releases are explicitly prepared.
Trunk-based development works well for smaller teams and teams that deploy frequently. As teams grow, the convention discipline required for TBD (always deployable, small batches, feature flags) requires more engineering culture investment.
Neither scales to all team sizes without adaptation. A team of 3 deploying a web service can do strict TBD. A team of 50 delivering software that customers install has different coordination needs.
What Actually Matters
The debate often misses the point. The branching strategy is a means, not an end. What matters:
How often do you integrate? The longer code sits unintegrated, the larger the integration batch and the higher the risk.
How quickly can you deploy? Regardless of branching strategy, the ability to deploy a fix quickly determines your recovery time from production incidents.
How confident are you in your test suite? TBD requires trusting that CI will catch problems. GitFlow provides a QA gate before release. Neither substitutes for a good test suite.
Can you deploy incomplete features safely? Feature flags enable this. Without them, TBD requires features to be releasable before they’re deployed.
Practical Recommendations
Small team, web service, continuous deployment: trunk-based development is simpler and provides faster feedback. Invest in feature flags and CI quality.
Larger team, multiple release lines, explicit versioning: GitFlow or a similar release-branch model provides useful coordination. Keep feature branches short (less than a week).
Any context: the most important thing is keeping branches short. Whether your branching strategy is called GitFlow or trunk-based, branches that live for weeks are a problem.
The debate between GitFlow and TBD is less important than the question: does your engineering practice support fast, safe delivery? The branching strategy should support that answer, not define it.