gh-stack
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesegh-stack
gh-stack
gh stackmain (trunk)
└── feat/auth-layer → PR #1 (base: main) - bottom (closest to trunk)
└── feat/api-endpoints → PR #2 (base: feat/auth-layer)
└── feat/frontend → PR #3 (base: feat/api-endpoints) - top (furthest from trunk)The bottom of the stack is the branch closest to the trunk, and the top is the branch furthest from the trunk. Each branch inherits from the one below it. Navigation commands (, , , ) follow this model: moves away from trunk, moves toward it.
updowntopbottomupdowngh stackmain (主干)
└── feat/auth-layer → PR #1 (基准: main) - 底层(最接近主干)
└── feat/api-endpoints → PR #2 (基准: feat/auth-layer)
└── feat/frontend → PR #3 (基准: feat/api-endpoints) - 顶层(最远离主干)堆叠的底层是最接近主干的分支,顶层是最远离主干的分支。每个分支都继承自其下方的分支。导航命令(、、、)遵循此模型: 远离主干移动, 向主干移动。
updowntopbottomupdownWhen to use this skill
适用场景
Use this skill when the user wants to:
- Break a large change into a chain of small, reviewable PRs
- Create, rebase, push, or sync a stack of dependent branches
- Navigate between layers of a branch stack
- View the status of stacked PRs
- Tear down and rebuild a stack to remove, reorder, or rename branches
当用户需要以下操作时使用该工具:
- 将大型变更拆分为一系列小型、便于审查的PR
- 创建、变基、推送或同步依赖型分支堆叠
- 在分支堆叠的不同层级间导航
- 查看堆叠PR的状态
- 拆解并重建堆叠以移除、重新排序或重命名分支
Prerequisites
前置条件
The GitHub CLI () v2.0+ must be installed and authenticated. Install the extension with:
ghbash
gh extension install github/gh-stackBefore using , configure git to prevent interactive prompts:
gh stackbash
git config rerere.enabled true # remember conflict resolutions (skips prompt on init)
git config remote.pushDefault origin # if multiple remotes exist (skips remote picker)必须安装并认证GitHub CLI()v2.0+。使用以下命令安装扩展:
ghbash
gh extension install github/gh-stack在使用之前,配置git以避免交互式提示:
gh stackbash
git config rerere.enabled true # 记住冲突解决方案(初始化时跳过提示)
git config remote.pushDefault origin # 存在多个远程仓库时(跳过远程选择器)Agent rules
Agent使用规则
All commands must be run non-interactively. Every command invocation must include the flags and positional arguments needed to avoid prompts, TUIs, and interactive menus. If a command would prompt for input, it will hang indefinitely.
gh stack- Always supply branch names as positional arguments to ,
init, andadd. Running these commands without arguments triggers interactive prompts.checkout - When a prefix is set, pass only the suffix to .
addwith prefixgh stack add auth→feat. Passingfeat/authcreatesfeat/auth.feat/feat/auth - Always use with
--autoto auto-generate PR titles. Withoutgh stack submit,--autoprompts for a title for each new PR.submit - Always use with
--json. Withoutgh stack view, the command launches an interactive TUI that cannot be operated by agents. There is no other appropriate flag — always pass--json.--json - Use when multiple remotes are configured, or pre-configure
--remote <name>. Without this,git config remote.pushDefault origin,push,submit, andsynctrigger an interactive remote picker.checkout - Avoid branches shared across multiple stacks. If a branch belongs to multiple stacks, commands exit with code 6. Check out a non-shared branch first.
- Plan your stack layers by dependency order before writing code. Foundational changes (models, APIs, shared utilities) go in lower branches; dependent changes (UI, consumers) go in higher branches. Think through the dependency chain before running .
gh stack init - Use standard and
git addfor staging and committing. This gives you full control over which changes go into each branch. Thegit commitshortcut is available but should not be the default approach—stacked PRs are most effective when each branch contains a deliberate, logical set of changes.-Am - Navigate down the stack when you need to change a lower layer. If you're working on a frontend branch and realize you need API changes, don't hack around it at the current layer. Navigate to the appropriate branch (,
gh stack down, orgh stack checkout), make and commit the changes there, rungh stack bottom, then navigate back up to continue.gh stack rebase --upstack
Never do any of the following — each triggers an interactive prompt or TUI that will hang:
- ❌ or
gh stack view— always usegh stack view --shortgh stack view --json - ❌ without
gh stack submit— always use--autogh stack submit --auto - ❌ without branch arguments — always provide branch names
gh stack init - ❌ without a branch name — always provide a branch name
gh stack add - ❌ without an argument — always provide a PR number or branch name
gh stack checkout - ❌ when a different local stack already exists on those branches — this triggers an unbypassable conflict resolution prompt; use
gh stack checkout <pr-number>first to remove the local stack, then retry the checkoutgh stack unstack
所有命令必须以非交互方式运行。 每次命令调用必须包含所需的标志和位置参数,以避免提示、TUI和交互式菜单。如果命令会提示输入,将无限期挂起。
gh stack- 始终为、
init和add提供分支名称作为位置参数。不带参数运行这些命令会触发交互式提示。checkout - 设置前缀后,仅将后缀传递给。例如,前缀为
add时,feat会创建gh stack add auth。如果传递feat/auth,则会创建feat/auth。feat/feat/auth - **始终在中使用
gh stack submit**以自动生成PR标题。如果不带--auto,--auto会为每个新PR提示输入标题。submit - 始终在中使用
gh stack view。不带--json时,该命令会启动Agent无法操作的交互式TUI。没有其他合适的标志——必须始终传递--json。--json - 配置多个远程仓库时,使用,或预先在git配置中设置
--remote <name>。如果不这样做,remote.pushDefault origin、push、submit和sync会触发交互式远程选择器。checkout - 避免分支跨多个堆叠共享。如果一个分支属于多个堆叠,命令会以代码6退出。先切换到非共享分支。
- 在编写代码前按依赖顺序规划堆叠层级。基础变更(模型、API、共享工具)放在较低的分支中;依赖这些变更的代码放在较高的分支中。在运行前仔细考虑依赖链。
gh stack init - 使用标准的和
git add进行暂存与提交。这样可以完全控制哪些变更进入哪个分支。git commit快捷方式可用,但不应作为默认方法——堆叠PR在每个分支包含一组明确、逻辑相关的变更时效果最佳。-Am - 需要修改底层分支时,导航到堆叠的下层。如果您在前端分支工作时意识到需要修改API,不要在当前层级临时处理。导航到相应的分支(、
gh stack down或gh stack checkout),在那里进行并提交变更,运行gh stack bottom,然后导航回上层继续工作。gh stack rebase --upstack
绝对不要执行以下操作——每项操作都会触发交互式提示或TUI,导致挂起:
- ❌ 或
gh stack view—— 始终使用gh stack view --shortgh stack view --json - ❌ 不带
gh stack submit—— 始终使用--autogh stack submit --auto - ❌ 不带分支参数 —— 始终提供分支名称
gh stack init - ❌ 不带分支名称 —— 始终提供分支名称
gh stack add - ❌ 不带参数 —— 始终提供PR编号或分支名称
gh stack checkout - ❌ 当本地已有基于这些分支的不同堆叠时,运行—— 这会触发无法绕过的冲突解决提示;先使用
gh stack checkout <pr-number>移除本地堆叠,然后重试checkoutgh stack unstack
Thinking about stack structure
堆叠结构设计
Each branch in a stack should represent a discrete, logical unit of work that can be reviewed independently. The changes within a branch should be cohesive—they belong together and make sense as a single PR.
堆叠中的每个分支应代表一个独立、逻辑完整的工作单元,可独立进行审查。分支内的变更应具有内聚性——它们属于同一组,作为单个PR是合理的。
Dependency chain
依赖链
Stacked branches form a dependency chain: each branch builds on the one below it. This means foundational changes must go in lower (earlier) branches, and code that depends on them goes in higher (later) branches.
Plan your layers before writing code. For example, a full-stack feature might be structured like this (use branch names relevant to your actual task, not these generic ones):
main (trunk)
└── feat/data-models ← shared types, database schema
└── feat/api-endpoints ← API routes that use the models
└── feat/frontend-ui ← UI components that call the APIs
└── feat/integration ← tests that exercise the full stackThis is illustrative — choose branch names and layer boundaries that reflect the specific work you're doing. The key principle is: if code in one layer depends on code in another, the dependency must be in the same branch or a lower one.
堆叠分支形成依赖链:每个分支都基于其下方的分支构建。这意味着基础变更必须放在较低(较早)的分支中,依赖这些变更的代码放在较高(较晚)的分支中。
在编写代码前规划层级。例如,一个全栈功能的结构可能如下(使用与实际任务相关的分支名称,而非这些通用名称):
main (主干)
└── feat/data-models ← 共享类型、数据库模式
└── feat/api-endpoints ← 使用模型的API路由
└── feat/frontend-ui ← 调用API的UI组件
└── feat/integration ← 测试全栈功能这只是示例——选择能反映具体工作的分支名称和层级边界。核心原则是:如果某一层级的代码依赖另一层级的代码,依赖项必须位于同一分支或更低层级的分支中。
Branch naming
分支命名
Prefer initializing stacks with a prefix (). Prefixes group branches under a namespace (e.g., , ) and keep branch names clean and consistent. When a prefix is set, pass only the suffix to subsequent calls — the prefix is applied automatically. Without a prefix, you'll need to pass the full branch name each time.
-pfeat/authfeat/apiadd建议使用前缀()初始化堆叠。前缀将分支分组到命名空间下(例如、),保持分支名称清晰一致。设置前缀后,后续的调用只需传递后缀——前缀会自动应用。如果没有前缀,每次都需要传递完整的分支名称。
-pfeat/authfeat/apiaddStaging changes deliberately
谨慎暂存变更
The main reason to use and directly is to control which changes go into which branch. When you have multiple files in your working tree, you can stage a subset for the current branch, commit them, then create a new branch and stage the rest there:
git addgit commitbash
undefined直接使用和的主要原因是控制哪些变更进入哪个分支。当工作区中有多个文件时,可以暂存当前分支的子集,提交它们,然后创建新分支并暂存剩余的文件:
git addgit commitbash
undefinedYou're on feat/data-models with several new files in your working tree.
您当前在feat/data-models分支,工作区中有几个新文件。
Stage only the model files for this branch:
仅暂存此分支的模型文件:
git add internal/models/user.go internal/models/session.go
git commit -m "Add user and session models"
git add db/migrations/001_create_users.sql
git commit -m "Add user table migration"
git add internal/models/user.go internal/models/session.go
git commit -m "Add user and session models"
git add db/migrations/001_create_users.sql
git commit -m "Add user table migration"
Now create a new branch for the API layer and stage the API files there:
现在为API层创建新分支并暂存API文件:
gh stack add api-routes # created & switched to feat/api-routes branch
git add internal/api/routes.go internal/api/handlers.go
git commit -m "Add user API routes"
This keeps each branch focused on one concern. Multiple commits per branch are fine — the key is that all commits in a branch relate to the same logical concern, and changes that belong to a different concern go in a different branch.gh stack add api-routes # 创建并切换到feat/api-routes分支
git add internal/api/routes.go internal/api/handlers.go
git commit -m "Add user API routes"
这样可以保持每个分支专注于一个关注点。每个分支可以有多个提交——关键是分支中的所有提交都与同一逻辑关注点相关,属于不同关注点的变更应放在不同的分支中。When to create a new branch
何时创建新分支
Create a new branch () when you're starting a different concern that depends on what you've built so far. Signs it's time for a new branch:
gh stack add- You're switching from backend to frontend work
- You're moving from core logic to tests or documentation
- The next set of changes has a different reviewer audience
- The current branch's PR is already large enough to review
当您开始一个新的关注点且该关注点依赖于已完成的工作时,创建新分支()。表明需要新分支的迹象:
gh stack add- 您从后端工作切换到前端工作
- 您从核心逻辑转向测试或文档
- 下一组变更的受众 reviewer 不同
- 当前分支的PR已经大到难以审查
One stack, one story
一个堆叠,一个故事
Think of a stack from the reviewer's perspective: the stack of PRs should tell a cohesive story about a feature or project. A reviewer should be able to read the PRs in sequence and understand the progression of changes, with each PR being a small, logical piece of the whole.
When to use a single stack: All the branches are part of the same feature, project, or closely related effort. Even if the work spans multiple concerns (models, API, frontend), they're all building toward the same goal.
When to create a separate stack: The work is unrelated to your current stack — a different feature, a bug fix in an unrelated area, or an independent refactor. Don't mix unrelated work into a single stack just because you happen to be working on both. Start a new stack with or switch to an existing stack with for each distinct effort.
gh stack initgh stack checkoutSmall, incidental fixes (e.g., fixing a typo you noticed) can go in the current stack if they're trivial. But if a change grows into its own project, it deserves its own stack.
从评审人员的角度考虑堆叠:PR堆叠应讲述一个连贯的功能或项目故事。评审人员应能够按顺序阅读PR,理解变更的进展,每个PR都是整体的一个小型、逻辑完整的部分。
何时使用单个堆叠: 所有分支都属于同一功能、项目或密切相关的工作。即使工作跨越多个关注点(模型、API、前端),它们都朝着同一个目标前进。
何时创建单独的堆叠: 工作与当前堆叠无关——例如不同的功能、无关领域的bug修复或独立的重构。不要仅仅因为您同时在处理两项工作就将无关工作混合到单个堆叠中。为每个不同的工作使用创建新堆叠,或使用切换到现有堆叠。
gh stack initgh stack checkout小型的偶然修复(例如您注意到的拼写错误)如果很琐碎,可以放在当前堆叠中。但如果变更发展成独立的项目,它应该有自己的堆叠。
Quick reference
快速参考
| Task | Command |
|---|---|
| Create a stack (recommended) | |
| Create a stack without prefix | |
| Adopt existing branches | |
| Set custom trunk | |
| Add a branch to stack (suffix only if prefix set) | |
| Add branch + stage all + commit | |
| Push branches to remote | |
| Push to specific remote | |
| Push branches + create PRs | |
| Create PRs as drafts | |
| Sync (fetch, rebase, push) | |
| Sync with specific remote | |
| Rebase entire stack | |
| Rebase upstack only | |
| Continue after conflict | |
| Abort rebase | |
| View stack details (JSON) | |
| Switch branches up/down in stack | |
| Switch to top/bottom branch | |
| Check out by PR | |
| Check out by branch (local only) | |
| Tear down a stack to restructure it | |
| 任务 | 命令 |
|---|---|
| 创建堆叠(推荐方式) | |
| 不带前缀创建堆叠 | |
| 采用现有分支 | |
| 设置自定义主干 | |
| 向堆叠添加分支(设置前缀后仅传递后缀) | |
| 添加分支+暂存所有+提交 | |
| 将分支推送到远程仓库 | |
| 推送到指定远程仓库 | |
| 推送分支并创建PR | |
| 创建草稿PR | |
| 同步(拉取、变基、推送) | |
| 与指定远程仓库同步 | |
| 变基整个堆叠 | |
| 仅变基上层分支 | |
| 解决冲突后继续 | |
| 中止变基 | |
| 查看堆叠详情(JSON格式) | |
| 在堆叠中向上/向下切换分支 | |
| 切换到顶层/底层分支 | |
| 通过PR编号切换 | |
| 通过分支名称切换(仅本地) | |
| 拆解堆叠以重构 | |
Workflows
工作流程
End-to-end: create a stack from scratch
端到端:从头创建堆叠
bash
undefinedbash
undefined1. Initialize a stack with the first branch
1. 使用第一个分支初始化堆叠
gh stack init -p feat auth
gh stack init -p feat auth
→ creates feat/auth and checks it out
→ 创建feat/auth并切换到该分支
2. Write code for the first layer (auth)
2. 为第一层(auth)编写代码
cat > auth.go << 'EOF'
package auth
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// verify token
next.ServeHTTP(w, r)
})
}
EOF
cat > auth.go << 'EOF'
package auth
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// verify token
next.ServeHTTP(w, r)
})
}
EOF
3. Stage and commit using standard git commands
3. 使用标准git命令暂存并提交
git add auth.go
git commit -m "Add auth middleware"
git add auth.go
git commit -m "Add auth middleware"
You can make multiple commits on the same branch
您可以在同一分支上进行多次提交
cat > auth_test.go << 'EOF'
package auth
func TestMiddleware(t *testing.T) {
// test auth middleware
}
EOF
git add auth_test.go
git commit -m "Add auth middleware tests"
cat > auth_test.go << 'EOF'
package auth
func TestMiddleware(t *testing.T) {
// test auth middleware
}
EOF
git add auth_test.go
git commit -m "Add auth middleware tests"
4. When you're ready for a new concern, add the next branch
4. 准备好处理新关注点时,添加下一个分支
gh stack add api-routes
gh stack add api-routes
→ creates feat/api-routes (prefix applied automatically — just pass the suffix)
→ 自动应用前缀,创建feat/api-routes
5. Write code for the API layer
5. 为API层编写代码
cat > api.go << 'EOF'
package api
func RegisterRoutes(mux *http.ServeMux) {
mux.HandleFunc("/users", handleUsers)
}
EOF
git add api.go
git commit -m "Add API routes"
cat > api.go << 'EOF'
package api
func RegisterRoutes(mux *http.ServeMux) {
mux.HandleFunc("/users", handleUsers)
}
EOF
git add api.go
git commit -m "Add API routes"
6. Add a third layer for frontend
6. 添加第三层用于前端
gh stack add frontend
gh stack add frontend
→ creates feat/frontend (just the suffix — prefix is automatic)
→ 自动应用前缀,创建feat/frontend
cat > frontend.go << 'EOF'
package frontend
func RenderDashboard(w http.ResponseWriter) {
// calls the API endpoints from the layer below
}
EOF
git add frontend.go
git commit -m "Add frontend dashboard"
cat > frontend.go << 'EOF'
package frontend
func RenderDashboard(w http.ResponseWriter) {
// calls the API endpoints from the layer below
}
EOF
git add frontend.go
git commit -m "Add frontend dashboard"
── Stack complete: feat/auth → feat/api-routes → feat/frontend ──
── 堆叠完成:feat/auth → feat/api-routes → feat/frontend ──
7. Push everything and create draft PRs
7. 推送所有内容并创建草稿PR
gh stack submit --auto --draft
gh stack submit --auto --draft
8. Verify the stack
8. 验证堆叠
gh stack view --json
> **Shortcut:** If you prefer a faster flow, `gh stack add -Am "message" branch-name` combines staging, committing, and branch creation into one command. This is useful for single-commit layers but bypasses deliberate staging.gh stack view --json
> **快捷方式:** 如果您更喜欢更快的流程,`gh stack add -Am "message" branch-name`将暂存、提交和分支创建合并为一个命令。这适用于单提交层级,但会跳过谨慎的暂存步骤。Making mid-stack changes
对堆叠中层进行修改
This is a critical workflow for agents. When you're working on a higher layer and realize you need to change something in a lower layer (e.g., you're building frontend components but need to add an API endpoint), navigate down to the correct branch, make the change there, and rebase.
bash
undefined这是Agent的关键工作流程。当您在较高层级工作时,意识到需要修改较低层级的内容(例如,您正在构建前端组件,但需要添加一个API端点),导航到正确的分支,在那里进行修改,然后变基。
bash
undefinedYou're on feat/frontend but need to add an API endpoint
您当前在feat/frontend分支,但需要添加一个API端点
1. Navigate to the API branch
1. 导航到API分支
gh stack down
gh stack down
or: gh stack checkout feat/api-routes
或:gh stack checkout feat/api-routes
2. Make the change where it belongs
2. 在合适的位置进行修改
cat > users_api.go << 'EOF'
package api
func handleGetUser(w http.ResponseWriter, r *http.Request) {
// new endpoint the frontend needs
}
EOF
git add users_api.go
git commit -m "Add get-user endpoint"
cat > users_api.go << 'EOF'
package api
func handleGetUser(w http.ResponseWriter, r *http.Request) {
// new endpoint the frontend needs
}
EOF
git add users_api.go
git commit -m "Add get-user endpoint"
3. Rebase everything above to pick up the change
3. 变基所有上层分支以获取变更
gh stack rebase --upstack
gh stack rebase --upstack
4. Navigate back to where you were working
4. 导航回之前工作的分支
gh stack top
gh stack top
or: gh stack checkout feat/frontend
或:gh stack checkout feat/frontend
5. Continue working — the API changes are now available
5. 继续工作——API变更现在可用
**Why this matters:** If you make API changes on the frontend branch, those changes will end up in the wrong PR. The API PR won't include them, and the frontend PR will have unrelated API diffs mixed in. Always put changes in the branch where they logically belong.
**为什么这很重要:** 如果您在前端分支上进行API变更,这些变更会进入错误的PR。API PR不会包含它们,而前端PR会混合无关的API差异。始终将变更放在逻辑上所属的分支中。Modify a mid-stack branch and sync
修改堆叠中层分支并同步
When you need to revisit a branch after the initial creation (e.g., responding to review feedback):
bash
undefined当初始创建后需要重新访问分支时(例如,响应审查反馈):
bash
undefined1. Navigate to the branch that needs changes
1. 导航到需要修改的分支
gh stack bottom
gh stack bottom
or: gh stack checkout feat/auth
或:gh stack checkout feat/auth
or: gh stack checkout 42 (by PR number)
或:gh stack checkout 42 (通过PR编号)
2. Make changes and commit
2. 进行修改并提交
cat > auth.go << 'EOF'
package auth
// updated implementation
EOF
git add auth.go
git commit -m "Fix auth token validation"
cat > auth.go << 'EOF'
package auth
// updated implementation
EOF
git add auth.go
git commit -m "Fix auth token validation"
3. Rebase everything above this branch
3. 变基此分支上方的所有分支
gh stack rebase --upstack
gh stack rebase --upstack
4. Push the updated stack
4. 推送更新后的堆叠
gh stack push
undefinedgh stack push
undefinedRoutine sync after merges
合并后的例行同步
bash
undefinedbash
undefinedSingle command: fetch, rebase, push, sync PR state
单个命令:拉取、变基、推送、同步PR状态
gh stack sync
undefinedgh stack sync
undefinedSquash-merge recovery
squash合并恢复
When a PR is squash-merged on GitHub, the original branch's commits no longer exist in the trunk history. detects this automatically and uses to correctly replay remaining commits.
gh stackgit rebase --ontobash
undefined当PR在GitHub上被squash合并后,原始分支的提交不再存在于主干历史中。会自动检测到这一点,并使用正确重放剩余的提交。
gh stackgit rebase --ontobash
undefinedAfter PR #1 (feat/auth) is squash-merged on GitHub:
PR #1(feat/auth)在GitHub上被squash合并后:
gh stack sync
gh stack sync
→ fetches latest, detects the merge, fast-forwards trunk
→ 拉取最新变更,检测到合并,快进主干
→ rebases feat/api-routes onto updated trunk (skips merged branch)
→ 将feat/api-routes变基到更新后的主干(跳过已合并的分支)
→ rebases feat/frontend onto feat/api-routes
→ 将feat/frontend变基到feat/api-routes
→ pushes updated branches
→ 推送更新后的分支
→ reports: "Merged: #1"
→ 报告:"Merged: #1"
Verify the result
验证结果
gh stack view --json
gh stack view --json
→ feat/auth shows "isMerged": true, "state": "MERGED"
→ feat/auth显示"isMerged": true, "state": "MERGED"
→ feat/api-routes and feat/frontend show updated heads
→ feat/api-routes和feat/frontend显示更新后的头部
If `sync` hits a conflict during this process, it restores all branches to their pre-rebase state and exits with code 3. See [Handle rebase conflicts](#handle-rebase-conflicts-agent-workflow) for the resolution workflow.
如果`sync`在此过程中遇到冲突,会将所有分支恢复到变基前的状态并以代码3退出。请参阅[处理变基冲突](#处理变基冲突-agent-workflow)了解解决流程。Handle rebase conflicts (agent workflow)
处理变基冲突(Agent工作流程)
bash
undefinedbash
undefined1. Start the rebase
1. 开始变基
gh stack rebase
gh stack rebase
2. If exit code 3 (conflict):
2. 如果退出代码为3(冲突):
- Parse stderr for conflicted file paths
- 解析stderr中的冲突文件路径
- Read those files to find <<<<<<< / ======= / >>>>>>> markers
- 读取这些文件以找到<<<<<<< / ======= / >>>>>>>标记
- Edit files to resolve conflicts
- 编辑文件以解决冲突
- Stage resolved files:
- 暂存已解决的文件:
git add path/to/resolved-file.go
git add path/to/resolved-file.go
3. Continue the rebase
3. 继续变基
gh stack rebase --continue
gh stack rebase --continue
4. If another conflict occurs, repeat steps 2-3
4. 如果再次发生冲突,重复步骤2-3
5. If unable to resolve, abort to restore everything
5. 如果无法解决,中止以恢复所有内容
gh stack rebase --abort
undefinedgh stack rebase --abort
undefinedParsing --json
output
--json解析--json
输出
--jsonbash
undefinedbash
undefinedGet stack state as JSON
获取JSON格式的堆叠状态
output=$(gh stack view --json)
output=$(gh stack view --json)
Check if any branch needs a rebase, and rebase if so
检查是否有分支需要变基,如果有则进行变基
needs_rebase=$(echo "$output" | jq '[.branches[] | select(.needsRebase == true)] | length')
if [ "$needs_rebase" -gt 0 ]; then
echo "Branches need rebase, rebasing stack..."
gh stack rebase
fi
needs_rebase=$(echo "$output" | jq '[.branches[] | select(.needsRebase == true)] | length')
if [ "$needs_rebase" -gt 0 ]; then
echo "Branches need rebase, rebasing stack..."
gh stack rebase
fi
Get all open PR URLs
获取所有开放PR的URL
echo "$output" | jq -r '.branches[] | select(.pr.state == "OPEN") | .pr.url'
echo "$output" | jq -r '.branches[] | select(.pr.state == "OPEN") | .pr.url'
Find merged branches
查找已合并的分支
echo "$output" | jq -r '.branches[] | select(.isMerged == true) | .name'
echo "$output" | jq -r '.branches[] | select(.isMerged == true) | .name'
Get the current branch
获取当前分支
echo "$output" | jq -r '.currentBranch'
echo "$output" | jq -r '.currentBranch'
Check if the stack is fully merged (all branches merged)
检查堆叠是否完全合并(所有分支都已合并)
echo "$output" | jq '[.branches[] | .isMerged] | all'
undefinedecho "$output" | jq '[.branches[] | .isMerged] | all'
undefinedRestructure a stack (remove a branch, reorder, or rename)
重构堆叠(移除分支、重新排序或重命名)
Use to tear down the stack, make structural changes, then re-init:
unstackbash
undefined使用拆解堆叠,进行结构性修改,然后重新初始化:
unstackbash
undefined1. Remove the stack (locally and on GitHub)
1. 移除堆叠(本地和GitHub上),然后重建
gh stack unstack
gh stack unstack
gh stack init --base main --adopt new-branch-1 new-branch-2 new-branch-3 # 重新排序
2. Make structural changes — e.g. delete a branch, reorder, rename
仅移除本地跟踪(保留GitHub上的堆叠)
git branch -m old-branch-1 new-branch-1
gh stack unstack --local
3. Re-create the stack with the new structure
指定分支以确定要拆解的堆叠
gh stack init --base main --adopt new-branch-1 new-branch-2 new-branch-3
---gh stack unstack feature-auth
---Commands
命令详解
Initialize a stack — gh stack init
gh stack init初始化堆叠 — gh stack init
gh stack initCreates a new stack. Always provide at least one branch name as a positional argument — running without branch arguments triggers interactive prompts that agents cannot use.
gh stack init [flags] <branches...>bash
undefined创建新堆叠。始终至少提供一个分支名称作为位置参数——不带分支参数运行会触发Agent无法使用的交互式提示。
gh stack init [flags] <branches...>bash
undefinedSet a branch prefix (recommended — subsequent add
calls only need the suffix)
add设置分支前缀(推荐——后续add
调用只需传递后缀)
addgh stack init -p feat auth
gh stack init -p feat auth
→ creates feat/auth
→ 创建feat/auth
Multi-part prefix (slashes are fine — suffix-only rule still applies)
多部分前缀(支持斜杠——仍适用仅传递后缀的规则)
gh stack init -p monalisa/billing auth
gh stack init -p monalisa/billing auth
→ creates monalisa/billing/auth
→ 创建monalisa/billing/auth
Create a stack with new branches (no prefix — use full branch names)
创建新分支堆叠(不带前缀——使用完整分支名称)
gh stack init branch-a branch-b branch-c
gh stack init branch-a branch-b branch-c
Use a different trunk branch
使用不同的主干分支
gh stack init --base develop branch-a branch-b
gh stack init --base develop branch-a branch-b
Adopt existing branches into a stack
采用现有分支到堆叠中
gh stack init --adopt branch-a branch-b branch-c
| Flag | Description |
|------|-------------|
| `-b, --base <branch>` | Trunk branch (defaults to the repo's default branch) |
| `-a, --adopt` | Adopt existing branches instead of creating new ones |
| `-p, --prefix <string>` | Branch name prefix. Subsequent `add` calls only need the suffix (e.g., with `-p feat`, `gh stack add auth` creates `feat/auth`) |
**Behavior:**
- Using `-p` is recommended — it simplifies branch naming for subsequent `add` calls
- Creates any branches that don't already exist (branching from the trunk branch)
- In `--adopt` mode: validates all branches exist, rejects if any is already in a stack or has an existing PR
- Checks out the last branch in the list
- Enables `git rerere` so conflict resolutions are remembered across rebases. On first run in a repo, this may trigger a confirmation prompt — pre-configure with `git config rerere.enabled true` to avoid it
---gh stack init --adopt branch-a branch-b branch-c
| 标志 | 描述 |
|------|-------------|
| `-b, --base <branch>` | 主干分支(默认为仓库的默认分支) |
| `-a, --adopt` | 采用现有分支而非创建新分支 |
| `-p, --prefix <string>` | 分支名称前缀。后续`add`调用只需传递后缀(例如,前缀为`feat`时,`gh stack add auth`会创建`feat/auth`) |
**行为:**
- 推荐使用`-p`——简化后续`add`调用的分支命名
- 创建任何不存在的分支(基于主干分支创建)
- 在`--adopt`模式下:验证所有分支是否存在,如果任何分支已属于某个堆叠或已有PR则拒绝
- 切换到列表中的最后一个分支
- 启用`git rerere`以便在变基时记住冲突解决方案。在仓库中首次运行时,可能会触发确认提示——预先配置`git config rerere.enabled true`以避免。
---Add a branch — gh stack add
gh stack add添加分支 — gh stack add
gh stack addAdd a new branch on top of the current stack. Must be run while on the topmost branch (or the trunk if the stack has no branches yet). Always provide a branch name — running without one triggers an interactive prompt.
gh stack add [flags] <branch>Recommended workflow — create the branch, then use standard git:
bash
undefined在当前堆叠的顶部添加新分支。必须在最顶层分支(或堆叠为空时的主干分支)上运行。始终提供分支名称——不带参数运行会触发交互式提示。
gh stack add [flags] <branch>推荐工作流程 — 创建分支,然后使用标准git命令:
bash
undefinedCreate a new branch and switch to it (just the suffix — prefix is applied automatically)
创建新分支并切换到该分支(仅传递后缀——前缀会自动应用)
gh stack add api-routes
gh stack add api-routes
Write code, stage deliberately, and commit
编写代码,谨慎暂存并提交
git add internal/api/routes.go internal/api/handlers.go
git commit -m "Add user API routes"
git add internal/api/routes.go internal/api/handlers.go
git commit -m "Add user API routes"
Make more commits on the same branch as needed
根据需要在同一分支上进行更多提交
git add internal/api/middleware.go
git commit -m "Add rate limiting middleware"
**Shortcut — stage, commit, and branch in one command:**
```bashgit add internal/api/middleware.go
git commit -m "Add rate limiting middleware"
**快捷方式 — 暂存、提交和分支创建一步完成:**
```bashCreate a new branch, stage all changes, and commit
创建新分支,暂存所有变更并提交
gh stack add -Am "Add API routes" api-routes
gh stack add -Am "Add API routes" api-routes
Create a new branch, stage tracked files only, and commit
创建新分支,仅暂存已跟踪文件并提交
gh stack add -um "Fix auth bug" auth-fix
| Flag | Description |
|------|-------------|
| `-m, --message <string>` | Create a commit with this message |
| `-A, --all` | Stage all changes including untracked files (requires `-m`) |
| `-u, --update` | Stage tracked files only (requires `-m`) |
**Behavior notes:**
- `-A` and `-u` are mutually exclusive.
- When the current branch has no commits (e.g., right after `init`), `add -Am` commits directly on the current branch instead of creating a new one.
- **Prefix handling:** Only pass the suffix when a prefix is set. `gh stack add api` with prefix `todo` → `todo/api`. Passing `todo/api` creates `todo/todo/api`. Without a prefix, pass the full branch name.
- If called from a branch that is not the topmost in the stack, exits with code 5: `"can only add branches on top of the stack"`. Use `gh stack top` to switch first.
- **Uncommitted changes:** When using `gh stack add branch-name` without `-Am`, any uncommitted changes (staged or unstaged) in your working tree carry over to the new branch. This is standard git behavior — the working tree is not touched. Commit or stash changes on the current branch before running `add` if you want a clean starting point on the new branch.
---gh stack add -um "Fix auth bug" auth-fix
| 标志 | 描述 |
|------|-------------|
| `-m, --message <string>` | 使用此消息创建提交 |
| `-A, --all` | 暂存所有变更,包括未跟踪文件(需要`-m`) |
| `-u, --update` | 仅暂存已跟踪文件(需要`-m`) |
**行为说明:**
- `-A`和`-u`互斥。
- 当当前分支没有提交时(例如,刚运行`init`后),`add -Am`会直接在当前分支上提交,而不是创建新分支。
- **前缀处理:** 设置前缀后仅传递后缀。前缀为`todo`时,`gh stack add api`会创建`todo/api`。如果传递`todo/api`,则会创建`todo/todo/api`。不带前缀时,传递完整分支名称。
- 如果从堆叠中非顶层的分支调用,会以代码5退出:`"can only add branches on top of the stack"`。先使用`gh stack top`切换到顶层分支。
- **未提交的变更:** 使用`gh stack add branch-name`而不带`-Am`时,工作区中所有未提交的变更(已暂存或未暂存)会被带到新分支中。这是标准的git行为——工作区不会被修改。如果希望新分支有一个干净的起点,在运行`add`之前提交或暂存当前分支的变更。
---Push branches to remote — gh stack push
gh stack push推送分支到远程仓库 — gh stack push
gh stack pushPush all stack branches to the remote.
gh stack push [flags]bash
undefined将所有堆叠分支推送到远程仓库。
gh stack push [flags]bash
undefinedPush all branches
推送所有分支
gh stack push
gh stack push
Push to specific remote
推送到指定远程仓库
gh stack push --remote upstream
| Flag | Description |
|------|-------------|
| `--remote <name>` | Remote to push to (use if multiple remotes exist) |
**Behavior:**
- Pushes all active (non-merged) branches atomically (`--force-with-lease --atomic`)
- Does **not** create or update pull requests — use `gh stack submit` for that
**Output (stderr):**
- `Pushed N branches` summary
---gh stack push --remote upstream
| 标志 | 描述 |
|------|-------------|
| `--remote <name>` | 要推送的远程仓库(存在多个远程仓库时使用) |
**行为:**
- 以原子方式推送所有活动(未合并)分支(`--force-with-lease --atomic`)
- **不会**创建或更新拉取请求——使用`gh stack submit`进行此操作
**输出(stderr):**
- `Pushed N branches` 摘要
---Submit branches and create PRs — gh stack submit
gh stack submit提交分支并创建PR — gh stack submit
gh stack submitPush all stack branches and create PRs on GitHub. Always pass — without it, prompts for a PR title for each new branch.
--autosubmitbash
undefined推送所有堆叠分支并在GitHub上创建PR。始终传递——不带时,会为每个新分支提示输入PR标题。
--auto--autosubmitbash
undefinedSubmit and auto-title new PRs (required for non-interactive use)
提交并自动生成新PR的标题(非交互使用必需)
gh stack submit --auto
gh stack submit --auto
Submit and create PRs as drafts
提交并创建草稿PR
gh stack submit --auto --draft
| Flag | Description |
|------|-------------|
| `--auto` | Auto-generate PR titles without prompting (**required** for non-interactive use) |
| `--draft` | Create new PRs as drafts |
| `--remote <name>` | Remote to push to (use if multiple remotes exist) |
**Behavior:**
- Pushes all active (non-merged) branches atomically (`--force-with-lease --atomic`)
- Creates a new PR for each branch that doesn't have one (base set to the first non-merged ancestor branch)
- After creating PRs, links them together as a **Stack** on GitHub (requires the repository to have stacks enabled)
- Syncs PR metadata for branches that already have PRs
**PR title auto-generation (`--auto`):**
- Single commit on branch → uses the commit subject as the PR title, commit body as PR body
- Multiple commits on branch → humanizes the branch name (hyphens/underscores → spaces) as the title
**Output (stderr):**
- `Created PR #N for <branch>` for each newly created PR
- `PR #N for <branch> is up to date` for existing PRs
- `Pushed and synced N branches` summary
---gh stack submit --auto --draft
| 标志 | 描述 |
|------|-------------|
| `--auto` | 自动生成PR标题而不提示(**非交互使用必需**) |
| `--draft` | 将新PR创建为草稿 |
| `--remote <name>` | 要推送的远程仓库(存在多个远程仓库时使用) |
**行为:**
- 以原子方式推送所有活动(未合并)分支(`--force-with-lease --atomic`)
- 为每个没有PR的分支创建新PR(基准分支设置为第一个未合并的祖先分支)
- 创建PR后,在GitHub上将它们链接为一个**Stack**(需要仓库启用堆叠功能)
- 为已有PR的分支同步PR元数据
**PR标题自动生成(`--auto`):**
- 分支上有单个提交 → 使用提交主题作为PR标题,提交正文作为PR正文
- 分支上有多个提交 → 将分支名称人性化(连字符/下划线转换为空格)作为标题
**输出(stderr):**
- 每个新创建的PR显示`Created PR #N for <branch>`
- 已有PR显示`PR #N for <branch> is up to date`
- 摘要显示`Pushed and synced N branches`
---Sync the stack — gh stack sync
gh stack sync同步堆叠 — gh stack sync
gh stack syncFetch, rebase, push, and sync PR state in a single command. This is the recommended command for routine synchronization.
gh stack sync [flags]| Flag | Description |
|---|---|
| Remote to fetch from and push to (use if multiple remotes exist) |
What it does (in order):
- Fetch latest changes from the remote
- Fast-forward trunk to match remote (skips if already up to date, warns if diverged)
- Cascade rebase all stack branches onto their updated parents (only if trunk moved). Handles squash-merged PRs automatically. If a conflict is detected, all branches are restored to their pre-rebase state and the command exits with code 3 — see Handle rebase conflicts for the resolution workflow
- Push all active branches atomically
- Sync PR state from GitHub and report the status of each PR
Output (stderr):
✓ Fetched latest changes from origin- or
✓ Trunk main fast-forwarded to <sha>✓ Trunk main is already up to date - per branch (if base moved)
✓ Rebased <branch> onto <base> ✓ Pushed N branches- per branch
✓ PR #N (<branch>) — Open - for merged branches
Merged: #N, #M ✓ Stack synced
在单个命令中完成拉取、变基、推送和同步PR状态。这是例行同步的推荐命令。
gh stack sync [flags]| 标志 | 描述 |
|---|---|
| 要拉取和推送的远程仓库(存在多个远程仓库时使用) |
执行步骤(按顺序):
- 拉取远程仓库的最新变更
- 快进主干以匹配远程仓库(如果已经是最新则跳过,如果分叉则发出警告)
- 级联变基所有堆叠分支到其更新后的父分支(仅在主干移动时)。自动处理squash合并的PR。如果检测到冲突,所有分支都会恢复到变基前的状态,命令以代码3退出——请参阅处理变基冲突了解解决流程
- 以原子方式推送所有活动分支
- 从GitHub同步PR状态并报告每个PR的状态
输出(stderr):
✓ Fetched latest changes from origin- 或
✓ Trunk main fast-forwarded to <sha>✓ Trunk main is already up to date - 每个分支显示(如果基准分支移动)
✓ Rebased <branch> onto <base> ✓ Pushed N branches- 每个分支显示
✓ PR #N (<branch>) — Open - 已合并的分支显示
Merged: #N, #M ✓ Stack synced
Rebase the stack — gh stack rebase
gh stack rebase变基堆叠 — gh stack rebase
gh stack rebasePull from remote and cascade-rebase stack branches. Use this when reports a conflict or when you need finer control (e.g., rebase only part of the stack).
syncgh stack rebase [flags] [branch]bash
undefined从远程仓库拉取并级联变基堆叠分支。当报告冲突或需要更精细的控制(例如,仅变基堆叠的一部分)时使用此命令。
syncgh stack rebase [flags] [branch]bash
undefinedRebase the entire stack
变基整个堆叠
gh stack rebase
gh stack rebase
Rebase only branches from trunk to current branch
仅变基从主干到当前分支的分支
gh stack rebase --downstack
gh stack rebase --downstack
Rebase only branches from current branch to top
仅变基从当前分支到顶层的分支
gh stack rebase --upstack
gh stack rebase --upstack
After resolving a conflict: stage files with git add
, then:
git add解决冲突后:使用git add
暂存文件,然后:
git addgh stack rebase --continue
gh stack rebase --continue
Abort and restore all branches to pre-rebase state
中止并将所有分支恢复到变基前的状态
gh stack rebase --abort
| Flag | Description |
|------|-------------|
| `--downstack` | Only rebase branches from trunk to the current branch |
| `--upstack` | Only rebase branches from the current branch to the top |
| `--continue` | Continue after resolving conflicts |
| `--abort` | Abort and restore all branches |
| `--remote <name>` | Remote to fetch from (use if multiple remotes exist) |
| Argument | Description |
|----------|-------------|
| `[branch]` | Target branch (defaults to the current branch) |
**Conflict handling:** See [Handle rebase conflicts](#handle-rebase-conflicts-agent-workflow) in the Workflows section for the full resolution workflow.
**Squash-merge detection:** If a branch's PR was squash-merged on GitHub, the rebase automatically handles this and correctly replays commits on top of the merge target.
**Rerere (conflict memory):** `git rerere` is enabled by `init` so previously resolved conflicts are auto-resolved in future rebases.
---gh stack rebase --abort
| 标志 | 描述 |
|------|-------------|
| `--downstack` | 仅变基从主干到当前分支的分支 |
| `--upstack` | 仅变基从当前分支到顶层的分支 |
| `--continue` | 解决冲突后继续变基 |
| `--abort` | 中止并恢复所有分支 |
| `--remote <name>` | 要拉取的远程仓库(存在多个远程仓库时使用) |
| 参数 | 描述 |
|----------|-------------|
| `[branch]` | 目标分支(默认为当前分支) |
**冲突处理:** 请参阅工作流程部分的[处理变基冲突](#处理变基冲突-agent-workflow)了解完整的解决流程。
**Squash合并检测:** 如果分支的PR在GitHub上被squash合并,变基会自动处理此情况,并在合并目标上正确重放提交。
**Rerere(冲突记忆):** `init`命令启用了`git rerere`,因此之前解决的冲突会在未来的变基中自动解决。
---View the stack — gh stack view
gh stack view查看堆叠 — gh stack view
gh stack viewDisplay the current stack's branches, PR status, and recent commits. Always pass — without it, this command launches an interactive TUI that agents cannot operate.
--jsonbash
undefined显示当前堆叠的分支、PR状态和最近的提交。始终传递——不带时,此命令会启动Agent无法操作的交互式TUI。
--json--jsonbash
undefinedAlways use --json
始终使用--json
gh stack view --json
| Flag | Description |
|------|-------------|
| `--json` | Output stack data as JSON to stdout (**required** for non-interactive use) |
**`--json` output format:**
```json
{
"trunk": "main",
"prefix": "feat",
"currentBranch": "feat/api-routes",
"branches": [
{
"name": "feat/auth",
"head": "abc1234...",
"base": "def5678...",
"isCurrent": false,
"isMerged": true,
"needsRebase": false,
"pr": {
"number": 42,
"url": "https://github.com/owner/repo/pull/42",
"state": "MERGED"
}
},
{
"name": "feat/api-routes",
"head": "789abcd...",
"base": "abc1234...",
"isCurrent": true,
"isMerged": false,
"needsRebase": false,
"pr": {
"number": 43,
"url": "https://github.com/owner/repo/pull/43",
"state": "OPEN"
}
}
]
}Fields per branch:
- — branch name
name - — current HEAD SHA
head - — parent branch's HEAD SHA at last sync
base - — whether this is the checked-out branch
isCurrent - — whether the PR has been merged
isMerged - — whether the base branch is not an ancestor (non-linear history)
needsRebase - — PR metadata (omitted if no PR exists).
prisstateor"OPEN"."MERGED"
gh stack view --json
| 标志 | 描述 |
|------|-------------|
| `--json` | 以JSON格式输出堆叠数据到stdout(**非交互使用必需**) |
**`--json`输出格式:**
```json
{
"trunk": "main",
"prefix": "feat",
"currentBranch": "feat/api-routes",
"branches": [
{
"name": "feat/auth",
"head": "abc1234...",
"base": "def5678...",
"isCurrent": false,
"isMerged": true,
"needsRebase": false,
"pr": {
"number": 42,
"url": "https://github.com/owner/repo/pull/42",
"state": "MERGED"
}
},
{
"name": "feat/api-routes",
"head": "789abcd...",
"base": "abc1234...",
"isCurrent": true,
"isMerged": false,
"needsRebase": false,
"pr": {
"number": 43,
"url": "https://github.com/owner/repo/pull/43",
"state": "OPEN"
}
}
]
}每个分支的字段:
- — 分支名称
name - — 当前HEAD的SHA
head - — 上次同步时父分支的HEAD SHA
base - — 是否为当前检出的分支
isCurrent - — PR是否已合并
isMerged - — 基准分支是否不是祖先(非线性历史)
needsRebase - — PR元数据(如果没有PR则省略)。
pr为state或"OPEN"。"MERGED"
Navigate the stack
堆叠导航
Move between branches without remembering branch names. These commands are fully non-interactive.
bash
gh stack up # Move up one branch (further from trunk)
gh stack up 3 # Move up three branches
gh stack down # Move down one branch (closer to trunk)
gh stack down 2 # Move down two branches
gh stack top # Jump to the top of the stack (furthest from trunk)
gh stack bottom # Jump to the bottom (first non-merged branch above trunk)Navigation clamps to stack bounds. Merged branches are skipped when navigating from active branches.
无需记住分支名称即可在分支间移动。这些命令完全是非交互式的。
bash
gh stack up # 向上移动一个分支(远离主干)
gh stack up 3 # 向上移动三个分支
gh stack down # 向下移动一个分支(靠近主干)
gh stack down 2 # 向下移动两个分支
gh stack top # 跳转到堆叠的顶层(最远离主干)
gh stack bottom # 跳到底层(主干上方的第一个未合并分支)导航会限制在堆叠范围内。从活动分支导航时会跳过已合并的分支。
Check out a stack — gh stack checkout
gh stack checkout检出堆叠 — gh stack checkout
gh stack checkoutCheck out a stack from a pull request number or branch name. Always provide an argument — running without arguments triggers an interactive selection menu.
gh stack checkoutgh stack checkout <pr-number | branch>bash
undefined通过拉取请求编号或分支名称检出堆叠。始终提供参数——不带参数运行会触发交互式选择菜单。
gh stack checkoutgh stack checkout <pr-number | branch>bash
undefinedBy PR number (pulls from GitHub)
通过PR编号(从GitHub拉取)
gh stack checkout 42
gh stack checkout 42
By branch name (local only)
通过分支名称(仅本地)
gh stack checkout feature-auth
When a PR number is provided (e.g. `123`), the command fetches the stack on GitHub, pulls the branches, and sets up the stack locally. If the stack already exists locally and matches, it switches to the branch.
> **⚠️ Agent warning:** If the local and remote stacks have different branch compositions, this command triggers an interactive conflict-resolution prompt that cannot be bypassed with a flag. To avoid this: run `gh stack unstack` first to remove the conflicting local stack, then retry `gh stack checkout <pr-number>`.
When a branch name is provided, the command resolves it against locally tracked stacks only. This is always safe for non-interactive use.
---gh stack checkout feature-auth
提供PR编号时(例如`123`),命令会在GitHub上获取堆叠,拉取分支,并在本地设置堆叠。如果堆叠已在本地存在且匹配,则切换到该分支。
> **⚠️ Agent警告:** 如果本地和远程堆叠的分支组成不同,此命令会触发交互式冲突解决提示,无法使用标志绕过。为避免这种情况:先运行`gh stack unstack`移除冲突的本地堆叠,然后重试`gh stack checkout <pr-number>`。
提供分支名称时,命令仅解析本地跟踪的堆叠。这对于非交互使用始终是安全的。
---Remove a stack — gh stack unstack
gh stack unstack移除堆叠 — gh stack unstack
gh stack unstackTear down a stack so you can restructure it — remove a branch, reorder branches, rename branches, or make other large changes. After unstacking, use to re-create the stack with the desired structure.
gh stack initgh stack unstack [flags] [branch]bash
undefined拆解堆叠以便重构——移除分支、重新排序分支、重命名分支或进行其他大型修改。拆解后,使用以所需结构重新创建堆叠。
gh stack initgh stack unstack [flags] [branch]bash
undefinedTear down the stack (locally and on GitHub), then rebuild
拆解堆叠(本地和GitHub上),然后重建
gh stack unstack
gh stack init --base main --adopt branch-2 branch-1 branch-3 # reordered
gh stack unstack
gh stack init --base main --adopt new-branch-1 new-branch-2 new-branch-3 # 重新排序
Only remove local tracking (keep the stack on GitHub)
仅移除本地跟踪(保留GitHub上的堆叠)
gh stack unstack --local
gh stack unstack --local
Specify a branch to identify which stack to tear down
指定分支以确定要拆解的堆叠
gh stack unstack feature-auth
| Flag | Description |
|------|-------------|
| `--local` | Only delete the stack locally (keep it on GitHub) |
| Argument | Description |
|----------|-------------|
| `[branch]` | A branch in the stack (defaults to the current branch) |
---gh stack unstack feature-auth
| 标志 | 描述 |
|------|-------------|
| `--local` | 仅在本地删除堆叠(保留GitHub上的堆叠) |
| 参数 | 描述 |
|----------|-------------|
| `[branch]` | 堆叠中的一个分支(默认为当前分支) |
---Output conventions
输出约定
- Status messages go to stderr with emoji prefixes: (success),
✓(error),✗(warning),⚠(info).ℹ - Data output (e.g., ) goes to stdout.
view --json - When piping output, use to suppress status messages if only data output is needed.
2>/dev/null
- 状态消息输出到stderr,带有emoji前缀:(成功)、
✓(错误)、✗(警告)、⚠(信息)。ℹ - 数据输出(例如)输出到stdout。
view --json - 管道输出时,如果只需要数据输出,使用抑制状态消息。
2>/dev/null
Exit codes and error recovery
退出代码与错误恢复
| Code | Meaning | Agent action |
|---|---|---|
| 0 | Success | Proceed normally |
| 1 | Generic error | Read stderr for details; may indicate commit/push failure |
| 2 | Not in a stack | Run |
| 3 | Rebase conflict | Parse stderr for conflicted file paths, resolve conflicts, run |
| 4 | GitHub API failure | Check |
| 5 | Invalid arguments | Fix the command invocation (check flags and arguments) |
| 6 | Disambiguation required | A branch belongs to multiple stacks. Run |
| 7 | Rebase already in progress | Run |
| 8 | Stack is locked | Another |
| 代码 | 含义 | Agent操作 |
|---|---|---|
| 0 | 成功 | 正常继续 |
| 1 | 通用错误 | 读取stderr获取详细信息;可能表示提交/推送失败 |
| 2 | 不在堆叠中 | 运行 |
| 3 | 变基冲突 | 解析stderr中的冲突文件路径,解决冲突,运行 |
| 4 | GitHub API失败 | 检查 |
| 5 | 参数无效 | 修正命令调用(检查标志和参数) |
| 6 | 需要消除歧义 | 一个分支属于多个堆叠。先运行 |
| 7 | 变基已在进行中 | 运行 |
| 8 | 堆叠已锁定 | 另一个 |
Known limitations
已知限制
- Stacks are strictly linear. Branching stacks (multiple children on a single parent) are not supported. Each branch has exactly one parent and at most one child. If you need parallel workstreams, use separate stacks.
- Stack disambiguation cannot be bypassed. If the current branch is the trunk of multiple stacks, commands error with code 6. Check out a non-shared branch first.
- Multiple remotes require or config. If more than one remote is configured, pass
--remoteor set--remote <name>in git config before runningremote.pushDefault,push, orsync.rebase - Merging PRs: Merging Stacked PRs from the CLI is not supported yet. Direct users to open the PR URL in a browser to merge PRs.
- Remote stack checkout requires a PR number. with a branch name only works with locally tracked stacks. Use a PR number (e.g.
checkout) to pull stacks from GitHub.gh stack checkout 123 - PR title and body are auto-generated. There is no flag to set a custom PR title or body during . The title and body are generated from commit messages plus a footer. Use
submitto modify PR title and body after creation.gh pr edit
- 堆叠严格线性。不支持分支堆叠(单个父分支有多个子分支)。每个分支恰好有一个父分支和最多一个子分支。如果需要并行工作流,使用单独的堆叠。
- 无法绕过堆叠歧义消除。如果当前分支是多个堆叠的主干,命令会以代码6错误退出。先切换到非共享分支。
- 多个远程仓库需要或配置。如果配置了多个远程仓库,在运行
--remote、push或sync之前,传递rebase或在git配置中设置--remote <name>。remote.pushDefault - 合并PR: 目前不支持从CLI合并堆叠PR。引导用户在浏览器中打开PR URL以合并PR。
- 远程堆叠检出需要PR编号。使用分支名称的仅适用于本地跟踪的堆叠。使用PR编号(例如
checkout)从GitHub拉取堆叠。gh stack checkout 123 - PR标题和正文自动生成。期间没有标志可以设置自定义PR标题和正文。标题和正文由提交消息加上页脚生成。创建后使用
submit修改PR标题和正文。gh pr edit