From 700d9cfc94b95c516f30aca5593d2408e8da951e Mon Sep 17 00:00:00 2001 From: Sameen Karim Date: Mon, 27 Jul 2026 01:43:55 -0400 Subject: [PATCH 1/6] Stop sync/rebase reporting success on a stale trunk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `gh stack sync` and `gh stack rebase` could print a full success report while leaving the stack based on the trunk it was created from. Two independent causes. 1. A rebase git refused was reported as a success. `tryAutoResolveRebase` returned nil whenever no rebase was in progress. That is only a valid success signal after an auto-`--continue`; on the first check it means `git rebase` exited non-zero without ever starting. Every rebase funnels through it, so the cascade printed `✓ Rebased X onto Y` for a rebase that never ran — a dirty tree, a branch checked out in another worktree, an unresolvable upstream, or stale rebase state. A rebase that never started is now a typed `*git.RebaseStartError`, which the cascade and `modify` treat as fatal rather than as a conflict, so no bogus recovery state is written and git's own message is surfaced. 2. The trunk ref was never verified against the remote. `fastForwardTrunk` only warned when it could not move the local trunk (checked out in another worktree, diverged, remote ref gone), and the cascade then rebased onto the stale local trunk. Every freshness check compared branches to the *local* trunk, so they all passed: `rebase` claimed "rebased locally with main" and `sync` concluded nothing was stale, force-pushed anyway, and said "Branches synced". `resolveTrunkTarget` now resolves the ref the cascade must target. When the local trunk cannot be updated it returns `/` and says why, so the stack ends up current regardless of why the local ref is stuck. When the trunk no longer exists on the remote it fails with an actionable message instead of silently rebasing onto a stale trunk. The post-cascade check measures against that ref, and `sync` runs it before pushing so an unrebased stack is never force-pushed. Also fixed along the way: - A remote-qualified trunk (`gh stack init --base origin/main`) is normalized instead of being re-qualified into `origin/origin/main`, in both commands and before fetch refspecs are built. - `git rebase