
字节笔记本
2026年10月6日 · 约 5 分钟读完
堆叠 PR 评审修复指南:归属、传播与验证
堆叠 PR(Stacked PR)把一个大改动拆成一串相互依赖的小 PR:A ← B ← C,B 建在 A 之上,C 又建在 B 之上。评审时的麻烦也随之而来:同一条评审意见可能同时命中链条上的好几层,改一处,上层每一层理论上都受影响。GitHub 提供了官方的堆叠关联能力,整条链应当通过它保持关联;在此基础上,真正的工作量集中在两件事上:修复落在哪一层(归属),以及修复如何向上传播(扩散)。本文整理出一套可直接照做的操作规程。

五条基本规则
1. 每个 PR 分支一个 worktree。 修复必须在该 PR 自己的 worktree 里进行,并行修复绝不共享同一个 checkout。堆叠链意味着多个分支同时处于待修改状态,共享工作区很容易把上一层的临时改动误带进下一层的提交。
2. GitHub 的 stack 对象是权威依据。 base 分支决定预期的依赖顺序,PullRequest.stack 和 stackEntry.position 则证明 GitHub 已经识别这条堆叠。没有检查过这些字段,就不能仅凭「分支链恰好吻合」就把它当成官方堆叠来对待。
3. 修复落在引入问题的那个 PR 上,然后向上流动。 当 PR B 上的评论指向 B 引入的代码时,就在 B 上修复,再把变更传播到 C,即使 C 同样包含这个文件。把修复直接做在下游的 C 上,后果是 B 会带着未修复的代码继续送审,而 B 的评审者完全看不到这处修复。
4. 每项评审修复都保持为独立 commit。 后续 rebase 可能改变它的 OID,这是正常现象;但不能用 amend 把已经推送、已经评审过的修复从分支历史里抹掉。只有自己尚未推送、尚未送审的工作,才可以 amend。
5. 明确选择 merge-forward 或 rebase。 评审之后允许这两种历史更新方式,但要明确选其中一种。所有改写历史的推送都必须受 lease 保护:如果远端 head 在此期间已经前移,操作必须中止,不能覆盖别人的提交。直接 --force 是被禁止的。
沿堆叠逐层处理评审意见
第一步,先核实再接受。 动手之前逐条审视评论:对照代码验证它的论断是否成立。评审者指出的症状往往是真的,但对原因的判断仍可能出错,照单全收会把误诊一路带进修复。
第二步,把发现映射回引入层。 每个被接受的发现,都定位到引入该问题的那个 PR,在那里提交修复,而不是就近在顶层打补丁。
第三步,按顺序向上传播。 修复完成后传播给每个受影响的子 PR,两条路线二选一:
- merge-forward: 把修复后的父分支合并进子分支,验证子分支,然后继续向上一层推进;base 需要重定向时,按增量方式更新,保留正在处理的检查点。
- 原生级联 rebase: 用
gh stack rebase改写整条链,逐层验证改写结果,再用gh stack push发布;也可以用gh stack sync,但该命令可能先行发布,所以同步完成后必须立即执行推送前检查。

第四步,委派的修复要信任但验证。 如果把修复交给 subagent,它的报告描述的是意图,不一定是实际落地的内容。要亲自在真实代码树上重跑门禁;对回归守卫,还必须证明它在未修复的代码上会失败:先引入回归、观察测试变红、再还原。两种情况下都通过的守卫什么也守不住。当 subagent 把问题重新定性为「已处理」时,恰恰是需要亲自深入的信号。
第五步,在原线程里回复。 用 gh api repos/{owner}/{repo}/pulls/{pr}/comments/{id}/replies 回到评审线程内回复,而不是另发顶层评论;回复中说明修复内容,以及当前承载修复的 commit 或 head。
第六步,每次改写推送后重新审计。 force-push 会改写 commit 的 OID,内联评论的锚点也可能过期,这些都证明不了「发现已解决」。每次推送后都要重新读取未解决线程、批准状态、可合并性和检查结果。
第七步,只走官方堆叠流程落地。 链上的 PR 尚未关联时,先把同一作者组成的链关联起来;作者不同时,先与对方确认;原生堆叠支持不可用时,直接停止落地流程。
验证清单
收尾时对照四项检查:
- 每个已修复 PR 的当前 diff,都在引入问题的那一层包含预期修正;
- GraphQL 报告的官方堆叠有且仅有一条,顺序符合预期,且每个子 PR 相对父 PR 的 diff 只显示该子 PR 自身的变更;
- 每次改写推送之后,都重新审计过未解决线程、批准状态、可合并性和检查结果;
- 相关门禁在堆叠里的每个受影响 PR 上都通过,而不仅仅是顶部那个。
堆叠 PR 的难点从来不在「改代码」,而在于让一条链上的每一层都保持可评审、可追溯。归属清晰、传播有序、推送受保护、结果可验证,这四件事做扎实,长链条也能改得安心。



