关于vim:如何使用vimdiff解决git合并冲突?

How do I use vimdiff to resolve a git merge conflict?

我只是在git中将一个分支合并到我的主服务器中,所以得到了Automatic merge failed; fix conflicts and then commit the result.现在我运行了git mergetool,并且vimdiff用下面的图像打开。 我不知道如何使用vimdiff。 每个面板在这里是什么意思,我应该如何解决合并冲突?

enter image description here


所有四个缓冲区都提供同一文件的不同视图。左上方的缓冲区(LOCAL)是文件在目标分支(合并对象)中的外观。右上方的缓冲区(REMOTE)是文件在源分支(合并源)中的外观。中间缓冲区(BASE)是两者的共同祖先(因此您可以比较左右版本之间的差异)。

在以下几点上,我可能会弄错。我认为合并冲突的根源是自BASE以来,两个文件都更改了文件的同一部分。 LOCAL已将引号从双引号更改为单引号,REMOTE进行了相同的更改,但背景值也从颜色更改为URL。 (我认为合并不够聪明,无法注意到对RECALE也存在对LOCAL的所有更改;它只是知道自BASE以来,LOCAL已在REMOTE所在的相同位置进行了更改)。

无论如何,底部缓冲区包含您可以实际编辑位于工作目录中的文件的文件。您可以进行任何所需的更改; vim向您展示了它与每个顶视图的不同之处,这些顶视图是自动合并无法处理的区域。如果您不想更改REMOTE,请从LOCAL中提取更改。如果您希望将更改从本地撤消,则从本地撤消。如果您认为REMOTE和LOCAL都不正确,请从BASE中拉出。如果您有更好的主意,请做一些完全不同的事情!最后,您在此处所做的更改是实际上将要落实的更改。


@chepner的答案很好,我想在问题的"我应如何继续解决合并冲突"部分中添加一些详细信息。如果您研究如何在这种情况下实际使用vimdiff,它将在下面介绍。

首先,解决"中止一切"选项-如果您不想使用" vimdiff"并中止合并:按Esc,然后键入:qa!并单击Enter。 (另请参见如何退出Vim编辑器?)。 Git会询问您合并是否完成,并用n答复。

如果您想使用vimdiff,这里有一些有用的快捷方式。假设您了解Vim的基础知识(导航和插入/正常模式):

  • 导航到底部缓冲区(合并结果):Ctrl-W j
  • 使用j / k导航到下一个差异;或者,最好使用] c [ c分别导航到下一个和上一个差异
  • 如果要查看更多上下文,请在折叠时使用z o打开它
  • 对于每个差异,按照@chepner的回答,您可以从本地版本,远程版本或基本版本中获取代码,也可以对其进行编辑并根据需要进行重做

    • 要从本地版本获取它,请使用:diffget LO
    • 从远程::diffget RE
    • 从基数::diffget BA
    • 或者,如果您想自己编辑代码,请先从本地/远程/库获取版本,然后进入插入模式并编辑其余版本
  • 完成后,保存合并结果,然后退出所有窗口:wqa

    • 如果要中止合并当前文件而不将其标记为已解决,请使用:cquit退出:如何取消外部git diff?
  • 通常,git检测到进行了合并并创建了合并提交

没有复制粘贴或自定义快捷方式,似乎无法同时添加本地和远程冲突块:https://vi.stackexchange.com/questions/10534/is-there-a-way-to-take-both-当使用vim作为合并工具时,这很遗憾,因为add add是一种常见的冲突类型。

为了防止vimdiff每次启动时都要求您按Enter键,请添加到您的.vimrc中:

1
set shortmess=Ot

如在https://vi.stackexchange.com/questions/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode中所述

您可以在Internet上搜索其他vimdiff快捷方式。我发现这很有用:https://gist.github.com/hyamamoto/7783966


如何使用vim -d在(BASE和LOCAL)与(BASE和REMOTE)之间进行区分

解决合并冲突时,您希望看到的最重要的事情之一是:

  • 我的新提交如何更改基本提交
  • 现有提交如何更改基本提交

然后尝试将它们放在一起。

虽然vimdiff可以很好地并排显示BASE,LOCAL和REMOTE的所有内容,但是我不能从中清楚地看到BASE的两个独立差异:

1
2
3
4
5
+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+

为了解决这个问题,我注意到当git mergetool运行vimdiff时,如果名为main.py的文件存在冲突,则git为每个版本生成文件,名称分别为:

1
2
3
main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

main.py在同一目录中,其中1367是git mergetool的PID,因此是一个"随机"整数,如下所述:在git merge冲突中,什么是BACKUP,BASE,LOCAL和REMOTE文件,产生?

因此,要查看我想要的差异,我首先使用git status查找生成的文件,然后打开新的终端并在我关心的文件对之间进行vimdiff设置:

1
2
vim -d main_BASE_1367.py main_LOCAL_1367.py
vim -d main_BASE_1367.py main_REMOTE_1367.py

git mergetool一起使用,此信息可帮助很多人快速了解发生了什么!

另外,即使mergetool正在运行,您也可以打开文件:

1
vim main.py

如果您觉得使用更大的编辑器窗口会更容易,则可以直接在此处进行编辑。

我想我们甚至可以进一步自动化操作,以自动打开所有这些文件,但是我还没有尝试过。

直接跳转以合并冲突

]c跳到vimdiff中的下一个差异点时,那里并不总是存在合并冲突。

为了解决这个问题,我在~/.vimrc中:

1
2
# Git Merge conflict
nnoremap <leader>gm /\v^\<\<\<\<\<\<\< \|\=\=\=\=\=\=\=$\|\>\>\>\>\>\>\> /<cr>

直接找到冲突。