merge操作
git在进行merge的时候,默认采用fast-forward进行合并,如果条件不满足时,会采用--no-ff方式合并。
fast-forward:直接将head移动到feature分支的最新提交点上,不生成commitId
--no-ff:将feature和master合并,并生成一个新的commitId。
参考下面两个图:
fast-forward
--no-ff
交叉合并Criss-Cross
我们在对分支进行合并时,可能会出现多种情况,交叉合并时一种比较复杂的情况。直观来看,交叉合并就是两个分支之间出现了交叉,即拥有两个共同祖先,有些地方也称这是两个共同的"基(base)"。从git分支图上可以看到,c5和c3两个提交点所在分支master和feature之间形成了十字交叉。
这种情况,我们在执行合并时,git默认采用recursive策略进行合并,首先为两个共同祖先创建一个虚拟祖先,基于这个共同祖先合并两个分支。
那么我们怎么才能知道到底有没有多个共同祖先呢,git给我们提供了相关命令。
git merge-base --all master feature2
通过该命令可以查找所有的共同祖先,如果不加--all,则只会显示依次合并后的唯一base。
开发中遇到的小坑
我们在使用java操作git时使用了jgit开源库,如果出现交叉合并的情况,直接使用jgit提供的merge是没有问题的,默认成功合并。但我们由于使用场景限制,需要在合并时采用resolve策略进行标记,保留冲突信息进行提交。jgit在使用该策略时会检测是否有多个共同祖先,如果有就会报
NoMergeBaseException: No merge base could be determined异常。
下面看一下源码:
可以看到已经有注释标记了该策略不支持多base情况。 进入merge代码最终执行的
call()方法,代码中判断如果merger是ResolveMerger情况下执行下面代码
继续走到merge方法,可以看到有一个
mergeImpl()
继续进入mergeBase()-->getBaseCommit(),在这个方法中进行base判断,在找到第一个base之后会去找第二个base,如果第二个base找到了就抛出异常,也就是校验是否有两个共同祖先。
参考:
Git合并那些事——Merge策略(上)
图解 Git 基本命令 merge 和 rebase - Michael翔 - 博客园
git 命令之git merge-base-CSDN博客
git merge-base 与 show-branch 命令-CSDN博客