GitHub 原生 Stacked PR 来了:长分支终于可以拆成有序评审链

2026-07-02 41 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

GitHub 终于开始把 stacked PRs 做进平台里了。官方第一方功能叫 gh-stack,目前还在 private preview,需要申请启用。对长期在一个大分支里憋功能、或者靠第三方工具维护 PR 链的团队来说,这件事的意义很直接:把一个大改动拆成一串有顺序的小 PR,并让 GitHub 原生理解它们之间的依赖关系。

Stack 到底解决什么问题

一个 stack 可以理解为一条有序的 PR 链。每个 PR 的 base branch 指向它下面那个 PR,最底层的 PR 最终指向 main

例如一个功能需要三步:

main
  ↑
PR #1: add-db-schema        base: main
  ↑
PR #2: add-service-layer    base: add-db-schema
  ↑
PR #3: add-api-endpoint     base: add-service-layer

传统做法里,开发者常常只有两个坏选择:

  • 把所有改动塞进一个巨大 PR,评审者一次看几千行 diff。
  • 拆成多个 PR,但手动维护 base branch、rebase、merge 顺序,稍不注意 diff 就乱掉。

Stacked PR 的价值在于,它承认“大功能天然有层次”。数据库 schema、内部服务、API、UI 可以分开评审,但仍然保持清晰的依赖顺序。

GitHub 原生支持为什么重要

Stacked PR 并不是新概念。很多团队已经用 Graphite、ghstack、自研脚本或纯 Git 分支纪律在做。但这些方案的问题是:GitHub 页面本身未必真正理解“这是一组相关 PR”。

官方 gh-stack 进入 private preview,说明 GitHub 开始把这个工作流当成平台能力,而不是外部工具补丁。它可能带来的变化包括:

  • PR 链关系更容易被平台展示和维护。
  • 评审者能按顺序看改动,而不是猜哪个 PR 应该先看。
  • 合并时可以更接近“从底到顶”的真实依赖顺序。
  • 团队不用只靠分支命名和 PR 描述来传递上下文。

需要注意的是,当前它仍处于 private preview。也就是说,具体命令、交互细节和限制可能变化。把它用于关键生产流程前,最好先在非核心仓库试跑一轮。

等待 gh-stack 时,可以先这样实践

如果你的仓库还没有启用官方 preview,也可以用现有 git 和 GitHub CLI 模拟 stacked PR 的基本结构。下面这个例子会创建三条分支,并让每个 PR 的 base 指向它下面那条分支。

运行前需要:

  • 已安装并登录 GitHub CLI:gh auth login
  • 当前目录是一个 GitHub 仓库
  • 本地 main 已经更新
  • 把示例里的提交内容替换成你的真实改动
git checkout main
git pull --ff-only

# PR 1: 最底层改动,base 是 main
git checkout -b add-db-schema
mkdir -p db
echo "-- add users table" > db/001_add_users.sql
git add db/001_add_users.sql
git commit -m "Add user table schema"
git push -u origin add-db-schema
gh pr create \
  --base main \
  --head add-db-schema \
  --title "Add user table schema" \
  --body "Bottom PR in the stack."

# PR 2: 基于 PR 1 的分支继续开发,base 指向 add-db-schema
git checkout -b add-service-layer
mkdir -p app
echo "class UserService: pass" > app/user_service.py
git add app/user_service.py
git commit -m "Add user service layer"
git push -u origin add-service-layer
gh pr create \
  --base add-db-schema \
  --head add-service-layer \
  --title "Add user service layer" \
  --body "Stacked on top of add-db-schema."

# PR 3: 基于 PR 2,base 指向 add-service-layer
git checkout -b add-api-endpoint
mkdir -p api
echo "def create_user(): return {'ok': True}" > api/users.py
git add api/users.py
git commit -m "Add create user API endpoint"
git push -u origin add-api-endpoint
gh pr create \
  --base add-service-layer \
  --head add-api-endpoint \
  --title "Add create user API endpoint" \
  --body "Top PR in the stack."

这样做不会获得 gh-stack 的原生体验,但能让团队先熟悉 stack 的核心约束:上层 PR 依赖下层 PR,下层变动会影响上层 diff。

评审和合并时要守住顺序

Stacked PR 的收益来自“分层”,风险也来自“分层”。如果下层 PR 频繁重写,上层 PR 的 diff 会跟着抖动;如果中间某个 PR 被拒绝,顶部 PR 可能需要拆掉或重做。

可以采用这套轻量规则:

1. 每个 PR 只表达一个层次:schema、service、API、UI 不要混在一起。
2. PR 标题或描述里标明位置:Stack 1/3、2/3、3/3。
3. 优先评审底部 PR,因为它决定上层 diff 的稳定性。
4. 合并从底到顶,不要跳过中间 PR。
5. 下层变更后,及时 rebase 或更新上层分支。

如果要更新上层分支,可以这样做:

# 假设 add-db-schema 已经更新,现在同步 add-service-layer
git checkout add-service-layer
git fetch origin
git rebase origin/add-db-schema
git push --force-with-lease

# 再同步更上层的 add-api-endpoint
git checkout add-api-endpoint
git rebase origin/add-service-layer
git push --force-with-lease

这里使用 --force-with-lease,而不是裸 --force。它会在远端分支出现别人新提交时拒绝覆盖,适合多人协作下的 stacked branch 更新。

是否现在就采用

如果你的团队经常遇到“大 PR 难评审、拆 PR 难维护”的问题,GitHub 原生 stacked PR 值得尽早试用 private preview。但别一上来就把所有复杂功能迁进去。

更稳妥的采用方式是:选一个中等规模功能,拆成 2 到 4 个 PR;明确谁负责维护 stack;约定从底到顶评审和合并;记录一次真实 rebase、修改、合并过程里的摩擦点。

Stacked PR 不是为了制造更多流程,而是为了让大改动有清楚的骨架。GitHub 把它做成第一方能力后,这个工作流有机会从少数团队的高级技巧,变成普通仓库也能稳定使用的日常工具。


相关推荐