gh-stack

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

gh-stack

gh-stack

gh stack
is a GitHub CLI 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
.
gh stack
是一个 GitHub CLI 扩展,用于管理堆叠式 branch 和 pull request。Stack 是一条以 trunk 为根的有序 branch 链,其中每个 branch 都有一个基于其下方 branch 的 PR,因此审查者只会看到该层的 diff。
gh stack
按 trunk 优先、从左到右的顺序打印 stack:
(main) <- auth <- api <- frontend
左侧是底部,右侧是顶部。
auth
基于
main
,会最先合并;
frontend
最后合并。
up
朝顶部移动,远离 trunk;
down
朝 trunk 移动。
基础性工作应放在底部,依赖它的代码放在上方。有关如何选择各层,请阅读
references/stack-design.md
。

Setup

Setup

Requires Git 2.36+ and an authenticated GitHub CLI.
bash
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
需要 Git 2.36+ 和已通过身份验证的 GitHub CLI。
bash
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 runNever run bareWhy
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.
gh stack
的行为取决于 stdout 是否为 TTY。在管道模式下,大多数命令会干净地报错或输出静态文本;在 PTY 下,相同命令会打开提示符或全屏 TUI,并一直阻塞。
Agent harness 的行为各不相同,因此始终传入下列 flags,不要依赖该检测机制。
**多个 remote:**除非已配置
remote.pushDefault
,否则运行
push
、
submit
、
sync
、
rebase
或
link
时始终要传入
--remote <name>
。
checkout
和
trunk
没有
--remote
flag,并且需要该配置。
始终运行不要裸执行原因
gh stack view --json
gh stack view
在 PTY 下会打开 TUI
gh stack submit --auto
gh stack submit
会提示输入每个新 PR 的标题
gh stack merge <target> --yes
gh pr merge
gh pr merge
无法合并 stack
gh stack init <branch>...
gh stack init
会提示输入 branch 名称
gh stack add <branch>
gh stack add
会提示输入名称,即使在管道模式下也会失败
gh stack checkout <target>
gh stack checkout
会打开选择菜单
gh stack up
/
down
/
top
/
bottom
gh stack switch
switch
仅支持菜单操作
—
gh stack modify
仅支持 TUI,没有非交互式路径
  • view --short
    在两种模式下都安全,但它面向人类格式化。需要解析时请使用
    --json
    。
  • **当另一个本地 stack 已覆盖这些 branch 时,无法强制执行
    checkout <pr>
    。**请先运行
    gh stack unstack --local
    (这会在 GitHub 上保留该 stack),然后重试。
  • **Worktree:**本地 stack 共享一个 common-directory catalog。将
    --print-path
    与导航操作或指定目标的
    checkout
    一起使用,以定位由其他 worktree 持有的 branch,而不会抢占其 checkout。未被占用的目标会优先在当前 worktree 中 checkout。切换目录前先检查退出状态;只解析路径模式成功时写入 stdout 的内容,绝不要解析状态消息。

Branch placement

Branch 层级安排

  • 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.
bash
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
  • **开始多项工作时:**在编写文件前创建 stack。不要在 trunk 上实现所有工作项,然后再进行拆分。应按从底到顶的顺序,将每个依赖性工作项分别放入一层。
  • **编辑现有 stack 时:**先 checkout 负责该变更的 layer,再进行编辑。绝不要在当前顶层 branch 上提交属于底层 layer 的工作。运行
    gh stack view --json
    ;如果归属不明确,请检查
    git log --all -- <path>
    。然后 checkout 所属 branch,编辑、提交、rebase upstack,再返回顶部。
bash
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

核心流程

bash
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
.
bash
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
为
submit
添加
--open
,可以创建已准备好供审查的 PR,而不是 draft PR。Branch 名称会按原样使用——
gh stack add refactor/foo
会创建
refactor/foo
。

Staying in sync

保持同步

bash
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
.
bash
gh stack sync                   # fetch, reconcile with GitHub, rebase, push, refresh PR state
gh stack sync --prune           # also delete local branches for merged PRs
在非交互模式下,如果不加
--prune
,绝不会执行 pruning。如果本地和远程 stack 已分叉,
sync
会打印两条 chain,不做任何更改,并以退出码 0 退出并显示
Sync aborted
——参见
references/troubleshooting.md
。

Merging

合并

Scope the merge with an argument:
bash
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.
使用参数限定合并范围:
bash
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>
传入 PR 编号时,会合并该 PR 及其下方的每个未合并 PR;传入 stack 编号时,会合并该 stack 中的每个未合并 PR。该操作具有全有或全无语义:如果集合中的任何 PR 无法合并,则所有 PR 都不会合并。
如果不传 method flag,则会沿用上次使用的方法。如果 base branch 使用 merge queue,则 stack 会改为进入队列,由队列决定合并方式,并忽略传入的 flag,同时给出 warning;排队中的 PR 可能以不同 group 合入。

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, base, isCurrent, isMerged, isQueued, needsRebase
branches[].pr   number, url, state ("OPEN" | "MERGED" | "QUEUED"); absent when no PR exists
base
is the saved SHA of the parent branch that this branch was last known to contain. It may be older than the parent's current tip.
needsRebase
is true when the current parent tip is no longer an ancestor of the branch.
gh stack view --json
会将 JSON 写入 stdout。状态消息会写入 stderr——不要解析这些消息,而应根据退出码进行分支判断。
trunk           string
currentBranch   string
branches[]      name, head, base, isCurrent, isMerged, isQueued, needsRebase
branches[].pr   number, url, state ("OPEN" | "MERGED" | "QUEUED"); absent when no PR exists
base
是父 branch 最后一次已知包含该 branch 时保存的 SHA。它可能早于父 branch 当前的 tip。当父 branch 当前的 tip 不再是该 branch 的 ancestor 时,
needsRebase
为 true。

Exit codes

退出码

CodeMeaningRecovery
0Success—
1Generic errorRead stderr
2Not in a stack
gh stack init
, or
gh stack checkout <target>
3Rebase conflictFollow the Exit 3 recovery below
4GitHub API failureCheck
gh auth status
, retry
5Invalid argumentsFix the invocation; see
<command> --help
6Disambiguation requiredBranch is in several stacks; check out a non-shared branch
7Rebase already in progress
gh stack rebase --continue
or
--abort
8Stack file lockedAnother
gh stack
process is writing; retry after ~5s
9Stacked PRs unavailableNot enabled on the repository; tell the user
10Modify recovery required
gh stack modify --abort
Exit 3 recovery:
  • After
    gh stack rebase
    : resolve the files, run
    git add
    , then
    gh stack rebase --continue
    ; use
    gh stack rebase --abort
    to restore the stack.
  • After
    gh stack sync
    : the stack has already been restored. Run
    gh stack rebase
    to recreate the conflict, then resolve and continue as above.
代码含义恢复方式
0成功—
1通用错误读取 stderr
2不在任何 stack 中
gh stack init
,或
gh stack checkout <target>
3Rebase 冲突按照下方“退出码 3 的恢复方式”操作
4GitHub API 失败检查
gh auth status
,然后重试
5参数无效修正调用方式;参见
<command> --help
6需要消除歧义该 branch 同时位于多个 stack 中;请 checkout 一个非共享 branch
7Rebase 已在进行中
gh stack rebase --continue
或
--abort
8Stack 文件已锁定另一个
gh stack
进程正在写入;约 5 秒后重试
9堆叠式 PR 不可用仓库未启用;请告知用户
10需要恢复 modify 操作
gh stack modify --abort
退出码 3 的恢复方式:
  • 执行
    gh stack rebase
    后:解决文件冲突,运行
    git add
    ,然后执行
    gh stack rebase --continue
    ;使用
    gh stack rebase --abort
    可恢复 stack。
  • 执行
    gh stack sync
    后:stack 已恢复。运行
    gh stack rebase
    重新触发冲突,然后按照上述方式解决并继续。

Constraints

限制

  • Stacks are strictly linear: one parent, at most one child. Use separate stacks for parallel work.
  • rebase
    and
    sync
    automatically update affected clean worktrees; they never auto-stash or create/remove worktrees. Mutations serialize across the clone, and paused operations require recovery in their recorded owners.
  • modify
    supports distributed stack branches, but its editor remains TUI-only. Actions run in affected clean owners; unoccupied branches use the origin. Drop/fold source branches and worktrees are preserved. Recovery flags may run from any worktree and use recorded native operation owners; never resolve/stage in the caller's tree unless the diagnostic names it.
  • There is no non-interactive reorder or removal. Errors may suggest
    gh stack modify
    , but it is TUI-only — restructure with
    unstack
    then
    init
    instead.
  • PR titles and bodies are auto-generated. Use
    gh pr edit
    afterwards to change them.
  • Stack 严格保持线性结构:一个 parent,最多一个 child。并行工作应使用不同的 stack。
  • rebase
    和
    sync
    会自动更新受影响的干净 worktree;它们不会自动 stash,也不会创建或移除 worktree。修改操作会在整个 clone 内串行执行;暂停的操作必须在记录其 owner 的位置恢复。
  • modify
    支持分布式 stack branch,但其编辑器仍仅支持 TUI。相关操作会在受影响的干净 owner 中执行;未被占用的 branch 使用 origin。Drop/fold 的 source branch 和 worktree 会保留。Recovery flag 可以从任意 worktree 运行,并使用已记录的原生命令 owner;除非诊断信息明确指出,否则绝不要在调用方的 tree 中解决冲突或执行 staging。
  • 不存在非交互式的 reorder 或 removal。错误可能建议
    gh stack modify
    ,但它仅支持 TUI——应改用
    unstack
    后再
    init
    来重组。
  • PR 标题和正文会自动生成。之后可使用
    gh pr edit
    修改。

More detail

更多信息

gh stack <command> --help
is authoritative for flags and arguments. Note that
gh stack help <command>
does not work — it prints the top-level help.
Open the reference whose trigger matches the task; no need to preload all three.
  • references/stack-design.md
    — read before creating a stack, when deciding how many layers to use, what belongs in each one, or whether work belongs in a new stack.
  • references/commands.md
    — read when a command fails unexpectedly or you need its preconditions, side effects, atomicity, or ordering guarantees.
  • references/troubleshooting.md
    — read on a rebase conflict, after a squash-merge, on local and remote divergence, when restructuring a stack, or when driving stacks from another tool.
gh stack <command> --help
是 flags 和参数的唯一权威依据。注意,
gh stack help <command>
不起作用——它会打印顶层 help。
仅打开与当前任务触发条件匹配的 reference;无需预加载全部三个。
  • references/stack-design.md
    ——在创建 stack 前、决定使用多少 layer、每一层应包含什么,或工作是否应放入新 stack 时阅读。
  • references/commands.md
    ——在命令意外失败,或需要了解其 precondition、side effect、atomicity 或 ordering guarantee 时阅读。
  • references/troubleshooting.md
    ——在遇到 rebase 冲突、squash-merge 后、local 和 remote divergence、重构 stack,或从另一工具驱动 stack 时阅读。