三个被合并的 PR:开源贡献的质量比数量重要

从 20 个被关闭的 PR 到 3 个被合并的 PR,我学到了选对问题比写对代码更重要。

· 2 min read

上一篇博客里我说”从零到两个合并的 PR”,现在可以更新标题了——三个了。

但这不是一篇”我好厉害”的炫耀文。恰恰相反,这是一个关于失败的故事。因为在拿到这三个 merged PR 之前,我有大约 20 个 PR 被关掉了。二十个。有的被 ignore,有的被 reject,有的干脆被 maintainer 一句 “not needed” 打发走。

所以当这三个 PR 在同一天之内先后被 merge 的时候,我的第一反应不是兴奋,而是——终于搞明白怎么回事了。


第一个:修别人不敢碰的 CI

MinionTech/vexilon #404 — 把废弃的 semgrep GitHub Action 迁移到官方 Docker 镜像。

这个项目的 CI 用的是 semgrep/semgrep-action@v1,但这个 Action 早就被官方废弃了。就像你家里那个用了十年的路由器,能用,但厂商已经不管安全更新了。

我的改动很纯粹:把 workflow YAML 里的 uses: semgrep/semgrep-action@v1 换成直接拉 semgrep/semgrep 官方镜像跑 CLI。扫描规则一个没动,SARIF 输出和 GitHub Security tab 的上传逻辑也原封不动。

维护者 DerekRoberts 直接 approve,还专门留了句感谢的话。

我学到了什么: CI/基础设施的维护是开源项目的盲区。大家都想写 feature,没人想修 pipeline。但安全扫描工具过期了是真·风险——这种 PR 虽然不性感,但维护者心里清楚它的价值。


第二个:删没人注意的死代码

sktime/sktime #10129 — 删除 tests/_config.py 里两条过期的测试排除配置。

sktime 是一个大型 ML 项目,测试配置文件里有两条排除规则,对应 SeriesToPrimitivesRowTransformerSeriesToSeriesRowTransformer 这两个类。问题是——这两个类早就从代码库里删了。排除配置变成了幽灵,谁也不会去触发它,但谁也没注意到它还在那儿。

改动:删了 4 行。两条配置,两行注释。没了。

sktime 的核心维护者 fkiraly 的 review 只有两个词:

Good find.

两个字。但我盯着屏幕看了好久。

我学到了什么: 大型项目里,“清理残留”是一种被低估的贡献。代码库越大,这种死配置越容易被忽略。而能被 fkiraly 本人 approve,说明他们认可的不是代码量,是你读代码的细心程度。


第三个:9 行代码修一个会 crash 的 bug

Sakura520222/Sakura-AI-Reviewer #228 — 给 read_file 工具加了目录路径的防护。

这个项目有个 read_file 工具,底层调 GitHub API 的 get_contents() 读文件。但 get_contents() 有个坑:传文件路径返回单个文件对象,传目录路径返回一个 list。原代码只处理了文件的情况,直接调 content_file.size——一遇到目录就炸:'list' object has no attribute 'size'

经典边界条件 bug。

我在已有的 null guard 后面加了一个 isinstance(content_file, list) 检查,如果是目录就返回明确的错误信息,提示用户用 list_directory。9 行代码,修了一个会 crash 的 bug。

项目的 AI reviewer 给了 9/10 分,项目作者也手动 approve。

我学到了什么: GitHub API 的返回类型不是你想的那样。get_contents() 对文件和目录返回不同类型,这种”隐式多态”是最容易被忽略的坑。而修复这种 bug 的性价比极高——改动小,影响大,谁都能看懂。


20 个被拒 PR 教会我的事

回头看那 20 个被关掉的 PR,原因各不相同,但归结起来就几类:

  • 选错了项目。 有些项目根本不需要外部贡献,或者维护者有自己的 roadmap,你提的改动方向不对。
  • 选错了问题。 改了个 typo,改了个格式,改了个”我觉得这样更好”——但维护者不觉得。
  • 改动太大。 一口气重构了半个模块,reviewer 看了一眼就关了。
  • 没读 CONTRIBUTING.md。 每个项目都有自己的规矩,不读就提交 = 白交。

而这三个被 merge 的 PR 有一个共同点:改动精准,解决真实问题,最小化修改。

不是”我觉得这样更好”,而是”这里有个 bug”或”这里有段死代码”。不是重构半个模块,而是删 4 行、加 9 行、改个 YAML。


给想开始开源的 CS 学生

如果你也在考虑给开源项目提 PR,我的建议是:

  1. 先当读者,再当作者。 花时间读 issue tracker,读已有的 PR,读 CONTRIBUTING.md。理解这个项目需要什么。
  2. 找 bug,不要找 feature。 Bug 是客观存在的,feature 是主观判断的。维护者很难拒绝一个合理的 bug fix。
  3. 最小化修改。 改得越少,review 越快,merge 概率越高。
  4. 接受被拒。 20 个被关的 PR 没有白费,每一个都让我更了解”什么不该做”。

开源贡献不是写代码比赛。它是关于理解一个项目、尊重维护者的时间、以及找到你能真正帮上忙的地方。


——Jiahao Ren, 2026 年 5 月