Trunk-Based Development vs Long-Lived Feature Branches
My old git habit was simple and yet sometimes costly: open a feature branch, keep stacking commits, tell myself I would merge when it was ready, and deal with the fallout weeks later when main had moved on without me.
I am retraining on trunk-based workflow instead: short branches, merge often, keep main honest. Deliberate practice every time I touch git.
Names, quickly
Trunk-based development treats one branch (usually main) as the trunk: the line of truth that should stay releasable. You still branch. You branch short, merge often, and integrate continuously.
Long-lived feature branches keep work separate for weeks or longer. Sometimes informal (“my branch”). Sometimes formal (GitFlow: develop, release, hotfix branches with rules for each).
The argument is not “branches bad, main good.” It is about how long work stays isolated and how honest main stays while you build.
The habit I am unlearning
Long-lived branches felt safe. Work in progress stayed tucked away. No half-done feature on main.
The bill shows up later:
- Merge day becomes its own project.
- “Works on my branch” stops meaning “works with today’s main.”
- Fixes land on main but not on my branch, or the other way around.
- Reviewers get a diff so big they skim.
I did this for years across personal repos, work repos, and “just until this refactor is done” side quests.
The mental model
Think of main as a highway.
- Trunk-based: lots of small merges. Traffic keeps moving. Conflicts stay mitigated in small chunks.
- Long-lived branch: you built a parallel road for a month, then merge eight lanes into four at once.
Both can work in the right context. Waiting hurt me more often than it helped.
Why I am moving toward trunk-based
Main stays honest. Green CI on main means you are closer to something you could ship. Green on a stale branch is a weaker promise.
Smaller merges. A fifty-line Pull Request (PR) is reviewable. A five-thousand-line merge after six weeks is archaeology.
Less merge debt. Every day main diverges from your branch, you pay interest. Trunk-based pays that bill daily, in small coins.
Better fit for portfolio and homelab repos. Short lifetime, clear branch name, one logical change. Trunk-based style even when every change still goes through a PR.
What trunk-based costs
Discipline on main. Half-finished work cannot land unless I split the change, use a flag, or ship a thin, safe slice. “Merge now, fix later” rots the trunk.
CI has to be worth trusting. Slow or flaky pipelines push people back toward batching work on long branches.
Not every repo is a solo portfolio project. Big refactors and fixed release trains still exist. Trunk-based is my default, not a universal law.
When long-lived branches still make sense
Big, risky refactors. Sandbox until the new shape compiles and tests pass, then plan the merge window. “Temporary” should not become a season.
Release trains and versioning. Strict semver (semantic versioning), long QA, or quarterly ship dates often formalize branches because the calendar is fixed.
Multiple supported versions. If customers run 2.x and 3.x at once, branch strategy follows support obligations.
I am not pretending those cases do not exist. I am stopping myself from using them as an excuse for every branch that lives too long.
What I am practicing now
Balance between small meaningful changes and a longer stretched projects that may require batched changes.
For most tasks, I’ll aim to keep it simple
- Work in small commits on that branch.
- Open a PR early when the change is non-trivial. CI is the gate.
- Merge when green and the change set is one logical thing.
- Delete the branch and sync main before the next task:
How to choose (practical)
| Situation | What tends to work |
|---|---|
| Solo or small team, deploy often, strong CI | Short branches, main always releasable |
| Big bang rewrite, tests not ready yet | Longer branch, but plan the merge window and rebase often |
| Fixed release calendar, multiple supported versions | Formal release branches; keep feature branches short if you can |
| ”We might need this someday” | Do not keep a branch alive. Merge a flag, a stub, or close the PR |
If you are not sure, ask: how painful will merging this be if main moves for two weeks without me? If the answer makes you wince, the branch is already too long.
What I am not claiming
Trunk-based is not “no branches.” It is not “YOLO push to production.” It is not incompatible with PR review.
Long-lived branches are not evil. It has its place in the workflow.
Where this connects
Bigger workflow choices go in Demystifying ADRs when the decision has lasting impact. Branch strategy is smaller than picking a database, but the same idea applies: decide, document why, revisit when reality changes.
One line to hold onto: integrate early so main never lies to you for long.