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'
Where branch time goesAn illustrative breakdown of a typical two-day branch. Writing the code takes a few hours. Most of the elapsed time is waiting: for a first review, for a second round, and for CI. Shortening branches is mostly about shortening the waits.hours in each phase of a typical branch (illustrative)writing code4 hwaiting for review19 haddressing review2 hwaiting for CI3 hwaiting to merge6 hthe code is rarely the slow part

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.

Large, slow changes against small, fast onesA large branch takes days to write, waits for a reviewer who needs an hour to read it, and conflicts with trunk at merge. A small branch takes hours to write, gets a quick review because it is quick to read, and merges cleanly because trunk has barely moved.Large branchSmall branchwritingdayshoursreview effortan hour+, postponedminutes, done nowconflicts at mergelikelyrarerollbackwhole featureone small stepsmaller changes get reviewed sooner because they are easier to review

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
A day in a short-branch workflowIn the morning a developer pulls trunk and creates a small branch. By midday the change is pushed and a pull request opened. A colleague reviews within an hour or two, CI is green, and the change merges before the end of the day. The next slice starts from the new trunk.Branchfrom fresh trunk09:00PR openedsmall diff12:30Reviewedwithin 90 min14:00CI greenunder 10 min14:15Mergednext slice starts14:30one slice a day keeps every branch measured in hours

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.