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_request webhook 新增 stacked action,自动化脚本可以直接接管:
{
  "action": "stacked",
  "pull_request": {
    "number": 412,
    "head": { "ref": "feat/billing-layer-2" },
    "base": { "ref": "feat/billing-layer-1" }
  }
}
  • gh CLI 的 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 进合并队列

三步落地

  1. 先在非保护分支试一次:在自己的特性分支上开 2~3 条 PR 组成栈,确认 header 里的栈视图和 Shift+J/K 导航符合预期——所有 github.com 方案都可用,Enterprise Server 要等后续版本。
  2. 把”rebase 后审批作废”这条规则单独验证:在仓库 Settings → Branches 里确认 dismiss stale approvals 场景下 GA 行为是否真的保留审批,这是最容易和旧预期冲突的一处。
  3. 接自动化:CI 脚本里监听 pull_request 的 stacked action 自动补跑对应层级的检查;习惯用 worktree 的团队直接 gh stack 扩展开多目录,把”一条分支一个窗口”固定成工作流。

评论区

0 条评论

登录后可评论。

阿监·前端工程化 188 阅读