工程化篇 | Git工作流
前言
Git 几乎是每个开发者每天都在用的工具,但很多人对 Git 的使用停留在 add → commit → push 三板斧。真到面试被问到工作流层面的问题,就开始含糊了。
- 你们团队用的是什么 Git 工作流?为什么选择这个?
- Git Flow 和 GitHub Flow 有什么区别?
- Trunk Based Development 是什么?为什么大厂在推它?
- Commit Message 有什么规范?为什么要规范?
- Code Review 怎么做才高效?
这些问题考察的不是你”会不会用 Git”,而是你对团队协作和研发流程的理解。一个能清晰阐述工作流选择和原因的候选人,在面试官眼里会加分不少。
本章,我们从三种主流 Git 工作流的对比讲起,再聊分支命名规范、Commit Message 规范、Code Review 流程,以及如何与 CI/CD 集成。
诊断自测
Q1:Git Flow 中有哪些分支?各自的作用是什么?
点击查看答案
Git Flow 定义了五种分支:
- main(master):生产环境代码,始终可部署
- develop:开发主分支,集成所有已完成的功能
- feature/:功能分支,从 develop 分出,开发完合回 develop
- release/:发布分支,从 develop 分出,用于发布前的准备和 bug 修复
- hotfix/:热修复分支,从 main 分出,修复生产环境紧急 bug
Q2:Conventional Commits 规范中,feat 和 fix 分别对应语义化版本(SemVer)的哪个位?
点击查看答案
feat(新功能)对应 Minor 版本(如 1.1.0 → 1.2.0)fix(修复)对应 Patch 版本(如 1.1.0 → 1.1.1)- 如果 Commit Message 的 footer 中包含
BREAKING CHANGE,则对应 Major 版本(如 1.1.0 → 2.0.0)
这也是 Changesets、semantic-release 等工具自动化版本管理的基础。
一、Git Flow:经典但沉重
1.1 核心思路
Git Flow 由 Vincent Driessen 在 2010 年提出,是最早被广泛采用的 Git 分支策略。
它的核心思路是:用不同类型的分支承载不同阶段的代码。
main ────────●────────────────────●──────────
↑ ↑
hotfix/fix-xxx merge release
│
develop ──●──●──●──●──●──●──●──●──●──●───────
↑ ↑ ↑
feature/a feature/b release/1.0
1.2 完整工作流
- 日常开发在
feature/*分支上进行 - 功能完成后,通过 PR 合并到
develop - 准备发版时,从
develop创建release/*分支 - 在
release/*上做发布前的最后修复 release/*合并到main(打 tag)和develop- 如果生产环境有紧急 bug,从
main创建hotfix/*,修复后合并到main和develop
1.3 优缺点
优点:
- 角色明确,适合有明确发版周期的项目
- 生产代码和开发代码完全隔离
缺点:
- 分支多、流程重,merge 冲突频繁
- 不适合持续部署(Continuous Deployment)
- 在 CI/CD 时代显得过于繁琐
二、GitHub Flow:简单即正义
2.1 核心思路
GitHub Flow 极度简化,只有一个规则:main 分支始终可部署,所有改动通过 PR 合入。
main ─────●─────●─────●─────●─────●─────
↑ ↑ ↑ ↑
feat-a fix-b feat-c feat-d
2.2 完整工作流
- 从
main创建一个描述性命名的分支(如add-user-auth) - 在分支上开发、提交
- 开发完成后创建 Pull Request
- 团队 Code Review
- CI 检查通过后合并到
main - 合并后自动部署
2.3 优缺点
优点:
- 极简——只有
main和功能分支 - 天然适合持续部署
- 低学习成本
缺点:
- 不区分”开发中”和”待发布”的代码
- 不适合需要维护多个版本的场景(如桌面软件、SDK)
- 对 CI/CD 的依赖很强——如果没有自动化测试保障,直接合入 main 风险大
三、Trunk Based Development:大厂之选
3.1 核心思路
Trunk Based Development(TBD)的核心理念是:所有开发者直接向主干(trunk/main)提交代码,使用短生命周期的分支。
main ──●──●──●──●──●──●──●──●──●──●──●──
↑ ↑ ↑ ↑
PR1 PR2 直接 PR3
push
3.2 关键原则
- 分支生命周期极短:通常不超过 1-2 天,最好当天创建当天合入
- 小步提交:每次提交都是一个小的、可工作的改动
- Feature Flags:还没完成的功能用 Feature Flag 隐藏,而不是放在长期分支上
- 高频集成:每天至少合入一次到主干
3.3 Feature Flags
Feature Flags(功能开关)是 TBD 的核心配套技术:
// 功能还没开发完,但代码已经在 main 上了
if (featureFlags.isEnabled('new-dashboard')) {
return <NewDashboard />;
} else {
return <OldDashboard />;
}
这样你可以把半成品代码合入 main 而不影响线上用户——功能开关关着就行。等功能完成、测试通过,打开开关上线。
3.4 优缺点
优点:
- 几乎没有 merge 冲突(分支生命周期极短)
- 代码始终在主干上,团队对代码库的认知一致
- 天然适合持续集成/持续部署
缺点:
- 对团队能力要求高:需要熟练的小步提交习惯
- 需要 Feature Flags 基础设施
- 需要强大的自动化测试保障
3.5 谁在用 TBD?
Google、Facebook(Meta)、微软、字节跳动等大厂都在推行 TBD。Google 甚至把整个公司的代码放在一个巨大的 Monorepo 里,所有人直接向主干提交。
四、三种工作流对比
| 维度 | Git Flow | GitHub Flow | Trunk Based |
|---|---|---|---|
| 复杂度 | 高 | 低 | 中 |
| 分支数量 | 多 | 少 | 极少 |
| 分支生命周期 | 长 | 中 | 极短(<1天) |
| 适合的发布模式 | 定期发版 | 持续部署 | 持续部署 |
| 对 CI/CD 的要求 | 中 | 高 | 极高 |
| 对团队的要求 | 中 | 中 | 高 |
| 适合场景 | 传统软件、SDK | Web 应用、开源项目 | 大型团队、高频迭代 |
| Feature Flags | 不需要 | 不需要 | 核心依赖 |
选型建议:
- 有明确发版周期的项目 → Git Flow
- Web 应用、需要快速迭代 → GitHub Flow
- 大型团队、持续部署、高频迭代 → Trunk Based Development
五、分支命名规范
好的分支命名让团队成员一眼就能看出这个分支在做什么。
5.1 命名规则
<type>/<description>
type: feature, fix, hotfix, refactor, docs, chore, release
description: 用短横线连接的简短描述
5.2 示例
feature/user-authentication
feature/shopping-cart
fix/login-redirect-loop
hotfix/payment-crash
refactor/api-client
docs/api-documentation
chore/upgrade-webpack
release/v2.1.0
5.3 反面例子
❌ my-branch ← 不知道在做什么
❌ test ← 太笼统
❌ wip ← 不够描述性
❌ fix-bug ← 什么 bug?
❌ feature/add-new-feature-for-user-authentication-and-authorization ← 太长了
六、Commit Message 规范:Conventional Commits
6.1 为什么需要规范?
没有规范的 Commit Message 通常长这样:
fix bug
update
wip
aaa
final fix
final final fix
这样的提交记录毫无价值——你不知道改了什么、为什么改、影响了哪里。
规范的 Commit Message 有三大好处:
- 提交历史可读:
git log就能看出每次提交做了什么 - 自动化:可以自动生成 CHANGELOG、自动确定版本号
- 团队协作:新人看提交历史就能了解项目演进过程
6.2 Conventional Commits 格式
<type>(<scope>): <description>
[optional body]
[optional footer]
6.3 type 类型
| type | 说明 | 示例 |
|---|---|---|
feat | 新功能 | feat(auth): add OAuth2 login |
fix | Bug 修复 | fix(cart): resolve total calculation error |
docs | 文档修改 | docs(readme): update installation guide |
style | 格式调整(不影响逻辑) | style: fix indentation |
refactor | 重构(不改功能、不修 bug) | refactor(api): simplify error handling |
perf | 性能优化 | perf(list): optimize virtual scroll rendering |
test | 添加/修改测试 | test(auth): add login unit tests |
chore | 构建/工具变动 | chore: upgrade webpack to v5 |
ci | CI 配置变动 | ci: add lint job to pipeline |
6.4 完整示例
feat(auth): add email verification flow
- Add email verification page
- Implement verification token generation
- Add expiration check for tokens
Closes #123
6.5 工具支持
- commitlint:校验 Commit Message 是否符合规范
- commitizen(cz-cli):交互式命令行工具,引导你填写符合规范的 Message
- husky:Git Hooks 工具,在 commit 前自动运行 commitlint
# 安装
npm install -D @commitlint/cli @commitlint/config-conventional husky
# 配置 commitlint
echo "module.exports = { extends: ['@commitlint/config-conventional'] }" > commitlint.config.js
# 配置 husky hook
npx husky add .husky/commit-msg 'npx commitlint --edit $1'
七、Code Review 流程
7.1 为什么需要 Code Review?
- 质量保障:多一双眼睛审查,减少 bug 和设计缺陷
- 知识共享:团队成员了解彼此的代码,降低”总线因子”
- 团队规范:通过 Review 统一代码风格和最佳实践
- 成长:新人通过 Review 学习,老手通过 Review 反思
7.2 好的 PR 长什么样?
- 小:200-400 行代码改动最佳。超过 800 行的 PR 很难认真 Review
- 单一职责:一个 PR 只做一件事
- 清晰的描述:说清楚改了什么、为什么改、怎么测试
- 自测通过:提 PR 前确保 CI 通过
7.3 PR 模板
## What
简要描述这个 PR 做了什么。
## Why
为什么要做这个改动?关联的 Issue/需求是什么?
## How
关键的实现思路或架构决策。
## Test Plan
- [ ] 单元测试通过
- [ ] 手动测试场景 A
- [ ] 手动测试场景 B
## Screenshots
(如果有 UI 变更,贴截图)
7.4 Review 的注意事项
作为 Reviewer:
- 关注设计和逻辑,不要只挑格式问题(格式问题交给工具)
- 给出建设性的反馈,而不是”这样不对”
- 对于不确定的地方,用提问代替断言
- 及时 Review,不要让 PR 挂着等好几天
作为 Author:
- 不要在 PR 中包含不相关的改动
- 主动在关键代码处添加注释说明
- 收到反馈后及时回复和修改
八、CI/CD 集成
8.1 CI 与 Git 工作流的配合
# GitHub Actions 示例
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
build:
needs: [lint, test] # lint 和 test 通过后才 build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
8.2 分支保护规则
- main 分支:禁止直接 push,必须通过 PR 合入
- PR 合入条件:CI 通过 + 至少 1 个 Approve
- squash merge:把 PR 的多次提交压缩成一个,保持 main 的提交历史干净
常见误区
误区一:“Git Flow 是最佳实践,所有项目都该用”
Git Flow 适合有明确发版周期的项目(如 SDK、桌面应用)。对于 Web 应用这种持续部署的场景,Git Flow 的 develop/release 分支反而是多余的负担。很多团队用了 Git Flow 后发现 develop 和 main 的差异越来越大,合并变得痛苦不堪。选工作流要根据项目类型和团队情况,而不是”别人用什么我就用什么”。
误区二:“Commit Message 规范是形式主义,浪费时间”
短期来看确实多花了几秒钟,但长期收益巨大:自动生成 CHANGELOG、自动化版本管理、提交历史可读可追溯。当你需要回溯三个月前的某个改动时,fix: resolve login redirect loop (#456) 比 fix bug 有用太多了。
误区三:“Code Review 就是挑毛病”
Code Review 的首要目的是质量保障和知识共享,不是找茬。如果你的 Review 只是指出”这个变量名不好”、“这里少个空行”,那确实是在浪费时间——这些应该交给 ESLint 和 Prettier。Review 应该关注架构设计、业务逻辑、边界条件、安全性等机器做不了的事情。
误区四:“Trunk Based Development 就是所有人直接往 main 推代码,不需要 Review”
错。TBD 鼓励频繁地向主干集成,但不意味着跳过 Review。大部分实践 TBD 的团队仍然使用短生命周期的分支 + PR Review,只是分支的生命周期很短(通常不超过一天),而不是像 Git Flow 那样维持数周的长期分支。
小结
本章我们对比了三种主流 Git 工作流(Git Flow、GitHub Flow、Trunk Based Development),梳理了分支命名规范和 Conventional Commits 规范,讲解了 Code Review 的最佳实践,以及如何与 CI/CD 集成。
核心要点
- Git Flow:分支多、流程重,适合有明确发版周期的项目
- GitHub Flow:极简,main + 功能分支,适合 Web 应用和持续部署
- Trunk Based Development:主干开发 + Feature Flags,适合大型团队和高频迭代
- Conventional Commits:结构化的提交信息,支持自动化版本管理和 CHANGELOG 生成
- Code Review:关注设计和逻辑,而不是格式;PR 要小而聚焦
- CI/CD:分支保护 + 自动化检查 + squash merge
本章思维导图
- Git Flow
- 五种分支:main / develop / feature / release / hotfix
- 适合有明确发版周期的项目
- 缺点:分支多、合并痛苦
- GitHub Flow
- 只有 main + 功能分支
- 通过 PR 合入,适合持续部署
- 简单但对 CI/CD 依赖强
- Trunk Based Development
- 主干开发,短生命周期分支
- Feature Flags 隐藏未完成功能
- 适合大型团队和高频迭代
- 分支命名规范
- <type>/<description>
- feature / fix / hotfix / refactor / docs / chore
- Commit Message 规范
- Conventional Commits:<type>(<scope>): <description>
- 工具:commitlint + husky + commitizen
- 支持自动化版本管理
- Code Review
- PR 要小(200-400 行)、单一职责
- 关注设计和逻辑,格式交给工具
- 及时 Review,建设性反馈
- CI/CD 集成
- PR 触发 CI(lint + test + build)
- 分支保护规则
- squash merge 保持历史干净
练习挑战
第一题 ⭐(基础):Commit Message 改写
请把下面不规范的 Commit Message 改写成符合 Conventional Commits 规范的格式:
fixed login bugadd new feature for user profile pageupdate README
点击查看答案与解析
fix(auth): resolve login redirect loop—— 使用fix类型,加上 scope 说明模块,description 描述具体修了什么feat(profile): add user profile page—— 使用feat类型,简洁描述新功能docs(readme): update installation guide—— 使用docs类型,说明更新了什么内容
改写要点:
- 使用正确的 type
- description 用英文祈使句(动词原形开头)
- 尽可能加上 scope
- 简洁但有信息量
第二题 ⭐⭐(进阶):工作流选型
你们团队有 5 个开发者,开发一个 ToB SaaS 产品。目前使用 Git Flow,但经常出现以下问题:
- develop 分支上积累了大量未发布的功能,和 main 的差异越来越大
- release 分支经常要处理很多合并冲突
- hotfix 合入 develop 时经常忘记
请分析问题原因,并提出改进方案。
点击查看答案与解析
问题分析:
这些问题是 Git Flow 的典型痛点:
- develop 积累过多未发布功能 → 说明发版周期太长,功能在 develop 上”排队等候”
- release 分支合并冲突多 → develop 和 main 差异太大的直接后果
- hotfix 忘记合入 develop → 分支太多,流程容易遗漏
改进方案:
对于 5 人团队的 SaaS 产品,建议迁移到 GitHub Flow:
- 去掉 develop 和 release 分支,只保留 main + 功能分支
- 每个功能完成后直接通过 PR 合入 main
- main 分支始终可部署,合入后自动部署到 staging 环境
- 手动触发从 staging 到 production 的部署(或根据信心程度自动部署)
- 配合自动化测试保障 main 的质量
如果某些功能需要较长时间开发,使用 Feature Flags 而不是长期分支:
if (featureFlags.isEnabled('new-billing')) {
return <NewBilling />;
}
return <OldBilling />;
这样功能代码可以频繁合入 main(持续集成),但用户看不到(通过 Flag 控制)。等功能完成测试后,打开 Flag 即可上线。
第三题 ⭐⭐⭐(综合):设计 Code Review + CI 流程
请为一个中型前端项目设计完整的 PR → Review → CI → 合并流程,包括:
- PR 创建时需要填写哪些信息?
- CI 应该跑哪些检查?
- Review 的标准和规则是什么?
- 合并策略是什么?
点击查看答案与解析
一、PR 创建规范
使用 PR 模板(.github/pull_request_template.md):
## Summary
一句话说明这个 PR 做了什么。
## Changes
- 改动点 1
- 改动点 2
## Related Issues
Closes #issue_number
## Test Plan
- [ ] 单元测试
- [ ] 本地手动测试
- [ ] 特殊场景测试(边界条件、错误状态等)
## Screenshots
(有 UI 改动时必填)
二、CI 检查项
jobs:
# 1. 代码质量
lint:
steps:
- run: pnpm lint # ESLint
- run: pnpm format:check # Prettier 格式检查
- run: pnpm typecheck # TypeScript 类型检查
# 2. 测试
test:
steps:
- run: pnpm test -- --coverage
- uses: codecov/codecov-action # 上传覆盖率报告
# 3. 构建
build:
needs: [lint, test]
steps:
- run: pnpm build
# 4. Bundle Size 检查
bundle-size:
steps:
- uses: andresz1/size-limit-action # 检查构建产物大小是否超标
# 5. Commit Message 检查
commitlint:
steps:
- run: npx commitlint --from ${{ github.event.pull_request.base.sha }}
三、Review 规则
- 至少 1 个 Approve 才能合入(关键模块要求 2 个)
- 配置 CODEOWNERS:特定目录的修改必须由对应的负责人 Review
- Review 关注点优先级:架构设计 > 业务逻辑 > 边界处理 > 性能 > 命名/风格
- Review SLA:24 小时内给出首次反馈
四、合并策略
- 使用 Squash Merge:把 PR 中的多次提交压缩成一个
- Squash Commit Message 使用 PR 标题(符合 Conventional Commits 格式)
- 合并后自动删除功能分支
- 合并后触发 staging 环境自动部署
自我检测
- 能描述 Git Flow、GitHub Flow、Trunk Based Development 三种工作流的核心差异
- 能根据项目类型和团队情况给出工作流选型建议
- 能说出 Trunk Based Development 中 Feature Flags 的作用
- 能写出符合 Conventional Commits 规范的 Commit Message
- 能说出为什么 Commit Message 规范对自动化版本管理很重要
- 能描述一个好的 PR 应该具备哪些特征
- 能设计一个完整的 PR → CI → Review → 合并流程
- 能配置 commitlint + husky 来自动化 Commit Message 校验
购买课程解锁全部内容
大厂前端面试通关:71 篇构建完整知识体系
¥89.90