在Git中使用Winmerge来比较文件


Answers:


113

6年后的2015年6月更新:

正如“ git mergetool winmerge ”中详细介绍的那样,简单git config diff.tool winmerge就足够了。

Git 2.5+(2015年第二季度)现在知道Winmerge是比较或合并工具!


原始答案(2009-2012)

(msysgit,1.6.5,DOS会话)

第一部分(使用winmerge)在“ 如何使用可视化差异程序查看'git diff'输出? ”中进行了介绍。

C:\myGitRepo>git config --replace --global diff.tool winmerge
C:\myGitRepo>git config --replace --global difftool.winmerge.cmd "winmerge.sh \"$LOCAL\" \"$REMOTE\""
C:\myGitRepo>git config --replace --global difftool.prompt false

将其winmerge.sh存储在您的目录的一部分中PATH

#!/bin/sh
echo Launching WinMergeU.exe: $1 $2
"$PROGRAMFILES/WinMerge/WinMergeU.exe" -e -u -dl "Local" -dr "Remote" "$1" "$2"

(请参阅WinMerge命令行选项

git difftool

现在将启动WinMerge。
如果要git diff启动WinMerge,只需设置:

set GIT_EXTERNAL_DIFF=winmerge.sh

但是真正的增值来自使用相同的差异工具来批量显示所有差异而不是顺序显示差异的能力,从而迫使您一次关闭一个文件的差异工具窗口。

2012年6月更新(两年半后):

比较目录而不是逐个文件将很快可用:
请参阅[ANNOUNCE] Git 1.7.11.rc1

git difftool”学习了--dir-diff产生外部差异工具的选项,该差异工具可以在填充两个临时目录之后一次比较两个目录层次结构而不是每个文件对运行一个外部工具实例

有关更多详细信息,请参见“ 补丁difftool:教difftool如何处理目录差异 ”,以及答案“ Git分支的目录比较 ”。


原始difftool按目录脚本(2009年12月)

正如Seba Illingworth他的回答中提到的,脚本git-diffall.sh(也放在路径中)可以做到这一点:

#!/bin/sh
git diff --name-only "$@" | while read filename; do
    git difftool "$@" --no-prompt "$filename" &
done

但这只能通过为n个文件打开n个窗口来起作用(如果您尝试使用WinMerge 的选项,则将不起作用,因为difftool太早删除了临时文件)-s


这就是为什么我喜欢GitDiff.bat的方法-使用GI进行功率差异,它允许您在选择一个文件以检查其内部差异之前查看具有差异的文件列表。
我已将其调整为仅使用DOS命令

@echo off

setlocal

if "%1" == "-?" (
    echo GitDiff - enables diffing of file lists, instead of having to serially
    echo diff files without being able to go back to a previous file.
    echo Command-line options are passed through to git diff.
    echo If GIT_FOLDER_DIFF is set, it is used to diff the file lists. Default is windff.
    goto END
)

if "%GIT_DIFF_COPY_FILES%"=="" (
    rd /s /q %TEMP%\GitDiff
    mkdir %TEMP%\GitDiff
    mkdir %TEMP%\GitDiff\old
    mkdir %TEMP%\GitDiff\new

    REM This batch file will be called by git diff. This env var indicates whether it is
    REM being called directly, or inside git diff
    set GIT_DIFF_COPY_FILES=1

    set GIT_DIFF_OLD_FILES=%TEMP%\GitDiff\old
    set GIT_DIFF_NEW_FILES=%TEMP%\GitDiff\new

    set GIT_EXTERNAL_DIFF=%~dp0\GitDiff.bat
    echo Please wait and press q when you see "(END)" printed in reverse color...
    call git diff %*

    if defined GIT_FOLDER_DIFF (
        REM This command using GIT_FOLDER_DIFF just does not work for some reason.
        %GIT_FOLDER_DIFF% %TEMP%\GitDiff\old %TEMP%\GitDiff\new
        goto END
    )

    if exist "%ProgramFiles%\Beyond Compare 2\BC2.exe" (
        set GIT_FOLDER_DIFF="%ProgramFiles%\Beyond Compare 2\BC2.exe"
        "%ProgramFiles%\Beyond Compare 2\BC2.exe" %TEMP%\GitDiff\old %TEMP%\GitDiff\new
        goto END
    )

    "%ProgramFiles(x86)%\WinMerge\WinMergeU.exe" -r -e -dl "Local" -dr "Remote"  %TEMP%\GitDiff\old %TEMP%\GitDiff\new
    goto END
)

REM diff is called by git with 7 parameters:
REM     path old-file old-hex old-mode new-file new-hex new-mode
copy %TEMP%\%~nx2 %GIT_DIFF_OLD_FILES%\%1
copy %5 %GIT_DIFF_NEW_FILES%

:END

它不能足够强大地处理不同目录中具有相同名称的文件,但是它为您提供了可能的一般思路:
在这里,仅打开一个WinMerge,文件列表具有内部差异。您可以单击要检查的内容,然后将简单ESC关闭所有WinMerge-diff会话。


1
尝试使用git版本1.6.5.1.1367.gcd48,它似乎不会在那些临时文件夹中生成任何文件。有什么想法可以找到问题吗?谢谢!
艺术

@Art:在那些调试情况下,我尝试通过简化脚本来隔离问题:1 /如果脚本使用7参数调用(git diff的第一遍,以复制文件)2 /是至少被回调的脚本在末git diff
VonC

1
@Erik:关于该选项-ub,请参阅WinMerge常见问题解答:它与-u:告诉WinMerge不要将文件添加到MRU相同。
VonC

1
@Erik:您应该在c:\Temp\GitDiff\old和中看到文件的比较,而c:\Temp\GitDiff\new不是' /tmp'。您确定要从DOS会话(而不是bash会话)执行此DOS程序吗?
VonC

1
@coffeemakr ""在我的情况下,它没有评估为结果(git config从Windows CMD 执行命令。但是您是对的:""如果从bash shell执行,它将评估为
。– VonC

19

我在2个地方使用第一部分时遇到了麻烦,并按照以下步骤进行了修复

  1. 设置winmerge.cmd的第二个命令要求在cmdline上加一个斜杠(在$ LOCAL和$ REMOTE之前),否则cygwin将cmdline替换为变量

    C:\myGitRepo>git config --replace --global difftool.winmerge.cmd "winmerge.sh \"\$LOCAL\" \"\$REMOTE\""
    
  2. 将winmerge.sh文件更改为(没有此文件,则出现右路径无效错误)

    #!/bin/sh
    echo Launching WinMergeU.exe: "$(cygpath -aw "$1")" "$(cygpath -aw "$2")"
    "$PROGRAMFILES/WinMerge/WinMergeU.exe" -e -ub -dl "Base" -dr "Mine" "$(cygpath -aw "$1")" "$(cygpath -aw "$2")"
    

3
我完全按照VonC的指示进行操作,但是在winmerge.sh脚本中接收到空参数。使用多余的斜杠可以解决该问题。谢谢!
ashagi 2011年

6

由于线程变得混乱和分散,这里是用于msysgit Git Windows的目录列表“ --dir-diff” WinMerge方法的合并说明。

步骤1-在路径可访问的位置(例如/home/bin/winmerge.sh)创建一个名为winmerge.sh的文件,其中包含以下内容。

#!/bin/sh
echo Launching WinMergeU.exe: $1 $2
"$PROGRAMFILES/WinMerge/WinMergeU.exe" -r -ub -dl "Remote" -dr "Local" "$1" "$2"

第2步 -在Git Bash中键入以下命令,以指示git将winmerge.sh用作difftool(这些选项存储在/home/.gitconfig中):

git config --replace --global diff.tool winmerge
git config --replace --global difftool.winmerge.cmd "winmerge.sh \"$LOCAL\" \"$REMOTE\""
git config --replace --global difftool.prompt false

步骤3-现在您可以通过在Git Bash中键入以下命令来启动WinMerge差异进行测试:

git difftool --dir-diff

第4步 -为了更快地访问,可以通过在主文件夹中的.bashrc中添加以下行来为此命令创建别名(或者,如果文件尚不存在,则使用此行创建.bashrc文件):

alias diffdir='git difftool --dir-diff'

步骤5-现在,只需在Git Bash中键入以下命令,即可快速查看WinMerge中的差异

diffdir

这将是有帮助的人能解释的含义$LOCAL$REMOTE
Tola Odejayi

6

我有一个脚本,可以使用不需要单独的.sh文件的适当参数在Git配置中设置Diff和Merge工具。对我来说似乎很好。

git config --global diff.tool winmerge
git config --global difftool.prompt false
git config --global difftool.winmerge.cmd "\"\$PROGRAMFILES\"/WinMerge/WinMergeU.exe -r -u -e -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\""

git config --global merge.tool winmerge
git config --global mergetool.prompt false
git config --global mergetool.winmerge.trustExitCode true
git config --global mergetool.winmerge.cmd "\"\$PROGRAMFILES\"/WinMerge/WinMergeU.exe -r -u -e -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\" \"\$BASE\" \"\$MERGED\""

注意 -整个.cmd部分都用引号引起来,以便在.gitconfig中正确列出参数


1
以下命令对我不起作用。 git config --global difftool.winmerge.cmd "\"\$PROGRAMFILES\"/WinMerge/WinMergeU.exe -r -u -e -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\"" 注意:此命令必须从命令提示符运行,而不是从powershell运行。手动将以下内容添加到我的.gitconfig [difftool "winmerge"]部分中对我有用: cmd = 'C:/Program Files (x86)/WinMerge/WinMergeU.exe' -r -u -e -dl \"Local\" -dr \"Remote\" \"$LOCAL\" \"$REMOTE\"
Josh

1
它不起作用,但是进行了一些更改,它可以起作用:以管理员身份打开cmd,然后运行:git config --global mergetool.winmerge.cmd "\"C:\Program Files (x86)\WinMerge\WinMergeU.exe\" -r -u -e -dl \"Local\" -dr \"Remote\" \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\""。有一些不正确的转义字符串(请注意,在此之前还有一些多余的反斜杠$-我想$不需要转义)。另外,它在"之后还没有结束WinMergeU?.exe。运行git config --get mergetool.winmerge.cmd查看实际设置的内容。无论如何,感谢非.sh版本:+1!
falsarella 2015年

5

在Windows上,您可以这样操作:

1)打开.gitconfig文件。它位于您的主目录中:c:\ users \ username.gitconfig

2)添加下面的行。注意包裹winmerge路径的单引号:

[diff]
    tool = winmerge
[difftool "winmerge"]
    cmd = "'C:/Program Files (x86)/WinMerge/WinMergeU.exe'" -e "$LOCAL" "$REMOTE"
[difftool]
    prompt = false
[merge]
    tool = winmerge
[mergetool "winmerge"]
    cmd = "'C:/Program Files (x86)/WinMerge/WinMergeU.exe'" \"$MERGED\" \"$REMOTE\"
[mergetool]
    keepBackup = false
    trustExitCode = false

还应注意命令路径中的斜杠而不是反斜杠。
Wisbucky

5

没有配置:

git difftool --tool winmerge

假设:

  • Winmerge已安装
  • 从“ git version 2.12.0.windows1”或更高版本开始安装Windows的Git(尽管git的早期版本可能已经引入了该命令)。

谢谢,这是最简单的解决方案
code4j

2

我很困惑为什么解决方案以DOS批处理文件的形式出现,因为我的Git安装带有bash shell。我也无法从bash运行DOS上下文,因此我试图适应以前在bash上下文中共享的内容。

由于git diff似乎为每个文件运行一次指定的命令,因此我将解决方案分为两个bash脚本:

首先,gitprepdiff.sh如前所述配置为difftool

#!/bin/sh
#echo ...gitprepdiff.sh
cp -v $1 "$TMP/GitDiff/old/$2"
cp -v $2 "$TMP/GitDiff/new"

我还指出,git configure可以在以下位置直接找到和编辑命令的结果C:\Users\<username>\.gitconfigure

gitdiff.sh 然后在您通常会调用的命令行上运行 git diff

#!/bin/sh
#echo Running gitdiff.sh...

DIFFTEMP=$TMP/GitDiff

echo Deleting and re-creating $DIFFTEMP...
rm -rf $DIFFTEMP;
mkdir $DIFFTEMP;

echo Creating $DIFFTEMP/old...
mkdir $DIFFTEMP/old;

echo Creating $DIFFTEMP/new...
mkdir $DIFFTEMP/new;

git diff --name-only "$@" | while read filename; do
    git difftool "$@" --no-prompt "$filename";
done

"$PROGRAMFILES\WinMerge\WinMergeU.exe" -r -e -dl "Repository" -dr "Working" $LOCALAPPDATA\\Temp\\1\\GitDiff\\old $LOCALAPPDATA\\Temp\\1\\GitDiff\\new

另外值得注意的是,在我的安装中,/tmp(在bash中)映射到了%LOCALAPPDATA%\Temp\1\(在Windows中),因此这就是为什么我在对WinMerge的调用中使用后者的原因。


2
我换gitprepdiff.sh#!/bin/sh #echo ...gitprepdiff.sh mkdir -vp "$TMP/GitDiff/old/$(dirname $2)" cp -v $1 "$TMP/GitDiff/old/$2" cp -v --parents $2 "$TMP/GitDiff/new"谢谢!
dobau

跳过这么多圈来完成这项工作似乎很荒谬,但是确实如此。您可以一次性获得所有文件差异。我也必须进行@dobau提到的更改,以正确处理子目录中的文件。
汤姆

1
git config --global diff.tool winmerge
git config --global difftool.winmerge.cmd "\"$PROGRAMFILES\\WinMerge\\WinMergeU.exe\" -u -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\""
git config --global difftool.prompt false

按照 WinMerge命令行手册:“参数以正斜杠(/)或破折号(-)字符为前缀”

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.