GitHub 悄悄把 stacked PR 做成了原生功能:10 月 6 日 GA——从靠 Graphite 和人肉维护分支栈,变成 Rebase stack 保住审批和签名
把一个 3000 行的改动拆成三条互相依赖的分支,过去要么装 Graphite、要么人肉 rebase 到天荒地老;2026 年 10 月 6 日,GitHub 把 stacked pull requests 从 public preview 直接推到 GA,审批、签名、合并队列全部跟着栈走。
过去 stack 难在哪:不是不会拆,是拆完维护不动
Stacked PR 的模型本身很简单:一条大改动拆成 base → next → next 的链,每条 PR 都只 review 自己那几十到几百行。麻烦全在”底下的分支动了之后”:
- base 分支(通常是 main)往前走了,你得逐层 rebase,rebase 完 GitHub 常常判定”有新提交”,审批直接作废(开了 dismiss stale approvals 的仓库尤其致命);
- 分支规则要求签名提交时,rebase 出来的替换提交签名丢了,CI 卡在签名校验;
- 想用 merge queue 保绿,队列一次只认一条 PR,栈里六条要排队六次,中间任何一次 main 动了又得重来;
- 底部 PR 的 base 分支被删,整个栈直接变成”closed”,只能手工 retarget。
这些不是假想,GitHub 自己在 2026-07-30 把 stacked pull requests 放进 public preview 时就承认了维护成本;更早的社区讨论(Hacker News 上 2021 年那篇《A Better Model for Stacked Pull Requests》110 points、2024 年的《Understanding the Stacked Pull Requests Workflow》、2026-09-14 的 jj-stack)说明这个痛点已经存在了至少五年,工具链一直是 Graphite、gh-stack、jj-stack 这类第三方在补。
GA 版本改了什么:六条维护成本被直接吃掉
GitHub Changelog 2026-10-06 的 GA 公告里,改动全部指向”栈在变动之后还能不能活”:
| 场景 | preview 之前(before) | GA 之后(after) |
|---|---|---|
| main 前进,栈要 rebase | 审批按新提交处理,全部重走 | 代码没变的部分审批保留,即使仓库开了 dismiss stale approvals |
| 分支规则要求签名 | 替换提交无签名,校验失败 | Rebase stack 生成签名的替换提交,保留原作者信息;部分合并后的自动 rebase 同样签名 |
| 合并队列 | 栈里每条 PR 单独进队,六条排六次 | 整个栈作为一个 merge group 进出;用 merge commit 时每条 PR 各出一个 merge commit,不再是整坨一个 |
| 底部 PR 的 base 被删 | 底部 PR 关闭,栈断掉 | 自动 retarget,支持一个栈从另一个栈分叉的写法 |
| 有 bypass 权限的人 | 只能按普通规则逐条合 | bypass 权限可用于合并栈里最低的那条未合并 PR |
| 一次性全合 | 不支持 | auto-merge for stacks(GA 后数周内铺开):一组 PR 满足仓库合并要求后自动一起合 |
Preview 到 GA 中间隔了 68 天(2026-07-30 → 2026-10-06),这 68 天的数据 GitHub 也放出来了:用上 stack 的仓库合并代码量比同类仓库多 9%,头部 1% 仓库里超过三分之二在用 stacked PR,time-to-merge 改善 5%。Astral 创始人 Charlie Marsh 在公告里直接说”用 GitHub 的 Stacked PR 合了一次,我就知道它成了”。
栈变成一等公民之后,自动化才有落点
以前栈只存在于你的本地 git 和第三方工具里,现在它是 PR 页面上的持久状态:
- PR 页面常驻 header 显示所属栈,PR 列表也能看栈归属;
- Shift+J / Shift+K 在栈内上下条 PR 之间跳转;
- 时间线记录某条 PR 何时入栈/出栈,
pull_requestwebhook 新增stackedaction,自动化脚本可以直接接管:
{
"action": "stacked",
"pull_request": {
"number": 412,
"head": { "ref": "feat/billing-layer-2" },
"base": { "ref": "feat/billing-layer-1" }
}
}
ghCLI 的 stack 扩展这次加了 Git worktree 支持,初始化、checkout、导航都提速——也就是说”栈里每条分支单独开一个目录同时改”不再需要自己写脚本。
before/after 对照到代码层面就是这件事:
# before:底部分支被 main 超过之后,你必须逐层手工搬
git rebase origin/main feat/layer-1 # 审批没了
git rebase feat/layer-1 feat/layer-2 # 签名没了
git rebase feat/layer-2 feat/layer-3 # CI 全部重跑,merge queue 又排一轮
# after:Rebase stack 一条命令搬完整条链
# - 代码没动的提交,审批保留
# - 替换提交仍然带签名
# - 整个栈作为一个 merge group 进合并队列
三步落地
- 先在非保护分支试一次:在自己的特性分支上开 2~3 条 PR 组成栈,确认 header 里的栈视图和 Shift+J/K 导航符合预期——所有 github.com 方案都可用,Enterprise Server 要等后续版本。
- 把”rebase 后审批作废”这条规则单独验证:在仓库 Settings → Branches 里确认 dismiss stale approvals 场景下 GA 行为是否真的保留审批,这是最容易和旧预期冲突的一处。
- 接自动化:CI 脚本里监听
pull_request的stackedaction 自动补跑对应层级的检查;习惯用 worktree 的团队直接gh stack扩展开多目录,把”一条分支一个窗口”固定成工作流。
评论区
登录后可评论。