去年十月,一个约4k星的中型命令行工具仓库,三周内涌进380个拉取请求。平时的月均数字是25。到10月12日,两名维护者已经连续多天把整个晚上花在分诊PR上,而不是写代码。

常规建议是"每个PR都按其实质内容评审"。在每月25个PR的节奏下,这套做法完全可行。但当节奏变成每天15个PR、其中一半结构上几乎一模一样时,它就不成立了。

打开网易新闻 查看精彩图片

真正的开销不是拒绝劣质PR——在GitHub上那是两次点击的事。开销在于分诊:打开每个PR、读diff、判断它是否触及了有意义的部分、检查有没有关联issue,然后还得写一段礼貌的拒绝说明,而不是直接点关闭。

每天15个PR,哪怕每个只花三分钟,也是45分钟的纯管理开销——这还没开始看任何一行真正的代码。

所以目标不是"拒绝更多垃圾",而是"在显而易见的垃圾上花零个人工分钟,把全部注意力留给真正重要的东西"。

他们构建的GitHub Action

他们构建了一个GitHub Action,在每个pull_request事件上运行,在人类看到之前先做一轮分诊。它本身不自动关闭任何东西——它只打标签,而标签驱动后续流程。

这个Action先计算diff统计:改动了多少文件、多少行。然后标记出只动了markdown或空白、完全没碰src/或lib/的PR。接着根据规则打标签:

  • 没碰代码且改动少于5行 → 打上"低信号"标签
  • 改动超过500行 → 打上"大diff"标签

"低信号"这个标签成了最有用的单一信号。它不自动等于"坏PR"——有些真正优秀的文档修复就是五行。但它意味着人类应该用30秒扫一眼,而不是走完整的评审流程。

三个针对Hacktoberfest式垃圾的检查

除了识别琐碎diff,他们还加了三个专门针对Hacktoberfest模式垃圾的检查。

第一,要求关联issue。他们在CONTRIBUTING.md里加了一条规则:任何非琐碎的PR都必须引用一个issue,格式为Closes #123。一个机器人评论会检查这个模式,并提醒一次。

第二,账号年龄与历史启发式。他们不自动拒绝新账号——很多首次贡献者是真诚的。但一个48小时内创建、没有任何其他公开活动、向无关文件提交一行改动的账号,会被自动打上"疑似垃圾"标签,以便更快人工分诊。他们用GitHub REST API用户对象上的created_at字段加上public_repos数量作为快速启发式。方法粗糙,但正确标记了约70%最终被证实为垃圾的内容,误报率在他们可接受范围内。

第三,"good first issue"标签上的重复检测。他们加了一步:在允许第二个PR引用同一个issue之前,先检查该issue是否已经有一个关联的、处于打开状态的PR,如果没有就加一条评论警告。仅这一项就省下了几十次冗余评审。

文化转变:允许自己用模板回复关闭

自动化只能解决一半问题。更大的转变是文化上的:当PR命中"疑似垃圾"或"低信号且无关联issue"时,他们明确允许自己用模板化的、非个性化的回复直接关闭。

模板大意是:感谢贡献,但经评审这个改动不太符合项目方向,欢迎看看其他开放的issue。另一版更直接:关闭——此PR没有关联issue,也没有修改任何源文件,参见CONTRIBUTING.md了解什么算有效的Hacktoberfest贡献,欢迎带着更多上下文重新打开。

头几次用的时候,感觉挺冷酷。但替代方案是:维护者每周四十次,为一个只往README里加了一个句号的PR写一整段充满同理心的反馈。

他们把那种长而友善、详细的回复,留给了那些明显是真诚努力、只是在技术上没做对的PR——这些贡献者值得真正的反馈。