Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: github/gh-stack
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.0.5
Choose a base ref
...
head repository: github/gh-stack
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.0.6
Choose a head ref
  • 11 commits
  • 36 files changed
  • 4 contributors

Commits on May 29, 2026

  1. Bump github.com/cli/cli/v2 in the go_modules group across 1 directory (

    …#110)
    
    Bumps the go_modules group with 1 update in the / directory: [github.com/cli/cli/v2](https://github.com/cli/cli).
    
    
    Updates `github.com/cli/cli/v2` from 2.92.0 to 2.93.0
    - [Release notes](https://github.com/cli/cli/releases)
    - [Changelog](https://github.com/cli/cli/blob/trunk/docs/release-process-deep-dive.md)
    - [Commits](cli/cli@v2.92.0...v2.93.0)
    
    ---
    updated-dependencies:
    - dependency-name: github.com/cli/cli/v2
      dependency-version: 2.93.0
      dependency-type: direct:production
      dependency-group: go_modules
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored May 29, 2026
    Configuration menu
    Copy the full SHA
    5ed5693 View commit details
    Browse the repository at this point in the history

Commits on Jun 1, 2026

  1. link: block merged, closed, queued, and auto-merge-enabled PRs (#112)

    The `link` command previously allowed PRs in any state to be added to a
    stack, including PRs that had already been merged, were closed, were
    sitting in a merge queue, or had auto-merge enabled. Adding such PRs to
    a stack is invalid because they have already been or will soon be merged,
    which breaks the stacked PR workflow.
    
    Add a new validation phase (Phase 2b) to `runLink` that checks the
    eligibility of every existing PR found during lookup, before any new PRs
    are created or stack operations are performed. Only open/draft PRs
    without auto-merge enabled are eligible. All ineligible PRs are reported
    at once with a clear per-PR error message indicating the specific reason
    (merged, closed, in merge queue, or auto-merge enabled).
    
    Changes:
    
      internal/github/github.go:
      - Add AutoMergeRequest struct and field on PullRequest
      - Add IsAutoMergeEnabled() method on *PullRequest
      - Update FindPRByNumber and FindPRForBranch GraphQL queries to fetch
        the autoMergeRequest field
    
      internal/github/github_test.go:
      - Add TestPullRequest_IsAutoMergeEnabled (nil, non-nil, nil receiver)
    
      cmd/link.go:
      - Add pr field to resolvedArg to retain full PR data from lookup
      - Add validatePREligibility() that rejects merged/closed/queued/
        auto-merge-enabled PRs with descriptive error messages
      - Wire validation into runLink between PR lookup and stack operations
    
      cmd/link_test.go:
      - Add 7 tests covering each disallowed state by PR number and branch
        name, plus a multi-invalid-PR reporting test
    skarim authored Jun 1, 2026
    Configuration menu
    Copy the full SHA
    d2a390f View commit details
    Browse the repository at this point in the history

Commits on Jun 15, 2026

  1. alert for unsupported auth tokens (#113)

    When users authenticate the GitHub CLI with a personal access token
    (PAT) instead of OAuth (`gh auth login`), the `cli_internal` stacks
    API endpoints return 404. The CLI previously interpreted this as
    "Stacked PRs are not enabled for this repository," which is misleading
    — the feature may be enabled, but the token type simply cannot access
    the internal endpoints.
    
    This is a recurring source of user confusion. The docs already note
    that PATs are not supported, but users don't always read them before
    hitting the error.
    
    This change adds token-type detection by inspecting the `gh` auth
    token prefix:
    
      - `gho_`        → OAuth (supported)
      - `ghs_`        → GitHub App installation token (supported)
      - `ghp_`        → Classic PAT (NOT supported)
      - `github_pat_` → Fine-grained PAT (NOT supported)
    
    When a PAT is detected, the CLI now shows:
    
      ⚠ Personal access tokens are not supported by gh stack
        Run `gh auth login` to authenticate with OAuth instead.
    
    Instead of the misleading:
    
      ⚠ Stacked PRs are not enabled for this repository
    
    Changes:
    
    - Add `internal/config/auth.go` with auth detection methods on Config:
      `IsPersonalAccessToken()`, `WarnIfPAT()`, and `RepoHost()`. Uses a
      `TokenForHostFn` field on Config for test overrides, following the
      same pattern as `GitHubClientOverride`.
    
    - Add a pre-flight PAT check in `cmd/submit.go` before the
      `ListStacks` call. If a PAT is detected, the command aborts early
      with a clear error instead of making a doomed API call.
    
    - Update all 404 handlers for `cli_internal` endpoints to check the
      token type and show the appropriate message:
      - `cmd/submit.go` (createNewStack)
      - `cmd/link.go` (listStacksSafe, createLink)
      - `cmd/checkout.go` (checkoutRemoteStack)
    
    - Add `warnStacksUnavailableOrPAT()` helper in `cmd/utils.go` that
      shows the PAT-specific warning when applicable, falling back to the
      generic "not enabled" message for non-PAT tokens.
    
    - Add unit tests in `internal/config/auth_test.go` for token prefix
      detection and warning output.
    
    - Add integration tests in `cmd/submit_test.go` verifying that both
      classic PATs (`ghp_`) and fine-grained PATs (`github_pat_`) trigger
      the pre-flight check and abort before any API calls.
    
    - Add `warnStacksUnavailableOrPAT` tests in `cmd/utils_test.go`
      verifying correct message selection based on token type.
    
    - Update existing 404 tests to explicitly set an OAuth token so they
      continue exercising the ListStacks 404 path.
    skarim authored Jun 15, 2026
    Configuration menu
    Copy the full SHA
    d235a21 View commit details
    Browse the repository at this point in the history
  2. submit: disable auto-merge on existing PRs before adding to stack (#120)

    When a user runs `gh stack submit` and an existing PR is discovered for
    a branch via `FindPRForBranch`, that PR may have auto-merge enabled.
    Auto-merge is incompatible with stacked PRs because the PR would merge
    on its own, breaking the stack's base chain.
    
    Previously, the eligibility guard for auto-merge was only in the `link`
    command (which blocks such PRs with an error). The `submit` command had
    no such check, allowing users to add auto-merge-enabled PRs to a stack
    by running `init` followed by `submit`.
    
    This change adds auto-merge detection and automatic disabling in
    `submit`'s `ensurePR` function. When an existing PR with auto-merge
    enabled is discovered, the CLI disables auto-merge via the
    `disablePullRequestAutoMerge` GraphQL mutation and warns the user.
    If the disable call fails, submit continues with a warning (non-fatal).
    
    The `link` command retains its stricter behavior of blocking auto-merge
    PRs outright, since the user explicitly chose those PRs and can fix
    them before retrying.
    
    Changes:
    
      internal/github/github.go:
      - Add DisableAutoMerge() method using the
        disablePullRequestAutoMerge GraphQL mutation
    
      internal/github/client_interface.go:
      - Add DisableAutoMerge(prID string) error to ClientOps interface
    
      internal/github/mock_client.go:
      - Add DisableAutoMergeFn field and mock implementation
    
      cmd/submit.go:
      - In ensurePR, after discovering an existing PR with auto-merge
        enabled, call DisableAutoMerge before proceeding. Warns on
        success ("Disabled auto-merge for PR #N (incompatible with
        stacked PRs)") and on failure ("failed to disable auto-merge").
    
      cmd/submit_test.go:
      - Add TestSubmit_DisablesAutoMergeOnExistingPR: verifies auto-merge
        is disabled and warning is shown
      - Add TestSubmit_DisableAutoMergeFailure_ContinuesWithWarning:
        verifies submit continues even if the disable call fails
      - Add TestSubmit_NoAutoMerge_SkipsDisable: verifies DisableAutoMerge
        is not called for PRs without auto-merge
    skarim authored Jun 15, 2026
    Configuration menu
    Copy the full SHA
    a4485f5 View commit details
    Browse the repository at this point in the history
  3. parse PR URLs in args (#122)

    * Accept PR URLs in link and checkout commands
    
    Add support for GitHub PR URLs (e.g. https://github.com/owner/repo/pull/42)
    as arguments to `gh stack link` and `gh stack checkout`, in addition to
    the existing PR number and branch name support.
    
    For `link`: PR URLs are parsed in findExistingPR before the numeric check.
    Unlike numeric args, if a URL-extracted PR number doesn't exist, the command
    errors immediately rather than falling through to branch name lookup (since
    a URL can never be a valid branch name).
    
    For `checkout`: PR URLs are parsed in runCheckout before the numeric check,
    routing to resolveNumericTarget which supports both local and remote API
    fallback — same behavior as passing a PR number directly.
    
    Closes #115
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * update docs
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    skarim and Copilot authored Jun 15, 2026
    Configuration menu
    Copy the full SHA
    4999852 View commit details
    Browse the repository at this point in the history
  4. Fix force-with-lease push for branches without tracking refs (#124)

    gh stack sync could rebase a stack successfully then fail the final
    force push with "stale info" when a branch lacked a local tracking ref
    (refs/remotes/<remote>/<branch>). This happened because:
    
    1. FetchBranches pre-filtered branches by existing tracking ref, so a
       branch with no tracking ref was never fetched and never gained one.
    2. Push used a bare --force-with-lease flag, which has no lease basis
       for a branch without a tracking ref, causing git to reject the push.
    
    FetchBranches now uses explicit refspecs for every branch:
      +refs/heads/<branch>:refs/remotes/<remote>/<branch>
    This creates or updates tracking refs regardless of prior state. The
    fast-path (single fetch) and per-branch fallback (for branches absent
    on the remote) are preserved.
    
    Push now builds explicit per-branch lease arguments when force=true:
      --force-with-lease=refs/heads/<branch>:<tracking-ref-sha>
    for branches with a tracking ref, or:
      --force-with-lease=refs/heads/<branch>:
    (empty expected value = "must not exist") for branches absent on the
    remote. Explicit destination refspecs (<branch>:refs/heads/<branch>)
    remove dependence on push.default and upstream configuration. The
    non-force push path is unchanged.
    
    Added 6 integration tests using real bare git remotes:
    - Branch with current tracking ref: push succeeds
    - Tracking ref deleted locally (regression test for #118): push succeeds
    - Remote advanced by another client: push rejected (safety preserved)
    - New branch absent on remote: created via empty-expect lease
    - New branch race condition: rejected (safety preserved)
    - Mixed stack (tracked + untracked branches): all succeed after fetch
    
    Fixes #118
    skarim authored Jun 15, 2026
    Configuration menu
    Copy the full SHA
    7413e88 View commit details
    Browse the repository at this point in the history
  5. sync: skip trunk fast-forward silently when local branch doesn't exist (

    #125)
    
    When the trunk branch (e.g. main) doesn't exist locally — only the
    remote tracking ref (origin/main) exists — `fastForwardTrunk` called
    `git rev-parse main origin/main` which failed, emitting:
    
      ⚠ Could not compare trunk main with remote — skipping trunk update
    
    This also caused `stackNeedsRebase` to always return true (since
    `IsAncestor("main", ...)` errors out), forcing an unnecessary rebase
    and force-push on every sync.
    
    Add a `BranchExists` check at the top of `fastForwardTrunk`. If the
    local trunk doesn't exist, return silently — there's nothing to
    fast-forward, and the remote tracking ref is sufficient for rebasing
    via git's DWIM resolution.
    skarim authored Jun 15, 2026
    Configuration menu
    Copy the full SHA
    8c2d9e3 View commit details
    Browse the repository at this point in the history
  6. remove silent prefix detection in init (#126)

    * Remove silent prefix detection from args path in init
    
    When explicit branch names containing slashes were passed to `gh stack
    init` (e.g. `gh stack init myprefix/branch`), detectPrefix would
    silently extract the prefix and store it in the stack config. This
    caused `gh stack add otherbranch` to unexpectedly produce
    `myprefix/otherbranch` without the user ever opting in.
    
    Remove the automatic prefix detection from the args path so that
    explicit branch names are taken literally. Users who want a prefix
    should use `--prefix`. The interactive path (no args) continues to
    prompt for confirmation before setting a prefix.
    
    * Remove dead detectPrefix function and its tests
    
    After removing the silent prefix detection from the args path,
    detectPrefix has no production callers. Remove the function and
    its table-driven unit test to avoid maintaining unused code.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    skarim and Copilot authored Jun 15, 2026
    Configuration menu
    Copy the full SHA
    f8c0100 View commit details
    Browse the repository at this point in the history
  7. ensure local trunk branch for required operations (#127)

    * Ensure trunk branch exists locally before commands that need it
    
    When a user starts a stack after renaming their initial branch
    (e.g. `git branch -m newbranch`), the trunk branch (e.g. main) may
    not exist as a local branch. Commands that pass the trunk name to git
    operations like merge-base, rebase, or rev-parse then fail with:
    
      fatal: Not a valid object name main
    
    Add an `ensureLocalTrunk` helper that checks whether the trunk branch
    exists locally and, if not, fetches it from the remote and creates a
    local tracking branch. This mirrors the pattern already used in the
    checkout command for importing stacks.
    
    Commands updated:
    - modify: call ensureLocalTrunk before the linearity check in
      CheckStackLinearity, which uses IsAncestor(trunk, branch). This was
      the originally reported failure.
    - rebase: call ensureLocalTrunk after fetch and before fastForwardTrunk
      and the cascade rebase. git rebase requires a locally resolvable ref;
      the remote tracking ref alone is not sufficient.
    - trunk: call ensureLocalTrunk before CheckoutBranch so that
      `gh stack trunk` works even when trunk was never created locally.
    - checkout: refactor the existing inline BranchExists + CreateBranch
      block to use the shared helper.
    
    Also fix an incorrect comment in fastForwardTrunk that claimed "the
    remote tracking ref is sufficient for rebasing" — verified empirically
    that `git rebase main` fails when main has no local branch, even after
    fetching origin/main.
    
    Commands that were already safe and required no changes:
    - sync: fetches trunk explicitly and fastForwardTrunk guards with
      BranchExists
    - push, switch, navigate, unstack: do not reference trunk
    - add, submit: do not require trunk as a local git ref
    - view: handles IsAncestor errors gracefully (false positive is
      acceptable since rebase will fix it)
    
    * add check to avoid unnecessary remote selection prompt
    skarim authored Jun 15, 2026
    Configuration menu
    Copy the full SHA
    756002b View commit details
    Browse the repository at this point in the history
  8. cache selected remote (#128)

    * Save selected remote to gh-stack.remote git config
    
    Users with multiple git remotes are prompted to choose a remote on
    every gh stack operation, which is tedious. This adds the ability to
    persist that choice so it only needs to be made once.
    
    When a user interactively selects a remote (because multiple remotes
    exist and none is configured as a push default), they are now shown a
    Y/n follow-up prompt offering to save that remote for all future gh
    stack operations. If accepted, the choice is written to the local git
    config key `gh-stack.remote`, and instructions for changing or clearing
    it are printed.
    
    The saved remote is checked in `ResolveRemote` after the standard git
    push config keys (branch.<name>.pushRemote, remote.pushDefault,
    branch.<name>.remote) but before falling back to listing all remotes.
    This means per-branch git push configuration still takes precedence,
    and the --remote flag on individual commands continues to override
    everything.
    
    All commands that resolve a remote (push, submit, sync, rebase,
    checkout, link, modify, trunk) go through the shared `pickRemote`
    helper, so they all benefit automatically.
    
    Changes:
    
    - Add GetSavedRemote, SaveRemote, ClearRemote to the git Ops interface,
      defaultOps implementation, public wrappers, and MockOps
    - Check gh-stack.remote in ResolveRemote's priority chain
    - Move pickRemote from push.go to utils.go as a shared helper
    - Add save-remote confirmation prompt after interactive remote selection
    - Add unit tests for pickRemote save/decline/skip/override flows
    - Add integration tests for ResolveRemote with saved remote and
      precedence, and for the SaveRemote/GetSavedRemote/ClearRemote
      lifecycle
    
    * add error message for save failure
    
    Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
    skarim and Copilot authored Jun 15, 2026
    Configuration menu
    Copy the full SHA
    4c05e58 View commit details
    Browse the repository at this point in the history
  9. rebase without trunk (#129)

    * flag for rebasing without trunk
    
    * update docs with new rebase flag
    skarim authored Jun 15, 2026
    Configuration menu
    Copy the full SHA
    e45a88c View commit details
    Browse the repository at this point in the history
Loading