Updating stacked branches with --update-refs Jump to heading
Stacked branches β feature/api on main, feature/ui on feature/api, feature/docs on feature/ui β let you split large work into reviewable pull requests that build on each other. The cost used to be maintenance. Rebasing the bottom branch onto a new main left the upper branches pointing at the old commits, and each had to be moved separately with careful --onto commands. Since Git 2.38, git rebase --update-refs does it in one step: rebase the top of the stack, and every branch that pointed into the rebased range is moved to the corresponding new commit. This page shows the workflow for keeping a stack current, editing a lower branch, and pushing the result, within interactive rebase workflows.
When to use this approach Jump to heading
- You split a large change into dependent branches, each reviewed as its own pull request.
- Main has moved and the whole stack needs to follow.
- A reviewer requested a change in a lower branch, and the upper branches must pick it up.
- You use Git 2.38 or newer. The surrounding review practice is in stacked pull requests without a dedicated tool.
Step 1 β Turn it on by default Jump to heading
rebase.updateRefs makes every rebase update branches pointing into the rebased range. It is safe to enable globally: it only moves branches whose commits are being rewritten anyway.
git config --global rebase.updateRefs true
git --version # 2.38 or newer # Verification: the stack's branches all sit on one line of history
git log --oneline --decorate main..feature/docs
# 6c1f2e0 (feature/docs) Document export API
# 1d7a9b3 (feature/ui) Add export button
# 8e2c4f5 Wire export form
# 4b9d0a7 (feature/api) Add export endpoint Step 2 β Rebase the whole stack onto a new main Jump to heading
Check out the top branch and rebase it. Every branch below it in the range is updated to its rewritten commit.
git switch feature/docs
git rebase main
git log --oneline --decorate main..feature/docs # all three branch names moved In the interactive todo list, --update-refs shows as update-ref lines, one per branch, placed after the commit each branch should point to. You can see exactly what will move.
pick 4b9d0a7 Add export endpoint
update-ref refs/heads/feature/api
pick 8e2c4f5 Wire export form
pick 1d7a9b3 Add export button
update-ref refs/heads/feature/ui
pick 6c1f2e0 Document export API Step 3 β Edit a lower branch and carry the change upward Jump to heading
A reviewer asks for a change in feature/api. Make it as a fixup on the top branch and let autosquash place it, or make it as a new commit in the right place during an interactive rebase. Either way, rebase from the top so every branch updates.
git switch feature/docs
# change the endpoint, then record it as a fixup for the api commit
git commit -a --fixup=4b9d0a7
git rebase -i --autosquash main The fixup is folded into the api commit, and the update-ref lines move feature/api, feature/ui and feature/docs to the rewritten commits. The edit technique itself is described in editing an old commit in the middle of a branch.
Step 4 β Push every branch in the stack Jump to heading
Each branch backs a pull request, so all of them must be pushed. Push them together, each with a lease, so a reviewerβs push to one of them is not overwritten.
git push --force-with-lease origin feature/api feature/ui feature/docs
# or with --atomic, so either all update or none do
git push --atomic --force-with-lease origin feature/api feature/ui feature/docs β οΈ SAFETY WARNING: Force-pushing a stack rewrites every pull request in it. If a collaborator pushed to any branch in the stack,
--force-with-leaserefuses that branch; fetch and incorporate their commit before pushing again. If a rebase of the stack went wrong, the reflog of each branch records its previous tip:git reflog show feature/ui.
Step 5 β Land the stack from the bottom Jump to heading
When the bottom pull request merges, the next one should retarget to main. If the bottom was squash-merged, its original commits are not on main, and the next branch must be moved off them with --onto.
# After feature/api was squash-merged into main
git fetch origin
git switch feature/docs
git rebase --onto origin/main feature/api feature/docs # update-refs moves feature/ui too
gh pr edit "$(gh pr view feature/ui --json number --jq .number)" --base main
git push --force-with-lease origin feature/ui feature/docs Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Does update-refs move branches that are checked out in another worktree? Jump to heading
No. Git refuses to move a branch checked out elsewhere, and the todo list notes it. Switch that worktree to another branch first, or update it separately after the rebase.
What if I only want to rebase the bottom branch? Jump to heading
Rebasing a lower branch alone leaves the upper ones behind. Always rebase from the top; if you only want to change the bottom, the upper branches still need to follow its new commits.
Do I still need a stacking tool? Jump to heading
For a few branches, --update-refs covers most needs. Dedicated tools add conveniences β automatic retargeting, a dashboard of stack status β that become worthwhile with deep stacks or many people stacking.
Related Jump to heading
- Interactive Rebase Workflows β the parent topic.
- Rebasing onto a New Base with --onto β moving a stack off a squash-merged branch.
- Splitting a Branch into Reviewable Pull Requests β creating the stack in the first place.
- Integrating Dependent Feature Branches β the alternatives when stacking is not the right fit.