Skip to content

Stack trunk is not migrated when the trunk branch's PR is squash-merged and the branch deleted #225

Description

@myot233

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):

main
 └── feat/base        → PR #1 (base: main)        ← stack trunk, created with --base feat/base
  └── feat/layer-2    → PR #2 (base: feat/base)
   └── feat/layer-3   → PR #3 (base: feat/layer-2)

PR #1 is then squash-merged into main on GitHub and feat/base is deleted. GitHub automatically retargets PR #2's base to main.

Observed

The stack's local metadata keeps trunk: { branch: "feat/base", head: <old sha> } forever:

  • gh stack view --json still reports the deleted branch as trunk.
  • sync cannot fast-forward the trunk (its remote ref no longer exists), and nothing offers to migrate the stack onto main.
  • Because the trunk commits were squashed, the layers also need a rebase --onto to 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 X exists, sync (or a dedicated command) should offer to migrate the stack trunk to X and cascade-rebase, mirroring the existing squash-merge recovery for in-stack branches. Even just a gh stack init --retrunk <branch> escape hatch would help — today init --adopt refuses branches that already have PRs, so there is no supported path.

Workaround that worked

  1. git branch -f feat/base origin/main (keep the local trunk name, point it at main)
  2. gh stack rebase (cascades cleanly; git skips the squashed patches)
  3. Hand-edit the gh-stack JSON state file in .git/ to set trunk: { branch: "main", head: <origin/main sha> }

After step 3, sync works 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.

Activity

  1. added
    bugBug Reports
    topic: cli - sync`gh stack sync`: pruning, base updates after merge, trunk migration, squash-merge replays.
    on Jul 26, 2026
  2. favilo commented on Aug 21, 2026

    @favilo

    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_deleted at :29, closed at :30 — see also #443).
    The merge was done with plain gh pr merge --squash --delete-branch, not
    gh stack merge.

    Additional papercuts during recovery:

    • init --adopt refuses 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-stack directly (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 sync that detects "trunk PR merged + trunk branch deleted" and
    offers re-trunk + cascade-rebase would have handled all of this.

  3. favilo commented on Aug 21, 2026

    @favilo

    Follow-up: after manually re-trunking the stack onto main, we tried to
    merge the remaining layer with gh 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/N
    

    So today there is no stack-aware merge path: gh stack merge is a stub that
    redirects to the web UI, and falling back to gh 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 if merge either errored as unimplemented in --help
    output or warned about the consequences of merging a trunk out from under
    its stack.

  4. favilo commented on Aug 21, 2026

    @favilo

    Version correction to my follow-up above: the "gh stack merge is not
    implemented" experience was on gh-stack v0.0.1. After upgrading to
    v0.1.0 we can see gh stack merge is 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugBug Reportstopic: cli - sync`gh stack sync`: pruning, base updates after merge, trunk migration, squash-merge replays.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions