云计算百科
云计算领域专业知识百科平台

【规范】这套 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 那次迭代举例,从头到尾走一遍。你看完就知道下次怎么不背锅。


🎯主要目标

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

  • 认识两个永远存在的正式员工:master 和 develop
  • 从拉分支到上线,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

此刻做两件事:

  • 修改版本号:2.0.0 变成 2.1.0
  • 把 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-* sprint sprint 我的功能我做主
    sprint-* develop develop 一迭代一收口
    bugfix-* sprint/release 原地 提测 bug 专用
    release-* develop master+develop 发布前的隔离病房
    hotfix-* master master+develop 线上救火队

    表2:合并方式怎么选

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

    表3:版本号什么时候变

    时机变化例子
    切 release 时 定下本次版本 2.0.0 → 2.1.0
    切 hotfix 时 PATCH +1 2.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/develop 1 人 Approve
    PROD Docker 镜像(手动触发) 仅 master 正式镜像 2 人 Approve

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


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

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

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

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

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【规范】这套 Git 规范,救了整个团队
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!