使用svn diff与vimdiff结合,以获取每个修改文件的标签式差异页面

7
有没有可能使用vim结合svn来获取一系列包含每个文件差异的选项卡页?这将是比“svn diff | view -”更好的选择,但它不会像线性列表一样显示差异,而是使用vimdiff。
过去,我已经找到了一种方法,可以让svn diff为每个编辑的文件打开多个vims,但是能够回顾旧文件将非常有用。因此,给定一组文件S的元组,我需要一个vim shell命令,该命令将在不同的选项卡页中打开S中第一个位置的每个文件,并将其与S中第二个位置的相应文件进行比较。

我已经编写了脚本,可以完成您所要求的操作,但是使用的是git而不是svn。实际上,它们只在一个地方调用git,因此我认为修改以适用于svn应该很容易。这些脚本在此处有文档记录:http://www.xenomachina.com/2012/02/multi-diff-with-vim-andor-git.html - Laurence Gonsalves
2个回答

6
您可以通过Subversion的--diff-cmd命令行选项或在Subversion配置文件中指定自己想要使用的diff命令(Unix命令行客户端的配置文件为$HOME/.subversion/config)。最重要的是了解向您的SVN diff命令传递了哪些参数:
  • 倒数第四个参数 - 左侧程序标题
  • 倒数第三个参数 - 右侧程序标题
  • 倒数第二个参数 - 左侧临时文件
  • 最后一个参数 - 右侧临时文件
首先传递的参数是用于Subversion diff命令的开关。例如:
  • -u
  • -L
您可以利用这些信息创建一个查看VIM文件的脚本。这里是一个简单的Perl脚本:
#! /usr/bin/env perl

use strict;
use warnings;

my $diff = "/usr/bin/vimdiff";

my $num_of_params = $#ARGV;

my $file1 = $ARGV[$num_of_params - 1];
my $file2 = $ARGV[$num_of_params];

my $title1 = $ARGV[$num_of_params - 4];
my $title2 = $ARGV[$num_of_params - 3];

my $title = "$title1 - $title2";
$title =~ s/\t/    /g;
$title =~ s/ /\\ /g;

system qq($diff -c "set titlestring=$title" "$file1" "$file2");

您必须确保您的system命令(如vimdiff)保持命令行。我曾尝试在我的Mac上使用mvim,但是临时文件在mvim命令执行之前被删除了。

现在,您可以这样做:

$ svn diff --diff-cmd mydiff -rPREV

如果您的脚本在路径中并且可执行,它应该可以工作。


感谢ZyX

以下是采纳了ZyX的建议后改进的程序。我不得不进行一些更改。我的diff命令实际上是mvim,我需要传入两个参数(-d表示它是一个diff,-f表示不将mvim置于后台)。这意味着像ZyX建议的那样传递$DIFF会导致我的system命令认为mvim -d -f是我的命令,然后出现错误。为了解决这个问题,我将命令存储在数组中。顺便说一下,我也将数组设置为常量。

以下是程序代码。将DIFF更改为指向您的diff命令(可能是vimdiffgvim -d -fvim -d)。如果您在Windows上,并且完整路径位于C:/Program Files/Vim下,则可以使用C:/Progr~1/Vim来去除空格。否则,您需要执行以下操作:

use constant DIFF => ('C:/Program Files/Vim/VIM73/gvim', '-f', '-d')

由于您无法使用qw,我们能不能说“感谢微软为没有任何理由将所有命令存储的目录名称中加入空格?” 我知道你可以。顺便说一句,如果您的编辑器所在的目录在PATH中,您不需要指定完整的目录名称。

#! /usr/bin/env perl

use strict;
use warnings;

use constant DIFF => qw(mvim -d -f);

my $parameters = $#ARGV;
my $file1 = $ARGV[$parameters - 1];
my $file2 = $ARGV[$parameters];
my $title1 = $ARGV[$parameters - 4];
my $title2 = $ARGV[$parameters - 2];

$ENV{TITLE} = "$title1  -   $title2";

system DIFF, '-c', 'let &titlestring=$TITLE', $file1, $file2;

1
将参数从perl传递到vim的方式不好,因为它们没有得到适当的引用。我会这样写:$ENV{"TITLE"}=$title; system vimdiff => '-c', 'let &titlestring=$TITLE', $file1, $file2;。请注意,您还有两个拼写错误:$title1 =~应该没有1,而qq(diff应该是qq(vimdiff - ZyX
@ZyX - 感谢您的评论。由于我在一个系统上显示我的脚本,而在另一个系统上阅读Stackoverflow时进行输入,因此出现了拼写错误。脚本可以正常工作,但我从来不喜欢如何引用标题。您的方法看起来更好,我会尝试一下。如果有效,我将重新修改我的答案以加入它。 - David W.
请查看我上面的回答中修改后的脚本。 - David W.
这不是我想要的。我知道如何做到这一点。我是在寻求一个vim命令,所以不是为每个要进行差异比较的文件打开单独的vimdiff,而是打开一个包含每个文件选项卡页的单个vim。选项卡页是关键词。本质上,它与diffuse -m所做的相同。 - solinent
@solinent - 问题在于 svn diff 对每个要进行差异比较的文件都会调用一次您的差异命令。您需要编写一个差异命令来收集 svn diff 给您的信息,然后再编写一个包装器来组合各种差异调用中的所有信息。更糟糕的是,svn diff 返回给您临时文件,这些文件在每次调用您的差异程序后都会被删除。在您的差异运行时,您需要将这些临时文件复制到其他地方。我想一旦您把所有这些东西凑齐了,您就可以编写一个 vimdiff 脚本来设置它。 - David W.
显示剩余3条评论

3
这可以通过几个脚本来实现,并利用vim的“服务器”功能。下面的脚本可以稍微改进一下,例如它假设您想在图形化的Vim中执行此操作,并且您不希望脚本在退出此Vim之前退出。此外,默认使用水平分割来进行差异比较。

我使用以下两个脚本来完成此操作。在要运行差异比较的目录中执行bash脚本:

#!/bin/bash

export VIM_SERVERNAME="SVN-$RANDOM"

# Start up a vim, graphical, in the foreground, but backgrounded...
vim -g -f --servername "$VIM_SERVERNAME" &
# So we get can it's PID to wait on later
gvim_pid=$!

# Wait for the server to start up enough
sleep 0.5

# Use svn diff to get the right set of files to pass to vimdiff
svn diff --diff-cmd "vim_tab_diff_helper.py" >/dev/null

# Move to the start of the list; remove the first tab which will be the empty
# tab
vim --servername "$VIM_SERVERNAME" --remote-send ":tabfirst<Return>"
vim --servername "$VIM_SERVERNAME" --remote-send ":bd<Return>"

# Wait for the user to exit vim before returning
wait $gvim_pid

帮助脚本“vim_tab_diff_helper.py”的内容如下:

#!/usr/bin/python

import os
import subprocess
import sys

def vim_send(command):
  global vim_server
  subprocess.call(['vim', '--servername', vim_server, '--remote-send',
    command + '<Return>'])

vim_server = os.environ['VIM_SERVERNAME']
svn_orig_file = sys.argv[ len(sys.argv) - 2 ]
modified_file = sys.argv[ len(sys.argv) - 1 ]

vim_send(":tabnew")
vim_send(":e " + svn_orig_file)
vim_send(":diffsplit " + modified_file)

我将此标记为答案,因为它几乎到位了!目前在我的机器上似乎正在对比错误的两个文件。我现在没有时间来修复它,但是等我有时间时我会去解决这个问题的。 - solinent
2
要查看它尝试差异的内容,可以运行类似于“svn diff --diff-cmd = echo”的命令;我的脚本中所使用的最后两个参数就是这些。 - Sam Jansen
FYI:sys.argv[len(sys.argv) - N] 可以更简洁地写成 sys.argv[-N] - musiphil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接