git合并冲突:哪个提交是共同的祖先



我想知道"共同祖先";在git合并冲突解决过程中提交。

换句话说:当我在git merge期间解决冲突时,我想知道从中提取BASE版本的修订版的哈希。

希望有一个命令能告诉我这些信息?

为什么我想知道

  • 我(很不幸)正在进行一个非常复杂的合并,有很多冲突
  • 我希望能够可视化这两条变化路径(BASE -> LOCALBASE -> REMOTE),为我提供更多关于这两组变化是如何发生的,是谁做出的,何时,在什么分支上,等等的上下文

有用的(?)相关信息

  • 回想一下,对于任何特定的冲突文件,都有

    • 一个BASE版本(git show :1:<path>),它来自公共祖先提交(其身份是我问题的答案)
    • LOCAL(分支I位于:git show :2:<path>)版本,并且
    • REMOTE(我正在合并的分支:git show :3:<path>)版本
  • 我知道我可以通过使用git ls-files -u来获得BASE文件本身的SHA哈希,它给出了类似的输出

$ git ls-files -u | grep "<path>"
100644 <SHA of BASE file> 1 <path>
100644 <SHA of LOCAL file> 2 <path>
100644 <SHA of REMOTE file> 3 <path>
  • 我使用git mergetoolgvimdiff3来查看冲突。此工具显示每个冲突文件(带有"<<<"">>>""|||"冲突标记),以及其他三个可供参考的文件:LOCAL、BASE和REMOTE。一切都很好。

  • 我的BASE文件有时会有冲突标记(!),看起来像这样:

<<<<<<<<< Temporary merge branch 1
<snip>
||||||||| merged common ancestors
=========
<snip>
>>>>>>>>> Temporary merge branch 2
  • 我(我认为)正在使用递归合并策略,该策略声称:

When there is more than one common ancestor that can be used for 3-way merge, it creates a merged tree of the common ancestors and uses that as the reference tree for the 3-way merge.

  • 我想我看到的是;共同祖先";是几个提交的合并混合体。尽管如此,合并后的混血儿一定是以某种方式产生的,一定有SHA,而且一定有我想知道身份的父母

这个很棘手,而且有点讨厌。你在这里完全正确:

我想我看到的是;共同祖先";是几个提交的合并混合体。尽管如此,合并后的混血儿一定是以某种方式产生的,一定有SHA,而且一定有我想知道身份的父母。

正如LeGEC所说,当Git因合并冲突而停止时,HEADMERGE_HEAD都可用。

您可以使用找到合并基的哈希ID(复数)

git merge-base --all HEAD MERGE_HEAD

由于您使用的是合并递归,Git所做的是:

  • 选择两个合并基
  • 对它们运行git merge-recursive。(这本身可能会找到两个以上的合并基;如果是,请参阅此过程。)
  • 提交结果。到目前为止,这是合并的基础。(此提交具有哈希ID。)
  • 如果有两个以上的合并基,则拾取下一个合并基,并将其与迄今为止的合并基合并;到目前为止,这是新的合并基础
  • 重复此步骤,直到所有合并基数都用完为止

此过程的最终输出是提交哈希ID。此哈希ID不会保存或显示在任何位置当然,您可以从git merge-base --all获得该过程的所有输入

通常,当合并发生冲突时,Git会停止并让您修复它们。但是,当合并合并基产生冲突时,Git只是继续并提交冲突的合并基。这是。。。不好。(我并不是说这里的很糟糕,只是不好:变得非常混乱。我认为新的合并端口没有做到这一点,但我还没有确切地理解它的作用。)这些冲突标记确实是你所看到的。

Git在这里拥有的工具并不能完全胜任这项工作,但使用git merge-base --all,您至少可以检查每个输入。

如果您处于由git merge触发的冲突中(例如:不是cherry-pickrebase):

  • 您当前的提交仍然是HEAD
  • 合并后的提交存储在特殊引用.git/MERGE_HEAD

所以你可以得到:

  • 您当前的提交("我的"):git rev-parse HEAD
  • 另一个提交("他们的"):git rev-parse MERGE_HEAD
  • 基本提交:git merge-base MERGE_HEAD HEAD

您实际上可以使用HEADMERGE_HEAD作为有效名称来指向这些提交,因此:

  • CCD_ 29或CCD_;他们";由于分叉点
  • CCD_ 31或CCD_;我"从分叉点开始

关于三点符号git diff A...B的注释,引用文档:

git diff A...B等效于git diff $(git merge-base A B) B


要解决单个文件的冲突:

  • kdiff3在3路合并中默认显示4个窗格,允许您在同一屏幕上查看:
    • LOCALBASE的差异
    • CCD_ 39与CCD_
    • 将要保存在底部窗格中的结果

我不熟悉vimdiff,但肯定有一种方法可以使用这个4窗格视图,也可以使用命令在3向合并和两个diff中的任何一个之间切换。

  • 我使用meld作为图形差异查看器,我知道这个查看器具有:
    • 一个--auto-merge标志,它在3向合并视图中自动组合不冲突的diff块
    • 一种从命令行打开几个diff视图的方法,因此我在单独的选项卡中打开LOCAL BASEBASE REMOTEdiff

以下是我添加到gitconfig:的配置设置

git config --global mergetool.meld3.cmd 
'meld --auto-merge $LOCAL $BASE $REMOTE -o $MERGED'
' --diff $LOCAL $BASE --diff $BASE $REMOTE'
git config --global merge.tool meld3

我很确定其他diff查看器,如vimdiff3kdiff3,也有等效的--auto-merge选项,但我会让您扫描文档,了解它的名称和使用方法。