That last big merge you did — how long did it take to resolve?
If the answer is "more than 20 minutes" — or worse, "a whole day" — that's not a Git problem. It's a branching strategy problem.
The wrong mental model
Most teams treat branches as safe parallel worlds. You open a branch, work in peace, and when you're done you bring it back into main.
The problem: while you work in your parallel universe, the rest of the team keeps changing the main one. And the more time passes, the further those worlds drift apart.
Science fiction calls it timeline divergence. Developers call it a merge conflict.
Gitflow: the architecture of conflict
Gitflow was proposed by Vincent Driessen in 2010. That was the year people still used SVN, deploys were manual, and companies shipped software every three months.
The flow makes sense in that context: a develop branch, feature branches, release branches, hotfix branches. Very tidy on paper.
The problem is that context no longer exists. And Gitflow carries that mental model into a present where teams want to deploy daily and feedback cycles are hours, not weeks.
What Gitflow produces in practice:
- Branches that live for days (sometimes weeks)
- Merges that break builds unpredictably
- Integration that happens "later" and never at the right moment
- A
developbranch that is, on average, broken
The building you can't move into
Think of Gitflow as a building under construction with a "nobody comes in until it's finished" policy.
The architect draws the plans. The foundations take two months. The structure, two more. When they finally open it, they find the power outlets are nowhere near where anyone wanted them, and the main bathroom sits directly across from the elevator.
Trunk-based development is a different model: the hotel opens its first floor while the upper ones are still going up. The guests on the first floor give you real feedback. If a room isn't ready, you close it temporarily — a feature flag — and fix it without bothering anyone.
What trunk-based development is
The core idea is simple: everyone integrates into main (the trunk) frequently — at least once a day.
There are no long-lived branches. If a branch survives more than a day or two, that's an alarm, not a normal working state.
Short branches exist, but their purpose is review, not isolation. The goal is to integrate fast and often.
Google, Meta and Shopify all run variants of this model. Google specifically has a single repository where thousands of engineers integrate into the trunk every day. Not because they're extraordinary — because they designed their practices to make it possible.
The key enabler: feature flags
The obvious question: "if I integrate unfinished code into main, don't I break it?"
That's what feature flags (or feature toggles) are for.
A feature flag is the technical equivalent of the hotel's "room under renovation" sign. The new feature's code exists in production, but it's switched off for real users. You turn it on when it's ready — by environment, by user, by percentage of traffic.
if (flags.newCheckout) {
return <NewCheckoutFlow />
}
return <OldCheckoutFlow />
This buys you concrete advantages:
- Deploy without release: you can deploy code without turning the feature on publicly
- Rollback without reverting commits: if something goes wrong, you switch the flag off
- Testing in real production: you turn the feature on for 5% of users and measure the impact before scaling up
Tools like LaunchDarkly, Unleash, or even a table in your database make this possible. You don't need magic — you need discipline.
The small commit as a practice
Trunk-based development forces you to think in small, integrable commits. Not "I finished the checkout feature" — but:
- Add the database schema for cart v2
- Add the totals calculation service (behind a feature flag, off)
- Add the cart v2 UI (hidden behind the flag)
- Turn the flag on for the internal team
- Turn the flag on for 10% of traffic
Every one of those commits integrates into the trunk. Every one is deployable. Every one can be reviewed in isolation.
This model forces you to break work into units that stand on their own — which is exactly what you want, because that's the kind of work that scales.
CI/CD as the safety net
At the circus, acrobats attempt riskier tricks when there's a net below. Teams integrate more often when there's CI backing them up.
Continuous integration isn't just "run the tests automatically". It's the social contract that says: if the build is green, the code can be integrated. The pipeline has to be fast (under 10 minutes ideally), reliable and final.
If the build breaks, it's urgent — you don't leave it red while everyone keeps working. A broken pipeline nobody repairs is worse than having none at all: it teaches the team that automated feedback can be ignored.
A slow pipeline has the same problem. If it takes 40 minutes, nobody waits for the result before committing again. Investing in pipeline speed isn't premature optimization — it's what makes the model possible in the first place.
How to start from where you are
You don't need to migrate everything at once.
First, shorten the branches you already have. If a branch is more than three days old, ask yourself whether you can integrate what already exists — incomplete and all — behind a feature flag. In most cases, you can.
Second, make the trunk the source of truth. Main has to be in a deployable state at all times. If someone breaks it, that's priority one — not "I'll look at it when I get a chance".
Third, invest in the pipeline. A 40-minute build makes trunk-based development impossible. You need feedback in under 10.
Fourth, look at the size of your PRs. An 800-line PR is a sign the work isn't broken down enough. Aim for PRs focused on one thing, reviewable in under 15 minutes.
Fifth, introduce feature flags gradually. Start with an environment variable or a simple table. You don't need a complex platform to get going.
The change that isn't technical
Resistance to trunk-based development is almost never technical. It's cultural.
"What if I integrate unfinished code and something goes wrong?" — Exactly what happens now, but faster to detect and easier to diagnose, because the change set is small.
"If everyone integrates into the same place, how do we know who broke what?" — You know exactly, because every commit is small and attributable.
The long-branch model creates an illusion of safety. The branch feels safe because it's isolated. But that isolation is the cause of the pain — not the cure.
Trunk-based development is uncomfortable at first because it takes that illusion away. What it puts in its place is better: real visibility into the state of the system, at all times.
And that, over time, is what lets you sleep the night before a deploy.