Gitflow, watched one branch at a time
Gitflow is not a Git command. It is a set of rules about where a branch is allowed to start, and where it must go back to.
Git lets you branch from anywhere and merge into anything. That freedom gets messy fast on a team. Gitflow picks five kinds of branch and fixes the arrows between them, so nobody has to guess.
The five branches
Two branches live forever:
main: what is running in production right now. Every commit here is something real users have.develop: the next release, being built. It is always ahead ofmain.
Three kinds of branch are short-lived. You make them, use them, merge them, and delete them:
feature/*: one new thing. Starts fromdevelop, goes back todevelop.release/*: getting ready to ship. Starts fromdevelop, goes tomainand back todevelop.hotfix/*: a production bug that cannot wait. Starts frommain, goes tomainand back todevelop.
The two "and back to develop" rules are the ones people forget. Watch what
they do below.
The normal path: a feature becomes a release
From a feature branch to a tagged release
1 / 7Two branches never go away. main is what is live. develop is what comes next.
Notice what the release branch really buys you. From the moment it is cut, two
things happen at once: the release is being tested and fixed, and develop is
already taking the next batch of features. Without it, the whole team has to
stop and wait while one version is tested.
The emergency path: a hotfix
Production is broken. develop has three weeks of half-finished work in it, so
you cannot ship from there. This is the one case where you branch off main.
Fixing production without shipping unfinished work
1 / 4Version 1.0 is live. develop has already moved on with new work that is not ready.
That last step is the classic Gitflow bug. The fix is live, everyone moves on,
and three weeks later the release goes out and the same bug comes back. It was
never in develop, so the new release simply does not contain it.
Where the arrows must point
This is the whole model in one table. If you remember nothing else, remember this.
| Branch | Starts from | Merges back into | Lives for |
|---|---|---|---|
feature/* | develop | develop | Days to weeks |
release/* | develop | main and develop | Days |
hotfix/* | main | main and develop | Hours |
develop | n/a | n/a | Forever |
main | n/a | n/a | Forever |
Should you actually use it?
Gitflow was designed for software that ships on a schedule and supports more than one version at a time: desktop apps, mobile apps, on-premise products. That is what all the ceremony is paying for.
Most web teams deploy several times a day. For them, develop becomes a second
main that nobody trusts, and long feature branches drift far away from
everyone else's work. Trunk-based development is the common alternative: short
branches straight off main, merged within a day or two.
Same feature, two ways of working
1 / 3Gitflow
The branch is cut from develop, which is one step away from main already.
git switch -c feature/x developTrunk-based
The branch is cut straight from main. There is nothing in between.
git switch -c feature/x mainOne team, one feature, two sets of rules. Both start the same way, with a branch.
| Gitflow | Trunk-based | |
|---|---|---|
| Long-lived branches | Two: main and develop. | One: main. |
| Where a feature starts | From develop. | From main. |
| How long a branch lives | Days to weeks. | Hours to a couple of days. |
| Getting to production | feature → develop → release → main. | feature → main. |
| Merge conflicts | More. Branches drift apart while they wait. | Fewer. Everyone merges into the same place daily. |
| Supporting old versions | Built in: a release branch per version. | Awkward. You need extra long-lived branches. |
| Best fit | Scheduled releases, versioned products. | Continuous deployment, web services. |
| Needs feature flags? | No: unfinished work hides on its branch. | Yes: unfinished work sits in main, turned off. |
Common mistakes
Branching a feature off main. You then merge into develop and drag along
whatever was in main but not in develop. Always cut features from develop.
Forgetting the merge back into develop. Both release and hotfix have
two arrows out of them. Missing the second one is how a fix goes live and then
disappears in the next version.
Letting a feature branch live for a month. develop moves on without you.
The merge at the end is no longer a merge. It is a rewrite. Merge develop
into your branch regularly, or keep the branch small.
Committing straight to main. In Gitflow, nothing lands on main except a
merge from release or hotfix. Protect the branch so the rule is enforced,
not just agreed.
Cutting a hotfix from develop. It feels faster. It ships three weeks of
untested work to production along with your one-line fix.
Remember this
- 1main and develop live forever. feature, release and hotfix are made, merged, and deleted.
- 2release and hotfix each merge into TWO places: main and develop. Missing the second one is the bug that brings old problems back.
- 3Features come off develop. Hotfixes come off main. That single difference is what keeps unfinished work out of production.
- 4Gitflow is built for versioned releases. If you deploy several times a day, trunk-based is usually the better fit.
Now try these questions
- A critical production bug needs an emergency fix, but your PR process takes two hours. What do you do?
- A developer started a feature branch from an outdated main. How would you fix it?
- Two CI pipelines try to create the same Git release tag at the same time. What happens?
- Your repository has hundreds of branches, many already merged into main. What would you change?