软件项目开发全流程 · 第 13 课 · Git 进阶:分支策略与 PR
1、三个人的团队,为什么会互相踩脚
第 12 课我们学会了"个人的 Git"。但团队一上来就遇到新问题:
- 小王在
main上直接提交,把大家跑不起来的代码推了上去,全员停工半小时。 - 小李的 PR 挂了 3 天没人看,等他合进去时,
main已经变了 200 个文件,冲突解到怀疑人生。 - 团队没有约定分支怎么命名,仓库里躺着
test、dev2、new-new、老王分支……
这些都不是技术问题,是协作流程问题。本课解决:
- 团队用什么样的分支策略?
- 代码怎么进主干(Pull Request / 代码评审)?
- 评审怎么才有效,而不是走过场?
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?
- 多一道审查:别人帮你看过,能拦住低级错误。
- 有讨论记录:为什么这么改,留在 PR 里可追溯。
- 能挂自动化:CI 在 PR 上跑测试和检查(第 16 课)。
- 保护主干:
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 课)。
- 拼写 → 用拼写检查工具。
评审的黄金准则:
- 就事论事,评代码不评人:"这个函数职责太多" ✅;"你写得真乱" ❌。
- 解释为什么:"建议抽成函数(L42-60 做了三件事,测试时没法单独 mock 中间那步)"。
- 区分必须改与建议:用
nit:(小建议)、must:(必须改)标注,给作者明确预期。 - 作者也有权讨论:评审是对话,不是命令。
- 及时:评审拖延 = 阻塞队友。团队可以约定"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、动手实验 🎯
任务:为一个三人小组设计并搭建协作流。
- 选分支策略:为"一个持续部署的 Web 产品"选一种(说明理由),再为一个"要同时维护 3 个已发布版本的桌面软件"选一种(说明差异)。
- 定一份分支命名约定(4 类分支 + 例子)。
- 写一份 PR 描述模板(含"做了什么/为什么/怎么验证/风险/自查清单"五块)。
- 模拟一次评审:找一段自己写的代码,写 3 条评审评论,要求分别用
nit:和must:标注,且每条都要"指位置 + 说问题 + 给方案"。 - 为你的
main分支列出分支保护清单(至少 4 条规则),说明每条防的是什么问题。 - 挑一个你见过的"大 PR",思考怎么把它拆成 3 个小 PR(用"脚手架 → 功能 → 清理"或特性开关的思路)。
做完这步,团队协作就有了可执行的流程和机制——下一课补齐让评审变轻的那部分:编码规范与静态检查。
8、今天你带走的三句话
- 分支越少、活得越短,协作越顺;大多数团队用 GitHub Flow 就够,别急着上 Git Flow。
- PR 越小越好(<400 行),评审要"指位置 + 说问题 + 给方案",就事论事不评人。
- 规范要靠机制保障:分支保护 + 必须评审 + CI 全绿,比口头约定可靠得多。
下一课进入编码规范与静态检查——把"风格之争"交给机器,让人专注真正的设计问题。