前言:为什么PR和代码审查如此重要

在上一篇文章中,我们学习了分支策略。良好地划分和管理分支固然重要,但最终这些分支合并的过程才是决定团队协作质量的关键。这正是Pull Request(PR)和代码审查发挥核心作用的地方。

坦白说,刚开始开发时,可能会觉得PR和代码审查很麻烦。"我写的代码为什么要给别人看?"、"直接合并不行吗?"等想法可能会出现。但随着经验的积累,你会逐渐认识到PR和代码审查是多么宝贵的流程。

运作良好的代码审查文化对于早期发现bug、知识共享以及保持代码质量的一致性起着决定性作用。本文将从PR的基础知识到有效的代码审查方法,再到GitHub的各种功能,全面讲解可以在实际工作中立即应用的内容。

1. 什么是Pull Request

1.1 PR的概念

Pull Request(PR)是"请求将我的分支的更改合并到另一个分支"的意思。它不仅仅是简单地合并代码,还是一个告诉团队成员"我做了这些更改,请确认一下"的沟通工具。

在GitLab中称为Merge Request(MR),在Bitbucket中也叫Pull Request。名称不同,但本质概念是相同的。

1.2 PR的作用

  • 代码审查的平台:这是团队成员审查代码并交换反馈的空间。
  • 变更历史记录:记录了为什么需要这个更改以及采用了什么方式实现。
  • 质量关卡:可以设置只有通过自动化测试和检查才能合并。
  • 知识共享:通过查看其他团队成员的代码,可以学习新的技术或模式。

1.3 创建PR

在GitHub上创建PR有多种方法。

# 1. 将分支推送到远程
git push origin feature/user-profile

# 2-1. 在GitHub网页上创建PR
# 推送分支后,GitHub会显示"Compare & pull request"按钮

# 2-2. 使用GitHub CLI创建PR
gh pr create --title "Add user profile feature" --body "添加用户个人资料功能。"

# 2-3. 以交互方式创建PR
gh pr create

2. 编写优质PR的方法

2.1 编写优质的PR标题

PR标题应该清晰明了,能够一眼看出更改内容。

好的示例:

  • feat: 添加用户个人资料页面
  • fix: 修复登录时会话过期错误
  • refactor: 改善支付模块代码结构
  • docs: 在API文档中添加认证部分

应避免的示例:

  • 修复 - 无法知道修复了什么
  • WIP - 除了正在进行中之外没有其他信息
  • asdf - 无意义的标题

2.2 编写有效的PR描述

PR描述(body)应包含审查者理解更改所必需的信息。

## 更改内容
- 添加用户个人资料查询API端点 (`GET /api/users/:id/profile`)
- 添加个人资料修改API端点 (`PUT /api/users/:id/profile`)
- 实现个人资料图片上传功能

## 更改原因
用户需要能够管理自己的个人资料信息的功能。
以前只有管理员可以修改用户信息,
现在用户可以直接管理自己的个人资料了。

## 测试方法
1. 登录后访问 `/profile` 页面
2. 修改个人资料信息后点击保存按钮
3. 刷新后确认更改是否保持

## 截图
(如适用,附上UI更改截图)

## 检查清单
- [x] 编写单元测试
- [x] 通过E2E测试
- [x] 更新文档
- [ ] 性能测试(大文件图片上传)

2.3 管理PR大小

小的PR就是好的PR。研究表明,200-400行左右的更改能获得最有效的审查。

  • 小PR的优点:审查速度快,发现bug的概率高,回滚容易。
  • 大PR的问题:审查者容易疲劳,容易忽略重要问题,冲突可能性高。

将大功能拆分成多个小PR。例如,"用户个人资料功能"可以拆分为:

  1. 数据库模式更改
  2. 后端API实现
  3. 前端UI实现
  4. 测试和文档化

这样就可以分成4个PR。

3. 创建PR模板

3.1 为什么需要PR模板

创建模板让团队以一致的格式编写PR有很多好处:

  • 防止遗漏必要信息
  • 缩短审查者的理解时间
  • 提高整个团队的文档质量

3.2 创建PR模板的方法

在项目根目录创建 .github/pull_request_template.md 文件。

<!-- .github/pull_request_template.md -->

## 概述
<!-- 请简要说明此PR解决了什么问题 -->

## 更改内容
<!-- 请以列表形式列出主要更改 -->
-
-
-

## 关联Issue
<!-- 请链接相关的Issue编号(例如:Closes #123) -->

## 测试
<!-- 请说明测试方法 -->

## 截图
<!-- 如有UI更改,请附上截图 -->

## 检查清单
- [ ] 测试代码编写完成
- [ ] 文档更新完成
- [ ] 遵守代码风格指南
- [ ] 自我审查完成

3.3 使用多个模板

可以根据PR类型(功能、bug修复、文档等)使用不同的模板。

.github/
  PULL_REQUEST_TEMPLATE/
    feature.md
    bugfix.md
    documentation.md

创建PR时,在URL中添加 ?template=feature.md 可以选择特定模板。

4. 代码审查的重要性

4.1 代码审查的目的

代码审查提供的价值远不止简单地查找bug:

  • 早期发现bug:在部署到生产环境之前发现问题。
  • 知识共享:团队成员相互理解和学习对方的代码。
  • 保持代码质量:保持一致的编码风格和模式。
  • 验证设计:确认实现方式是否合适。
  • 形成团队文化:建立建设性的反馈文化。

4.2 代码审查的统计效果

多项研究已经证实了代码审查的效果:

  • 通过代码审查可以提前发现60-90%的bug。
  • 经过审查的代码比未经审查的代码缺陷密度低30%。
  • 投资于代码审查的时间相比bug修复时间节省4-8倍。

5. 有效的代码审查方法

5.1 审查前的准备

为了进行有效的审查,首先要了解上下文:

  1. 阅读PR描述和相关Issue。
  2. 浏览更改的文件列表。
  3. 了解整体更改规模。
  4. 计划重点关注哪些部分。

5.2 审查时需要确认的事项

功能方面:

  • 是否满足需求?
  • 是否处理了边界情况?
  • 错误处理是否适当?

代码质量:

  • 是否易于阅读和理解?
  • 是否有重复代码?
  • 命名是否清晰?
  • 函数/类是否遵循单一职责原则?

性能和安全:

  • 是否有可能成为性能问题的部分?
  • 是否存在安全漏洞?
  • 是否暴露了敏感信息?

测试:

  • 测试是否充分?
  • 测试是否覆盖了有意义的用例?

5.3 审查时间管理

有效审查的时间管理技巧:

  • 一次200-400行:太长的审查会降低注意力。
  • 60分钟以内:一次会话不超过60分钟。
  • 24小时内进行首次审查:PR放置太久会失去上下文。
  • 分配固定时间:每天分配一定时间用于代码审查。

6. 提供优质反馈

6.1 建设性反馈的原则

代码审查中最重要的是建设性的态度。请记住以下几个原则:

  • 批评代码,而不是批评人:用"这里..."而不是"这代码..."来表达。
  • 以提问的形式提建议:"这样做怎么样?"比"这样做"更好。
  • 解释原因:不要只说"请修改",要解释为什么。
  • 也要提到优点:对做得好的部分给予表扬也是反馈。

6.2 反馈示例

不好的反馈:

这个为什么这样写?太复杂了。

好的反馈:

这个逻辑看起来有点复杂,为了提高可读性,
把它拆分成单独的函数怎么样?例如:

function calculateDiscount(price, userType) {
  // 折扣逻辑
}

这样的话,以后折扣政策变更时
只需修改这个函数就可以了。

6.3 反馈分类

标注反馈的重要程度可以让作者更容易确定优先级:

  • [必须][Blocker]:必须修改才能合并
  • [建议][Optional]:值得考虑的事项
  • [提问]:为了理解而提出的问题
  • [称赞][Nice!]:做得好的部分
  • [Nit]:小细节(拼写错误、风格等)

7. 使用GitHub的审查功能

7.1 三种审查状态

在GitHub上提交PR审查时,可以选择三种状态之一:

状态 含义 使用时机
Comment 一般评论 需要提问或讨论时
Approve 批准 认为可以合并时
Request changes 请求更改 需要修改时

7.2 逐行评论

在GitHub上可以直接对特定代码行添加评论。使用这个功能:

  • 明确是针对哪个部分的反馈。
  • 代码更改时,该评论会自动标记为"outdated"。
  • 可以选择多行进行评论。

7.3 Suggestion功能

使用GitHub的Suggestion功能可以直接用代码展示修改建议:

```suggestion
const userAge = calculateAge(birthDate);
```

作者只需点击一下就可以直接应用这个建议,非常方便。

7.4 批量提交审查

点击"Start a review"按钮,将多个评论一起提交。如果一个个提交评论,会多次通知作者,造成干扰。

8. 使用Draft PR

8.1 什么是Draft PR

Draft PR是"仍在进行中,尚未准备好接受审查"的PR。这是2019年GitHub引入的功能,在多种情况下很有用。

8.2 Draft PR的使用场景

  • 初步反馈:想提前确认大方向是否正确时
  • 分享工作:想告诉团队成员"我正在做这个工作"时
  • CI测试:想在合并前运行CI流水线测试时
  • 渐进式工作:跨多天逐步推进工作时

8.3 创建Draft PR的方法

# 使用GitHub CLI创建Draft PR
gh pr create --draft --title "WIP: 支付系统重构" --body "进行中。"

# 或者在网页上创建PR时选择"Create draft pull request"

8.4 从Draft转为Ready

工作完成后,将Draft PR更改为可审查状态:

# 使用GitHub CLI更改状态
gh pr ready

# 或者在网页上点击"Ready for review"按钮

9. 自动化审查设置

9.1 CODEOWNERS设置

使用CODEOWNERS文件可以为特定文件或目录指定"所有者"。当该区域发生更改时,指定的人员会自动被分配为审查者。

# .github/CODEOWNERS

# 整个代码库的默认所有者
* @tech-lead

# 前端代码
/frontend/ @frontend-team
*.jsx @frontend-team
*.tsx @frontend-team

# 后端代码
/backend/ @backend-team
*.py @backend-team

# 基础设施配置
/infra/ @devops-team
Dockerfile @devops-team
docker-compose.yml @devops-team

# 文档
/docs/ @tech-writer
*.md @tech-writer

# 数据库迁移(需要特别注意)
/migrations/ @dba @tech-lead

9.2 Branch Protection Rules

使用GitHub的Branch Protection功能可以设置PR合并前的必要条件:

  • Require pull request reviews:需要至少1-2人批准
  • Require status checks:必须通过CI测试
  • Require CODEOWNERS review:必须获得代码所有者的批准
  • Require conversation resolution:所有评论都解决后才能合并
  • Require linear history:保持整洁的历史记录

9.3 自动分配审查者

使用GitHub Actions可以实现更复杂的审查者自动分配逻辑:

# .github/workflows/auto-assign.yml
name: Auto Assign Reviewers

on:
  pull_request:
    types: [opened, ready_for_review]

jobs:
  assign-reviewers:
    runs-on: ubuntu-latest
    steps:
      - uses: kentaro-m/auto-assign-action@v1.2.5
        with:
          configuration-path: '.github/auto_assign.yml'
# .github/auto_assign.yml
addReviewers: true
addAssignees: author

reviewers:
  - reviewer1
  - reviewer2
  - reviewer3

numberOfReviewers: 2
reviewGroups:
  frontendReviewers:
    - frontend-dev1
    - frontend-dev2
  backendReviewers:
    - backend-dev1
    - backend-dev2

10. 建立PR审查文化

10.1 健康审查文化的特征

拥有良好代码审查文化的团队特征:

  • 快速反馈:PR不会放置超过24小时。
  • 尊重的态度:反馈不具攻击性,而是建设性的。
  • 学习导向:抱着通过审查相互学习的心态。
  • 明确的标准:有什么是可以通过的代码的标准。
  • 平衡的参与:审查不会集中在特定人员身上。

10.2 PR请求者的责任

提交PR的人也应该考虑审查者:

  • 保持PR大小小。
  • 编写充分的说明。
  • 先进行自我审查。
  • 在测试通过的状态下提交PR。
  • 以开放的心态回应反馈。

10.3 审查者的责任

审查者也应该负责任地进行审查:

  • 迅速开始审查。
  • 集中精力仔细检查。
  • 提供建设性的反馈。
  • 不要对小事过于执着。
  • 也要认可做得好的部分。

总结:PR和代码审查是团队成长的引擎

到目前为止,我们学习了从Pull Request编写到有效的代码审查方法,再到GitHub的各种自动化功能。PR和代码审查不仅仅是合并代码的程序。这是团队共同成长、创建更好软件的核心流程。

一开始可能会觉得麻烦,但良好的审查文化从长远来看提供了巨大的价值。bug减少,代码质量提高,所有团队成员都能理解整个代码库。最重要的是,"共同创造"的感觉增强了团队的凝聚力。

今天学到的内容请立即应用。创建PR模板,设置CODEOWNERS,下次审查时尝试使用Suggestion功能。这些小变化累积起来可以改变整个团队的协作文化。

下一篇将介绍GitHub Actions和CI/CD。继续关注Git & GitHub系列,您将获得在实际工作中可以立即使用的协作能力。