18、Git高级合并策略:递归合并、章鱼合并、子树合并、合并策略选择

合并,是Git日常操作里最核心的一环。但很多人只会用git merge,遇到冲突就慌。

其实Git内置了好几种合并策略。每种策略都有自己的脾气和适用场景。今天我就带你挨个捋一遍。

一、合并策略到底是个啥?

说白了,合并策略就是Git在合并两个分支时,采用的“算法”和“规则”。

你执行git merge时,Git会自动选一个策略。但有时候,自动选的不一定是最优解。你需要手动指定。

核心观点: 理解合并策略,不是为了炫技,而是为了在关键时刻,知道该用哪把钥匙开哪把锁。

Git 高级合并策略体系 git merge 递归合并 默认策略,处理两个分支 章鱼合并 合并多个分支 子树合并 合并不同仓库 策略选择 按场景选最优 四种策略各有侧重,选对策略事半功倍

二、递归合并(Recursive Merge)

这是Git的默认策略。你平时敲git merge,用的就是它。

它的工作方式很聪明:找到两个分支的共同祖先,然后做三路合并。如果遇到多个共同祖先,它会递归地合并这些祖先,直到找到一个稳定的基点。

我的经验: 递归合并处理常规合并非常稳。我在项目中遇到的大部分冲突,都是靠它解决的。但要注意,如果分支历史特别复杂,递归合并可能会慢一点。

举个例子:

# 默认就是递归合并
git merge feature-branch

# 也可以显式指定
git merge -s recursive feature-branch

递归合并有几个子选项,我常用的有两个:

  • ours:遇到冲突时,自动选择当前分支的版本。适合你确定要保留自己代码的场景。
  • theirs:遇到冲突时,自动选择传入分支的版本。适合你完全信任对方代码的场景。

注意: ourstheirs是递归合并的子选项,不是独立的合并策略。别搞混了。

三、章鱼合并(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