| name | using-gh-stack |
| description | MUST be used when working with stacked PRs. gh-stack is a CLI tool for managing stacked PR workflows in squash-merge repos (a Graphite alternative). Covers creating stacks, pushing/creating PRs with submit, navigating (up/down/top/bottom), syncing with main, restacking, merging, and agent/CI usage. Triggers on: stacked PR, gh-stack, create stack, submit stack, push stack, restack, sync stack, stack navigation, up down top bottom, PR dependencies, stack visualization, manage PRs, stacked branches. |
Using gh-stack
Generated by gh-stack learn from gh-stack v0.17.1.
This file is produced by the binary — don't hand-edit it. Refresh after
upgrading with gh-stack learn --skill.
gh-stack is a CLI for managing stacked PRs in squash-merge repositories
(a Graphite/gt alternative). A stack is a chain of dependent branches, each
its own PR, sitting on top of the trunk (usually main).
Install: npm install -g gh-stack (or bun install -g gh-stack)
Terms
| Term | Meaning |
|---|
| trunk | Base branch (usually main) |
| stack | A chain of dependent branches |
| upstack | Child branches (depend on current) |
| downstack | Parent branches (current depends on) |
The current stack follows your current branch
There is no "switch stack" state to manage — gh-stack always operates on the
stack that contains the branch you're on. It resolves this from your current
git branch: the branch's own stack, or (for a new branch built on top of one)
the nearest tracked ancestor's stack. Every command (log, submit, status,
restack, …) acts on that stack automatically.
So to switch stacks, just switch branches — there's nothing gh-stack-specific to
run:
git switch other-feature-branch
gh-stack log
Or use the interactive picker when you don't remember the branch names:
gh-stack checkout --stack
(Plain gh-stack checkout picks a branch within the current stack; add
--stack to pick a different stack.)
Agent/CI mode — read this first
Run non-interactively with --yes/-y or GH_STACK_YES=1 (also enables
--plain: no spinners/colors/box-drawing — clean for log capture).
export GH_STACK_YES=1
- Discover topology without parsing internals:
gh-stack stacks --json
(network-free) or gh-stack status --json (adds PR/CI/review state).
- Always pass
-t/-b to submit so PRs get real titles/bodies instead
of generic auto-generated ones (see below).
- Commands that rebase (
restack, sync, merge) refuse to run on a dirty
tree — commit or stash first.
Core workflow
1. Start a stack
From existing branches (e.g. main → feat-1 → feat-2) — go to the TOP;
init walks down and reconstructs the chain automatically:
git checkout feat-2
gh-stack init
From scratch:
git checkout -b kiliman/first-WEB-1234
gh-stack init
gh-stack create kiliman/second-WEB-5678
gh-stack create kiliman/third-WEB-9012
init options: --name <stack>, --parent <trunk>, --description <text>.
Track a local WIP branch without publishing it — gh-stack add. If you
created a branch with git checkout -b and want to sync/restack it before
opening a PR, add registers it in a stack (network-free — no push, no PR):
gh-stack add
gh-stack add <branch>
It walks local ancestry: a branch sitting on top of an existing stack is adopted
into it (parent auto-detected); otherwise a new stack is created from the chain.
This resolves the catch-22 where sync/restack said "not in any stack" for a
tip you hadn't submitted yet. (submit still auto-tracks too — add is just the
no-publish path.)
2. Push & create PRs — submit
submit is the workhorse: idempotent, scope-aware, self-healing. It pushes
changed branches with --force-with-lease (skips up-to-date ones), creates
missing PRs with the correct base, fixes PR bases, and refreshes the stack
visualization in every PR body.
gh-stack submit
gh-stack submit -d
gh-stack submit --dry-run
gh-stack submit --restack
gh-stack submit -t "<title>" -b "<body>"
gh-stack submit -t "<title>" --body-file /tmp/body.md
gh-stack submit -n
Agents: provide title + body explicitly. --title implies --no-edit
(no prompts); title/body apply to all new PRs created in scope:
gh-stack submit \
-t "Store raw transcription JSON and WebVTT [WEB-7409]" \
-b "$(cat <<'EOF'
## Summary
- Store raw transcription JSON alongside pre-rendered WebVTT
## Test plan
- [ ] Verify both formats persist
EOF
)"
submit -t/-b also updates an existing PR in place — pass them while on a
branch that already has a PR to change just that one (visualization-safe).
--restack chains a restack after submit. submit owns DOWNSTACK (trunk →
current); restack owns UPSTACK (the children). Together they're the everyday
downstack-fix loop in one command: drop downstack → fix → commit →
gh-stack submit --restack pushes the fix AND rebases the children onto it.
3. Navigate
gh-stack log
gh-stack ls
gh-stack up [n]
gh-stack down [n]
gh-stack top
gh-stack bottom
gh-stack checkout
4. Sync & restack
gh-stack sync
gh-stack restack
gh-stack restack --dry-run
⚠️ Restack propagates UPWARD from the current branch. Run it from the
lowest branch you changed, never from the top:
gh-stack bottom
gh-stack submit
gh-stack restack
Changing multiple branches? Finish each one fully before moving up —
edit → test → commit → push → restack, then gh-stack up and repeat. Don't
edit several branches then restack once at the end (only the last branch ends
up pushed).
On rebase conflict: resolve, git add <files>, git rebase --continue,
then gh-stack restack --resume to finish the remaining branches.
sync is self-correcting: if you merged the bottom PR in the GitHub UI,
sync detects it and advances the stack past the merged branch (re-rooting onto
trunk) instead of replaying squashed commits and conflicting.
5. Status
gh-stack status
gh-stack status --current
gh-stack status --json
6. Merge & ship
gh-stack merge
gh-stack merge --approved
gh-stack merge --base
gh-stack merge --dry-run
Merge is top-down everywhere (collapse PRn → PRn-1 → … → base PR, then base → trunk):
merge: the whole stack is approved → lands as a single squash commit.
merge --approved: collapse the contiguous-from-base approved run into
one commit on trunk. Approval is read from the base up — the first un-approved
PR caps the run (unapproved PR4 stops at PR3 even if PR5 is approved). The
unapproved tail is left in place; after the base lands, run gh-stack sync to
re-root the tail onto trunk (it does not block on CI).
merge --base: squash-merge only the bottom PR into trunk and re-root
the next branch onto trunk — one PR per run, re-run for the next. Use this to
land reviewed PRs one at a time. Auto-advances past a bottom PR already merged
outside gh-stack.
--collapse (with merge or merge --approved): stop after collapsing
into the base PR — review on GitHub, then re-run merge to finish.
7. Maintenance
gh-stack delete
gh-stack split
gh-stack rename
gh-stack undo
gh-stack archive
gh-stack doctor
gh-stack update-prs
Stack visualization
submit auto-maintains a ### 📚 Stacked on footer in every PR body. Do not
hand-write your own stack list — it's regenerated each run, so a manual copy
just goes stale and contradicts the auto footer. Describe this PR in its body;
let submit describe the stack. Link a specific sibling inline in prose if
needed.
Safety model
- Snapshots before every destructive op (restack/sync/merge/remove); roll
back with
gh-stack undo. Think of them as a reflog for stack operations.
- Squash-merge safe — uses temporary tags for stable rebasing (handles the
merge-base problem squash-merge creates).
- Never force-pushes trunk.
- Metadata is local and never committed: per-stack files under
.git/.gh-stack/ plus git branch config. Inspect it via gh-stack stacks --json, not by reading the store. (gh-stack doctor migrates the old v2
.git/gh-stack-metadata.json monolith.)
Don'ts
- Don't use
gt/Graphite commands — this is gh-stack.
- Don't restack from the top of the stack — restack flows upward.
- Don't edit multiple branches then restack once — finish each branch first.
- Don't hand-write a stack section in PR bodies —
submit owns it.