Skip to content
Git & PRs
Skill

/gh-stack

Manages stacked PRs and splits multi-part work into reviewable branches with gh-stack. Use for stack creation, viewing, edits, push, submit, sync, rebase, merge, or checkout; when asked to split or isolate work for review; whenever a user mentions a stack, branch layers,

From plugin
gh-stack
1.8k1 skill

Claude Code

$ npx -y skills add github/gh-stack --skill gh-stack --agent claude-code

SKILL.md

gh-stack.SKILL.md
name: gh-stack
description: >
  Manages stacked PRs and splits multi-part work into reviewable branches with gh-stack.
  Use for stack creation, viewing, edits, push, submit, sync, rebase, merge, or checkout;
  when asked to split or isolate work for review; whenever a user mentions a stack,
  branch layers, dependent PRs, or gh stack; or when a stack is checked out.
metadata:
  author: github
  version: "0.2.0"

gh-stack

`gh stack` is a [GitHub CLI](https://cli.github.com/) extension for stacked branches and pull requests. A stack is an ordered chain of branches rooted on a trunk, where each branch has one PR based on the branch below it, so a reviewer sees only that layer's diff.

`gh stack` prints a stack trunk-first, left to right:

(main) <- auth <- api <- frontend

Left is the **bottom**, right is the **top**. `auth` is based on `main` and merges first; `frontend` merges last. `up` moves toward the top, away from trunk; `down` moves toward it. Foundational work belongs at the bottom, code that depends on it above. For how to choose the layers, read `references/stack-design.md`.

Setup

Requires Git 2.36+ and an authenticated GitHub CLI.

gh extension install github/gh-stack
git config rerere.enabled true         # remember conflict resolutions
git config remote.pushDefault origin   # required if the repo has more than one remote

Non-interactive use

`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.

**Multiple remotes:** never run `push`, `submit`, `sync`, `rebase`, or `link` without `--remote <name>` unless `remote.pushDefault` is configured. `checkout` and `trunk` have no `--remote` flag and require the config.

| Always run | Never run bare | Why | |---|---|---| | `gh stack view --json` | `gh stack view` | opens a TUI under a PTY | | `gh stack submit --auto` | `gh stack submit` | prompts for a title per new PR | | `gh stack merge <target> --yes` | `gh pr merge` | `gh pr merge` cannot merge a stack | | `gh stack init <branch>...` | `gh stack init` | prompts for branch names | | `gh stack add <branch>` | `gh stack add` | prompts for a name, and fails even when piped | | `gh stack checkout <target>` | `gh stack checkout` | opens a selection menu | | `gh stack up` / `down` / `top` / `bottom` | `gh stack switch` | `switch` is menu-only | | — | `gh stack modify` | TUI-only, no non-interactive path |

  • `view --short` is safe in both modes, but it is formatted for humans. Use `--json` to parse.
  • **`checkout <pr>` when a different local stack already covers those branches** cannot be forced.

Run `gh stack unstack --local` first (this keeps the stack on GitHub), then retry.

  • **Worktrees:** local stacks share one common-directory catalog. Use `--print-path` with

navigation or explicit-target `checkout` to locate a foreign-owned branch without stealing its checkout. Unoccupied targets are checked out here first. Check the exit status before changing directories; parse only successful path-mode stdout, never status messages.

Branch placement

  • **Starting multi-part work:** create the stack before writing files. Do not implement every

concern on trunk and split it later. Put one dependent concern in each layer, bottom to top.

  • **Editing an existing stack:** check out the layer that owns the change before editing. Never

commit a lower layer's concern on the current top branch. Run `gh stack view --json`; if ownership is unclear, inspect `git log --all -- <path>`. Then check out the owner, edit, commit, rebase upstack, and return to top.

gh stack down                   # or: gh stack checkout api
git add ... && git commit -m "Add get-user endpoint"
gh stack rebase --upstack       # replay every branch above onto the change
gh stack top                    # return to where you were
gh stack push

Core loop

gh stack init auth              # create the stack and check out its branch
git add ... && git commit -m "Add auth middleware"
gh stack add api                # next layer, branched from the current one
git add ... && git commit -m "Add API routes"
gh stack submit --auto          # push every branch and open draft PRs
gh stack view --json            # confirm

Add `--open` to `submit` to create PRs ready for review instead of drafts. Branch names are verbatim — `gh stack add refactor/foo` creates `refactor/foo`.

Staying in 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. If the local and remote stacks have diverged, `sync` prints both chains, makes no changes, and exits 0 with `Sync aborted` — see `references/troubleshooting.md`.

Merging

Scope the merge with an argument:

gh stack merge 42 --yes          # PR #42 plus every unmerged PR below it
gh stack merge 7 --yes           # every unmerged PR in stack #7
gh stack merge 42 --yes --squash # or --merge, --rebase, --merge-method <method>

Pass a PR number to merge that PR and every unmerged PR below it, or a stack number to merge every unmerged PR in that stack. The operation is all-or-nothing: if any PR in that set cannot merge, none do.

Without a method flag the last-used method is reused. If the base branch uses a merge queue, the stack is queued instead and the queue picks the method, ignoring any flag you passed with a warning; queued PRs may land in separate groups.

Reading state

`gh stack view --json` writes JSON to **stdout**. Status messages go to **stderr** — do not parse them, branch on exit codes instead.

trunk           string
currentBranch   string
branches[]      name, head, b
Read more
Stats
1,757
Stars
99
Forks
Active
Maintenance
Go
Language
MIT
License
Last commit
Created

Repo: github/gh-stack

@github
Ships withgh-stack

A GitHub CLI extension for managing stacked branches and pull requests. Stacked PRs break large changes into a chain of small, reviewable pull requests that build on each other.

Stars on GitHub

Momentum

stars in total
1.8k
Star history of github/gh-stack on GitHub, a chart by star-history.com

More skills from other plugins.

gh

gh

Patterns for invoking the GitHub CLI (gh) from agents. Covers structured output, pagination, repo targeting, search vs list, gh…

cli11d47k
@cli@cliInstall Skill
release

release

Worktrunk release workflow. Use when user asks to "do a release", "release a new version", "cut a release", or wants to publish a…

worktrunk10d9.7k
@max-sixty@max-sixtyInstall Skill
field-test

field-test

Exercise git tools, resources, and prompts against a live HTTP server via MCP JSON-RPC over curl. Starts the server, surfaces the…

@cyanheads@cyanheadsInstall Skill
git-surgeon

git-surgeon

Non-interactive hunk-level git staging, unstaging, discarding, undoing, fold, amend, squash, commit splitting, and commit…

@raine@raineInstall Skill

Questions about gh-stack.

Which coding agents can use gh-stack?
gh-stack installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.