如果你的团队经常出现「一个 PR 改了 2000 行代码」「Reviewer 看了三天还没看完」「合并冲突比写代码还痛苦」——你可能需要 Stacked PRs(堆叠式 PR)。
这并不是什么新概念。Google、Uber、Linear 等团队内部已经用了很多年。只是随着 GitHub 生态工具的成熟(gh stack、Graphite),这个工作流开始从「大厂秘技」变成所有开发者都能用的常规操作。
这篇文章带你从原理到实战,一次性搞懂 Stacked PRs。
简单来说:Stacked PRs 就是把一个大 PR 拆成多个小 PR,像叠罗汉一样一个堆在另一个上面。每个 PR 独立 Review、独立合并,但逻辑上构成一个完整的功能。
一、为什么需要 Stacked PRs?
传统 PR 工作流的痛点
假设你要实现一个「用户导入 CSV」的功能,涉及:
- 解析 CSV 文件的工具函数
- 数据校验逻辑(邮箱格式、手机号去重)
- 数据库写入逻辑
- 前端上传界面
- 错误提示和日志
在传统工作流下,你只能在同一个分支上做完所有工作,然后提交一个 2000 行的 PR。结果就是:
- Reviewer 压力巨大 —— 没人愿意 Review 2000 行的 PR,拖几天甚至几周
- 反馈周期长 —— Reviewer 在第 5 个文件里发现架构问题,你可能需要重写 6 个文件
- 合并冲突地狱 —— 同样的文件被多个人修改,谁先合并都是灾难
- CI 反馈慢 —— 每次 push 跑全量测试,等半小时才能知道结果
Stacked PRs 怎么解决?
同样的功能,用 Stacked PRs 拆成 3 个 PR:
| PR #1 | CSV 解析工具函数(~100 行) | 2 小时 Review 通过 ✅ |
|---|---|---|
| PR #2 | 数据校验 + 数据库写入(~200 行) | 半天 Review 通过 ✅ |
| PR #3 | 前端界面 + 错误处理(~300 行) | 半天 Review 通过 ✅ |
每个 PR 都只有几百行,Reviewer 可以在十分钟内看完,给出有意义的反馈。第一个 PR 被合并后,后面的 PR 自动 rebase,基本没有冲突。
二、Stacked PRs 的核心概念
依赖链(Dependency Chain)
Stacked PRs 的核心是依赖关系。PR #2 依赖于 PR #1(因为它用了 PR #1 写的工具函数),PR #3 依赖于 PR #2。
main
└── PR #1 (csv-parser) ← 独立,可以随时合并
└── PR #2 (validation) ← 依赖 PR #1
└── PR #3 (ui) ← 依赖 PR #2
Base Branch 的自动管理
传统工作流中,你需要手动管理分支:
git checkout -b feature/csv-parser
git checkout -b feature/validation # 基于 csv-parser
git checkout -b feature/ui # 基于 validation
用工具自动管理后,你只需要:
gh stack create # 自动创建整个栈
gh stack edit # 修改某个 PR
gh stack sync # 同步所有分支
三、实战:用 gh stack 搭建 Stacked PRs 工作流
GitHub CLI 从 2025 年起内置了 gh stack 命令,这是目前最简单的方式。
安装和初始化
# 确保 gh CLI >= 2.60
gh --version
# 启用 gh stack
gh extension install github/gh-stack
创建 Stacked PRs
# 1. 从 main 创建第一个分支
cd my-project
gh checkout -b feature/add-api
# 写代码、提交
git add -A
git commit -m "Add user API endpoint"
# 2. 自动创建 PR #1 并推送到 GitHub
gh pr create --fill
# 3. 创建第二个分支(自动以当前分支为 base)
gh checkout -b feature/add-frontend
# 写代码、提交
git add -A
git commit -m "Add user management frontend"
# 4. 创建第二个 PR
gh pr create --fill
# 这会自动检测 PR #1 是它的 base,形成 Stack
Stack 管理命令
# 查看当前 Stack
gh stack status
# 输出:
# main → feature/add-api (#15) → feature/add-frontend (#16)
# 修改 PR #1 后更新整个 Stack
gh stack sync
# 自动 rebase #16 到新的 #15 之上
# 查看 Stack 依赖关系
gh pr view #15 --json stack --jq '.stack'
# 当 PR #1 被合并后,自动调整 PR #2 的 base
# gh stack 会自动把 PR #2 的 base 改为 main
四、工具选择:gh stack vs Graphite
| 特性 | gh stack | Graphite |
|---|---|---|
| 性质 | GitHub 官方 CLI 扩展 | 第三方 CLI + Web UI |
| 安装 | gh extension install | npm install -g @withgraphite/graphite-cli |
| Web UI 可视化 | ❌ 无独立 UI | ✅ 有 Stack 可视化面板 |
| 自动 rebase | ✅ gh stack sync | ✅ gt stack fix |
| 冲突处理 | 传统命令行提示 | ✅ 冲突导航工具 |
| 代码审查提示 | 基本 | ✅ CI 状态 + Review 进度追踪 |
| 定价 | 免费(内置) | 免费版有限制,Team $15/月 |
| 适合团队 | 小团队、追求极简 | 中大型团队、需要可视化 |
💡 我的建议:个人项目或 2-5 人团队用 gh stack 就够了,少装一个东西是一件事。如果你在 10 人以上的团队里推行 Stacked PRs,Graphite 的可视化面板和冲突导航工具能显著降低团队的学习成本。
五、Stacked PRs 的最佳实践
1. 控制 Stack 的深度
一个 Stack 建议不要超过 3-4 个 PR。太深的 Stack 会导致:
- 最底层的 PR 改动影响太大,上层继续等
- 一个 Stack 卡住就卡住整个功能
- Rebase 冲突时排查困难
2. 每个 PR 保持独立价值
一个好的 Stacked PR 是每个 PR 都可以独立 Review、独立上线。如果 PR #1 合并后,PR #2 单独上线是安全的,说明拆分是合理的。
3. 从底层往上 Review
Review 顺序应该从最底层的 PR 开始(不依赖任何其他 PR)。底层通过了再往上看,每一步 Review 都建立在前面的基础上。
4. 小步提交,频繁推送
# 不好的做法:一口气写了一周,推送 5000 行
git commit -m "WIP: lots of changes" # ❌
# 好的做法:每完成一个小功能就提交 + 推送
git commit -m "feat: add CSV parser" # ✅
git commit -m "feat: add validation" # ✅
git commit -m "feat: add DB writer" # ✅
5. 保持 CI 绿色
Stacked PRs 的 CI 特别重要。底层的 PR 如果 CI 失败,上层的 PR 也有问题。建议:
- 每个 PR push 时都跑 CI
- 底层 PR 合并后,触发上层的 CI 重新跑
- 考虑用 GitHub Actions 的
workflow_call组合测试
六、常见坑与解决
坑 1:合并顺序搞错。 如果你不小心先合并了顶层的 PR,底层的 PR 还在 review。解决方法:用 git rebase 把顶层 PR 的 commit 摘出来,重新开一个独立 PR。
坑 2:Rebase 冲突扩散。 如果 PR #1 和 PR #2 改了同一个文件,rebase 时的冲突会同时影响两个 PR。建议:尽量让不同 PR 改不同文件,如果真的需要改同一个文件,可以考虑合并 PR #1 和 #2。
坑 3:团队不习惯。 推行 Stacked PRs 最大的阻力不是技术,是习惯。建议从小团队开始试点,先在一个 sprint 里尝试,对比 Review 速度和质量。
💡 小技巧:在 PR 描述里用「Part 1 / 3」「Part 2 / 3」的标注,让 Reviewer 一眼看出这是 Stack 中的哪一个环节。Graphite 会自动标注,gh stack 需要手动加。
七、总结:什么时候该用?
✅ 适合用 Stacked PRs 的场景
- 功能比较大,能自然地拆成 2-4 个独立模块
- 团队人数 3 人以上,代码 Review 是瓶颈
- PR 经常超过 300 行,Review 周期超过 1 天
- 项目有完善的 CI/CD 流程
❌ 不太适合的场景
- 团队只有 1-2 个开发者(直接沟通比 Stack 高效)
- 每个功能的改动很小(100 行以内,没必要拆)
- 项目还没有 CI(Stacked PRs 需要 CI 保障质量)
- 团队对 Git 操作还不太熟悉(学习成本暂时太高)
总的来说,Stacked PRs 是 2026 年成熟开发团队的标配工作流。工具链已经足够成熟(gh stack / Graphite),没有理由不尝试。从下一个 PR 开始,试着拆一拆吧。