团队用了6年的Git分支管理规范,合并再也没有打过架

0 阅读10分钟

团队用了6年的Git分支管理规范,合并再也没有打过架


一、那次上线,差点把我们送走

刚接手团队那会儿,代码管理用的是SVN。

说是"管理",其实跟没管一样。每个人往同一个主干上提交,没有分支策略,没有提交规范,没有合并机制。全靠自觉。

自觉这东西,在代码面前不值钱。

有一天发版,测试环境跑得好好的,结果上线前一小时,一个开发突然在群里问:"诶,我在 trunk 上改的那个订单状态流转怎么没了?"

然后另一个开发接了一句:"啊?我也改了那个文件,我以为是我自己加的判断逻辑不对,就给你覆盖重新提交了。"

全组沉默了三秒。

那天晚上,我们三个开发加一个测试,围着一台电脑,打开 Beyond Compare,把 trunk 上的代码一行一行跟昨天的备份做对比。订单、支付、退款,三个核心模块的代码混在一起,谁也搞不清哪行是对的、哪行是后来覆盖上去的。

从晚上八点比对到凌晨一点。五个小时,比对出来 17 处差异。其中 3 处是功能缺失——代码被覆盖后直接丢了。最要命的一个,退款金额计算漏了一行乘法,上线就是资损。

最后发版推迟到第二天。老板在群里发了一句话:"技术部在干什么。"

这句话比任何 bug 都难受。


二、换了 Git,问题就解决了吗?没有

后来团队从 SVN 迁移到 Git。我以为换个现代工具就没事了。

结果该乱的还是乱。

Git 比 SVN 强大,但没人定规矩,强大就意味着更花式的混乱。有人从 master 拉分支,有人从 dev 拉分支,有人直接在 master 上改。一个项目同时活着七八个长期分支,谁也不知道哪个是最新的。合并的时候,Git 的冲突提示比 SVN 还长——因为每个人的基线都不一样。

那段时间我明白了一件事:

工具换了没用,换的是习惯。习惯不改,GitHub 来了照样乱。

于是我坐下来,跟两个组长一起,花了整整两天,把我们踩过的坑一个一个倒出来,反推出了一套分支管理规范。

这套规范我们用了六年,迭代了好几个版本。从 5 个人的小团队用到几十号人的技术部门,合并冲突的次数一只手数得过来。再也没出现过"上线前发现代码丢了"这种事。

下面就是这套规范的全部内容。没有花活,全是实操。


三、三个核心原则

在讲具体流程之前,先定三条铁律。这些铁律每一条后面都有血泪教训。

原则一:主干永远可发布

不管什么时候,不管谁在干什么,trunk(主分支)上的代码必须是可以直接编译、直接部署、直接上线的。如果 trunk 挂了,整个团队的交付就停了。

怎么保证?后面讲。

原则二:一次提交只做一件事

修 bug 就是修 bug,重构就是重构,加功能就是加功能。三个搅在一起,出了问题你根本不知道是哪部分引起的。而且三个月后谁也看不懂这条 commit 到底干了什么。

原则三:提交信息要能让人看懂

"fix bug""update code""修改"——这种提交信息等于没写。提交信息要回答三个问题:做了什么、为什么做、影响范围是什么。后面有具体格式。


四、正常版本迭代流程

当一个需求版本定下来之后,按以下步骤走:

第1步:从 trunk 拉出版本分支

确认 trunk 是最新的,从 trunk 拉出发布分支。分支名带上版本号和 SNAPSHOT 标记,比如 release/1.0.0-SNAPSHOT

SNAPSHOT 后缀的意思是:这个版本还在开发中,随时可能变。等测试验收全部通过,去掉 SNAPSHOT,就是正式的发布版本。

这样做的原因是:一眼就能看出哪个版本是开发中、哪个版本是已发布。避免把未完成的版本当正式版发出去了——我们干过这种事。

第2步:开发人员在分支上开个人功能分支

不是直接在 release 分支上改代码。每个人从 release 分支再拉出自己的功能分支 feature/xxx,开发完再合回 release。

多一层分支的好处:功能之间互相隔离。A 的功能没写完,不影响 B 的功能测试。

第3步:自测 + 联调

个人功能分支合入 release 后,在 release 分支上做自测和联调。这个阶段发现问题直接在 release 上修。

第4步:发布到测试环境,交给测试

自测通过后,把 release 分支的代码发到测试环境。测试人员在测试环境进行功能测试和性能测试。这期间开发人员只修测试提的 bug,不加新需求——新需求走下一个版本。

第5步:主干代码合并到版本分支

测试通过后,把 trunk 的最新代码合并到 release 分支。

这一步很多团队会搞反——把 release 合回 trunk。为什么要反过来?因为测试期间 trunk 上可能有其他人合了线上 bug 修复或者公共组件改动,这些改动发布分支还没包含。先把 trunk 合到 release,确保 release 分支包含了测试期间 trunk 上所有的变更。

第6步:预发布环境回归测试

合并完成后,把 release 发布到预发布环境,做回归测试。范围包括:本次需求版本的全部功能 + 测试期间 trunk 上合入的补丁内容。

这一关过了,才算真过了。

第7步:提交产品验收

测试通过后让产品部门在预发布环境验收。产品说 OK,代码才算 OK。不要跳过这一步——测试验的是"对不对",产品验的是"是不是我要的"。两个维度。

第8步:去掉 SNAPSHOT,改为正式版本号

产品验收通过后,把 1.0.0-SNAPSHOT 改成 1.0.0。版本号正式确定的那一刻起,这个分支的代码就是发布版,不允许再有任何修改(除非发布后发现问题,走补丁流程)。

第9步:发布上线 + 线上回归

发布到生产环境后,立即在线上做一轮快速回归——验证核心业务流程是否正常。不要等用户来报 bug。

第10步:将版本分支合并回 trunk

线上稳定运行后(通常观察 1-2 天),把 release 分支合回 trunk。至此 trunk 上包含了这个版本的全部正式代码,一个完整的迭代周期结束。


五、线上 Bug 修复流程

线上出了问题要马上修,流程跟正常迭代不一样。核心区别就一个字:快。但快不等于乱。

第1步:在最新的版本分支上修复

紧急 bug 从哪里修?不是从 trunk,是从当前线上对应的 release 分支拉出修复分支。

如果修复涉及公共组件或基础 jar 包,需要改基础包的代码,则在基础包的版本号后加临时 SNAPSHOT 标记,比如 common-1.0.1-SNAPSHOT。表示这是一个临时构建,待补丁验证通过后再去掉 SNAPSHOT 发正式版。

第2步:开发自测联调

修完代码后在本地自测。紧急补丁不能省略自测——越急越容易出错。

第3步:提交到测试环境,测试验证

测试人员只测这个补丁本身,不测全量功能(时间不允许)。但补丁涉及的核心路径必须覆盖。

第4步:预发布环境验证

补丁通过后发预发布,在预发布环境再做一轮验证。

第5步:有基础包修改的,去掉 SNAPSHOT

确认补丁没问题后,把临时 SNAPSHOT 版本号改为正式版本号。临时构建绝不带到生产环境。

第6步:发布上线 + 线上回归

发版后立即验证补丁是否生效。别发了就关了,确认线上问题真的解决了再收工。

第7步:将修复分支合并回 trunk

补丁在线上验证通过后,把修复代码合并回 trunk。这一步不能省——否则下一个版本发布的时候,这个补丁就丢了,bug 会重新上线。


六、关于 AB 角:为什么合并代码不能只有一个人做

我们团队有一个规矩:代码合并到主干,由各组的 AB 角来操作。

什么是 AB 角?就是每个模块分配两个人——A 角是主要负责人,B 角是备份人。日常合并 A 角做,A 请假了 B 顶上。但有一条硬规则:自己不能合自己的代码。 你写的代码,必须由另一个人来看一眼再合。

为什么定这个规矩?

起源是有一次,一个开发把自己写的 feature 分支直接合到了 trunk,没有通知任何人。他觉得"我就改了几行配置文件"。结果那几行配置文件里有一个数据库连接字符串的改动,直接导致预发布环境连上了测试库。全组排查了两个小时。

后来我们定了规矩:代码合并必须两个人。不是因为不信任,是因为任何人都会对自己的代码有盲区。你自己写的代码,你脑子里的上下文是完整的,你看不出问题。但旁边的人一眼就能看出不对劲。

具体操作很简单:

  • 每个开发组指定 AB 角两个人
  • 代码合并到 trunk 由 AB 角执行
  • 合并的人不是写代码的人
  • 合并前看一眼 diff,确认没有不该进去的东西
  • A 角休假,B 角接管,确保合并通道不会因为一个人不在就中断

七、提交代码的规矩

提交信息格式我们强制要求写清楚三件事:

[类型] 解决了什么问题
涉及模块:xxx
修复版本:x.x.x

类型只允许这几种:

类型用途
fix修 bug
feat新功能
refactor重构(不改功能)
docs文档
chore构建、依赖、配置

举个例子——好的提交信息长这样:

fix: 修复退款金额计算缺少手续费扣除的问题

涉及模块:退款模块 RefundService
修复版本:1.2.1

差的提交信息:

fix bug

区别一目了然。前者半年后出问题,看一眼就知道这条提交干了什么、影响了哪里、在哪个版本修了。后者翻出来等于没翻。


八、这套规范怎么落地

规范写出来容易,推下去难。我们当时是这样做的:

  1. 先跟组长对齐。 把两个组长叫到一起,让他们先理解为什么每条规则存在。组长不认可,下面的人更不会执行。

  2. 第一次发布让所有人参与。 不是说发就完了,是让每个人亲自走一遍流程。走一遍比看十遍文档有用。

  3. 头三次发布,组长在旁边看着。 有人漏步骤立刻指出。三次以后形成肌肉记忆,就不用盯了。

  4. 违反规范的后果要说清楚。 不是罚钱,是"谁违规导致的问题谁负责善后"。半夜上线你合并漏了代码?你来修复,我来陪。做一次就记住了。


九、总结

这套规范的核心思想就一句话:让每一步操作都可追溯,让每一个决定都有据可查。

不是约束你,是保护你。规范越清楚,出问题的时候越不用慌——因为你知道是哪一步出了错、谁做的、什么时候做的、怎么恢复。

六年前那次上线前的崩溃,教会了我这件事。希望你的团队不用经历同样的教训。


我把这套规范整理成了一份「Git 分支管理 Checklist 模板」,包含发布流程检查清单 + 提交信息模板 + AB 角操作说明。需要的评论区留言,我发你。