团队 Git 开发规范:分支、Commit、Merge Request 与 CI/CD 流程详解
在团队开发中,Git 不只是一个“代码上传工具”。
如果每个人都按照自己的习惯提交代码,很快就会出现很多问题:
fix
update
修改了一下
123
测试
最终版本
最终版本2
真的最终版本
等到线上出了问题,再去翻 Git 记录时,基本无法快速判断:
- 这次提交改了什么?
- 为什么修改?
- 哪个提交引入了问题?
- 这个分支是从哪里拉出来的?
- 代码有没有经过 Code Review?
- 哪一版最终发布到了线上?
所以,一个团队必须有一套统一的 Git 规范。
本文主要介绍四部分内容:
1. Git Commit 提交规范
2. Git 分支规范
3. Merge Request / Code Review 流程
4. CI/CD 发布流程
最终目标其实非常简单:
让每一次代码修改,都能够被追踪、被理解、被审核、被安全发布。
一、为什么一定要有 Git 规范?
假设一个项目有 10 个开发人员。
如果每个人提交代码都是:
update
fix
修改代码
修复问题
半年以后查看日志:
git log
看到:
fix
update
fix
测试
修改
update
你根本不知道这些提交做了什么。
但是如果提交记录是:
feat/multi_merchant: 支持多商户下单
bugfix/user: 修复用户手机号为空导致登录失败
perf/user_login: 优化用户登录查询性能
hotfix/create_order: 修复线上重复创建订单问题
是不是马上清晰很多?
所以 Git 规范最大的价值,就是:
让代码修改本身具有可读性。
二、Git Commit 提交规范
团队提交代码时,需要根据本次修改的类型选择对应的 Commit 类型。
常见类型如下:
| 类型 | 含义 | 示例 |
|---|---|---|
| feat | 新功能 | feat/multi_merchant |
| bugfix | 普通 Bug 修复 | bugfix/user |
| hotfix | 紧急线上问题修复 | hotfix/create_order |
| perf | 性能优化 | perf/user_login |
| style | 格式、代码清理等不影响业务的修改 | style/log_print |
| refactor | 代码重构 | refactor/user |
| test | 测试相关 | test/user |
| docs | 文档、注释修改 | docs/user |
| chore | 依赖、脚手架、配置等琐事 | chore/dependency |
下面分别说明。
三、feat:开发新功能
feat 表示:
Feature,新功能。
例如我们要开发:
多商户功能
那么可以写:
feat/multi_merchant
Commit 信息建议写完整:
feat/multi_merchant: 支持多商户下单功能
或者:
feat/multi_merchant: 新增商户切换及订单归属逻辑
不要只写:
feat
因为虽然知道是新功能,但不知道:
到底是什么新功能。
四、bugfix:修复普通 Bug
bugfix 用于普通功能问题修复。
例如:
用户模块存在 Bug:
用户手机号为空时登录报错
可以提交:
bugfix/user: 修复手机号为空导致登录失败的问题
如果是订单模块:
bugfix/order: 修复取消订单后库存未释放的问题
这里非常重要:
Commit 信息不要只写:
bugfix/user
最好进一步说明:
bugfix/user: 修复用户信息为空导致空指针异常
因为真正有价值的信息,是:
修复了什么问题。
五、hotfix:线上紧急 Bug 修复
hotfix 通常用于:
线上严重问题的紧急修复。
例如:
线上订单出现重复创建
这种问题已经影响真实用户或真实业务,就应该使用:
hotfix/create_order: 修复订单重复创建问题
例如:
hotfix/payment: 修复支付回调重复处理导致订单金额异常
bugfix 和 hotfix 的区别可以简单理解成:
bugfix
普通 Bug
hotfix
线上紧急 Bug
例如:
测试环境发现按钮无法点击
→ bugfix
而:
线上用户无法支付
→ hotfix
所以 hotfix 一般优先级非常高。
六、perf:性能优化
perf 表示:
Performance,性能优化。
注意规范应该写成:
perf
而不是:
pref
例如用户登录接口比较慢。
原来:
500ms
优化以后:
80ms
那么可以提交:
perf/user_login: 优化用户登录接口查询性能
例如:
perf/order_query: 优化订单列表分页查询
常见性能优化包括:
SQL 优化
索引优化
缓存优化
批量查询
减少数据库访问
减少远程调用
算法优化
这些都可以使用:
perf
七、style:代码格式和非业务修改
style 很容易被误解。
它不是:
修改前端 CSS 样式。
在 Git Commit 规范中,style 更多表示:
不影响业务逻辑的代码调整。
例如:
删除无用注释
调整代码格式
删除无用 import
调整空格
日志格式调整
例如:
style/log_print: 统一订单模块日志输出格式
或者:
style/user: 删除用户模块无用注释
特点就是:
代码看起来变了,但是业务行为没有发生改变。
八、refactor:代码重构
refactor 表示:
重构代码,但是不改变原有业务功能。
例如以前用户注册写成:
public void register() {
// 200 行代码
}
后来拆成:
validateUser();
createUser();
saveUser();
sendRegisterMessage();
功能没有变化。
只是代码结构变好了。
可以提交:
refactor/user: 重构用户注册逻辑
再例如:
refactor/order: 拆分订单创建流程
需要注意:
修 Bug
不要写:
refactor
应该写:
bugfix
因为:
refactor
原则上表达的是:
代码结构变化,但是业务行为不变化。
九、test:测试相关修改
test 用于:
单元测试
集成测试
测试数据
测试代码
测试用例
例如:
test/user: 补充用户登录单元测试
或者:
test/order: 增加订单创建异常场景测试
如果修改的是正常业务代码,就不应该使用:
test
十、docs:文档和注释修改
docs 表示:
Documentation。
用于:
README
接口文档
技术文档
业务文档
代码注释
例如:
docs/user: 补充用户登录接口说明
或者:
docs/order: 完善订单状态说明
十一、chore:依赖、配置和日常维护
chore 通常表示:
不直接涉及业务功能的工程维护。
例如:
升级 Spring Boot
升级 Maven 依赖
修改脚手架
调整构建脚本
修改代码扫描配置
更新 Docker 配置
例如:
chore/dependency: 升级 hutool 版本
或者:
chore/maven: 调整 Maven 打包配置
十二、完整 Commit 示例
一个比较好的 Commit 应该做到:
类型 / 模块 : 做了什么事情
例如:
feat/multi_merchant: 支持多商户下单
bugfix/user: 修复手机号为空导致登录失败
hotfix/create_order: 修复线上订单重复创建问题
perf/user_login: 优化用户登录 SQL 查询
style/log_print: 统一日志打印格式
refactor/user: 重构用户注册流程
test/order: 补充订单创建单元测试
docs/user: 补充用户接口文档
chore/dependency: 升级 Spring Boot 依赖
这样以后执行:
git log
看到的历史记录会非常清晰。
十三、不推荐的 Commit 写法
以下 Commit 应尽量避免:
fix
update
修改
优化
测试
代码修改
解决问题
因为这些信息没有上下文。
例如:
fix
到底修了什么?
不知道。
而:
bugfix/user: 修复用户昵称过长导致保存失败
信息就非常完整。
所以一个好的 Commit 至少应该回答两个问题:
1. 这是什么类型的修改?
2. 这次具体修改了什么?
十四、Git 分支规范
除了 Commit,团队还需要统一:
分支从哪里拉取。
团队主要存在以下几个核心分支:
| 分支 | 是否保护 | 作用 |
|---|---|---|
| test | 是 | 测试环境分支 |
| pre | 是 | 预发布环境分支 |
| prod | 是 | 线上生产环境分支 |
| master | 是 | 线上代码存档,与 prod 保持同步 |
| 其他开发分支 | 否 | 日常开发使用 |
可以简单理解:
开发分支
↓
test
↓
pre
↓
prod
↓
master
不同公司的发布流程可能略有不同,但是环境含义基本就是:
test = 测试环境
pre = 预发布环境
prod = 正式生产环境
master = 线上稳定代码存档
十五、已上线项目从哪里拉分支?
如果系统:
已经上线生产环境。
新的开发分支应该基于:
prod
或者团队规定的:
master
拉取最新代码。
例如:
git checkout prod
git pull
然后创建开发分支:
git checkout -b feat/multi_merchant
为什么不能随便从 test 拉?
因为 test 里面可能存在:
正在测试但尚未上线的代码
如果你从 test 拉新功能:
test
↓
你的开发分支
就有可能把别人还没上线的功能一起带进去。
所以对于已经上线的系统:
应该从当前线上稳定代码拉取新的开发分支。
也就是:
prod / master
十六、未上线项目从哪里拉分支?
如果项目还处于:
开发阶段
还没有正式上线。
那么统一从:
test
拉取最新代码。
例如:
git checkout test
git pull
git checkout -b feat/user_login
因为此时 test 可以认为:
当前项目最新的集成开发基线。
十七、开发分支如何命名?
建议开发分支与 Commit 类型保持一致。
例如:
新功能:
feat/multi_merchant
Bug:
bugfix/user_login
线上紧急修复:
hotfix/create_order
性能优化:
perf/order_query
重构:
refactor/payment
文档:
docs/api
这样看到分支名称,就知道这个分支在干什么。
不要出现:
zhangsan
test2
new
aaa
dev123
临时
因为其他人完全不知道分支用途。
十八、一个标准的新功能开发流程
假设现在需要开发:
多商户功能
并且项目已经上线。
第一步:
切换线上分支。
git checkout prod
第二步:
拉取最新代码。
git pull
第三步:
创建开发分支。
git checkout -b feat/multi_merchant
然后开始开发。
十九、开发完成后提交代码
首先查看修改:
git status
然后添加文件:
git add .
提交:
git commit -m "feat/multi_merchant: 支持多商户下单功能"
然后 Push 到远程仓库:
git push origin feat/multi_merchant
此时只是:
把自己的开发分支上传到了远程仓库。
并不代表代码已经进入 test。
二十、为什么不能直接 Push 到 test?
test、pre、prod、master 都属于:
公共环境分支。
如果所有开发人员都能:
git push origin test
那么很容易出现:
未经审核的代码进入测试环境
错误代码覆盖别人代码
冲突没有处理好
线上 Bug 被意外带入
错误功能直接进入公共分支
所以这些核心分支应该设置:
Protected Branch
也就是:
受保护分支。
开发人员正常情况下不直接 Push。
而是走:
Merge Request。
二十一、什么是 Merge Request?
Merge Request 简称:
MR
GitHub 中通常叫:
Pull Request
也就是:
PR
本质上是一样的:
请求把一个分支的代码合并到另一个分支。
例如:
feat/multi_merchant
↓
test
开发完成以后,在远程 Git 平台发起:
Source Branch:
feat/multi_merchant
Target Branch:
test
也就是:
开发分支
↓
Merge Request
↓
test
二十二、Merge Request 发起以后做什么?
发起 MR 后:
不要直接自己合并。
需要把 MR 链接发送到团队群。
并:
@技术负责人
例如:
多商户功能已开发完成。
MR:
xxxxxx
麻烦帮忙 CR 一下。
@技术负责人
这里的 CR 指:
Code Review
代码审查。
二十三、什么是 Code Review?
Code Review 简称:
CR
它不是简单看一下:
代码能不能编译。
而是检查:
代码逻辑是否正确
是否可能有 Bug
代码规范是否符合要求
是否存在性能问题
SQL 是否合理
是否存在安全问题
异常是否处理
日志是否完整
有没有重复代码
设计是否合理
例如看到:
for (User user : users) {
userMapper.selectById(user.getId());
}
负责人可能会指出:
这里存在 N+1 查询问题。
要求改成:
批量查询
开发人员修改以后再次 Push:
git add .
git commit -m "perf/user_query: 优化用户批量查询逻辑"
git push
MR 会自动更新。
然后继续 CR。
二十四、为什么一定要 Code Review?
因为程序员写自己的代码时,很容易出现:
自己看自己的代码,看不出自己的问题。
Code Review 相当于:
开发者
↓
第一道检查
技术负责人 / Reviewer
↓
第二道检查
测试
↓
第三道检查
比直接:
开发完成
↓
上线
安全得多。
尤其是:
支付
订单
库存
金额
权限
数据删除
这种核心业务代码。
必须严格 CR。
二十五、CR 通过以后才能合并
当技术负责人确认代码没有明显问题以后:
Approve
才允许执行:
Merge
例如:
feat/multi_merchant
↓
Merge
↓
test
此时开发代码才真正进入:
test
二十六、Merge 成功后 CI/CD 自动开始工作
代码成功合并到 test 后,可以通过 CI/CD 自动完成:
拉取代码
↓
编译
↓
单元测试
↓
代码扫描
↓
打包
↓
构建镜像
↓
部署
↓
测试环境
开发人员不应该每次都手动:
登录服务器
git pull
mvn package
java -jar
杀进程
重新启动
这种方式:
风险高,而且不可追踪。
现代开发流程一般通过:
Git
+
CI/CD
自动完成。
二十七、完整提测流程
整个流程可以理解为:
从基准分支拉代码
↓
创建开发分支
↓
开发功能
↓
Git Commit
↓
Push 开发分支
↓
创建 Merge Request
↓
发送群里
↓
@技术负责人
↓
Code Review
↓
修改问题
↓
Review 通过
↓
Merge 到 test
↓
CI/CD
↓
自动构建
↓
自动部署
↓
测试环境
↓
测试人员测试
这就是一个比较完整的团队 Git 开发流程。
二十八、Bug 修复流程举例
假设测试人员发现:
用户修改头像后头像没有立即刷新。
创建分支:
git checkout test
git pull
git checkout -b bugfix/user_avatar
修改完成:
git add .
提交:
git commit -m "bugfix/user_avatar: 修复用户头像更新后缓存未刷新问题"
Push:
git push origin bugfix/user_avatar
然后创建:
bugfix/user_avatar
↓
test
的 MR。
技术负责人 CR。
通过以后 Merge。
CI/CD 自动部署测试环境。
测试人员验证 Bug。
二十九、线上 Hotfix 流程举例
线上突然发现:
创建订单可能重复扣库存。
这是严重线上问题。
此时不能从:
test
拉代码。
因为 test 里面可能还有:
没有上线的新功能。
应该从当前生产代码:
prod
拉。
例如:
git checkout prod
git pull
git checkout -b hotfix/create_order
修改:
重复扣库存问题
Commit:
git commit -m "hotfix/create_order: 修复重复提交导致库存重复扣减"
然后按照线上 Hotfix 发布流程进行 Review 和发布。
核心原则是:
修线上 Bug,必须基于线上代码修改。
否则你可能本来只想修一个 Bug,却顺便把 test 中十几个尚未上线的功能全部带到生产。
这是非常危险的。
三十、为什么 master 要同步 prod?
团队约定:
prod
表示:
真实线上运行代码。
而:
master
用于:
线上稳定代码归档。
所以应该保持:
prod
↓
master
实时或者按发布流程同步。
这样:
master
永远代表:
当前稳定生产版本。
实际采用 prod 作为唯一生产主线,还是采用 master 作为生产主线,各团队可以不同。
最重要的是:
团队必须统一,不能一半人认为 prod 是线上,一半人认为 master 是线上。
三十一、分支关系总结
可以简单记成:
┌─────────────┐
│ 开发分支 │
│ feat/* │
│ bugfix/* │
│ refactor/* │
└──────┬──────┘
│
↓
test
│
↓
pre
│
↓
prod
│
↓
master
其中:
test
pre
prod
master
应该受到保护。
开发人员主要操作:
feat/*
bugfix/*
hotfix/*
perf/*
refactor/*
三十二、团队开发最容易犯的错误
错误一:直接改 test
例如:
git checkout test
然后:
直接写代码。
不推荐。
应该:
test / prod
↓
创建开发分支
↓
开发
错误二:直接 Push test
例如:
git push origin test
应该禁止。
应该走:
开发分支
↓
MR
↓
Code Review
↓
test
错误三:Commit 写得太随便
不要:
fix
应该:
bugfix/user: 修复用户手机号为空导致登录失败
错误四:修线上 Bug 却从 test 拉代码
这是一个非常危险的问题。
错误:
test
↓
hotfix
↓
prod
因为 test 可能包含尚未上线的代码。
正确:
prod
↓
hotfix
↓
prod
错误五:MR 没有 CR 就直接合并
Merge Request 最大的价值之一就是:
Code Review
如果:
创建 MR
↓
自己 Merge
那 MR 很大程度上就失去了意义。
三十三、推荐团队最终执行规范
可以把整个规范浓缩成几条:
1. 所有开发必须建立独立分支
禁止直接在:
test
pre
prod
master
进行业务开发。
2. 已上线项目基于生产稳定分支创建开发分支
一般:
prod / master
具体按照团队约定。
3. 未上线项目基于 test 创建开发分支
例如:
test
↓
feat/*
4. Commit 必须有明确语义
例如:
feat/order: 支持批量创建订单
bugfix/user: 修复用户昵称为空导致保存失败
5. 开发完成先 Push 自己的分支
例如:
git push origin feat/multi_merchant
6. 需要提测时创建 MR
例如:
feat/multi_merchant
↓
test
7. MR 链接发团队群并 @负责人
由负责人:
Code Review
8. CR 通过以后才能 Merge
禁止未经 Review 直接进入公共分支。
9. Merge 后通过 CI/CD 自动部署
例如:
Merge test
↓
Pipeline
↓
Build
↓
Deploy
↓
测试环境
三十四、最终记忆版
如果是刚加入团队的新人,不想一次记太多,可以先记住下面这套流程:
先拉最新代码
↓
创建自己的开发分支
↓
写代码
↓
规范 Commit
↓
Push 自己的分支
↓
提交 MR
↓
把 MR 发群里
↓
@负责人 CR
↓
CR 通过
↓
Merge
↓
CI/CD 自动部署
Commit 类型记住:
feat 新功能
bugfix 普通 Bug
hotfix 线上紧急 Bug
perf 性能优化
style 格式、无业务影响修改
refactor 重构
test 测试
docs 文档
chore 依赖、配置等杂项
环境分支记住:
test
测试环境
pre
预发布环境
prod
生产环境
master
生产稳定代码存档
开发过程中最重要的一个原则就是:
不直接修改公共分支,不直接把未经审核的代码推到公共环境。
Git 规范看起来只是规定了一些分支名称和 Commit 格式,但它真正解决的是:
谁改了代码
为什么改
改了什么
代码有没有被审核
什么时候进入测试
什么时候进入生产
线上版本到底是哪一份代码
一个成熟团队的 Git 流程,最终追求的不是“看起来专业”,而是:
每一次代码变更,都有来源、有记录、有审核、有发布链路,并且出了问题能够快速定位和回滚。
这才是 Git 规范真正的价值。