blog.dopana

Back

在 GitHub 上使用堆叠的拉取请求时,您经常需要更改栈的结构 - 重新排序分支、合并它们或重命名它们。GitHub CLI 扩展 gh stack 提供了强大的工具来轻松处理这个问题。

问题#

使用堆叠 PR 开发功能时,您经常遇到以下情况:

  • 需要将分支移动到栈中更高或更低的位置
  • 想要合并两个分支
  • 需要从栈中删除分支但保留 PR
  • 想要在现有分支之间插入新分支
  • 需要重命名分支以更好地反映其内容

与其手动执行复杂的 git rebase 和 force push 操作,gh stack 提供了专门的命令。

解决方案#

GitHub CLI 提供两种主要方法来重新构建栈:

1. 使用 gh stack modify(推荐)#

此命令打开一个交互式终端 UI,让您可以进行结构更改并一次性应用所有更改。

gh stack modify
bash

TUI 界面支持以下键绑定:

操作描述
xDrop从栈中删除分支及其提交
dFold down将分支吸收到下方的分支中(向主干方向)
uFold up将分支吸收到上方的分支中(远离主干方向)
iInsert below在下方插入新的空分支(向主干方向)
IInsert above在上方插入新的空分支(远离主干方向)
Shift+↓Move down在栈中向下移动分支(向主干方向)
Shift+↑Move up在栈中向上移动分支(远离主干方向)
rRename重命名分支(打开内联提示)
zUndo撤消上次暂存的操作
Ctrl+SApply应用所有更改

2. 使用 gh stack unstack + gh stack init#

更手动的方法,但对于复杂更改很灵活:

# 1. 删除当前栈
gh stack unstack

# 2. 手动进行结构更改
git branch -m api-routes api-endpoints
git branch -d feature-removed

# 3. 使用新结构重新创建栈
gh stack init db-migrations api-endpoints frontend
bash

重新构建工作流程#

以下是重新构建栈的工作流程:

flowchart TD
    A[当前栈] --> B{方法?}
    B -->|交互式| C[gh stack modify]
    B -->|手动| D[gh stack unstack]
    
    C --> E[打开 TUI]
    E --> F[选择操作]
    F --> G[暂存更改]
    G --> H{完成?}
    H -->|否| F
    H -->|是| I[Ctrl+S 应用]
    
    D --> J[手动更改]
    J --> K[git branch -m/-d]
    K --> L[gh stack init]
    
    I --> M[级联 rebase]
    L --> M
    M --> N[gh stack push]
    N --> O[重新构建的栈]

实际示例#

示例 1:将分支向上移动#

假设您有一个从下到上的栈:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[frontend]
    D --> E[testing]

您想将 testing 移动到 api-routes 上方:

gh stack modify
# 使用 Shift+↑ 将 testing 向上移动
# Ctrl+S 应用
bash

结果:

graph TD
    A[main] --> B[db-migrations]
    B --> C[testing]
    C --> D[api-routes]
    D --> E[frontend]

示例 2:合并两个分支#

当您意识到两个分支应该合并时:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[api-validation]
    D --> E[frontend]

api-validation 折叠到 api-routes 中:

gh stack modify
# 选择 api-validation,按 d(fold down)
# Ctrl+S 应用
bash

结果:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes + validation]
    C --> D[frontend]

示例 3:插入新分支#

当您需要在现有分支之间添加层时:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[frontend]

api-routesfrontend 之间插入 auth-middleware

gh stack modify
# 将光标放在 api-routes 上
# 按 I(insert above)
# 为新分支命名
# Ctrl+S 应用
bash

结果:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[auth-middleware]
    D --> E[frontend]

级联 Rebase 过程#

当您使用 gh stack modify 应用更改时,会发生以下过程:

sequenceDiagram
    participant User as 您
    participant CLI as gh stack modify
    participant Git as Git
    participant Remote as GitHub Remote

    User->>CLI: gh stack modify
    User->>CLI: 暂存更改(移动/折叠/插入)
    User->>CLI: Ctrl-S 应用
    
    CLI->>Git: 如需要重命名分支
    CLI->>Git: 如需要插入新分支
    CLI->>Git: 级联 rebase
    loop 对于每个分支
        CLI->>Git: 将当前分支 rebase 到下方分支上
        Git-->>CLI: Rebase 完成
    end
    
    CLI->>User: 成功通知
    User->>CLI: gh stack push
    CLI->>Remote: 使用 `\-\-force-with-lease` 进行 force push
    Remote-->>CLI: Push 成功
    CLI-->>User: GitHub 上的栈已更新

重要注意事项#

[!WARNING]

  • 无法修改已合并 PR 的分支
  • 结构更改(drop、fold、insert、rename)不能在同一会话中混合
  • 始终使用 --force-with-lease 进行 gh stack push 以确保安全
  • 在大规模重新构建之前备份重要分支

最佳实践#

  • 检查当前栈:在进行更改之前始终运行 gh stack view
  • 使用 TUI:gh stack modify 更安全,因为它在应用之前预览更改
  • 本地测试:确保在推送之前 rebase 成功
  • 沟通:通知您的团队关于主要栈结构更改
  • 备份:为重要栈标记或分支备份

参考资料#