18、Git高级合并策略:递归合并、章鱼合并、子树合并、合并策略选择
合并,是Git日常操作里最核心的一环。但很多人只会用git merge,遇到冲突就慌。
其实Git内置了好几种合并策略。每种策略都有自己的脾气和适用场景。今天我就带你挨个捋一遍。
一、合并策略到底是个啥?
说白了,合并策略就是Git在合并两个分支时,采用的“算法”和“规则”。
你执行git merge时,Git会自动选一个策略。但有时候,自动选的不一定是最优解。你需要手动指定。
核心观点: 理解合并策略,不是为了炫技,而是为了在关键时刻,知道该用哪把钥匙开哪把锁。
二、递归合并(Recursive Merge)
这是Git的默认策略。你平时敲git merge,用的就是它。
它的工作方式很聪明:找到两个分支的共同祖先,然后做三路合并。如果遇到多个共同祖先,它会递归地合并这些祖先,直到找到一个稳定的基点。
我的经验: 递归合并处理常规合并非常稳。我在项目中遇到的大部分冲突,都是靠它解决的。但要注意,如果分支历史特别复杂,递归合并可能会慢一点。
举个例子:
# 默认就是递归合并
git merge feature-branch
# 也可以显式指定
git merge -s recursive feature-branch
递归合并有几个子选项,我常用的有两个:
ours:遇到冲突时,自动选择当前分支的版本。适合你确定要保留自己代码的场景。theirs:遇到冲突时,自动选择传入分支的版本。适合你完全信任对方代码的场景。
注意: ours和theirs是递归合并的子选项,不是独立的合并策略。别搞混了。
三、章鱼合并(Octopus Merge)
这个名字挺有意思。章鱼有很多触手,这个策略就是用来一次合并多个分支的。
你想想看,如果一次要合并3个、4个甚至更多分支,用递归合并得挨个来。章鱼合并可以一步到位。
# 一次合并三个分支
git merge -s octopus branch-a branch-b branch-c
但章鱼合并有个限制:它不能处理冲突。一旦有冲突,它就罢工了。
避坑指南: 我曾经在一个大型项目里,试图用章鱼合并一次合并5个特性分支。结果其中一个分支有冲突,整个合并就失败了。后来我学乖了:章鱼合并只适合“无冲突”的场景,比如合并几个互不干扰的特性分支。
什么时候用章鱼合并?
- 合并多个独立的、没有冲突的特性分支
- 在发布分支上,一次性合并多个已测试通过的分支
- 自动化脚本中,需要批量合并的场景
四、子树合并(Subtree Merge)
这个策略比较特殊。它用来合并两个不同的仓库。
比如,你有一个公共库,想把它作为子目录合并到当前项目里。用子树合并,可以保持两个仓库的历史独立,又能把代码整合到一起。
# 先把公共库添加为远程仓库
git remote add common-lib https://github.com/example/common-lib.git
# 获取代码
git fetch common-lib
# 用子树合并,将公共库合并到 lib/ 目录下
git merge -s subtree common-lib/main --squash
子树合并的好处是:你后续可以随时从上游拉取更新,而不会污染主项目的历史。
我的习惯: 在管理第三方依赖时,我倾向于用子树合并而不是子模块。子模块虽然功能强大,但操作起来太繁琐。子树合并更直观,团队成员也更容易理解。
子树合并的常用命令:
git merge -s subtree:执行子树合并git pull -s subtree:拉取并合并上游更新git subtree push:将子目录的改动推回上游仓库
五、合并策略选择
说了这么多,到底该怎么选?我总结了一个简单的判断逻辑:
| 场景 | 推荐策略 | 原因 |
|---|---|---|
| 合并两个分支 | 递归合并(默认) | 最稳定,支持冲突处理 |
| 合并多个无冲突分支 | 章鱼合并 | 一步到位,效率高 |
| 合并不同仓库的代码 | 子树合并 | 保持历史独立,便于后续更新 |
| 确定要保留当前分支 | 递归合并 + ours | 自动选择当前版本,省去手动解决 |
| 确定要保留传入分支 | 递归合并 + theirs | 完全信任对方代码时使用 |
核心原则: 能用默认的递归合并,就别折腾。只有在特定场景下,才考虑章鱼合并或子树合并。别为了炫技而用高级策略。
嗯,这里还要提一句。合并策略的选择,跟团队的工作流也有关系。
如果你的团队采用Git Flow,频繁合并特性分支到develop,递归合并就够用了。如果你的团队采用主干开发(Trunk-Based Development),频繁合并多个短命分支,章鱼合并可能更高效。
我曾经踩过的坑: 有一次,我为了图省事,用章鱼合并一次性合并了6个分支。结果其中一个分支的改动跟另一个分支有隐式依赖,合并后编译通过,但运行时出了bug。从那以后,我养成了一个习惯:合并前先检查分支之间的依赖关系。如果分支之间有依赖,就别用章鱼合并,老老实实挨个合并。
最后,送你一句话:合并策略是工具,不是目的。理解它们的原理,比记住命令更重要。遇到实际问题时,你自然知道该用哪个。
公众号:蓝海资料掘金营,微信deep3321