JavaDog程序狗
发布于 2026-08-19 / 1 阅读
0
0

【规范】这套 Git 规范,救了整个团队

前言

🍊缘由

凌晨2点,一次 force push 引发的血案

封面:凌晨2点的 force push 灾难

那天凌晨 2 点,小李一条 git push --force,把 master 上三天的提交历史抹得干干净净。
没人知道线上代码对应哪个 commit,没人敢发布,领导在群里甩了一个字:查。
事后复盘,领导写下一份团队 Git 规范。今天全文公开,只要团队超过 3 个人,照抄就能用。

🏀事情起因:
大家好,我是 JavaDog程序狗。今天聊点保命的,一套由团队领导制定,最全企业级Git规范。

你大概率见过这些分支名:

branch-1
branch-2
branch-final
branch-真final
branch-终极版-别删
张三的分支
修复一下

上线前的问题才要命。这个 bug 到底修没修?修了,在某个分支上,没人记得是哪个。线上跑的究竟是哪份代码?查不出来,版本号是上周三随手改的。真要回滚?回滚到哪,怎么滚,谁负责?

说白了就一句话:你没定死分支从哪来、合到哪去,所有人都在一个池子里瞎扑腾。

规范用一张表把这事钉死了。下面我拿电商 v2.1.0 那次迭代举例,从头到尾走一遍。你看完就知道下次怎么不背锅。


🎯主要目标

本文带你走完一次完整发版

  • 认识两个永远存在的正式员工:masterdevelop
  • 从拉分支到上线,7 步走完不踩坑
  • 蓝绿部署和秒级回滚,事故来了不慌
  • 五张速查表 + 五条红线,打印贴墙随时看

正文

🍪规范拆解

一.先认识两个永远存在的正式员工

分支是什么谁能改
master生产环境正在跑的代码,每个 commit 都能直接上线没人能直接改,只能通过 MR 合并
develop开发主线,功能都汇到这里同上

其他分支,不管是 feature、sprint、bugfix、release 还是 hotfix,都是临时工,用完就删。

👽人话解释
master 是生产环境正在跑的代码,每个 commit 都能直接上线;develop 是所有功能的汇合点。剩下那些分支都是临时工,活干完就删,别养着。

这就是第一道防线。master 上你顺手提交的代码,绝不可能出现。想直接动 master?门都没有,分支保护先把你挡回去。

分支模型:master 和 develop 是正式员工,其他是临时工


二.完整故事:电商平台 v2.1.0 迭代

背景先说清楚:线上现在跑的是 v2.0.0。这次迭代要干两件事,微信支付升级交给小张,用户中心重构交给小李。对,就是开头那个小李,这回他老实了。

1.迭代开始,拉 sprint 分支(迭代负责人做)

一个迭代需要一个收作业的分支:

git checkout develop && git pull origin develop
git checkout -b sprint-v2.1
git push origin sprint-v2.1

检查点:版本号先别动,还是 2.0.0。日常开发阶段一律不改版本号,这条记死了,后面有大用。多少人栽在这:开发到一半手痒改了版本号,最后连自己都分不清打出来的包是啥。


2.小张开发微信支付(开发做)

铁律:永远别在 sprint 上直接开写,拉你自己的 feature 分支。你直接在 sprint 上改,等于全班共用一张草稿纸,谁都看不清谁写了啥。

git checkout sprint-v2.1 && git pull origin sprint-v2.1
git checkout -b feature-wechat-pay-v2

写代码、提交:

git commit -m "feat(pay): add WeChat Pay v3 API support"

sprint 有新代码进来了?同步,用 rebase 保持线性历史:

git checkout sprint-v2.1 && git pull origin sprint-v2.1
git checkout feature-wechat-pay-v2
git rebase sprint-v2.1

功能写完,别自己 merge,发起 MR:feature-wechat-pay-v2 合到 sprint-v2.1。

MR 会自动跑 CI,编译、lint、单测全套。还有个 AI Code Review 先扫一遍给建议,只建议不卡人,省得你等同事 review 时才发现低级错误。然后等一位同事 approve,再用 Squash Merge 合进去。

为什么用 Squash?你开发时的提交历史长这样:

feat(pay): add WeChat Pay v3 API support
fix: 修一下
fix: 再修一下
fix: 啊啊啊终于好了

看着就头皮发麻吧。Squash Merge 把它们压成 1 个干净的 commit,sprint 历史从此清爽,后人接手不用猜你中间那几发抽风是改了啥。

合并后,临时工走人:

git branch -d feature-wechat-pay-v2
git push origin --delete feature-wechat-pay-v2

小李的 feature-user-center 走同样流程。


3.联调,sprint 合回 develop

把 sprint-v2.1 部署到 TEST 环境(源码编译),QA 联调过了再说:

git checkout develop && git pull origin develop
git merge --no-ff sprint-v2.1     # 保留迭代痕迹
git push origin develop

为什么这次不用 Squash,改用 --no-ff?记住一句话:

个人工作分支压扁(Squash),公共里程碑留痕(--no-ff)。

--no-ff 会在历史图上留一个迭代汇总节点,十年后还能一眼看出 v2.1 迭代到底塞了哪些功能。Squash 和 --no-ff 不是二选一,是你个人的活压扁、公共的里程碑留痕,各用各的。

有个例外:迭代只有一个功能时,跳过 sprint,feature 直接合 develop 就行。规矩是为人服务的,不是反过来。


4.切 release 分支,此刻才定版本号

从 develop 拉 release,不是 sprint:

git checkout develop && git pull origin develop
git checkout -b release-v2.1.0
git push origin release-v2.1.0

此刻做两件事:

  1. 修改版本号:2.0.0 变成 2.1.0
  2. 把 SNAPSHOT 依赖换成正式版

铁律,SNAPSHOT 不过墙。SNAPSHOT 是能被别人随时覆盖的草稿依赖,今天打包用 1.2-SNAPSHOT,明天同事一覆盖,你就再也打不出一模一样的包。所以 SNAPSHOT 绝不许进 master 和 PROD。release 分支就是个隔离病房,发布前所有依赖在这里全部转正,谁也别想半路塞个草稿进来。


5.QA 验证,打 RC 候选镜像

docker build -t harbor.example.com/app:v2.1.0-rc1 .
docker push harbor.example.com/app:v2.1.0-rc1

QA 三板斧:

步骤验什么例子
① 主链路回归高频老功能没被改坏下单、支付、退款还能走通
② 变更功能验收新功能正确微信支付升级后能正常付款
③ 性能观察没变慢支付接口耗时对比上版本无明显劣化

QA 真发现问题了:支付金额四舍五入差 1 分钱。这 bug 上线就是客诉,线下就是真金白银。怎么办?从 release 拉个 bugfix 修:

git checkout -b bugfix-pay-rounding release-v2.1.0
# 修复代码……
git commit -m "fix(pay): correct rounding precision for amount"
# Squash Merge 回 release(1 人 Approve)
git checkout release-v2.1.0
git merge --squash bugfix-pay-rounding
git commit -m "fix(pay): correct rounding precision for amount"
git push origin release-v2.1.0
git branch -d bugfix-pay-rounding

修完重打镜像,rc 序号加一,变成 v2.1.0-rc2,再验证,直到全绿。

RC 候选版可以覆盖着打,但正式版 Tag 永不覆盖。这就是版本有唯一真源这个说法的由来,出事你能精确到 commit 指着鼻子说就是这版。


6.正式发布(master 需要 2 人 Approve)

git checkout master && git pull origin master
git merge --no-ff release-v2.1.0     # 2 人 Approve 才能合
git tag -a v2.1.0 -m "Release v2.1.0"
git push origin master --tags

构建正式镜像,正式版加 latest:

docker build -t harbor.example.com/app:v2.1.0 .
docker tag harbor.example.com/app:v2.1.0 harbor.example.com/app:latest
docker push harbor.example.com/app:v2.1.0
docker push harbor.example.com/app:latest

蓝绿部署,说白了就是两台一模一样的服务器。一台(BLUE)正扛着流量,新版本悄悄部署到另一台(GREEN),冒烟验证没问题,拨一下开关,流量切过去,用户全程无感。这一步运维来:

# 1. 当前 BLUE 在线 → 新版本部署到 GREEN
docker-compose -f docker-compose.green.yml up -d

# 2. 冒烟验证 GREEN
curl http://green-host:8080/health

# 3. 切流量,双活上线
nginx -s reload

# 4. 同步升级 BLUE,为下次发布做准备
docker-compose -f docker-compose.blue.yml up -d

蓝绿部署:双环境秒级切换

还有收尾这步别忘了:release 期间修的 bug 要同步回 develop,然后删掉 release 分支:

git checkout develop
git merge --no-ff release-v2.1.0
git push origin develop
git branch -d release-v2.1.0

v2.1.0 上线完成。


7.凌晨 2 点的事故:Hotfix 与秒级回滚

上线第二天,用户反馈支付偶发超时。

情况一:能定位、能修复,走 hotfix

# 从 master(不是 develop!)切分支
git checkout master
git checkout -b hotfix-pay-timeout

# 修复,版本号 PATCH +1:2.1.0 → 2.1.1
git commit -m "fix(pay): increase payment gateway timeout to 10s"

# 合回 master + 打 Tag(2 人 Approve)
git checkout master
git merge --no-ff hotfix-pay-timeout
git tag -a v2.1.1 -m "Hotfix: payment timeout"
git push origin master --tags

# 同步回 develop,删分支
git checkout develop
git merge --no-ff hotfix-pay-timeout
git push origin develop
git branch -d hotfix-pay-timeout

然后构建 v2.1.1 镜像,蓝绿部署上线(同第 6 步)。

情况二:太严重,根本来不及修,直接回滚

两行命令,秒级,零停机,旧版本还完整待在另一个环境里:

sed -i 's/server app-green/server app-blue/' nginx/nginx.conf
nginx -s reload

回滚:两行命令秒级恢复

回滚后必须第一时间通知全团队,不然开发还在基于坏代码继续干活,等于你 rollback 了线上、他们又给推回去了。

还记得开头小李的 force push 吗?现在 master 有分支保护、2 人 Approve、不可覆盖的 Tag,他想 force push 也得先过两道审,那种事故在物理上已经不可能发生。小李现在早就老实了。


三.全程一图流

全程一图流


四.五张速查表(打印贴墙版)

表1:分支从哪来、到哪去

分支从哪拉合到哪一句话
feature-*sprintsprint我的功能我做主
sprint-*developdevelop一迭代一收口
bugfix-*sprint/release原地提测 bug 专用
release-*developmaster+develop发布前的隔离病房
hotfix-*mastermaster+develop线上救火队

表2:合并方式怎么选

场景方式记忆口诀
feature/bugfix 合入Squash个人分支压扁
sprint/release/hotfix 合入--no-ff里程碑留痕
同步最新代码Rebase搬家保持线性

表3:版本号什么时候变

时机变化例子
切 release 时定下本次版本2.0.0 → 2.1.0
切 hotfix 时PATCH +12.1.0 → 2.1.1
其他任何时候不许动

表4:Commit Message 抄作业

feat(pay): add WeChat Pay v3 API support
fix(pay): correct rounding precision for amount
fix(pay): increase payment gateway timeout to 10s
docs(readme): update deployment guide
refactor(user): extract login service from controller

规则:type(scope) 用动词开头英文小写描述,不超过 72 字符,结尾不加句号;BREAKING CHANGE 全大写写 footer。配套工具三件套 commitlint、husky、standard-version,格式问题从此消失,再也没人跟你吵 commit 该写成啥样。

表5:环境与审批门槛

环境部署方式来源审批
TEST源码编译sprint/release/develop1 人 Approve
PRODDocker 镜像(手动触发)仅 master 正式镜像2 人 Approve

TEST 资源冲突时优先级是 hotfix 大于 release 大于 develop 大于 sprint,线上故障永远排第一,这个没得商量。


五.五条红线,一条都别踩

  1. git push --force 到公共分支,这就是开头那次事故的根,直接毁掉别人历史。踩这条我当场就想收他分支权限。
  2. 直接在 master/develop 上 commit,所有保护全绕过去了,等于家门没锁。
  3. 跳过 Code Review 直接合并,质量等于裸奔,出问题谁都救不了你。
  4. SNAPSHOT 依赖进 master,上线后根本没法复现,半夜被叫起来你哭都找不着原因。
  5. 回滚后不通知团队,这是协作灾难,别人还以为线上好好的继续堆代码。

🍈猜你想问

如何与狗哥联系进行探讨?

加瓦狗联系方式

关注公众号【JavaDog程序狗】,回复【入群】或【加入】,一起聊技术、聊踩坑。


评论