为什么需要工作流规范
多人协作时,每个人都有自己的 Git 使用习惯:有人直接提交到 main,有人创建分支但从不删除,有人提交信息写"fix"、"update"、"aaa"……这导致:
- 主分支代码随时可能不稳定
- 谁也不知道哪个版本是可以发布的
- 代码 Review 形同虚设
- 紧急 bug 修复与功能开发互相干扰
工作流(Workflow)是一套团队约定,规定了分支如何创建、命名、合并和删除,让所有人按照相同的节奏协作。
Git Flow
Git Flow 由 Vincent Driessen 在 2010 年提出,适合有明确版本周期、需要维护多个版本的项目(如桌面软件、移动 App、库)。
分支结构
│ ↑ ↑
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 应用。
│ ↑ 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!/👍)
分支保护与合并策略配置
工作流的落地需要平台层面的保护,防止团队成员绕过规范:
GitHub 分支保护规则(推荐配置)
| 规则 | 说明 | 推荐值 |
|---|---|---|
| Require pull request reviews | 合并前需要 N 个批准 | 最少 1 个(小团队),2 个(中大团队) |
| Require status checks to pass | CI 必须全部通过 | 开启,选择所有必要的 check |
| Require branches to be up to date | 合并前分支必须是最新的 | 开启(避免合并过时分支) |
| Restrict who can push | 限制直接 push 权限 | 只有维护者可以直接推送 |
| Allow force pushes | 允许 force push | 关闭(保护历史) |
合并策略的选择
GitHub/GitLab 提供三种合并 PR 的方式:
- Merge commit(三方合并) 保留完整的分支历史,创建 merge commit。适合 Git Flow 工作流,能清楚看到功能分支的开发历史。
- Squash and merge 将分支所有 commit 压缩为单个 commit 合并。历史线性清晰,但丢失了分支内部的提交历史。适合 GitHub Flow,功能分支的零散 commit 不需要保留。
- Rebase and merge 将分支 commit 逐个 rebase 到目标分支顶端,线性历史。每个 commit 都保留,但哈希改变。适合想要线性历史同时保留每个提交的团队。
团队要统一合并策略 — 混用三种合并方式会导致历史混乱。建议在仓库 Settings 中禁用不需要的合并方式,只保留团队统一使用的那一种。例如 GitHub Flow 团队通常只保留 "Squash and merge"。
工作流常见误区
Git Flow 不适合持续部署 — Git Flow 设计之初是为了有明确版本节奏的软件。如果你的团队每天部署多次,Git Flow 会显得极其繁琐(每次发布都需要 release 分支、多次合并)。持续部署的团队应选择 GitHub Flow 或 Trunk-Based。
Trunk-Based 的前提条件不可忽视 — Trunk-Based Development 的核心假设是"main 始终可部署"。要实现这一点,需要高度的测试覆盖率(通常 > 80%)、成熟的 CI/CD 流水线,以及团队有使用 Feature Flag 的工程文化。在这些条件不具备时强行采用,会导致 main 频繁不可用。
本章小结 — 工作流的选择取决于项目类型和团队规模:Git Flow 适合有版本发布节奏的项目(App、库),GitHub Flow 适合持续部署的 Web 应用,Trunk-Based 适合高度自动化的成熟团队。Conventional Commits 规范让提交信息可以机器读取,支持自动生成 CHANGELOG 和版本号。无论选择哪种工作流,通过 Protected Branch 配置在平台层面强制执行规范是必要的。