Keeping branches short-lived in trunk-based development Jump to heading
Trunk-based development is defined less by its branches than by their lifespan. Teams that practise it still use branches and pull requests; the difference is that a branch lives hours, or a day or two at most, before merging into trunk. Short branches mean small diffs, quick reviews, few conflicts and continuous integration in the literal sense. Long branches quietly turn trunk-based development back into feature-branch development with extra ceremony. Keeping branches short is not a matter of willpower: it depends on how work is sliced, how fast review and CI respond, and whether unfinished work can merge safely. This page covers the practices that make short-lived branches the easy path, within trunk-based development setup.
When to use this approach Jump to heading
- Your team has adopted, or wants to adopt, trunk-based development.
- Branches routinely live longer than two or three days.
- Reviews of large pull requests stall, and conflicts at merge time are common.
- You have measured branch lifetimes, for instance with measuring trunk-based adoption from Git history.
Step 1 β Set the target in hours, not days Jump to heading
A short-lived branch in trunk-based practice usually merges the same day or the next. Make that the stated expectation, with a visible measure.
# Median hours from first commit on a branch to merge, last 100 merged PRs
gh pr list --state merged --limit 100 --json createdAt,mergedAt \
--jq '[.[] | ((.mergedAt|fromdateiso8601) - (.createdAt|fromdateiso8601)) / 3600] | sort | .[length/2|floor] | floor' Step 2 β Slice work so each branch is a few hours Jump to heading
The biggest lever is the size of each change. A feature is not one branch; it is a sequence of small, safe, mergeable steps: a data model, an endpoint behind a flag, a UI behind the same flag, a migration, the flag turned on.
PAY-812 Export scheduling β planned as five branches, each < 1 day
1. feat/PAY-812-schedule-model model + migration (unused)
2. feat/PAY-812-scheduler-service service + tests (unused)
3. feat/PAY-812-api API endpoint behind flag `export-scheduling`
4. feat/PAY-812-ui settings UI behind the same flag
5. chore/PAY-812-enable flag on for pilot accounts Each step must leave trunk working and releasable. Unfinished functionality stays dark behind a flag, as described in feature flags vs feature branches for unfinished work.
Step 3 β Make reviews fast Jump to heading
If a pull request waits a day for its first review, the branch lives a day. Agree a review response target β a few working hours β and make small pull requests the norm so reviews are quick to do.
# Pull requests waiting for a first review, oldest first
gh pr list --search "review:none -is:draft" --json number,title,createdAt \
--jq 'sort_by(.createdAt) | .[] | "\(.createdAt[:16]) #\(.number) \(.title)"' Review targets and escalation are covered in setting review turnaround targets and escalation, and size limits in enforcing pull request size limits.
Step 4 β Keep CI under ten minutes Jump to heading
CI that takes forty minutes adds forty minutes to every branch, and people batch more into each branch to avoid waiting twice. Keep the pre-merge pipeline fast with caching, affected-only testing and parallel jobs; move slow suites to a merge queue or post-merge.
# Recent pipeline durations on pull requests
gh run list --event pull_request --limit 30 --json createdAt,updatedAt \
--jq '.[] | ((.updatedAt|fromdateiso8601) - (.createdAt|fromdateiso8601)) / 60 | floor' | sort -n | tail -5 The tooling is covered in CI caching and runner performance.
Step 5 β Integrate at least daily Jump to heading
Even a branch that will take two days should pull trunk in daily, and push to its pull request daily, so conflicts surface early and reviewers can follow along. For trunk-based teams the habit is usually to merge something every day β a small step β rather than to sync a long branch.
# Morning routine on an open branch
git fetch origin && git rebase origin/main && make test && git push --force-with-lease Step 6 β Watch for the long tail Jump to heading
Some branches will still run long β a spike, an awkward migration. Label them, give them an owner and a sync plan, and keep them exceptional. If the tail grows, revisit slicing and review practice rather than accepting it.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Is committing directly to trunk better than short branches? Jump to heading
Some teams commit directly with pair programming and strong pre-commit checks. Most use short branches and pull requests for review and CI, which is fully compatible with trunk-based development as long as branches stay short.
What if a change cannot be split? Jump to heading
Most can, with flags or branch by abstraction. Genuine exceptions β a large mechanical rename β should be done quickly, announced, and merged in one go, rather than kept open for days.
How do we handle work that spans several services? Jump to heading
Slice it so each serviceβs change is backward compatible and independently deployable; then order the slices so each one works with the previous state of the others.
Related Jump to heading
- Trunk-Based Development Setup β the parent topic.
- Keeping Trunk Green β the other half of trunk-based practice.
- Branch by Abstraction for Large Changes β slicing changes that seem indivisible.
- Limiting Feature Branch Lifetime β the same goal in feature-branch workflows.