git 合并冲突:哪个提交是共同的祖先?
git merge conflicts: which commit was the common ancestor?
我想知道 git 合并冲突解决期间“共同祖先”提交的身份。
换句话说:当我在 git merge
期间解决冲突时,我想知道从 提取 BASE 版本的 修订的散列。
希望有一个命令可以告诉我这些信息?
为什么我想知道
- 我(很不幸)正在做一个非常复杂的合并,有很多冲突。
- 我希望能够可视化这两条变化路径(
BASE -> LOCAL
和 BASE -> REMOTE
),以便为我提供更多有关这两组变化如何发生、谁做出的、何时发生的背景信息什么分支等等...
有帮助(?)的相关信息
回想一下,对于任何特定的冲突文件,
- 一个 BASE 版本 (
git show :1:<path>
),来自共同祖先提交(其身份是我问题的答案)
- 本地(我所在的分支:
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 mergetool
和 gvimdiff3
查看冲突。此工具显示每个冲突文件(带有 "<<<"
、">>>"
、"|||"
冲突标记,以及其他三个供参考的文件:LOCAL、BASE 和 REMOTE。一切都很好.
我的 BASE 文件有时会有冲突标记 (!),看起来像这样:
<<<<<<<<< Temporary merge branch 1
<snip>
||||||||| merged common ancestors
=========
<snip>
>>>>>>>>> Temporary merge branch 2
- 我(我认为)正在使用 recursive merge strategy,它声称:
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,并且必须具有 parents 我想知道的身份。
如果您处于由 git merge
触发的冲突中(例如:不是 cherry-pick
或 rebase
):
- 您当前的提交仍然是
HEAD
- 合并的提交存储在一个特殊的引用中
.git/MERGE_HEAD
所以你可以得到:
- 您当前的提交(“我的”):
git rev-parse HEAD
- 另一个提交(“他们的”):
git rev-parse MERGE_HEAD
- 基本提交:
git merge-base MERGE_HEAD HEAD
您实际上可以使用 HEAD
和 MERGE_HEAD
作为指向这些提交的有效名称,因此:
git diff HEAD...MERGE_HEAD
或 git difftool -d HEAD...MERGE_HEAD
将显示自分叉点以来“他们”引入的更改,
git diff MERGE_HEAD...HEAD
或 git difftool -d MERGE_HEAD...HEAD
将显示自分叉点以来“我”中引入的更改。
关于三点符号 git diff A...B
的注释,引用 the docs :
git diff A...B
is equivalent to git diff $(git merge-base A B) B
解决单个文件的冲突:
kdiff3
3 路合并默认显示 4 个窗格,这允许您在同一屏幕上查看:
LOCAL
和BASE
的区别
BASE
和REMOTE
的区别
- 您要在底部窗格中保存的结果
我不熟悉 vimdiff
,但肯定有一种方法可以拥有这个 4 窗格视图,或者可以在 3 路合并和两个差异中的任何一个之间切换的命令。
- 我使用
meld
作为图形差异查看器,我知道这个有:
- a
--auto-merge
标志,在 3 路合并视图中,自动合并不冲突的 diff 块,
- 一种从命令行打开多个差异视图的方法,所以我在单独的选项卡中打开
LOCAL BASE
和 BASE REMOTE
差异
这是我添加到我的 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
我很确定其他差异查看器(例如 vimdiff3
或 kdiff3
具有等效的 --auto-merge
选项,但我会让您扫描文档以了解它的命名方式以及如何使用它。
这个很棘手,而且有点讨厌。你在这里完全正确:
I guess what I am seeing is that the "common ancestor" is a merged hybrid of several commits. Nevertheless, that merged hybrid must have been generated somehow, must have a SHA, and must have parents whose identities I want to know.
与 一样,当 Git 因合并冲突而停止时,您确实可以使用 HEAD
和 MERGE_HEAD
。
您可以通过以下方式找到合并基(复数)的哈希 ID:
git merge-base --all HEAD MERGE_HEAD
由于您使用的是合并递归,Git 所做的是:
- Select两个合并基地
- 运行
git merge-recursive
在他们身上。 (这本身可能会找到两个以上的合并基础;如果是这样,请参阅此过程。)
- 提交结果。这是目前为止的合并基础。 (此提交有一个哈希 ID。)
- 如果有两个以上的碱基,选择下一个合并碱基,并将其与merge-base-so-far合并;这是目前新的合并基础。
- 重复直到用完所有合并基数。
此过程的最终输出是提交哈希 ID。 此哈希 ID 不会保存或显示在任何地方。当然,您可以从 git merge-base --all
获取此过程的所有 输入。
通常,当合并发生冲突时,Git 会停止并让您修复它们。但是当合并合并基础产生冲突时,Git 只是继续并提交冲突的合并基础。这个不好。 (我并不是说它 不好 在这里,只是说它 不好: 它变得非常混乱。新的 merge-ort 不这样做,我想,但我还没有准确地消化它的作用。)这些冲突标记确实是你所看到的。
这里的工具 Git 并不能胜任这项工作,但是使用 git merge-base --all
,您至少可以检查每个输入。
我想知道 git 合并冲突解决期间“共同祖先”提交的身份。
换句话说:当我在 git merge
期间解决冲突时,我想知道从 提取 BASE 版本的 修订的散列。
希望有一个命令可以告诉我这些信息?
为什么我想知道
- 我(很不幸)正在做一个非常复杂的合并,有很多冲突。
- 我希望能够可视化这两条变化路径(
BASE -> LOCAL
和BASE -> REMOTE
),以便为我提供更多有关这两组变化如何发生、谁做出的、何时发生的背景信息什么分支等等...
有帮助(?)的相关信息
回想一下,对于任何特定的冲突文件,
- 一个 BASE 版本 (
git show :1:<path>
),来自共同祖先提交(其身份是我问题的答案) - 本地(我所在的分支:
git show :2:<path>
)版本和 - REMOTE(我要合并的分支:
git show :3:<path>
)版本
- 一个 BASE 版本 (
我知道我可以使用
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 mergetool
和gvimdiff3
查看冲突。此工具显示每个冲突文件(带有"<<<"
、">>>"
、"|||"
冲突标记,以及其他三个供参考的文件:LOCAL、BASE 和 REMOTE。一切都很好.我的 BASE 文件有时会有冲突标记 (!),看起来像这样:
<<<<<<<<< Temporary merge branch 1
<snip>
||||||||| merged common ancestors
=========
<snip>
>>>>>>>>> Temporary merge branch 2
- 我(我认为)正在使用 recursive merge strategy,它声称:
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,并且必须具有 parents 我想知道的身份。
如果您处于由 git merge
触发的冲突中(例如:不是 cherry-pick
或 rebase
):
- 您当前的提交仍然是
HEAD
- 合并的提交存储在一个特殊的引用中
.git/MERGE_HEAD
所以你可以得到:
- 您当前的提交(“我的”):
git rev-parse HEAD
- 另一个提交(“他们的”):
git rev-parse MERGE_HEAD
- 基本提交:
git merge-base MERGE_HEAD HEAD
您实际上可以使用 HEAD
和 MERGE_HEAD
作为指向这些提交的有效名称,因此:
git diff HEAD...MERGE_HEAD
或git difftool -d HEAD...MERGE_HEAD
将显示自分叉点以来“他们”引入的更改,git diff MERGE_HEAD...HEAD
或git difftool -d MERGE_HEAD...HEAD
将显示自分叉点以来“我”中引入的更改。
关于三点符号 git diff A...B
的注释,引用 the docs :
git diff A...B
is equivalent togit diff $(git merge-base A B) B
解决单个文件的冲突:
kdiff3
3 路合并默认显示 4 个窗格,这允许您在同一屏幕上查看:LOCAL
和BASE
的区别
BASE
和REMOTE
的区别
- 您要在底部窗格中保存的结果
我不熟悉 vimdiff
,但肯定有一种方法可以拥有这个 4 窗格视图,或者可以在 3 路合并和两个差异中的任何一个之间切换的命令。
- 我使用
meld
作为图形差异查看器,我知道这个有:- a
--auto-merge
标志,在 3 路合并视图中,自动合并不冲突的 diff 块, - 一种从命令行打开多个差异视图的方法,所以我在单独的选项卡中打开
LOCAL BASE
和BASE REMOTE
差异
- a
这是我添加到我的 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
我很确定其他差异查看器(例如 vimdiff3
或 kdiff3
具有等效的 --auto-merge
选项,但我会让您扫描文档以了解它的命名方式以及如何使用它。
这个很棘手,而且有点讨厌。你在这里完全正确:
I guess what I am seeing is that the "common ancestor" is a merged hybrid of several commits. Nevertheless, that merged hybrid must have been generated somehow, must have a SHA, and must have parents whose identities I want to know.
与 HEAD
和 MERGE_HEAD
。
您可以通过以下方式找到合并基(复数)的哈希 ID:
git merge-base --all HEAD MERGE_HEAD
由于您使用的是合并递归,Git 所做的是:
- Select两个合并基地
- 运行
git merge-recursive
在他们身上。 (这本身可能会找到两个以上的合并基础;如果是这样,请参阅此过程。) - 提交结果。这是目前为止的合并基础。 (此提交有一个哈希 ID。)
- 如果有两个以上的碱基,选择下一个合并碱基,并将其与merge-base-so-far合并;这是目前新的合并基础。
- 重复直到用完所有合并基数。
此过程的最终输出是提交哈希 ID。 此哈希 ID 不会保存或显示在任何地方。当然,您可以从 git merge-base --all
获取此过程的所有 输入。
通常,当合并发生冲突时,Git 会停止并让您修复它们。但是当合并合并基础产生冲突时,Git 只是继续并提交冲突的合并基础。这个不好。 (我并不是说它 不好 在这里,只是说它 不好: 它变得非常混乱。新的 merge-ort 不这样做,我想,但我还没有准确地消化它的作用。)这些冲突标记确实是你所看到的。
这里的工具 Git 并不能胜任这项工作,但是使用 git merge-base --all
,您至少可以检查每个输入。