Pete 前几天发了一篇 rant,标题就叫 "Stop sending me huge PRs"。他说自己审 PR 审到心力交瘁,几千行的 diff 一篇接一篇,AI 让 agent 越来越容易一次把整个 issue 改完。我读的时候一直点头,读到他把锅甩给 AI 那一段突然觉得不对——问题不在 AI 会写大 PR,问题在于我们压根没告诉 agent 什么叫"小"。
他的几个观点我其实都赞成。小 PR 的目的是让 review 更容易,不是每一段都能单独上线,这个说法很准确;他说人对代码的理解时间随行数指数增长,虽然他没给数据,但审过一千行 diff 的人都知道他说的是哪个方向。我唯一不认同的是结论:与其骂 AI,不如给 agent 立个规矩,让它根本产生不了大 PR。二十分钟,搭一个。
开搞之前先确认:
- 项目根目录已经有
CLAUDE.md,没有的话先建一个空白文件凑合 - 用的是 Claude Code,别的 agent 逻辑一样,改改路径就能移植
都齐了咱们就开搞。
Step 1:在 CLAUDE.md 里写进 PR 尺寸协议
先在项目根目录的 CLAUDE.md 末尾加这样一段:
## PR 尺寸协议
- 单次 PR 的 diff 行数上限:300 行
- 超过 300 行时,禁止直接提交,必须拆分成多个小 PR
- 拆分原则:每个小 PR 只解决一个逻辑变更,不要求单 PR 可独立部署
- 只允许在独立改动无法拆分时,才提交超过 300 行的 PR
这段的意思是:agent 每次动手前先读到这个约定,把"一次干完整个 issue"当成违规操作。Pete 那篇文章里说得很对,小 PR 不是为了可独立上线,是为了让人审得动。咱们不要求 agent 每段都跑得通,只要求它别把两千行一次砸过来。
写完先验证一下:随便跑一句 cat CLAUDE.md | head -30,能看到这段协议在里面,就通了。
Step 2:把规则变成 agent 必须执行的硬约束
光写进 CLAUDE.md 还不够——规则文件是"建议",agent 赶工的时候照样略过。咱们把"先读协议"变成它每次开工的强制动作:
## 强制流程
- 开始任何代码变更前,先完整阅读本文件的"PR 尺寸协议"章节
- 修改完成后,计算本次变更的 diff 行数
- 若超过协议上限,必须停下并输出拆分方案,不得自行提交
这里有个关键点:让 agent 自己计算 diff 行数。它不是做不到,是我们之前从来没要求过。Claude Code 里执行 git diff --stat 就行,agent 完全有这个能力,缺的是指令。
这一步的验证方法:故意让 agent 改一个跨多个文件的 feature,然后看它提交前有没有先报 diff 行数。没有的话,回去检查 CLAUDE.md 的格式,大概率是缩进有问题。
Step 3:写一条命令检查 agent 是否真的在遵守
现在咱们给自己留个后门——不用等 agent 自觉,随时能查。在项目里加一个 npm script 或者直接放一个 scripts/check-pr-size.sh:
#!/bin/bash
# 检查当前改动是否超过 PR 尺寸协议上限
LIMIT=300
DIFF_LINES=$(git diff --numstat | awk '{sum += $1 + $2} END {print sum + 0}')
if [ "$DIFF_LINES" -gt "$LIMIT" ]; then
echo "❌ 当前 diff ${DIFF_LINES} 行,超过协议上限 ${LIMIT} 行"
echo "请拆分后再提交。拆分指引见 CLAUDE.md 的 PR 尺寸协议"
exit 1
else
echo "✅ diff ${DIFF_LINES} 行,在协议范围内"
exit 0
fi
注意 git diff --numstat 统计的是当前工作区的未暂存改动,如果你已经 git add 了,要用 git diff --cached --numstat。这一步很多人会卡在这——加了文件之后跑脚本永远输出 0,不是脚本坏了,是统计对象不对。
验证:改一个文件加几行,跑 bash scripts/check-pr-size.sh,应该显示在范围内。然后把 300 改成 10 再跑一次,确认它真的会拒绝,再改回来。
Step 4:让 agent 提交前自动跑这个脚本
最后一步,把检查接进 agent 的收尾流程。回到 CLAUDE.md,在强制流程里加一条:
- 提交代码前,必须运行 `bash scripts/check-pr-size.sh`
- 该命令返回非零状态码时,不得执行 git commit
这样 agent 每次想提交,都得先过一个它自己绕不过去的闸门。脚本是外部的,agent 改不动,它要是真想作弊只能去改脚本本身——真到那一步,已经不是 PR 大小的问题了。
收尾验收
到这里,这套"大 PR 拦截器"就搭完了。跑起来了吗,照这个清单自查:
-
CLAUDE.md里能看到 PR 尺寸协议和强制流程两段 - 故意制造一个超过 300 行的改动,
check-pr-size.sh返回非零状态 - 让 agent 尝试提交一个大改动,它被脚本拦住并输出了拆分方案
都打勾了,这篇就算交付。
Pete 文章里还有个观点我没接上——他说用 AI 审 AI 生成的代码等于没解决问题,最后还是人审。我同意一半。AI 审 AI 确实容易两个一起犯错还互相认可,但拦在提交前和审在提交后是两码事。前者是让 AI 干它干得好的活(数行数、判定超没超限),后者才是需要人判断力的领域。别让 AI 替你做判断,让它替你把不需要判断的活干了,这大概是这篇文章真正想搭的东西。
