前言

源程序文件(通常是纯文本文件)比较和合并工具一直是软件开发过程中比较重要的组成部分。

当远程工作在Unix/Linux平台上的时候,恐怕最简单而且到处存在的就是命令行工具,比如diff。可惜diff的功能有限,使用起来也不是很方便。作为命令行的比较工具,我们仍然希望能拥有简单明了的界面,可以使我们能够对比较结果一目了然;我们还希望能够在比较出来的多处差异之间快速定位,希望能够很容易的进行文件合并……。而Vim提供的diff模式,通常称作vimdiff,就是这样一个能满足所有这些需求,甚至能够提供更多的强力工具。

我们一起来看看vimdiff的基本使用。

使用方法

#启动

$ vimdiff left_filename right_filename

或者:

$ vim -f left_filename right_filename

或者在启动vim之后,在vim的命令行中输入:

:vertical diffsplit right_filename

现在你会看到垂直分割的两个vim窗口打开了两个文件,并对差异部分作出了标识。

如果希望交换两个窗口的位置,或者希望改变窗口的分割方式,可以使用下列命令:(其中1和3两个操作会把窗口改成水平分割方式。)

  1. Ctrl-w K(把当前窗口移到最上边)
  2. Ctrl-w H(把当前窗口移到最左边)
  3. Ctrl-w J(把当前窗口移到最下边)
  4. Ctrl-w L(把当前窗口移到最右边)

如果你在已经打开两个垂直分割的窗口,这时候你可以对要进行diff的每个窗口输入:

:diffthis

这将会将每个窗口变为需要进行对比的窗口。

光标移动

接下来试试在行间移动光标,可以看到左右两侧的屏幕滚动是同步的。这是因为”scrollbind”选项被设置了的结果,vim会尽力保证两侧文件的对齐。如果不想要这个特性,可以设置:

:set noscrollbind

可以使用快捷键]c跳转到下一个差异点,快捷键[c到上一个差异点。

文件合并

  • 如果希望把一个差异点中当前文件的内容复制到另一个文件里,可以使用命令dp,可以理解为diff put;如果希望把另一个文件的内容复制到当前行中,可以使用命令do,diff “get”,之所以不用dg,是因为dg已经被另一个命令占用了。

  • 如果希望在两个窗口之间跳转,可以使用Ctrl-w, w

  • 在修改一个或两个文件之后,vimdiff会试图自动来重新比较文件,来实时反映比较结果。但是也会有处理失败的情况,这个时候需要手工来刷新比较结果::diffupdate

  • 如果希望撤销修改,可以和平常用vim编辑一样,直接<esc> u,但是要注意一定要将光标移动到需要撤销修改的文件窗口中。

上下文展开和查看

比较和合并文件的时候经常需要结合上下文来确定最终要采取的操作。Vimdiff 缺省是会把不同之处上下各 6 行的文本都显示出来以供参考。其他的相同的文本行被自动折叠。如果希望修改缺省的上下文行数,可以这样设置:

:set diffopt=context:3

可以用简单的折叠命令来临

在vimdiff的两个窗口中,相同的代码行会被折叠,用来让不同的代码区域显示地更加清晰。当光标位于被折叠处时候,可以用zo展开被折叠的相同的文本行,这个快捷键可以理解为folding open,之所以用z这个字母,是因为它看上去比较像折叠着的纸;然后可以用zc命令来重新折叠,即folding close。使用快捷键zMzR 可以用来展开和折叠所有的片段。

使用vimdiff处理git merge conflict

首先需要设置vimdiff为git默认的处理合并冲突的工具:

git config merge.tool vimdiff

同时可以设置让vimdiff同时显示BASE,LOCAL,REMOTE三个版本,其中LOCAL是本地分支的版本,REMOTE是远程分支的版本,BASE是LOCAL和REMOTE的Common ancestor。

git config merge.conflictstyle diff3

这时打开的vim窗口会为分割成一个3列的布局,每个窗口内部是一个不同的版本,窗口和版本的对应关系如下:

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

你可以在MERGED窗口手动编辑内容来完成合并冲突的处理,或者使用vim的命令来对每个冲突的地方选择使用LOCAL,BASE还是REMOTE版本的内容,这些命令是:

:diffg RE  # get from REMOTE
:diffg BA  # get from BASE
:diffg LO  # get from LOCAL

处理完毕后,在命令行输入git commit -am 'merged from several branches'来完成提交。

你可以使用git mergetool --tool-help来查看当前机器可以使用哪些工具作为mergetool,除了vimdiff之外,还可以使用Ediff, kdiff3, meld, tortoisemerge

结论

现在市场上很多功能很强大的专用比较和合并工具,比如 BeyondCompare;很多IDE 或者软件配置管理系统,比如Eclipse, Rational ClearCase都提供了内建的功能来支持文件的比较和合并。在无法使用图形化的比较工具的时候,或者在需要快速比较和合并少量文件的时候,vimdiff是最好的选择。

Reference