Skip to content

prompts interactively to prune merged branches under a PTY and fails to force-push after  #533

Description

@MichaelDoyle

Gemini got a little aggressive with the description, but I've been running into gh stack sync hanging in my coding agent (Google internal build of Antigravity).


Environment

  • gh stack version: v0.1.1

Issue 1: Bare gh stack sync blocks on ? Prune N merged branches? (Y/n) in PTY-based agent harnesses (and contradicts skills/gh-stack/SKILL.md)

In skills/gh-stack/SKILL.md, the Non-interactive use section specifically warns that AI agent harnesses allocate a PTY (stdout is a TTY):

gh stack branches on whether stdout is a TTY. Piped, most commands error cleanly or print static text; under a PTY the same commands open a prompt or a full-screen TUI and block forever. Agent harnesses differ, so always pass the flags below instead of relying on that detection.

However, under Staying in sync, SKILL.md instructs agents to run bare gh stack sync:

gh stack sync                   # fetch, reconcile with GitHub, rebase, push, refresh PR state
gh stack sync --prune           # also delete local branches for merged PRs

Pruning never happens without `--prune` when non-interactive.

What happens in practice

When an agent runs bare gh stack sync inside a PTY-based terminal harness on a stack where one or more lower PRs have been merged on GitHub, gh stack sync sees isatty(stdout) == true and blocks waiting for interactive input:

? Prune 4 merged branches? (Y/n)

Additionally, gh stack sync only offers a boolean --prune flag—there is no --no-prune (or --yes) flag to run gh stack sync under a PTY without pruning and without prompting.

Suggested Fix

  1. Add --no-prune (or --prune=false) to gh stack sync so callers under a PTY can explicitly opt out of both pruning and the interactive (Y/n) prompt.
  2. Update skills/gh-stack/SKILL.md (and the "Always run / Never run bare" table) to instruct agents to always pass gh stack sync --prune (or --no-prune) rather than bare gh stack sync.

Issue 2: gh stack sync fails to push with --force-with-lease if branches were already rebased via gh stack rebase

gh stack sync --help states that step 5 pushes with --force-with-lease:

  1. Pushes all branches atomically (using --force-with-lease --atomic)

However, if a user or agent rebases locally first (for example, when resolving a rebase conflict via gh stack rebase --upstack -> git add -> gh stack rebase --continue, as instructed by gh stack's conflict recovery message) and then runs gh stack sync:

  1. gh stack sync sees that the local branches are already rebased onto origin/main, so step 4 (cascade rebase) is a no-op.
  2. Step 5 then attempts a regular (non-force) push instead of --force-with-lease, which fails:
Skipping 4 merged branches
Pushing 7 branches to origin...
⚠ Push failed — branches may need force push after rebase
  Run `gh stack push` to push with --force-with-lease.

Expected Behavior

gh stack sync should push active stack branches using --force-with-lease --atomic even when the rebase happened in a prior gh stack rebase step rather than inside the gh stack sync invocation itself.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions