打开 GitHub,很多同学的第一反应是“这个仓库 star 多、代码能不能看懂”,却很少有人会专门去翻一个仓库的 Pull requests 列表,尤其是已经合并(merged)的 PR。原因很真实:PR 动态更新快、信息密度高,看起来不像源码那样有稳定的阅读入口。但如果你希望提高代码设计能力、理解一个成熟项目为什么会变成今天的样子,已合并的 PR 比源码本身更值得阅读。
这篇文章会围绕一个核心问题展开:哪些仓库(repos)的已合并 PR 值得读?如何快速找到它们?读的时候又应该重点看什么?我会从 GitHub 搜索语法、GitHub CLI、API 调用,到具体阅读方法,给出可以直接照做的流程。无论你是刚入门开源的同学,还是已经写了几年业务代码、想提升代码设计能力的开发者,这套方法都适用。
1. 背景与核心概念
1.1 什么是已合并的 PR
Pull Request(简称 PR)是 GitHub 上的一种协作机制。开发者从主干分支切出一个新分支,完成一段功能或修复后,向原仓库发起合并请求,维护者和其他贡献者可以在 PR 里查看代码差异、提出评论、反复修改,最终由有权限的人点击“Merge pull request”完成合并。
PR 的状态通常有三种:
- Open:还在讨论和修改中。
- Closed:不是被合并,而是被关闭,比如功能取消、分支废弃。
- Merged:已经被合入目标分支,是仓库正式演进的一部分。
我们说的“已合并 PR”就是第三类。它和普通的 commit 不同:一个 PR 可能包含多个 commit,也会包含完整的描述、评审意见、自动化检查结果、讨论过程,甚至还有对应的 issue 链接。所以它是一个比 commit 更完整的“改动单元”。
1.2 从源码阅读到 PR 阅读的转变
很多同学阅读开源项目时只盯住主干分支的源码文件,比如从src/core/index.ts开始往下看。这种方式不是不行,但会遇到几个问题:
- 不知道某个函数为什么这么写。
- 看不到设计取舍和备选方案。
- 很难还原代码演进过程。
而一个 merged PR 恰好补上了这些信息。它把一次修改的“为什么做、怎么做、改了什么、如何测试”放在同一个页面上。阅读源码是看“结果”,阅读 PR 是看“过程”。把两者结合起来,才能更完整地理解一个项目。
1.3 已合并 PR 的三个核心价值
第一,学习代码规范与风格。大型项目通常有严格的 ESLint、Prettier、Checkstyle、Go fmt 等规范,PR 里的每一个新改动都会经过这些检查。反复看高质量 PR,能慢慢培养出自己的代码审美。
第二,理解架构演进的取舍。比如 Vue Core 某次重构从某个函数改成了另一个设计,为什么要换?PR 描述里往往会写动机,review 里也经常出现“为什么不直接这样写”的讨论。
第三,学习测试思路。很多高质量的 PR 会同步补充最小化复现用例、单元测试、快照测试或端到端测试。测试代码往往比业务代码更能体现对边界条件的思考。
所以,阅读 merged PR 本质上是在围观一次真实的代码评审过程。这种学习方式比单纯刷文档有意思得多,也更贴近大厂内部 Code Review 的日常。
2. 哪些仓库和 PR 更值得读
2.1 优秀 merged PR 的特征
不是所有 merged PR 都值得逐字阅读。有些 PR 可能只是改了一个错别字,或者更新了文档链接。我们优先找具备下面这些特征的 PR:
| 特征 | 说明 |
|---|---|
| 改动范围适中 | 能在一个 PR 里看完,通常 100 到 500 行 |
| 功能或修复目标明确 | 对应具体的 issue 或需求 |
| 有高质量描述 | 说明背景、方案、风险和测试方法 |
| Review 讨论丰富 | 维护者提出过有效修改意见 |
| 包含测试用例 | 新增或修改测试 |
| Commit 划分清晰 | 一个 PR 拆成多个逻辑连贯的 commit |
| 来自成熟仓库 | 有完善贡献规范和自动化检查 |
如果你看到一个 PR 改了几十个文件、超过 3000 行,有时候也值得读,但更适合有经验后再挑战。新手一开始还是从“范围适中、信息完整”的 PR 入手。
2.2 选择仓库的策略
关于“Which repos have merged PRs worth reading”,可以先从你自己熟悉的项目开始。熟悉一个项目的业务概念和模块结构后,看它的 PR 会轻松很多。
也可以从下面几类仓库里选:
- 你日常使用的开源框架或工具,比如 Vue、React、Vite、Express 等。
- 以代码质量著称的项目,比如 TypeScript、Rust 官方工具链、GitLab CE。
- 你所在技术栈的知名企业项目,比如 Spring 系列、Kubernetes、Go 语言相关项目。
- 通过 GitHub Trending、GitHub 官方博客、开源年会分享了解到的新项目。
不建议一开始就挑战特别庞大、提交极其频繁的大型仓库,而是选择“中等活跃”的项目。这类项目既有真实的讨论,又不会因为 PR 数量太多让人无从下手。
2.3 如何判断一个 PR 是否值得读
在打开 PR 之前,可以通过列表页的标题和标签先做一轮过滤:
- 标题中出现
fix,feat,refactor,perf,chore等关键词。 - 有
good first issue、help wanted、reviewed等标签。 - 打开后看到绿色
Merged状态,且描述不是一句话带过。
如果一个 PR 的描述里有“Issue: #1234”“Motivation”“Solution”“Test plan”这样的结构化内容,大概率是作者认真写过的,阅读价值往往更高。
3. 用 GitHub 网页搜索定位值得读的 merged PR
3.1 高级搜索语法入门
GitHub 自带的高级搜索足以完成大部分筛选工作。我们可以直接在 GitHub 搜索框里输入条件,也可以打开https://github.com/search?q=...&type=pullrequests进入专有的 PR 搜索页。
最简单的语法是:
repo:vuejs/core is:pr is:merged这条语句表示:在vuejs/core仓库中,只搜索类型为 Pull Request,且已经被合并的记录。
如果你希望限制更新时间,可以加上:
repo:reactjs/react.js is:pr is:merged merged:2024-01-01..2024-12-31GitHub 高级搜索支持的常用条件还包括:
| 语法 | 含义 |
|---|---|
repo:owner/name | 限定仓库 |
is:pr | 只搜索 Pull Request |
is:merged | 只看已合并的 PR |
label:bug | 按标签过滤 |
reviewed-by:user | 指定评论人 |
author:user | 指定作者 |
commenter:user | 指定评论参与者 |
head:branch-name | 按来源分支过滤 |
base:main | 按目标分支过滤 |
merged:>=2024-01-01 | 按合并日期过滤 |
组合使用效果更好。比如我想找 React 仓库中被某个知名维护者评审过的小型重构:
repo:facebook/react is:pr is:merged review:required3.2 保存搜索与订阅
搜索条件确定后,在搜索页面右上角点击“Save search”可以保存。下次通过左侧菜单快速打开,还能看到动态变化。另外在仓库首页的 “Pull requests” 页签里,可以结合搜索框再次过滤,并把 URL 收藏到浏览器书签中。
如果你想持续关注某个仓库的合并情况,可以在仓库页右上角点击 Watch,然后进入子菜单选择 “Releases only” 或 “Custom” 折叠中的 “Pull requests”。这样新 PR 动态就会出现在 GitHub 通知中心,更新频率适中,不会太打扰。
3.3 搜索词示例
下面给你几个可以直接使用的搜索示例,复制到 GitHub 搜索框即可:
repo:vuejs/core is:pr is:mergedrepo:facebook/react is:pr is:merged label:"Component: Developer Tools"org:vitejs is:pr is:merged merged:>=2024-01-01is:pr is:merged author:yyx990803 archived:false最后一条中的archived:false用来排除已归档仓库。虽然是个人作者维度,但也能筛出很多有代表性的 PR。
4. 用命令行快速拉取 merged PR
网页适合一次两次查看,但如果你想把一个仓库的 merged PR 批量拉下来,或者写脚本做统计分析,命令行工具更高效。
4.1 安装 gh CLI 与认证
GitHub 官方命令行工具是gh,支持 Windows、macOS、Linux。安装完成后需要进行认证:
gh auth login按提示选择 GitHub.com,然后选择 HTTPS 和浏览器授权即可。认证成功后,可以用下面命令测一下:
gh auth status如果看到类似Logged in to github.com as yourname的输出,说明认证成功。没有安装 gh 的同学可以暂时用 curl 加 token 访问 GitHub API,但gh在体验上会舒服很多。
4.2 获取某个仓库最近合并的 PR
gh pr list是查看 PR 列表最常用的命令,指定--state merged就可以只看已合并的:
gh pr list --repo vuejs/core --state merged --limit 10这条命令会输出最近合并的 10 个 PR 的编号、标题和分支信息。如果你希望输出更清晰的字段,可以加--json:
gh pr list --repo vuejs/core --state merged --limit 10 \ --json number,title,mergedAt,url,author这个命令会输出 JSON 数组,方便后续用 jq 处理。执行效果大致如下:
[ { "number": 12345, "title": "fix(runtime-core): handle patchFlag in updateProps", "mergedAt": "2024-06-15T08:30:00Z", "url": "https://github.com/vuejs/core/pull/12345", "author": { "login": "someone" } } ]注意:gh pr list默认显示当前分支所在仓库。指定--repo可以避免切目录。
4.3 查看单个 PR 的详情与文件变更
拿到 PR 编号后,使用gh pr view查看详情:
gh pr view 12345 --repo vuejs/core这里默认显示 PR 描述和状态。如果想看文件变更,可以加--comments查看评论,配合--json输出更多结构化信息:
gh pr view 12345 --repo vuejs/core --json title,description,files,reviews,comments这个命令在分析 PR 质量时非常好用,因为files字段会包含每个文件的additions、deletions和路径,reviews会包含评审状态与关键评论。
在终端里快速查看某个文件的 diff:
gh pr diff 12345 --repo vuejs/core > pr-12345.diff然后打开pr-12345.diff或直接使用 IDE 的分屏查看功能。保存到本地后,也方便做笔记和后续搜索。
4.4 使用 GitHub API 批量过滤
如果想绕过 gh 命令,直接用 GitHub REST API 也可以。仓库的 Pull Request 列表接口如下:
GET /repos/{owner}/{repo}/pulls?state=closed&per_page=100注意这里必须用state=closed,因为 /pulls 接口没有merged状态。关闭的 PR 包括两种:已合并和未合并被关闭。要判断是否真正合并,需要看每个 PR 的merged_at字段,非空表示已合并。
使用 curl 加 jq 可以一次性清洗出合并 PR:
curl -s -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/vuejs/core/pulls?state=closed&per_page=50&page=1" \ | jq '[.[] | select(.merged_at != null)] | .[] | {number, title, merged_at, user: .user.login}'执行后会输出类似:
{ "number": 12345, "title": "fix(runtime-core): handle patchFlag in updateProps", "merged_at": "2024-06-15T08:30:00Z", "user": { "login": "someone" } }需要提醒的是,GitHub API 未认证状态每小时有 60 次请求限制。如果只是教学作用,这个量基本够用;如果要写脚本批量拉取,建议设置环境变量:
export GH_TOKEN=你的token然后在 curl 中加入请求头:
curl -s -H "Authorization: Bearer $GH_TOKEN" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/vuejs/core/pulls?state=closed&per_page=100"注意:不要把 token 硬编码到代码里,更不要提交到公开仓库。生产环境使用 GitHub Actions 时应该优先使用secrets.GITHUB_TOKEN或secrets.PAT。
5. 一次完整的 merged PR 阅读流程
找到 PR 只是第一步,真正有效的是阅读方法。下面推荐一套具体流程,按顺序执行能帮你减少遗漏,也能提高吸收率。
5.1 阅读顺序建议
第一步,先看标题和描述。标题已经概括了这次改动的大方向,比如fix(compiler): improve error message for unknown directive。描述里更可能包含背景、Issue 链接、方案对比、测试计划。
第二步,看提交记录。一个 PR 里通常有多个 commit,先看 commit message 的演变,能理解作者的思考过程。比如先加测试、再实现功能、再重构代码,就是一个很好的开发节奏。
第三步,看文件变更总览。了解src/core/index.ts改了多少行、新增了哪些测试文件。优先关注核心源码,测试文件放到第二步一起看。
第四步,逐文件阅读 diff。不要只看新增行,还要看删除和修改的位置。很多重构的价值就在“删掉了哪些复杂度”。
第五步,看 review 评论。维护者的评论往往是整个 PR 中最有价值的部分,因为它在指出“哪里不够好、为什么不够好、可以怎么改”。
第六步,看合并后的结果。如果 PR 包含了 API 变更,可以再看看文档或 changelog,确认实际使用方式。
5.2 关注 review 讨论
Review 是 PR 和普通 commit 最大的不同。一个高质量 PR 的评论区,通常包含这些类型的对话:
- “这里的命名是否更贴近现有语义?”
- “为什么不用已有的工具函数?”
- “这个边界条件需要补充测试。”
- “性能上有没有更优做法?”
这些内容就是活生生的 Code Review 教程。我们可以多问自己一个问题:如果我是 reviewer,我会不会也提出同样的意见?久而久之,自己的审查能力也会提升。
建议在阅读时打开两个窗口:一个窗口显示 diff,另一个窗口显示 review 评论。这样可以避免来回滚动,阅读体验更好。
5.3 动手复现和延伸
阅读本身是被动行为,配合动手才会更牢固。你可以做下面三件事:
- 把 PR 的分支拉下来本地运行。
- 尝试复制 PR 的变更,从零实现一个小版本。
- 在 PR 基础上补充新的测试用例,给自己设定一个“如果我来改,我会怎么做”的任务。
如果 PR 对应一个 issue,也值得打开 issue 看看用户报障的问题和讨论。这样你学到的不仅是“代码怎么改”,还包括问题从报告到解决的完整链路。
6. 常见问题与排查思路
在筛选和分析 merged PR 时,最容易遇到下面这些问题。这里列出高频现象和解决思路,方便你保存。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| GitHub 高级搜索没有结果 | 搜索语法输入错误,或仓库本身不存在 | 检查repo:大小写,确认仓库地址是否正确 |
| 搜出来的 PR 没有合并 | 搜索时漏掉is:merged | 补上is:merged,重新执行搜索 |
gh命令提示 command not found | gh CLI 未安装或未加入 PATH | 按官方文档安装最新版,重启终端 |
gh pr list --state merged返回空 | 仓库确实没有合并 PR,或 gh 未认证 | 执行gh auth login,换一个活跃仓库测试 |
| GitHub API 请求 403 | 未认证或达到限流 | 等待一小时恢复,或使用带 token 的请求 |
| API 返回的 PR 列表包含未合并项 | 拉取的是state=closed,不是merged | 用merged_at != null进行过滤 |
| 打开 PR 后文件 diff 太大 | 选择了跨分支合并或规模过大的 PR | 先按文件拆分阅读,或者换一个小型 PR |
| review 评论很多但看不懂 | 对项目背景不熟悉 | 先阅读相关模块源码,再回到 PR 评论 |
这几个问题最常见的根因是“搜索状态”和“接口状态”不一致。尤其是 GitHub API 的 /pulls 接口,很多人会问为什么state=merged不生效,因为 REST API 本身没有这个枚举值,必须用state=closed再根据merged_at判断。
避免这个问题的方法是优先使用 GitHub 高级搜索的is:merged,或者使用 gh CLI 的--state merged。两者在底层都帮你做了额外过滤,表达更直观。
7. 将阅读能力转化为工程能力
阅读别人的 merged PR 最终会沉淀为自己的工程能力。这一节我们聊聊如何把“看 PR”和“写 PR”打通。
7.1 写 PR 时借鉴高质量 PR 结构
一个值得被阅读的 PR,往往有一个清晰的模板。常见的结构是:
- 相关 Issue。
- 改动背景。
- 实现方案。
- 测试计划。
- 影响范围与风险。
你完全可以在自己的仓库里建立这样一个 PR 模板,提交到.github/pull_request_template.md文件。这样团队每次提 PR 都会自动套用模板,时间久了,整个仓库的 PR 质量都会提升。
一个简单的模板示例:
## Description 请描述这次改动要解决的问题。 ## Related Issue Fixes #123 ## Type of change - [ ] Bug fix - [ ] New feature - [ ] Breaking change ## How Has This Been Tested? 请描述测试环境和测试步骤。 ## Checklist - [ ] 代码格式检查通过 - [ ] 本地测试通过 - [ ] 文档已同步更新7.2 让 Code Review 更有针对性
读高水平 PR 的时候,可以顺手记录 reviewer 常用的提问方式,整理成自己的审查清单:
- 是否缺少异常处理?
- 是否考虑到边界输入?
- 公共 API 是否有兼容性风险?
- 是否应该添加日志?
- 是否有更简单的实现方式?
当你在自己的 Code Review 中反复使用这些问题时,审查效率会明显提高。别人也会慢慢觉得你的 review 有深度。
7.3 建立自己的 PR 收藏库
GitHub 本身支持给 PR 点赞和评论,但更好的做法是建一个笔记仓库,比如awesome-merged-prs,用于整理你读过的优质 PR。
可以按照这样分类:
- 按语言:Go、TypeScript、Rust、Java、Python。
- 按关注点:错误处理、并发编程、缓存设计、API 设计、重构手法。
- 按复杂度:入门、进阶、挑战。
每条笔记至少写清楚三个点:这个 PR 解决了什么问题;有哪些值得学习的点;如果让我重新实现,我会怎么改进。这样你积累的不只是收藏链接,而是一套自己的代码设计知识库。
8. 总结与学习路线
这篇文章主要回答了 “Which repos have merged PRs worth reading” 这个问题。我们了解了已合并 PR 与普通 commit 的区别,知道了什么样的 PR 更值得读,也掌握了通过搜索语法、gh CLI 和 GitHub API 批量定位 merged PR 的方法。更重要的是,我们整理了一套完整的阅读流程:先看描述,再看提交记录,然后逐文件看 diff,最后结合 review 评论吸收经验。
如果你的基础比较薄弱,建议先从 Vue、React、Vite 这类文档完善、社区活跃的项目开始,每周只精读一个 PR,配合本地运行和笔记。等技术积累足够后再挑战大型基础设施项目,比如 Kubernetes、Rust 工具链等。阅读时不要贪多,重要的是把每个 PR 里的设计理由、测试思路和审查意见真正消化掉。
从现在开始,挑一个你常用的开源项目,打开 Pull requests 页签,筛选 merged,然后按今天说的流程动手读一个 PR 吧。你可能会发现,代码世界里最有学习价值的内容,并不总是藏在最终版本里。