vimdiff 介绍
vimdiff
等同于 vim -d
命令,即 Vim 编辑器的 diff 模式。
该命令后面通常会接两个或多个文件名作为参数,这些文件会同时在 Vim 编辑器的分割窗口中打开,并高亮显示文件之间内容有差异的部分。
同时,该模式下还提供部分快捷按键用于完成文件内容的合并等操作。
启动 vimdiff
vimdiff
命令常用于编辑同一文件的不同历史版本,对各文件的内容进行比对与调整。如下面两个文件:
1 |
|
1 |
|
可以使用 vim -O2 file1 file2
命令,在左右排列的两个窗口中同时打开 file1 和 file2 两个文件,如下图所示:
而 vimdiff file1 file2
命令会以同样的形式打开这两个文件,并且用不同的背景色高亮显示彼此间有差别的内容,如下图:
从上面的两幅截图中可以得出 vimdiff 标记差别内容时的几个规则:
- 只在某一个文件中存在的行背景色设置为蓝色,而另一文件中的对应位置则被标记为绿色。(或者说,相对于另一个文件,当前文件中“多余”的行标记为蓝色,“缺少”的行则标记为绿色)
- 两个文件中同时存在但是内容有差异的行,都标记为粉色,而引起差异的文字标记为红色
除了 vimdiff FILE_LEFT FILE_RIGHT
或者 vim -d FILE_LEFT FILE_RIGHT
的形式外,也可以通过在 Vim 中输入命令进入 diff 模式。
比如先进入 Vim 编辑 FILE_LEFT 文件(vim FILE_LEFT
),再输入以下命令进入 diff 模式::vertical diffsplit FILE_RIGHT
光标移动
可以使用下列两种快捷键,在文件的各个差异点之间前后移动:
], c
:跳转到下个差异点[, c
:跳转到上个差异点
至于光标在两个窗口之前的切换,可以使用如下按键:
Ctrl-w, l
:光标切换到右侧的窗口Ctrl-w, h
:光标切换到左侧的窗口Ctrl-w, w
:光标在两个窗口间彼此切换
内容合并
可以使用 d, p
(即 diff put)命令,将当前差异点中的内容覆盖到另一文件中的对应位置。
如当光标位于左侧文件(file1)中的第一行时,依次按下 d
、p
键,则 file1 中的 Line one
被推送到右侧,并替换掉 file2 中对应位置上的 Line 1
。截图如下:
而 d, o
(即 diff obtain)命令可以将另一窗口中差异点处的内容拉取到当前位置并进行替换操作。截图如下:
即在 file1 的第一行执行 d o
命令后,file2 中的第一行内容 Line 1
被拉取到 file1 中并替换掉原来位置上的 Line one
。
多文件编辑
vimdiff 实际上是 Vim 编辑器的 diff 模式,因此适用于 Vim 编辑器的命令和快捷键也同样可以在该模式下使用。常用的几个命令如下:
:qa
:退出所有文件:wa
:保存所有文件:wqa
:保存并退出所有文件qa!
:强制退出(不保存)所有文件z o
:查看被折叠的内容z c
:重新折叠
其他常用的命令与快捷键可参考 Vim 速查手册
vimdiff 解冲突
使用 vimdiff
作为 Git 的合并工具确实可能会让新手感到困惑,但它是一个功能强大的工具,一旦掌握了它,就可以非常高效地进行代码合并和比较
Git配置
在开始之前,需要知道如何将vimdiff设置为Git的合并工具。具体步骤如下:
1 |
|
这将把Git设置为默认的合并工具,在合并时显示共同祖先,并禁用打开vimdiff的提示。
git config merge.tool vimdiff
: 这会将vimdiff
设置为默认的合并工具。git config merge.conflictstyle diff3
: 这会告诉 Git 在合并冲突时显示共同祖先的版本,这样就可以看到两个分支以及它们的共同起点的内容。git config mergetool.prompt false
: 这会禁用打开合并工具时的提示,Git 将自动打开vimdiff
而不询问是否想要继续。
创建冲突
下面用一个例子举例:
创建一个名为”zoo”的目录,并进入”zoo”目录,然后初始化Git仓库,最后新建一个animals.txt
。
1 |
|
在文件中添加一些动物信息后并保存:
1 |
|
之后提交该文件
1 |
|
添加文件animals.txt
到Git,提交文件,并附上消息”Initial commit”。
创建一个名为”octodog”的分支,并切换到”octodog”分支,并打开文件animals.txt
,并将”octopus”改为”octodog”。
1 |
|
添加文件animals.txt
到Git,提交文件,并附上消息”Replace octopus with an octodog”。
1 |
|
切换到”master”分支,打开文件animals.txt
,并将”octopus”改为”octoman”。
1 |
|
添加文件animals.txt
到Git,提交文件,并附上消息”Replace octopus with an octoman”。
1 |
|
合并”octodog”分支到”master”分支。
1 |
|
此时,会得到一个合并错误:
1 |
|
这表明在animals.txt
文件中存在合并冲突。
解决冲突
解决这个冲突可以输入以下命令:
1 |
|
执行上述命令后,Git会尝试使用vimdiff作为合并工具来解决冲突。vimdiff会打开一个窗口,显示两个版本的文件,中间会有冲突标记。需要手动比较这两个版本,并选择一个解决方案来替换冲突的部分。使用 hjkl
键在窗口之间导航,使用 :diffget LOCAL
、:diffget REMOTE
或 :diffget BASE
来将对应窗口的内容复制到 MERGED
窗口中。解决冲突后,保存并关闭文件,Git会提示你提交冲突的解决结果。
上述窗口看起来很迷糊,其实很好理解,下面解释一下都有什么。从左到右,从上到下:
LOCAL
:- 这是当前分支(通常是执行
git merge
命令时所在的分支)的文件内容。 - 在合并过程中,这代表了您的最新更改。
- 这是当前分支(通常是执行
BASE
:- 这是两个分支的共同祖先的文件内容。
- 它显示了自从两个分支从共同点分开以来,发生了哪些变化。
REMOTE
:- 这是试图合并进来的分支的文件内容。
- 在
git merge
命令中,`` 就是这里的REMOTE
。
MERGED
:- 这是合并后的文件内容将显示的地方。
- 目标是将
LOCAL
和REMOTE
的更改合并到这个窗口中,以解决所有冲突。
假设想要保留“octodog”的更改(来自REMOTE)。为此,将光标移动到MERGED文件(Ctrl + w, j),然后移动到合并冲突区域。接着,可以选择保留LOCAL版本、BASE版本或REMOTE版本中的哪一部分,或者合并这些内容。完成后,保存并关闭文件,Git会提示你提交冲突的解决结果。
1 |
|
这会将REMOTE中相应的更改添加到MERGED文件中,也可以:
1 |
|
这些命令允许快速地从一个特定的版本中获取内容,并将其应用于MERGED区域。一旦解决了所有的冲突,保存并关闭文件,Git会提示提交冲突的解决结果。
保存文件并退出(快速写入并退出多个文件的方法是::wqa)。一旦解决了所有冲突并保存了文件后运行git commit
,完成这些步骤后,就成功地解决了合并冲突,并将更改提交到了 Git 仓库。
以下是一些其他的命令:
- 使用
:diffthis
命令来打开两个版本之间的差异,这样可以更清楚地看到差异。 - 使用
:nextdiffto
命令来切换到下一个差异,这样可以逐步解决多个冲突。 - 使用
:diffoff
命令来关闭差异显示,这样可以更专注于编辑。 - 使用
:diffmerge
命令来合并两个版本,这将覆盖当前的MERGED区域。 - 使用
:diffmergeoff
命令来关闭合并显示,这样可以回到正常的编辑模式。