1、三个人的团队,为什么会互相踩脚

第 12 课我们学会了"个人的 Git"。但团队一上来就遇到新问题:

  • 小王在 main 上直接提交,把大家跑不起来的代码推了上去,全员停工半小时。
  • 小李的 PR 挂了 3 天没人看,等他合进去时,main 已经变了 200 个文件,冲突解到怀疑人生。
  • 团队没有约定分支怎么命名,仓库里躺着 test、dev2、new-new、老王分支……

这些都不是技术问题,是协作流程问题。本课解决:

  1. 团队用什么样的分支策略?
  2. 代码怎么进主干(Pull Request / 代码评审)?
  3. 评审怎么才有效,而不是走过场?

2、分支策略:三种主流模式

模式一:主干开发(Trunk-Based Development)

所有人频繁直接向 main 提交(或极短命的分支,几小时到一两天就合回)。

main ──●──●──●──●──●──●──●──   大家都往这里合,一天多次
  • 优点:集成频繁、冲突小、持续交付顺畅。
  • 要求:必须有自动化测试和特性开关(Feature Flag)兜底(未完成的功能用开关藏起来)。
  • 适合:成熟团队、CI/CD 完善(第 16 课)。

模式二:GitHub Flow(最常用、最好上手)

从 main 拉短分支 → 开发 → 提 PR → 评审 → 合并 → 删除分支。

main    ──●───────●──────────●──
            \     /  \       /
feature/a    ●──●     ●──●  ← 每个功能一条短分支,合完即删
feature/b
  • 优点:简单、清晰,只有一个长期分支(main)。
  • 适合:绝大多数中小团队和产品迭代。推荐作为默认起点。

模式三:Git Flow(重流程)

有 main、develop、feature、release、hotfix 五种分支,适合有明确版本发布节奏的产品(如客户端软件、需要维护多个版本的产品)。

  • 优点:能并行管理多个发布版本。
  • 缺点:复杂,对一个持续部署的 Web 服务来说是过度设计。

怎么选?

团队情况建议
小团队 / 持续部署 / 追求快主干开发或 GitHub Flow
绝大多数产品团队GitHub Flow(默认推荐)
多版本并行、发布节奏固定Git Flow
一条原则:分支越少、活得越短,协作越顺畅。 不要为了"看起来规范"引入一堆长期分支。

3、Pull Request:代码进入主干的唯一通道

Pull Request(PR,GitLab 里叫 Merge Request / MR) 是"我改完了,请把它合进主干"的正式请求。

为什么必须走 PR,而不是直接 push 到 main?

  1. 多一道审查:别人帮你看过,能拦住低级错误。
  2. 有讨论记录:为什么这么改,留在 PR 里可追溯。
  3. 能挂自动化:CI 在 PR 上跑测试和检查(第 16 课)。
  4. 保护主干:main 设成受保护分支,只有通过评审和 CI 才能合。

一个 PR 应该多大?

越小越好。 研究与实践都表明:超过 400 行的 PR,评审质量会断崖式下降——没人能认真看完。

拆小 PR 的方法:

  • 先提交"脚手架/重构",再提交"基于它的功能"。
  • 用特性开关把半成品藏起来,先合代码,最后开开关。
  • 一个 PR 只解决一个问题,别把"顺手改的"塞进来。

PR 描述模板:

## 做了什么
给登录接口增加验证码校验。

## 为什么
防止机器人暴力撞库(关联 issue #128)。

## 怎么验证
1. 连续输错 3 次密码,第 4 次应要求输入验证码。
2. 跑 `npm test -- login`,新增 4 个用例全绿。

## 影响面 / 风险
- 影响登录接口,不改数据库。
- 有开关 `ENABLE_CAPTCHA`,可快速关闭。

## 自查清单
- [ ] 有测试覆盖
- [ ] 更新了相关文档
- [ ] 无遗留调试代码

4、评审(Code Review):到底审什么

评审不是为了抓人错,而是为了:

  • 正确性:逻辑对吗?边界处理了吗?
  • 可读性:半年后的同事能看懂吗?
  • 设计:放在这里合适吗?有没有更好的位置?
  • 测试:关键路径有测试吗?
  • 风险:安全、性能、兼容性有隐患吗?

评审不该纠结的(交给工具):

  • 缩进、空格、命名风格 → 用格式化器 + Linter 自动管(第 14 课)。
  • 拼写 → 用拼写检查工具。

评审的黄金准则:

  1. 就事论事,评代码不评人:"这个函数职责太多" ✅;"你写得真乱" ❌。
  2. 解释为什么:"建议抽成函数(L42-60 做了三件事,测试时没法单独 mock 中间那步)"。
  3. 区分必须改与建议:用 nit:(小建议)、must:(必须改)标注,给作者明确预期。
  4. 作者也有权讨论:评审是对话,不是命令。
  5. 及时:评审拖延 = 阻塞队友。团队可以约定"PR 提交后 24 小时内响应"。

一个高信息量的评审评论长这样:

must: L42 —— 这里直接拼接 SQL 字符串,会有注入风险。建议用参数化查询 db.query("...WHERE id = ?", [id])。可参考 user_repo.py:L88 的写法。

——指位置、说问题、给方案、给参考,作者照着就能改。

5、合并方式:Merge / Squash / Rebase

PR 通过后,怎么合进 main?三种方式:

方式效果适合
Merge commit保留分支上所有提交 + 一个合并提交想完整保留开发过程
Squash and merge把分支所有提交压成 1 个,再合入推荐默认,主干历史干净
Rebase and merge把分支提交逐个"搬"到主干顶端,线性历史追求线性、提交质量高

为什么推荐 Squash?

功能分支上常有"改错字""忘了加文件""再试一次"这类噪声提交。Squash 把它们合成一个语义完整的提交合入主干——主干历史干净,git log 一眼看清每个功能。

分支命名约定(团队统一即可):

feature/login-captcha      新功能
fix/login-null-password    修 bug
hotfix/payment-timeout     紧急修复
chore/upgrade-deps         杂务

6、把规则"焊死"在仓库上(分支保护)

光靠约定不够,要靠机制。 GitHub/GitLab 的分支保护规则(Branch Protection)能强制约束:

针对 main(或 develop)配置:

  • ✅ 禁止直接 push,所有改动必须走 PR。
  • ✅ 至少 1~2 人批准才能合并。
  • ✅ CI 必须全绿才能合并(第 16 课)。
  • ✅ 必须解决所有对话(评审意见)才能合并。
  • ✅ 合并后自动删除功能分支。

这样,"规范"就不再依赖人的自觉——制度保障 > 口头约定。

7、动手实验 🎯

任务:为一个三人小组设计并搭建协作流。

  1. 选分支策略:为"一个持续部署的 Web 产品"选一种(说明理由),再为一个"要同时维护 3 个已发布版本的桌面软件"选一种(说明差异)。
  2. 定一份分支命名约定(4 类分支 + 例子)。
  3. 写一份 PR 描述模板(含"做了什么/为什么/怎么验证/风险/自查清单"五块)。
  4. 模拟一次评审:找一段自己写的代码,写 3 条评审评论,要求分别用 nit: 和 must: 标注,且每条都要"指位置 + 说问题 + 给方案"。
  5. 为你的 main 分支列出分支保护清单(至少 4 条规则),说明每条防的是什么问题。
  6. 挑一个你见过的"大 PR",思考怎么把它拆成 3 个小 PR(用"脚手架 → 功能 → 清理"或特性开关的思路)。

做完这步,团队协作就有了可执行的流程和机制——下一课补齐让评审变轻的那部分:编码规范与静态检查。

8、今天你带走的三句话

  1. 分支越少、活得越短,协作越顺;大多数团队用 GitHub Flow 就够,别急着上 Git Flow。
  2. PR 越小越好(<400 行),评审要"指位置 + 说问题 + 给方案",就事论事不评人。
  3. 规范要靠机制保障:分支保护 + 必须评审 + CI 全绿,比口头约定可靠得多。

下一课进入编码规范与静态检查——把"风格之争"交给机器,让人专注真正的设计问题。

标签: 软件工程, 项目管理, 开发流程

添加新评论