如何使用vimdiff解决git合并冲突?


159

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

在此处输入图片说明


3
参见本页。如果这是“正确”的意思,则代码的当前状态在左上方。
romainl

@romainl读完这些书后,我仍然感到困惑,快捷方式是什么?如何选择将哪个文件用作主分支?
酷男哟


另请参阅:
skelliam

Answers:


142

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

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

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


4
快速提问如何保存在vim中?
酷家伙哟

6
:x:w(也:x退出)加上“返回”。
乔纳森·勒夫勒

4
Anders:如果您不熟悉使用方法,则可以使用其他合并工具vim
chepner

3
@AndersKitson,由于您使用的是Mac OS X,因此FileMerge是完美的,免费的,并且带有XCode。
romainl

8
为什么要下票?如果确实有不正确的地方,请修复它,或者至少指出它。
chepner 2013年

91

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


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


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

  • 导航到底部缓冲区(合并结果): Ctrl-W j
  • 导航到与下一个DIFF j/ k; 或者,最好使用] c[ c分别导航到下一个和上一个差异
  • z o如果您想查看更多上下文,请在折叠时使用
  • 对于每个差异,按照@chepner的回答,您可以从本地,远程或基本版本中获取代码,也可以对其进行编辑并根据需要进行重做
    • 要从本地版本获取它,请使用 :diffget LO
    • 从远程: :diffget RE
    • 从基础: :diffget BA
    • 或者,如果您想自己编辑代码,请先从本地/远程/库获取版本,然后进入插入模式并编辑其余版本
  • 完成后,保存合并结果,然后退出所有窗口 :wqa
  • 通常,git检测到进行了合并并创建了合并提交

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

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

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


10
应该对此进行x1000次投票,并接受更好的答案。
安德烈·波特诺伊

要快速跳转到下一个冲突,只需搜索===即可。做“ / ===”并输入
Apit John Ismail,

如果使用找到多个匹配项,请参阅这篇文章(stackoverflow.com/questions/51520705/…:diffget
杰森

7

最终的mergetool取代vimdiff

这有点开玩笑,但这是我尝试使用vimdiff后最终趋向于成为vimmer的想法。

要解决合并冲突,我几乎总是需要看到:

  • 远程
  • 本地
  • 两个差异:
    • diff基本远程
    • diff基本本地

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

尽管vimdiff确实在屏幕上显示BASE,LOCAL和REMOTE:

    +--------------------------------+
    | LOCAL  |     BASE     | REMOTE |
    +--------------------------------+
    |             MERGED             |
    +--------------------------------+

我不知道如何使它清晰地显示出我需要的那两个差异,此外还需要通过左右左右多次观察。

此外,LOCAL和REMOTE在git merge冲突标记中已经可见,因此我无法从再次显示它们的工具获得太多收益。

因此,我创建了自己的微型“ difftool”,它实际上显示了我缺少的差异:

〜/ bin / cirosantilli-mergetool

#!/usr/bin/env bash
BASE="$1"
LOCAL="$2"
REMOTE="$3"
diff --color -u "$BASE" "$LOCAL"
diff --color -u "$BASE" "$REMOTE"
exit 1

GitHub上游

并安装:

git config --global mergetool.cirosantilli-mergetool.cmd 'cirosantilli-mergetool $BASE $LOCAL $REMOTE'
git config --global mergetool.cirosantilli-mergetool.trustExitCode true
# If you want this to become your default mergetool.
#git config --global merge.tool 'cirosantilli-mergetool'

现在,当您这样做时:

git mergetool -t cirosantilli-mergetool

它显示了我想要在终端上的两个差异,例如:

--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_LOCAL_15560.py       2019-12-27 13:46:41.979021479 +0000
@@ -994,7 +994,7 @@                                                              

     def setupBootLoader(self, cur_sys, loc):
         if not cur_sys.boot_loader:                           
-            cur_sys.boot_loader = [ loc('boot_emm.arm64'), loc('boot_emm.arm') ]
+            cur_sys.boot_loader = [ loc('boot.arm64'), loc('boot.arm') ]
         cur_sys.atags_addr = 0x8000000                  
         cur_sys.load_offset = 0x80000000                    

@@ -1054,7 +1054,7 @@                                           
             ]                                                     

     def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = [ loc('boot_emm_v2.arm64') ]
+        cur_sys.boot_loader = [ loc('boot_v2.arm64') ]
         super(VExpress_GEM5_V2_Base,self).setupBootLoader(
                 cur_sys, loc)                             

--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_REMOTE_15560.py      2019-12-27 13:46:41.991021366 +0000
@@ -610,10 +610,10 @@           
     def attachIO(self, *args, **kwargs):              
         self._attach_io(self._off_chip_devices(), *args, **kwargs)

-    def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = loc('boot.arm') 
-        cur_sys.atags_addr = 0x100                           
-        cur_sys.load_offset = 0       
+    def setupBootLoader(self, cur_sys, boot_loader, atags_addr, load_offset):
+        cur_sys.boot_loader = boot_loader      
+        cur_sys.atags_addr = atags_addr     
+        cur_sys.load_offset = load_offset

因此,您可以在此处看到转储到终端的两个差异:

  • RealView_BASE_15560.pyRealView_LOCAL_15560.py
  • RealView_BASE_15560.pyRealView_REMOTE_15560.py

如果差异很大,我将使用tmux超能力进行搜索。

是的,您确实失去了vimdiff提供的一些快捷方式,但是一般而言,解决冲突需要两种版本都进行仔细的复制粘贴,我可以在具有git冲突标记的普通vim会话中很好地完成此操作。

vimdiff运行时观察和区分文件

在我坐下来并使用自动化我的理想设置之前cirosantilli-mergetool,这就是我要获得所需的两个差异的方法。

git mergetool运行时vimdiff,如果名为的文件存在冲突main.py,则git为每个版本生成文件,名为:

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

在同一个目录中main.py,其中1367是git的合并工具的PID,因此,“随机”的整数,如提及:在git的合并冲突,什么是生成备份,BASE,本地和远程文件?

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

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

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

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

vim main.py

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

直接跳转以合并冲突

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

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

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

直接找到冲突。

git imerge

也许最好的选择是放弃使用vimdiff并依赖常规的vim + git imerge,该方法在以下文章中提到:我如何找出哪个Git提交导致冲突?因为vimdiff的学习曲线很烦人,并且没有执行我们最需要的功能。


1
已投票。我想我9年前在stackoverflow.com/a/3052118/6309中提到了这一点。(请参阅答案的最后部分)
VonC

@VonC是的,我想您赢了这个!XD
Ciro Santilli郝海东冠状病六四事件法轮功
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.