我正在尝试构建一个脚本来在某些条件下自动处理合并冲突。 我发现在不进行合并的情况下识别子模块引用中的合并冲突具有挑战性。
我的意思是,我想找到一种简单的方法来在进行合并之前识别两个分支之间子模块引用中的合并冲突(即使未提交)。
当我说子模块引用时,我并不是指子模块内的冲突。相反,我的意思可以用一个例子来解释,如果分支 A 中的子模块(在我的父存储库中)指向引用 X,而分支 B 中的相同子模块(在我的父存储库中)指向引用 Y。这将导致如果两个分支中的子模块引用均已更新,则发生冲突,并且在 SourceTree 中如下所示:
如您所见,一个子模块引用 PNG_ND_Drivers 没有冲突,而另一个子模块引用 EmbeddedSW_UnitTests 确实存在冲突。这些变化似乎具有相同的性质。无法从文件中的更改来识别是否存在冲突。那么在合并之前如何识别它呢?
注意:我可以使用 --no-commit 标志进行合并,然后使用 git status --short 查看文件的状态并在下面找到
未合并的路径:
两者均已修改:EmbeddedSW-UnitTests
而其他子模块出现在:
未暂存提交的更改:
修改:PNG_ND_Drivers(新提交)
所以我可以通过这种方式识别冲突。但我需要进行合并,然后中止并丢弃它。看起来太麻烦了,所以想问问大家有没有更有效的方法。
首先,我们需要了解Git Merge是如何工作的。当我们合并两个分支
A
和B
时,Git将为每个文件执行三向合并。基本上,它的工作原理是这样的:
A
上的文件内容与A
和B
之间的共同祖先上的内容相同,则B
中的内容将用于合并提交B
上的文件内容与A
和B
之间的共同祖先上的内容相同,则A
中的内容将用于合并提交A
、B
以及 A
和 B
之间的共同祖先上的文件内容不同,那么我们就会发生冲突。如果它是纯文本文件,那么如果更改不冲突,Git 将尝试在内部合并。这也是 Git 在合并子模块时所做的事情,但它不是比较文件的内容,而是比较子模块在每个分支上指向的提交和共同祖先。所以,你可以手动检查一下:
git rev-parse A:path_to_submodule
和git rev-parse B:path_to_submodule
将返回子模块在A
和B
上指向的提交的哈希值(示例中X
和Y
的哈希值)。如果它们相同,那么就不会有冲突git merge-base A B
将为您提供 A
和 B
git rev-parse <hash from step 2>:path_to_submodule
将返回子模块在共同祖先上指向的提交的哈希值。将其与步骤 1 中的两个哈希值进行比较。如果两者都不同,则存在冲突这可能有效:
x=$(git rev-parse A:path_to_submodule)
y=$(git rev-parse B:path_to_submodule)
common=$(git merge-base A B)
z=$(git rev-parse $common:path_to_submodule)
[ "$x" != "$y" ] && [ "$z" != "$x" ] && [ "$z" != "$y" ]
conflict=$?
如果想了解更多相关内容,我写了这篇文章来解释 Git 如何合并子模块:https://lucasoshiro.github.io/posts-en/2022-03-12-merge-submodule/。