A stack is a trunk-rooted branch chain. Each branch has a PR based on the branch below it, so its
diff shows only that layer. gh stack prints trunk first:
(main) <- auth <- api <- frontend
Left is the bottom and merges first; right is the top and merges last. up moves away from
trunk; down moves toward it.
Rules
- Repository instructions and explicit user direction override this skill.
- Never merge a stack without explicit user approval. Readiness, green checks, or a prior submit request is not merge authorization.
- Stacks are linear. A layer may represent a code dependency or one bounded issue in an explicitly shared release batch. Keep work outside that release unit in another stack or PR.
- Create the chain before implementation. Put each change on the lowest layer that owns it; edit a lower owner, cascade-rebase upstack, then return to the top.
Read references/stack-design.md before choosing layers.
Setup
gh stack --version || { gh extension install github/gh-stack && gh stack --version; }
git config rerere.enabled true
The contracts below target gh stack v0.1.0. If the installed version differs, current command
help wins.
With several remotes, pass --remote <name> where supported or configure one unambiguous remote
before noninteractive use.
Noninteractive use
gh stack treats terminal stdout as interactive. Run it without a PTY: under a PTY, bare
commands may prompt or open a full-screen TUI. Still use explicit arguments and flags:
| Run | Never run bare | Why |
|---|---|---|
gh stack view --json |
gh stack view |
bare view opens a TUI |
gh stack submit --auto |
gh stack submit |
prompts for each new PR title |
gh stack merge <target> --yes --squash |
gh stack merge |
prompts for scope and method |
gh stack init <branch>... |
gh stack init |
prompts for branch names |
gh stack add <branch> |
gh stack add |
prompts for a name |
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 noninteractive path |
view --short is safe but human-formatted; parse --json. Use current
gh stack <command> --help for exact flags; gh stack help <command> only prints top-level help.
Create and submit
Create one branch at a time while implementing dependent layers:
gh stack init --base <trunk> <bottom-branch>
# edit, validate, stage deliberately, commit
gh stack add <next-branch>
# repeat
gh stack submit --auto
gh stack view --json
Or create/adopt a planned issue-batch chain upfront, bottom to top, before assigning its branches:
gh stack init --base <trunk> <issue-branch-1> <issue-branch-2> <issue-branch-3>
init checks out the final branch. Existing branches are adopted; new ones are created in chain
order. Inspect existing ancestry first. Use ordinary git add and git commit so each branch owns
only its concern.
submit --auto pushes active branches, creates missing PRs as drafts, updates existing PRs where
possible, and links them into a GitHub stack. Read its warnings. Add --open only when PRs should
leave draft state, and use gh pr edit afterward for custom titles and bodies. Submit is not atomic;
rerun it after a partial failure.
Edit a lower layer
gh stack view --json
gh stack down # or checkout the owning branch or PR
# edit, validate, commit
gh stack rebase --upstack
gh stack top
gh stack push
push updates active branches with per-branch force-with-lease and can partially succeed. Inspect
remote heads after failure, repair the rejected branch, and rerun.
Synchronize
gh stack sync
gh stack view --json
sync fetches, reconciles GitHub stack membership, fast-forwards trunk, cascade-rebases, atomically
pushes active branches, refreshes PR state, and updates the GitHub stack object. Add --prune only
to delete local merged branches. On local/remote topology divergence it can print Sync aborted
while exiting 0; that means no changes were made.
Link externally managed branches
gh stack link --base <trunk> <bottom-branch-or-pr> <next> [<top>...]
link creates or updates only the GitHub stack, with no local tracking state. It may push branch
arguments, create PRs, and correct bases. Use it when another branch manager or worktree workflow
owns topology; use checkout <stack-or-pr> later if local tracking is needed.
Merge
After the user explicitly approves the merge, scope it with a PR or stack number and state the method:
gh stack merge <target> --yes --squash # or --merge / --rebase
A PR target merges that PR and every unmerged PR below it; a stack target merges the whole stack.
Direct stack merges are all-or-nothing. A merge queue overrides the method and may land queued PRs
in separate groups. Do not use gh pr merge for a native stack.
Machine-readable state
gh stack view --json writes JSON to stdout; status text goes to stderr. Its stable fields are:
trunk string
currentBranch string
branches[] name, head, base, isCurrent, isMerged, isQueued, needsRebase
branches[].pr number, url, state ("OPEN" | "MERGED" | "QUEUED"); absent without a PR
base is the saved parent SHA and can lag the parent's tip. needsRebase reports that the current
parent tip is no longer an ancestor of the branch.
Exit codes
| Code | Meaning | Recovery |
|---|---|---|
| 0 | Success | Check output: divergent sync can still abort |
| 1 | Generic error | Read stderr |
| 2 | Not in a stack | init, or checkout <stack-or-pr> |
| 3 | Rebase conflict | Resolve and stage, then rebase --continue; or --abort |
| 4 | GitHub API failure | Check gh auth status, then retry |
| 5 | Invalid arguments | Fix invocation from <command> --help |
| 6 | Disambiguation required | Use a branch unique to the intended stack |
| 7 | Rebase already active | rebase --continue or --abort |
| 8 | Stack file locked | Retry after the other process releases it |
| 9 | Stacked PRs unavailable | Report repository availability |
| 10 | Modify recovery required | gh stack modify --abort |
After a failed sync, branches have already been restored; run gh stack rebase to recreate a
conflict before resolving it.
References
Open only what the task needs:
references/stack-design.md— planning layers, branch names, and release batchesreferences/commands.md— command preconditions, side effects, atomicity, and orderingreferences/troubleshooting.md— conflicts, squash merges, divergence, restructuring, and external branch managers