为什么需要工作流规范
多人协作时,每个人都有自己的 Git 使用习惯:有人直接提交到 main,有人创建分支但从不删除,有人提交信息写"fix"、"update"、"aaa"……这导致:
- 主分支代码随时可能不稳定
- 谁也不知道哪个版本是可以发布的
- 代码 Review 形同虚设
- 紧急 bug 修复与功能开发互相干扰
工作流(Workflow)是一套团队约定,规定了分支如何创建、命名、合并和删除,让所有人按照相同的节奏协作。
Git Flow
Git Flow 由 Vincent Driessen 在 2010 年提出,适合有明确版本周期、需要维护多个版本的项目(如桌面软件、移动 App、库)。
分支结构
main ●───────────────────────────────● v1.0 ●─── v1.1
│ ↑ ↑
develop ●──●──●──────────────────●──●──────●──●──●──●
│ ↑↑
feature ●──●──●──●──→ (merge) │ │
│ └─── release/1.0 ──●──→ (merge to main + tag)
└─────── hotfix/xxx ──●──→ (merge to main + develop)
│ ↑ ↑
develop ●──●──●──────────────────●──●──────●──●──●──●
│ ↑↑
feature ●──●──●──●──→ (merge) │ │
│ └─── release/1.0 ──●──→ (merge to main + tag)
└─────── hotfix/xxx ──●──→ (merge to main + develop)
两条长期分支
-
main
只包含生产就绪的代码。每次合并都对应一个版本标签(
v1.0.0)。永远不要直接提交到 main。 - develop 开发主线,包含下一个版本的所有已完成功能。所有功能分支从此分出,完成后合并回来。
三类短期辅助分支
| 分支类型 | 从哪分出 | 合并回哪 | 命名格式 |
|---|---|---|---|
| Feature | develop | develop | feature/user-auth |
| Release | develop | main + develop | release/1.2.0 |
| Hotfix | main | main + develop | hotfix/critical-bug |
完整 Git Flow 示例
# 开始新功能开发
git switch develop
git switch -c feature/payment
# ... 开发功能 ...
git switch develop
git merge --no-ff feature/payment
git branch -d feature/payment
# 准备发布 1.0.0
git switch -c release/1.0.0
# 只做小修改:修改版本号、文档等
git commit -m "chore: bump version to 1.0.0"
# 发布完成:合并到 main 并打标签
git switch main
git merge --no-ff release/1.0.0
git tag -a v1.0.0 -m "Release version 1.0.0"
# 合并回 develop
git switch develop
git merge --no-ff release/1.0.0
git branch -d release/1.0.0
# 线上发现紧急 bug!
git switch main
git switch -c hotfix/login-crash
# ... 修复 bug ...
git switch main
git merge --no-ff hotfix/login-crash
git tag -a v1.0.1 -m "Hotfix: fix login crash"
git switch develop
git merge --no-ff hotfix/login-crash
git branch -d hotfix/login-crash
Git Flow 的优缺点
优点
• 结构清晰,职责分明
• 支持并行维护多个版本
• 适合有明确发布节奏的项目
缺点
• 分支太多,切换频繁
• 不适合持续部署
• 对于 Web 项目过于"重"
GitHub Flow
GitHub Flow 由 GitHub 在 2011 年提出,原则极简:只有一条长期分支(main),所有功能通过 PR 合并。适合持续部署的 Web 应用。
main ●────────────────────────────────●────────────────●
│ ↑ PR merge ↑ PR merge
feature-A ●──●──●──●──────────────┘
feature-B ●──●──●──●──────────────────────────────┘
│ ↑ PR merge ↑ PR merge
feature-A ●──●──●──●──────────────┘
feature-B ●──●──●──●──────────────────────────────┘
GitHub Flow 步骤
# 1. 从最新的 main 创建功能分支
git switch main
git pull origin main
git switch -c feature/new-dashboard
# 2. 持续开发并推送(可以多次 push,随时备份)
git commit -m "feat: add dashboard skeleton"
git push -u origin feature/new-dashboard
# 3. 创建 Pull Request,请求 Review
# 4. 根据 Review 修改,继续推送
# 5. PR 通过后合并到 main
# 6. main 合并后立即自动部署到生产环境
# 7. 删除功能分支
git branch -d feature/new-dashboard
GitHub Flow 特点
- 简单、开销小,团队快速上手
- 依赖强大的自动化测试(每次 PR 自动运行 CI)
- 合并到 main 即发布,要求代码随时可部署
- 适合 SaaS、Web 应用等只有一个"生产版本"的项目
Trunk-Based Development(主干开发)
Trunk-Based Development(TBD)是 Google、Facebook 等大型科技公司使用的模式:所有开发者频繁地(至少每天)将小变更提交到主干(main/trunk),通过 Feature Flag 控制未完成功能的可见性。
# 每天小步提交到 main
git pull --rebase origin main
# ... 小步骤改动 ...
git commit -m "refactor: extract payment service (behind flag)"
git push origin main
Feature Flag(特性开关)示例:
if (featureFlags.newCheckout) {
// 新结账流程(未完成,线上不可见)
renderNewCheckout();
} else {
// 旧结账流程
renderLegacyCheckout();
}
适用条件:成熟的 CI/CD、强大的自动化测试覆盖率、团队有使用 Feature Flag 的能力。
如何选择工作流
| 场景 | 推荐工作流 |
|---|---|
| Web 应用,持续部署 | GitHub Flow |
| 移动/桌面 App,有版本号 | Git Flow |
| 开源库,需维护多版本 | Git Flow |
| 成熟团队,高度自动化 | Trunk-Based |
| 小团队(1-3人) | GitHub Flow 或简化版 |
Commit 消息规范:Conventional Commits
Conventional Commits 是被广泛采用的提交信息规范,格式:
type(scope): description
[optional body]
[optional footer(s)]
| 类型 | 使用场景 | 影响版本号 |
|---|---|---|
feat | 新功能 | MINOR 递增 |
fix | Bug 修复 | PATCH 递增 |
feat! / BREAKING CHANGE | 破坏性变更 | MAJOR 递增 |
docs | 文档 | 不影响 |
style | 代码格式(不影响逻辑) | 不影响 |
refactor | 重构 | 不影响 |
test | 测试 | 不影响 |
chore | 构建/工具 | 不影响 |
perf | 性能优化 | PATCH 递增 |
ci | CI 配置 | 不影响 |
Code Review 最佳实践
PR 大小控制
- 一个 PR 只做一件事(单一职责)
- 尽量控制在 400 行变更以内
- 大功能拆分为多个小 PR 逐步合并
- PR 描述清楚 Why(为什么做)、What(做了什么)、How(如何测试)
Review 礼仪
- 区分 blocking(必须修改)和 non-blocking(建议)评论,如
nit:前缀表示 nitpick(小建议) - 评论代码,不评论人:说"这个函数可以拆分一下",不说"你为什么这样写"
- 提问而不是命令:"这里用 Map 是否会更高效?"
- 给出理由,并提供建议的替代方案
- 对于好的代码,给予正面反馈(
nice!/👍)