
Two Branches and Boring Deploys: A Simpler Take on GitFlow
Branching is one of those topics that can start a fight in a team chat. Some developers love GitFlow. Some developers hate it. Both camps are usually right, because they are arguing about different things.
On our projects, we want to move quickly without giving up stability. Full classic GitFlow, with release branches, hotfix branches, support branches, and the ceremony that comes with all of them, can feel like a lot of process for a small or medium team. So we run a trimmed-down version. Two long-lived branches, plus short feature branches. That is it.
Why does this work? Because those two branches map cleanly to our environments, and that mapping is what makes our deploys predictable. Let me walk through it.
The Two Branches
Here are the only long-lived branches we keep.
developmaps to QA, staging, and preview.mainmaps to production.
Everything else is short-lived and gets deleted after it merges. If you remember nothing else from this post, remember those two lines. The rest is just the reasoning behind them.
develop is the Playground
develop is the classic GitFlow integration branch. It is where all new work comes together.
Every push to develop auto-deploys to a test environment that closely mirrors production. Same configuration, same setup, no live user data. New features, bug fixes, and UX tweaks all land here first. We test them, iterate on them, and let them prove themselves before they go anywhere near a customer.
This is the part I want to stress. `develop` is a playground. Nothing here can hurt a user. That freedom is what lets the team move fast, because the cost of being wrong on `develop` is close to zero.
main Is Production, and Only Production
main (or master, if that is what your repo calls it) holds production-ready code and nothing else.
Once a change looks good in QA, we merge it into main, usually through a pull request so someone else gets a look first. That merge triggers the production deploy. Because only proven code reaches `main`, the history stays clean and every deploy comes from something we have already watched work.
Here is a rule we hold to: main MUST stay green and deployable at all times. If `main` is broken, everything else stops mattering.
Feature Branches Do the Actual Work
The real work happens on short-lived branches cut from `develop`.
feature/add-loginfix/broken-searchchore/upgrade-deps
For a tiny fix, you can branch directly off main, but that is the exception and not the habit. Whatever you name them, merge these branches back frequently. The longer a branch lives on its own, the worse the merge conflict at the end. Small and often beats big and painful every time.
Let the Branch Drive the Build Config
This is where the two-branch model earns its keep. We tie build configuration to the branch, using whatever substitution variables, environment files, or CI settings the platform gives us.
- QA runs lean. Cheap resources, low instance counts, sometimes even a free tier. It does not need to handle production traffic, so we do not pay for production capacity.
- Production scales up on its own when traffic arrives.
Same code, different configuration, decided by the branch it deploys from. No manual toggles, no forgetting to flip a setting before a release.
Why This Flavor Works for Us
A few things make this worth it.
- No endless long-lived branches and no complicated release or hotfix flows unless we truly need them.
mainstays deployable at all times.- Deploys are automatic and, more than anything, boring. Push to
develop, watch it in QA, merge tomain, and it is live.
“Boring” is the compliment here. When a deploy is a small, repeatable, unremarkable thing, you have removed most of the fear from shipping.
This is GitFlow’s core idea, develop for integration and main for releases, without the extra branches that slow smaller teams down.
It Does Not Care About Your Infrastructure
One more thing worth calling out. This pattern works the same whether you are on Cloud Run, ECS, Kubernetes, or a self-hosted box in a closet. The branching model does not know or care about the infrastructure underneath it. That is part of why it travels well from project to project.
So Should You Use GitFlow at All?
Let me be fair to the other side. Some people hate GitFlow, and they are not wrong that it adds overhead. If you are one developer on a small project, this may be more process than you need.
But the moment you have multiple developers working on the same project, or you have to support hotfixes to production while new work continues, some version of GitFlow starts to become necessary. The overhead you were avoiding gets replaced by a different, worse overhead: stepping on each other and firefighting on weekends.
If your deploys feel random, or merges hurt every time, try boiling GitFlow down to just these two branches. It saved us a lot of pain, and more than a few weekends.
If you have questions, you can reach me at @chadmichel on X.


