1. 为什么需要一套“开放式”的代码评审工作流
代码评审(code review)是很多研发团队想做好又做不好的事。我自己在团队里把一套名为 open-code-review 的工作流前后推了两轮,第一轮基本失败,第二轮才摸出点门道。今天把完整思路和落地方案整理出来,给正在搭评审流程的团队一个可参考的样板。
这个项目解决的核心问题很直接:PR 堆积无人看、评审流于形式、新人不知道从哪下口、老人觉得评审纯属浪费时间。我们把评审从“人盯人”的状态改成“机制自动流转 + 人只做判断”的模式,效果立竿见影。不管是三五人的小团队,还是几十人的中型团队,这套方案都能直接抄作业。
open-code-review 这个名字里有两个关键词:open 和 code review。open 不只是“开源”,更是“开放”——评审规则向全团队开放,评审数据向所有人透明,每个成员都能看到自己的评审效率、评论质量和影响范围。code review 本身不稀奇,但把它流程化、模板化、自动化,再配上数据复盘,就是一套完整的工程实践。
适合谁看?如果你是技术 Leader、研发效能工程师,或者正在为团队代码质量发愁的资深开发者,这篇内容可以直接落地。下文所有配置都基于 GitHub 生态,但思路和模板同样适用于 GitLab、Gitea 等其他平台,换一下语法就能用。
2. 核心机制拆解:评审规范与职责划分
2.1 把“评审标准”固化到模板和文档里
团队评审效率低,最大的原因不是大家不愿意看,而是不知道看什么、看到什么程度算通过。解决这个问题,我用的办法是把评审标准“显式化”——不靠口头约定,全部写进模板和文档。
第一件事是设计 PR 描述模板。模板不是走过场,而是逼着提交者把改动意图说清楚。我们的模板长这样:
## 改动目标 <!-- 这个 PR 解决什么问题?一句话说清楚 --> ## 改动范围 <!-- 改了哪些模块/文件?为什么这么改? --> ## 测试情况 - [ ] 本地单测通过 - [ ] 涉及前端改动已自测 - [ ] 涉及接口改动已联调 - [ ] 无影响(bugfix/文案) ## 自检清单 - [ ] 无调试代码残留(console.log / debugger / print) - [ ] 无明显重复代码 - [ ] 命名清晰可读 - [ ] 已补充必要注释 ## 相关链接 <!-- 需求文档、issue、设计稿链接 -->这里有个关键心法:自检清单不是给作者看的,是给 reviewer 看的。作者填了“已自检”,reviewer 就有依据快速过掉那些琐碎项,把精力集中在架构、性能和边界条件上。实测下来,有了这份模板之后,评审对话的起点高了不少,不再需要从“你这里为什么这么写”开始问。
第二件事是定义“什么是 Done”。很多团队代码合并了,但评审目标没达成——因为双方对“完成”的理解不一致。我们把 Done 定义为:需求逻辑闭环、测试覆盖到位、无遗留 TODO、CI 全绿、至少一名 reviewer 明确 Approve。这五条缺一不可,其中“明确 Approve”这条尤其重要,它逼着评审人说清楚自己的态度,而不是默默点个赞就完事。
2.2 职责分工与提交流程约定
一份清晰的职责表是评审流程的地基。我们定义了三个角色,责任边界非常明确:
| 角色 | 核心职责 | 常见错误 |
|---|---|---|
| 作者(Author) | 提供完整背景信息、主动自检、在合理时间内响应评审意见 | 不写描述、秒回“已改”不复核 |
| 评审人(Reviewer) | 在约定时间内完成评审、区分“必须改”和“建议改”、给出可执行的反馈 | 只点赞不说话、无限细节纠缠 |
| 维护者(Maintainer) | 把控合并节奏、处理争议、保证分支整洁 | 自行悄悄合并绕过评审 |
分支策略我们用的是最常规也最稳妥的:main 分支受保护,feature/、fix/、chore/ 等前缀标识不同目的,hotfix/ 用于生产环境紧急修复(这条后面会提到,它救过我们一次)。合并方式统一 squash merge,保持主分支历史是一条干净的直线,回滚时只需要 revert 一个 commit。
提交流程的硬性要求是写清“做了什么、为什么做”。我们的 commit message 遵循约定式提交规范:feat: 增加用户积分功能、fix: 修复订单金额精度丢失问题、refactor: 重构登录模块缓存逻辑。这个习惯养成了,自动生成 changelog 就顺理成章,版本管理也轻松很多。
3. 工具链选型与自动化配置
3.1 基于 GitHub 的评审流程与分支保护
选型这块,我们最终确定直接建立在 GitHub 原生能力之上,而不是引入一套重型管理平台。理由很简单:GitHub 的 Pull Request 模型已经是事实标准,reviewer 可以逐行评论、批量建议、直接 Approve;再加上分支保护、CODEOWNERS、GitHub Actions 这三个利器,足以覆盖 90% 的评审流程需求,没必要让团队再学一套新工具。
分支保护的配置是重中之重。在仓库 Settings -> Branches 里添加规则,我建议至少设置以下五项:
- Require a pull request before merging(禁用直接 push)
- Require approvals(至少 1 人,核心仓库建议 2 人)
- Dismiss stale reviews when new commits are pushed(新提交后旧 Approve 自动失效)
- Require status checks to pass before merging(CI 必须全绿)
- Require conversation resolution(所有评审对话必须 resolve 才能合并)
这五项里最容易忽略的是第三项。很多团队在第一次评审通过后,作者又往 PR 里推了新代码,结果整包代码没再经过评审就合并了。加了这项规则之后,任何新提交都会让旧的 Approve 失效,逼着重跑一轮确认,安全性高很多。
CODEOWNERS 文件是另一个被严重低估的功能。它把“谁来负责”直接编码进仓库。我们在.github/CODEOWNERS里这样写:
# 全局默认 owner * @core-maintainers # API 模块由后端小组负责 /api/ @backend-team /services/ @backend-team # 前端模块由前端小组负责 /src/components/ @frontend-team /src/pages/ @frontend-team # 配置文件改动需要架构组确认 /.github/ @infra-maintainers package.json @frontend-team @infra-maintainers这样一来,改动一旦触及不归你管的模块,系统会自动给对应负责人发评审请求。不用任何人催,责任就落到该负责的人身上了。
3.2 机器人自动检查与增量提示
有了基础分支保护还不够,我们在 GitHub Actions 里编排了一套自动化评审助理,把很多机械性工作从人身上接管过来。
第一层是 CI 门禁。每个 PR 必须跑完 lint、单测、构建三步,全部通过才能进入人工评审环节。这一层是为了把“低水平问题”挡在门外:格式化、明显错误、编译失败的代码根本走不到评审人眼前。配置一个最小的 workflow 其实很简单:
name: CI on: pull_request: branches: [main] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' - run: npm ci - run: npm run lint test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' - run: npm ci - run: npm test build: runs-on: ubuntu-latest needs: [lint, test] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm ci - run: npm run build第二层是自动评论机器人。我们用一个轻量脚本在 PR 打开时自动做三件事:检查分支名是否符合约定、检查 PR 描述是否填写完整、检查是否包含调试语句。不符合就直接在评论区标记@author提醒修改。这一步把 reviewer 从“又有人不填描述”的无奈中解放了出来。
第三层相对进阶,引入 AI 代码审查辅助。这里要提醒一句:AI 审回来的建议是“参考”不是“圣旨”,它的价值在于兜底——人容易漏掉的空指针、异常吞掉、API 误用,AI 往往一眼就能指出来。但架构合理性、业务逻辑是否跑偏,最终还是得靠人来判断。所以我们的策略是:AI 评论标记为“辅助建议”,不参与 Approve 判定,避免误导。
4. 实操过程:从零搭建一套 open-code-review 工作流
4.1 仓库初始化与基础配置全流程
说完了机制和工具,下面是一份可以照着敲的执行清单。整个流程大概需要一两个小时,一次配置,长期受益。
首先是文件清单。在仓库根目录下创建或者补充以下文件:
| 文件路径 | 作用 |
|---|---|
.github/PULL_REQUEST_TEMPLATE.md | PR 描述模板 |
.github/CODEOWNERS | 代码责任归属 |
.github/workflows/ci.yml | CI 门禁 |
.github/workflows/review.yml | 自动分配评审人、基础检查 |
.github/workflows/schedule.yml | 定时提醒未评审 PR |
CONTRIBUTING.md | 对外贡献指南,团队内部也适用 |
PR 模板的内容我直接放在第 2 章了,这里不再重复。CODEOWNERS 的写法也已经在第 3 章给出。真正要展开讲的是后面三个 workflow 文件。
review.yml的核心逻辑是:PR 打开或同步时,自动为 PR 分配 codeowner 以外的评审人,并跑一遍基础检查。这里我踩过一个坑:GitHub Actions 自带的pull_request_target事件存在权限风险,所以一律使用pull_request事件,且不执行任何 checkout,只通过 API 做信息读取。分配评审人我用了一个小脚本:
#!/bin/bash # 分配评审人:轮询选择最近被分配次数最少的人 # 依赖 gh cli,需要配置 token 权限 set -e PR_NUMBER=$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH") REPO="$GITHUB_REPOSITORY" AUTHOR=$(jq -r '.pull_request.user.login' "$GITHUB_EVENT_PATH") # 获取仓库协作成员列表 MEMBERS=$(gh api "repos/$REPO/collaborators?per_page=100" --jq '.[].login') # 获取每个成员的最近审查次数,选择最少的一位作为默认 BEST_REVIEWER="" MIN_COUNT=100000 for member in $MEMBERS; do if [ "$member" == "$AUTHOR" ]; then continue fi COUNT=$(gh search prs --reviewer "$member" --repo "$REPO" --state reviewed --limit 50 --json number --jq 'length') if [ "$COUNT" -lt "$MIN_COUNT" ]; then MIN_COUNT=$COUNT BEST_REVIEWER="$member" fi done gh pr edit "$PR_NUMBER" --repo "$REPO" --add-reviewer "$BEST_REVIEWER" echo "已自动分配 $BEST_REVIEWER 为评审人"这段脚本的核心逻辑很简单:轮询仓库内的协作成员,找最近被分配评审次数最少的人。注意它排除了 PR 作者本身,避免了自己审自己的尴尬。实际使用中说不上完美,但比随机分配智能得多。
4.2 自动化工作流的完整配置示例
schedule.yml用来处理评审拖延症。代码评审最大的敌人不是质量问题,而是“没人看”。我们用 cron 定时任务每天早上 10 点跑一次,自动列出 24 小时未收到评审响应的 PR,发到团队群里:
name: Review Reminder on: schedule: - cron: '0 2 * * *' # UTC 时间 2:00,北京时间 10:00 jobs: remind: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Generate reminder message run: | # 获取超过 24 小时未合并且无 review 的 PR gh pr list --repo "$GITHUB_REPOSITORY" --state open --limit 50 \ --json number,title,author,createdAt,reviews \ --jq '.[] | select(.reviews | length == 0) | select((now - (.createdAt | fromdateiso8601)) > 86400) | "PR #\(.number) \(.title)(\(.author.login))等待评审中"' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}为什么 cron 定在 UTC 2 点?这是很多人容易忽略的细节。GitHub Actions 的调度引擎基于 UTC,如果直接写cron: '0 10 * * *',那是北京时间 18 点,正好是大家准备下班的点,提醒了也白搭。写成 UTC 2 点,国内团队 10 点上班刚好看得到,效果最好。
CI 的配置在第 3 章已经写过了,这里补充一个生产项目的细节:在build步骤里把产物上传为 artifact,这样评审人可以下载构建产物直接联调,不用本地再折腾一遍环境。对于前端项目尤其好用:
- name: Upload build artifacts uses: actions/upload-artifact@v4 with: name: dist path: dist retention-days: 54.3 评审数据复盘与指标跟踪
如果只做到“能跑起来”,这套工作流还没发挥全部价值。我们在落地三个月后开始做评审数据复盘,用数据回答三个问题:
- 我们的评审效率是变好了还是变差了?
- 哪些环节在拖后腿?
- 团队的评审文化有没有真的建立起来?
数据从 GitHub API 拉,用脚本统计出三个指标:PR 从打开到合并的平均耗时、PR 等待首次评审的平均耗时、评审对话密度(平均每个 PR 的评论条数)。脚本用 node 写,也可以直接用 gh CLI 拉 json:
gh pr list --repo "$REPO" --state merged --limit 100 \ --json number,title,createdAt,closedAt,reviews \ --jq '.[] | {number, title, duration_hours: ((.closedAt | fromdateiso8601) - (.createdAt | fromdateiso8601)) / 3600, review_count: (.reviews | length)}'实测下来最关键的指标是“等待首次评审时间”。如果这个数长期大于 24 小时,说明不是大家不想评审,而是评审任务分配和提醒机制没起作用。我们的做法是把这个指标每周同步一次到团队公告,大家能看到自己的表现和团队的短板。数据是透明的,人自然会往好的方向努力,这比点名批评管用得多。
5. 常见问题与排查技巧实录
5.1 典型问题速查表
整个落地过程中,我记录下了下面这些高频问题。直接放出速查表,省得各位再踩一遍:
| 症状 | 根本原因 | 解决方案 |
|---|---|---|
| 分支保护规则不生效 | 保护规则只对 main 生效,团队直接在 main 上开发 | 检查默认分支设置,统一走 PR 流程 |
| PR 无法合并,CI 一直在跑 | 某些 check 需要等待较长时间或排队 | 合理拆分 lint/test/build 的并行度 |
| 自动分配评审人不生效 | Actions token 缺少读取协作成员的权限 | 在 workflow 中配置permissions: contents: read, pull-requests: write |
| CODEOWNERS 不触发自动指定 | 路径匹配规则写错,或 CODEOWNERS 文件格式有误 | 用* @owner兜底,逐行核对路径 |
| 旧 Approve 不随新代码失效 | 分支保护未勾选 dismiss stale reviews | 重新进入分支保护规则添加该项 |
| 机器人评论刷屏 | 工作流事件配置为pull_request_target,在 fork 场景下误触发 | 统一改用pull_request事件 |
这张表里的问题,前四个我都真实踩过。其中 CODEOWNERS 不生效那次最折腾——查了半天发现是文件里的@frontend-team写成了@frontend/team,小组名用反斜杠而不是斜杠,GitHub 直接静默忽略那行。这类问题没有报错日志,只能一行行比对团队名和文件路径。
5.2 我在落地过程中踩过的坑
第一个坑是分支保护策略设得太严。最开始我要求 main 分支必须 2 人 Approve,结果赶上一次线上紧急 bug,热修复 PR 卡在等第二个人评审,一卡就是 40 分钟。后来我们加了hotfix/分支例外规则,允许紧急修复只经过 1 人 Approve 并走完 CI 就合并,合完再补评审记录。尝到甜头之后,我现在建议所有团队都提前为“紧急情况”设计一条逃生通道,宁可平时用不到,也别在火线上做决策。
第二个坑是自动分配评审人的脚本太“公平”,导致有时把 PR 分配给了正在休假的人。后来在脚本里加了.github/REVIEWER_BLACKLIST文件,把当前不在岗的人写进去,每次分配先过滤黑名单。这个文件用 PR 方式维护,休假的人自己改,不依赖任何人记得去更新配置。
第三个坑是模板太好用了以至于团队产生了“填完模板=写完代码”的错觉。有人把自检清单全勾上但代码里有明显错误,reviewer 反而因为“自检过了”降低了警惕。后来我们改了一下规则:reviewer 可以随机挑 1 到 2 项自检清单实际验证,不局限于抽查。这一招有效拉回了评审人的注意力,代码质量又上了一个台阶。
5.3 评审效率提升的几个进阶技巧
最后分享几个我们没有写进文档但实测好用的技巧。
第一,把“建议改”和“必须改”分开。我们的评审约定里,用suggestion语法提行内修改建议,用[must]前缀标注必须修改项,其余一律视为可选优化。这个约定坚持一个月后,“评审情绪”明显改善了——作者不再觉得 reviewer 是来找茬的,reviewer 也不怕提建议会伤害关系。
第二,新人第一周只做评审不做开发。新加入的同事先看 10 个历史 PR,学习规范和讨论模式,然后在真实 PR 上发表自己的意见。这比让新人直接写代码再被评审要有效得多,因为评审视角的训练会反哺他们的代码设计能力。
第三,定期做“评审马拉松”。每隔两周选一个下午,全员聚在会议室开投影,逐个过所有待评审 PR。效率高的惊人——平时需要两天的评审积压,两个小时就能清完,而且现场讨论能解决很多线上打字说不清楚的问题。这个活动后来成了团队最受欢迎的技术分享会。
我个人在实际操作中的体会是:代码评审的终点不是代码合并,而是团队每个人都把评审当成一种习惯和能力来培养。工具和流程只是把舞台搭好,真正让这套 open-code-review 工作流转起来的,是大家愿意在别人代码上花时间的态度。