堆叠式 PR
大小预算
目标:每个 PR 约 300 行变更,上限 500 行。 在此规模下,人类可以轻松记住整个变更以进行快速审查,而审查代理也能提供清晰、具体的发现而非粗略浏览。
计数的内容: 手写代码和测试。
不计数的内容: 锁定文件、生成代码(迁移、代码生成、OpenAPI 输出)、快照、fixture 和 vendored 文件。这些内容会被粗略浏览,而非仔细阅读。请在 PR 正文中列出哪些文件是生成的,以便审查者知道跳过哪些。
在编写之前拆分,而非之后。 拆分在计划阶段就确定(参见 coding-process)。如果某个计划阶段会超过 500 行,则重新规划。常见的拆分点:
- 测试可以作为独立阶段提交。 例如,逻辑代码带上单元测试和集成测试,然后 UI 带上端到端测试。
- 数据模型或 schema,然后是使用它的服务,接着是 API 表面,最后是 UI。
- 先重构以使变更更容易,再进行实际变更。
- 一个文档同步阶段太大无法随附时,作为独立的纯文档阶段放在上层。
确实无法拆分的变更,例如一次连贯的数据库迁移或在 80 个文件中的重命名,可以超出预算。PR 正文需要说明原因,并指出审查者只需阅读哪部分。
每个 PR 内部仍然适用原子提交。预算按 PR 计算,不能替代提交规范。
堆叠
多阶段工作应作为 PR 堆叠 提交,而不是用一个分支承载整个计划。每个 PR 代表一个阶段,目标分支是前一阶段的分支,而不是 main。这样审查者看到的每次 diff 仅代表该阶段的变更,并且有风险的阶段(例如数据库迁移、认证变更)可以被独立审查和回退。
- 从上一阶段分支的头部创建新分支。只有最底层的 PR 目标可以是
main:gh pr create --base <上一阶段分支> - 在每个 PR 正文中注明其位置(
基于 #123 堆叠),以便未按顺序打开 PR 的审查者了解上下文。 - 从下往上落地。 当基础分支发生变化时(由于审查修复或基础分支合并),重新基于该分支 rebase 上方的分支,并进行强制推送。强制推送自己未合并的堆叠分支是常规操作。但绝不能强制推送
main或共享分支。 - 堆叠中的任一 PR 合并后,在开始下一阶段之前,将剩余 PR 同步到新的基础分支上。
- 来自 UI 表面的审查或验证通过的修复应作为新的阶段放在顶层,以便构建和修复可以分开审查。
- 堆叠工具如
gh stack、Graphite 或 git-town 是可选的。纯 git 和gh足以完成任务。
顺序审查
一次审查一个堆叠阶段。 仅向项目的审查者(参见 AGENTS.md 中的项目门禁)请求审查最底层的 PR,然后:
- 请求审查该阶段。
- 处理每一条发现(见下文)。
- 重新请求审查,直到该阶段被 批准。
- 只有此时才请求审查下一阶段。
不要一次性请求审查整个堆叠。阶段 1 的发现可能使阶段 2 到 5 已经写好的评论失效,顺序审查将审查者的精力限制在可控范围内。
如果某个阶段停滞(未收到审查回复,或发现需要产品决策的问题),请标记该情况,并在本地继续构建其上方的阶段(前提是它们不依赖该问题的答案)。
处理审查发现(任何 PR,无论是否堆叠)
- 在处理每条发现之前,先进行技术验证。阅读发现所指的代码,并尝试复现问题。
- 修复它,或者给出理由并反驳。 审查者(无论是人类还是机器人)在正常事件中也可能会自信地犯错。为了显得好说话而进行糟糕的更改比进行争论更糟糕。不要进行表演性的同意。
- 根据真实世界的概率判断发现。 对那些在现实场景中不可能发生的修复进行反驳,对增加复杂性却没有实际收益的建议也要反驳。
- 不要添加无法失败的测试。 无论 bug 是否存在都通过的测试是噪音。请先在存在 bug 的代码上运行它(参见
testing)。 - 回复每一条发现,以便审查者知道处理结果:在哪个提交中修复了,或者为什么没有修复。