git踩坑小笔记--合并

424 阅读2分钟

merge操作

git在进行merge的时候,默认采用fast-forward进行合并,如果条件不满足时,会采用--no-ff方式合并。

fast-forward:直接将head移动到feature分支的最新提交点上,不生成commitId --no-ff:将feature和master合并,并生成一个新的commitId。

参考下面两个图:

ff5bf48343cbc6b3bbedabb21a7812d8_QpdH5g.png

fast-forward

32d02249df947e28b749b88118ec7ad8_BIqlQW.png

--no-ff

交叉合并Criss-Cross

我们在对分支进行合并时,可能会出现多种情况,交叉合并时一种比较复杂的情况。直观来看,交叉合并就是两个分支之间出现了交叉,即拥有两个共同祖先,有些地方也称这是两个共同的"基(base)"。从git分支图上可以看到,c5和c3两个提交点所在分支master和feature之间形成了十字交叉。

8f264b861fd9f01f229f491bdcef8db9_merge-stories-11.png

这种情况,我们在执行合并时,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异常。

下面看一下源码: image.png

可以看到已经有注释标记了该策略不支持多base情况。 进入merge代码最终执行的call()方法,代码中判断如果merger是ResolveMerger情况下执行下面代码

image.png

继续走到merge方法,可以看到有一个mergeImpl()

image.png

继续进入mergeBase()-->getBaseCommit(),在这个方法中进行base判断,在找到第一个base之后会去找第二个base,如果第二个base找到了就抛出异常,也就是校验是否有两个共同祖先。

image.pngimage.png image.png

参考:

Git合并那些事——Merge策略(上)
图解 Git 基本命令 merge 和 rebase - Michael翔 - 博客园
git 命令之git merge-base-CSDN博客
git merge-base 与 show-branch 命令-CSDN博客