为什么 git mergetool 没有显示冲突,即使合并后文件中存在冲突标记?

Why does git mergetool show no conflicts, even though there are conflict markers present in files after a merge?

我在 feature/my-branch 和 运行 宁 git merge dev 检查过。添加到文件中的冲突标记是:

<<<<<<< HEAD
    let foo = "foo"
    let bar = "bar"
||||||| merged common ancestors
    let baz = "baz"
    let bar = "bar"
=======
    let baz = "baz"
    let qux = "qux"
>>>>>>> dev

我然后运行git mergetool。我将 p4mergetool 设置为我的合并工具,它似乎可以正常工作。我的 .gitconfig:

[merge]
    tool = p4mergetool
    conflictstyle = diff3
[mergetool "p4mergetool"]
    cmd = /Applications/p4merge.app/Contents/Resources/launchp4merge $PWD/$BASE $PWD/$REMOTE $PWD/$LOCAL $PWD/$MERGED
    trustExitCode = true

git mergetool 自动解决上述冲突(工具中显示 0 个冲突)为:

let foo = "foo"
let qux = "qux"

这有点道理:即使 HEAD 和 dev 发生冲突,我们也可以看到一个分支更新了一行,另一个分支更新了另一行。所以我们可以可能假设我们想要什么。

我的问题是:

  1. 有没有办法 run/configure git-mergetoolp4mergetool 不做这个假设并且仍然显示冲突?
  2. 我需要运行两个命令吗:

    git merge dev
    git mergetool
    

    让这个冲突自动解决? IE。产生输出:

    let foo = "foo"
    let qux = "qux"
    

换句话说:是否有一个 git merge strategy/arguments 可以用来简单地 运行 merge 命令生成:

let foo = "foo"
let qux = "qux"

This sort of makes sense: even though HEAD and dev are in conflict, we can see that one branch updated one line and the other branch updated the other line. So we can probably assume what we want.

完全正确。

  1. Is there a way to run/configure git-mergetool or p4mergetool specifically to NOT make this assumption and still show a conflict?

git mergetool没有做假设,所以我们可以断定p4mergetool一定是做的。不过,我没有 p4mergetool,所以我不知道它是否有配置旋钮来更改它。

  1. Do I need to run both commands ...

是的:Git 自己的合并有点愚蠢,只是注意到,天哪,左边的这个变化范围与右边的另一个变化范围邻接(接触)或重叠,所以让我们称之为冲突并让用户处理它。在这种情况下,左侧变化(从 baz 到 foo)刚好发生在右侧变化(bar 到 qux)之前,因此两个范围在边缘接触并且 Git 本身声明冲突。如果中间有一条线,git merge 会自行组合这些更改,而不会称其为冲突。

(请注意,使用 -X ours-X theirs 将通过丢弃一方的更改并仅使用另一方的更改来解决冲突。同样,您甚至永远不会达到 p4mergetool做自己的事。)

git mergetool 所做的是提取三个文件——合并基本版本、左版本或本地版本或 --ours、右版本或远程版本或某些文件的 --theirs 版本——以及 运行 其他一些非 Git 程序在三个文件上。当该程序完成时,git mergetool 可以相信它的退出代码来决定工具本身是否正确合并了文件,或者 运行 一些文件比较,或者直接问你:工作树副本是该文件现在是正确的合并副本吗?

如果工作树副本现在是正确的最终结果(或者至少 git mergetool 相信这一点),git mergetool 运行s git add,这标志着解决冲突。1 否则,它会保留冲突。

(我倾向于只在我的编辑器中解决合并冲突。)


1如果在任何非零索引槽中有文件的任何副本,则该文件是未合并。如果一个文件有一个副本,则该文件被 合并 ,位于插槽 0——正常的插槽编号。除了使用一些 Git 的低级诊断命令(git ls-index --stage,真的),你实际上 看不到 这些暂存槽号,但是git status 调用文件 unmerged 并告诉您它是在所有三个插槽中 (UU) 还是仅在左侧或右侧 (UDDU 分别)。我不确定 git status 关于插槽 1 中文件的说法,它代表具有 rename/rename 冲突的文件的合并基本副本。

通常我们只是使用 git addgit rm 来覆盖编号较高的插槽。在极少数情况下,想要将已解决的文件恢复到冲突状态,git checkout -m 可以做到。