Repository navigation
Stack trunk is not migrated when the trunk branch's PR is squash-merged and the branch deleted #225
Description
Activity
- addedbugBug ReportsBug Reportstopic: cli - sync`gh stack sync`: pruning, base updates after merge, trunk migration, squash-merge replays.`gh stack sync`: pruning, base updates after merge, trunk migration, squash-merge replays.
on Jul 26, 2026 Hit this exact scenario today, with one twist that contradicts the
"GitHub automatically retargets PR #2's base" assumption: in our case the
platform closed the dependent PR instead of retargeting it (timeline:
merge at :28,base_ref_deletedat :29,closedat :30 — see also #443).
The merge was done with plaingh pr merge --squash --delete-branch, not
gh stack merge.Additional papercuts during recovery:
init --adoptrefuses branches already tracked in a stack, so after
hand-fixing the situation there was no supported way to re-trunk; I ended
up editing.git/gh-stackdirectly (trunk →main, new head/base SHAs,
new PR number).- The reopened-then-force-pushed dependent PR could not be reopened
(platform limitation), so the PR had to be recreated — the stack metadata
then pointed at a dead PR number.
A
gh stack syncthat detects "trunk PR merged + trunk branch deleted" and
offers re-trunk + cascade-rebase would have handled all of this.Follow-up: after manually re-trunking the stack onto
main, we tried to
merge the remaining layer withgh stack merge— it turns out CLI merging
is not implemented at all:⚠ Merging stacked PRs from the CLI is not yet supported You can merge this PR at: https://github.com/OWNER/REPO/pull/NSo today there is no stack-aware merge path:
gh stack mergeis a stub that
redirects to the web UI, and falling back togh pr merge --delete-branch
is exactly what produces the un-migrated trunk (this issue) and, in our
case, the platform closing the dependent PR instead of retargeting it
(#443). It would help ifmergeeither errored as unimplemented in--help
output or warned about the consequences of merging a trunk out from under
its stack.Version correction to my follow-up above: the "
gh stack mergeis not
implemented" experience was on gh-stack v0.0.1. After upgrading to
v0.1.0 we can seegh stack mergeis now a real atomic stack merge — so
please disregard the stub-related part of that comment.The trunk-migration issue itself (this issue's subject) was also observed on
v0.0.1 and we have not re-tested it on v0.1.0; if v0.1.0's merge/sync already
handles "trunk PR squash-merged + branch deleted", feel free to close and
we'll reopen if we hit it again on the current version.
Scenario
A stack whose trunk is itself a feature branch with its own PR to
main(a common "stack on top of an in-review PR" setup):PR #1 is then squash-merged into
mainon GitHub andfeat/baseis deleted. GitHub automatically retargets PR #2's base tomain.Observed
The stack's local metadata keeps
trunk: { branch: "feat/base", head: <old sha> }forever:gh stack view --jsonstill reports the deleted branch as trunk.synccannot fast-forward the trunk (its remote ref no longer exists), and nothing offers to migrate the stack ontomain.rebase --ontoto shed the now-duplicated trunk commits — the merged-PR recovery that works so nicely for stack members doesn't cover the trunk.Expected
When the trunk's remote branch is gone and a merged PR from that branch into
Xexists,sync(or a dedicated command) should offer to migrate the stack trunk toXand cascade-rebase, mirroring the existing squash-merge recovery for in-stack branches. Even just agh stack init --retrunk <branch>escape hatch would help — todayinit --adoptrefuses branches that already have PRs, so there is no supported path.Workaround that worked
git branch -f feat/base origin/main(keep the local trunk name, point it at main)gh stack rebase(cascades cleanly; git skips the squashed patches)gh-stackJSON state file in.git/to settrunk: { branch: "main", head: <origin/main sha> }After step 3,
syncworks normally again. Editing an internal state file obviously isn't a supported interface, hence this issue.Version: gh-stack v0.0.8, gh 2.x, repo uses squash-merge as the default merge method.