Stack Upkeep — Stacked PRs Across Squash Merges
How to keep a chain of stacked PRs healthy as parents merge into main.
Battle-tested across four parallel tracks (~28 stacked PRs) in the June 2026
Shopify-app uplift. Audience: implementer teammates doing stack upkeep, and
leads dispatching it.
The core problem
This repo squash-merges. After a parent PR squash-merges, every child branch
still carries the parent's ORIGINAL commits, which no longer exist on main
in that form. GitHub then reports "merge conflicts" on the child — but they
are almost never real content conflicts; they're the child's stale copy of
the parent colliding with its own squashed equivalent.
The recipe: boundary rebase
Replay ONLY your own commits onto the new base; let the parent's stale copies fall away:
git fetch origin main
# <old-parent-tip> = the commit your branch was built on (the parent
# branch's tip BEFORE its squash-merge)
git rebase --onto origin/main <old-parent-tip> <your-branch>
- Expect zero manual conflict hunks. If git stops on a commit that is your
parent's content, it is patch-already-upstream —
git rebase --skipis correct (the squash brought that content in already). - If you hit a conflict in YOUR OWN commit's hunks, STOP and tell the lead — that's a real conflict and may warrant a delta re-verify of the resolution.
- Re-run the full gates after every rebase. The merged parent's tests on
mainare now the live ratchet — they must pass UNMODIFIED. - Push with
--force-with-lease, your feature branch only. Never force-push anything else (CLAUDE.md universal gate). - Then retarget the PR's base to
main(or to the next unmerged parent).
Hazard: the clean cherry-pick that reverts review fixes
Never rebuild a stack by cherry-picking onto a remembered base. A cherry-pick can apply "cleanly" against a PRE-review version of a file and silently revert fixes that review rounds added to the parent. (Caught live in the uplift: a re-cherry-picked test applied cleanly and would have undone a reviewer's raw-item assertion fix; only a merge-based rebuild surfaced it.) When a child must absorb an updated parent, prefer merging the parent branch in (or the boundary rebase above) over cherry-picks, and afterwards verify the parent's review-round changes are present in the final tree.
Hazard: shared-hunk files copied across stacks
When the same new file must exist on two independent stacks (e.g. a test
setup file needed by both a main-based test PR and a refactor stack), the
copies must stay byte-identical or they add/add-conflict when the second
stack merges. Discipline:
- Copy via
git checkout <source-branch> -- <path>, never by hand. - After either side changes in review, re-sync the other side immediately.
- Verify with blob hashes (
git ls-tree <branch> <path>) — identical hash = guaranteed clean merge. - Full-stack dry run:
git merge-tree --write-tree origin/main <stack-tip>exits 0 with no conflict section iff the whole stack merges cleanly.
Choreography when a parent merges
- Lead (or merge watcher) announces the merge.
- Child owner: retarget child PR base →
main, boundary-rebase, gates,--force-with-lease, confirm PR isMERGEABLE. - Walk the remaining chain in order — each grandchild rebases onto the freshly rebased child.
- Force-pushes dismiss bot approvals; CI and the auto-reviewer re-run. This is expected — flag it in the PR if a human already approved.
- With automerge enabled, children land as approvals arrive — the lead's merge watcher (see team-lead-protocol) catches each landing and triggers the next walk.