为啥 git mergetool 显示没有冲突,即使合并后文件中存在冲突标记?
Posted
技术标签:
【中文标题】为啥 git mergetool 显示没有冲突,即使合并后文件中存在冲突标记?【英文标题】:Why does git mergetool show no conflicts, even though there are conflict markers present in files after a merge?为什么 git mergetool 显示没有冲突,即使合并后文件中存在冲突标记? 【发布时间】:2020-07-21 09:08:26 【问题描述】:我已在 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 发生冲突,我们也可以看到一个分支更新了一行,而另一个分支更新了另一行。所以我们可以大概假设我们想要什么。
我的问题是:
-
有没有办法专门运行/配置
git-mergetool
或 p4mergetool
以不做出这种假设并仍然显示冲突?
我需要同时运行这两个命令吗:
git merge dev
git mergetool
让这个冲突自动解决? IE。产生输出:
let foo = "foo"
let qux = "qux"
换一种说法:有没有一个 git 合并策略/参数可以用来简单地运行merge
命令来产生:
let foo = "foo"
let qux = "qux"
【问题讨论】:
【参考方案1】:这种说法是有道理的:即使 HEAD 和 dev 发生冲突,我们也可以看到一个分支更新了一行,而另一个分支更新了另一行。所以我们可以大概假设我们想要什么。
完全正确。
有没有办法专门运行/配置
git-mergetool
或p4mergetool
以不做出这种假设并仍然显示冲突?
git mergetool
没有做这个假设,所以我们可以得出结论,p4mergetool
一定是做这件事的人。不过我没有p4mergetool
,所以我不知道它是否有一个配置旋钮来改变它。
我是否需要同时运行这两个命令...
是的:Git 自己的合并有点愚蠢,只是注意到,天哪,左边的这个变化范围邻接(接触)或重叠右边的另一个变化范围,所以让我们称之为冲突并让用户处理它。在这种情况下,左边的变化(从 baz 到 foo)就在右边的变化(bar 到 qux)之前,所以两个范围在边缘接触并且 Git 本身声明了冲突。如果中间有一条线,git merge
会自行合并这些更改,而不会称其为冲突。
(请注意,使用-X ours
或-X theirs
将通过丢弃一方的更改并仅使用另一方的更改来解决冲突。同样,您甚至永远不会达到让p4mergetool
做自己的事情的地步。)
git mergetool
所做的是提取三个文件——合并基础、左或本地或--ours
,以及某个文件的右或远程或--theirs
版本——并在这三个文件上运行其他一些非 Git 程序文件。当该程序完成时,git mergetool
可以信任其退出代码来决定工具本身是否正确合并文件,或者运行一些文件比较,或者直接询问您:文件的工作树副本现在是否正确合并复制?
如果工作树副本现在是正确的最终结果(或至少 git mergetool
相信这一点),git mergetool
运行 git add
,这标志着冲突已解决。1否则,它会留下冲突。
(我倾向于只在编辑器中解决合并冲突。)
1如果一个文件在任何非零索引槽中有任何副本,则该文件未合并。如果一个文件有一个副本,则该文件被合并,位于插槽 0(正常的插槽号)中。除了使用 Git 的一些低级诊断命令(git ls-index --stage
,真的),您实际上无法看到这些暂存槽编号,但 git status
调用文件 unmerged 并告诉您它是在所有三个插槽中(UU
)还是仅在左侧或右侧(分别为UD
和DU
)。我不确定git status
对插槽 1 中的文件所说的内容,它表示具有重命名/重命名冲突的文件的合并基础副本。
通常我们只使用git add
或git rm
来覆盖编号较高的插槽。在想要将已解决的文件恢复到冲突状态的极少数情况下,git checkout -m
可以做到这一点。
【讨论】:
谢谢@torek!即将接受答案。只是好奇:“不过,我没有 p4mergetool,所以我不知道它是否有一个配置旋钮来改变它。”您是否知道 任何 具有此配置的合并工具? 不——我不使用它们中的任何一个。我已经将 vimdiff 作为合并工具启动了一两次,只是为了看看它的外观,而且我曾经见过一个非 Git 合并工具在运行。我已经运行git mergetool
并指出了一些事情,但从未尝试过 kdiff3 或任何 KDE 合并工具......以上是关于为啥 git mergetool 显示没有冲突,即使合并后文件中存在冲突标记?的主要内容,如果未能解决你的问题,请参考以下文章
markdown 如何使用`git mergetool`来解决冲突
markdown 如何使用`git mergetool`来解决冲突
如何解决与“git mergetool”的多个冲突而不必关闭文件之间的编辑器?
02_创建Git仓库,克隆仓库,git add,git commit,git push,git pull,同行冲突,不同行冲突的结局方案,git mergetool的使用