版本控制与分支策略:不是选美,是选命

说实话,分支策略这东西,圈子里吵了十几年。有人把 Git Flow 奉为圣经,也有人一听到「长期分支」就皱眉。我的态度很简单:没有银弹,但一定有最适合你团队的套路。我自己在不同项目里换过三次策略,才慢慢摸清门道。

这章咱们就聊聊两个主流流派——Git Flow 和 Trunk-Based Development。我不打算念说明书,而是从实战视角告诉你:它们各自的「爽点」在哪儿,踩坑点又在哪儿。你想想看,选错了分支策略,CI 再漂亮也是白搭。

核心结论:分支策略决定了你的 CI 流程是「丝滑」还是「便秘」。选错了,每次合代码都像过鬼门关。

分支策略核心对比框架 Git Flow 模型 develop(开发主线) feature/* release/* hotfix/* master(稳定) Trunk-Based 模型 main(主干) 短命分支 PR + CI 门禁 每日多次合入主干 Git Flow 适合固定版本周期、多分支协同;Trunk-Based 适合持续交付、高频部署团队

Git Flow:经典但易胖

我记得2016年刚接手一个微服务项目时,团队直接照搬了 Git Flow。示意图上看着漂亮——develop、release、hotfix 各司其职。但实际跑起来,分支数量像吹气球一样膨胀。每次上线前,光解决冲突就要花半天。

Git Flow 的核心套路就这几条:

  • develop 是日常开发集散地。所有 feature 分支从这里拉,再合回来。
  • release 分支用于打版前收尾。只修 bug,不加新功能。
  • hotfix 分支从 master 拉。修完同时合进 master 和 develop,避免漏修。
  • master 永远可部署。每次合并都打 tag。

嗯,听着挺完美对吧?但我踩过一次大坑:有一次团队同时维护三个版本,release 和 hotfix 交叉,最后 develop 和 master 的差异越来越大,合并时直接炸了。

我的建议:如果团队不到10人,或者发版节奏超过两周一次,Git Flow 带来的管理成本可能比收益大。不如考虑简化版。

Trunk-Based Development:短跑选手的武器

后来我跳槽到一家做 SaaS 的公司,要求每天发版好几次。Git Flow 明显吃不消了。我尝试引入 Trunk-Based Development。说白了就是一个主干(main),所有开发人员直接或通过短命分支提交代码,每天至少合入一次主干。

为什么会有人觉得这太激进?因为「主干必须一直保持绿色」意味着:你的 CI 必须快、准、稳。有一次我们没加好门禁,有人合了一行有问题的代码,阻塞了全组半小时。后来我们加了 pre-merge 检查和自动回滚,才稳住。

这里的关键点是:

  • 分支存活时间不超过一天。超过一天的代码大概率会跟主干脱节。
  • CI 跑得越快越好。我建议控制在5分钟内。超过10分钟,开发人员就会用「我先合上再说」的心态绕过门禁。
  • 特性开关(Feature Toggle)是必需品。没完成的代码通过开关隐藏,而不是藏在分支里。

曾经我踩过的坑:没有特性开关就强推 Trunk-Based,结果未完成的功能被发布到了生产环境。还好是内部工具,不然就成大事故了。特性开关比你想的重要得多。

两条路,怎么选?

我们直接看对比表,不啰嗦:

维度 Git Flow Trunk-Based
发版频率 周/月级 日级甚至小时级
分支复杂度 高(5种以上分支) 低(1~2种)
冲突风险 中(集中在合并时) 低(分散到每次提交)
CI 门槛 低(可容忍较长流水线) 高(需要极快速+高频CI)
适合场景 传统企业、固定版本发布 微服务、SaaS、持续交付

我个人现在的习惯是:如果团队处于交付初期、还在搞 MVP,我会直接用 Trunk-Based。等产品稳定、需要同时维护多个版本时,再引入 Git Flow 的简化版——去掉 release 分支,只用 develop + master + hotfix。

实践要点:别让分支策略拖累 CI

不管你选哪条路,有几个坑你得避开。这些是我用真金白银换来的教训:

第一个建议:CI 流水线一定要在分支合并前运行。我之前试过「先合再跑 CI」,结果合进去一锅坏代码,回滚时所有人都在扒历史。

第二个建议:用 Git Hooks 或者 CI 规则拦住「不守规矩」的提交。比如禁止直接往 master 或 develop push,只允许通过 PR/MR 合入。

第三个建议:每次合并后,自动触发一次完整流水线。你可能会觉得浪费资源,但跟我遇到过「合并后测试通过了,部署时炸了」的情况相比,这点代价不算什么。

别忘了 git blame 的副作用:Trunk-Based 加上频繁 rebase 会导致 git blame 信息丢失。我们当时的解决方案是:只在 PR 合并时使用 squash merge,Commit 历史清晰又干净。到底用 merge 还是 rebase,我建议团队内统一规则,不然后面追查问题会吐血。

一句话总结

分支策略不是选好看的,是选能让你睡好觉的。Git Flow 给你确定性但牺牲速度,Trunk-Based 给你速度但需要更强的纪律和 CI 能力。别纠结对错,跟你的团队实际跑一遍就知道了。