如何使用我喜欢的diff工具/查看器查看’git diff’输出?

How do I view 'git diff' output with my preferred diff tool/ viewer?

当我键入git diff时,我想使用我选择的可视化diff工具(Windows上的sourcegear"diffmerge")查看输出。如何配置Git来执行此操作?


由于git1.6.3,您可以使用git difftool脚本:请参见下面的答案。

也许这篇文章会对你有所帮助。以下是最好的部分:

指定外部diff工具有两种不同的方法。

第一种方法是通过设置git_external_diff变量使用的方法。但是,变量应该指向可执行文件的完整路径。此外,由git_external_diff指定的可执行文件将使用固定的7个参数集进行调用:

1
path old-file old-hex old-mode new-file new-hex new-mode

由于大多数diff工具都需要不同的参数顺序(并且只需要一些参数),因此您很可能需要指定包装脚本,而包装脚本又调用真正的diff工具。

我更喜欢的第二种方法是通过"git"配置外部diff工具配置"。以下是我所做的:

1)创建一个包装脚本"git diff wrapper.sh",其中包含

1
2
3
4
5
6
7
8
-->8-(snip)--
#!/bin/sh

# diff is called by git with 7 parameters:
# path old-file old-hex old-mode new-file new-hex new-mode

"<path_to_diff_executable>""$2""$5" | cat
--8<-(snap)--

如您所见,只有第二个("旧文件")和第五个("新文件")参数将是传递到diff工具。

2)类型

1
$ git config --global diff.external <path_to_wrapper_script>

在命令提示下,替换为"git diff wrapper.sh"的路径,因此您的~/.gitconfig包含

1
2
3
4
-->8-(snip)--
[diff]
    external = <path_to_wrapper_script>
--8<-(snap)--

请确保使用正确的语法指定包装脚本和diff的路径工具,即使用正斜杠而不是反斜杠。就我而言,我有

1
2
[diff]
    external = "c:/Documents and Settings/sschuber/git-diff-wrapper.sh"

在.gitconfig和

1
"d:/Program Files/Beyond Compare 3/BCompare.exe""$2""$5" | cat

在包装脚本中。小心后面的"猫"!

(我想‘| cat’只适用于某些可能无法返回正确或一致返回状态的程序。如果diff工具具有显式返回状态,则可能希望尝试不使用跟踪cat)

(Diomidis Spinellis在评论中补充道:

The cat command is required, because diff(1), by default exits with an error code if the files differ.
Git expects the external diff program to exit with an error code only if an actual error occurred, e.g. if it run out of memory.
By piping the output of git to cat the non-zero error code is masked.
More efficiently, the program could just run exit with and argument of 0.)

这(上面引用的文章)是通过配置文件(而不是通过环境变量)定义的外部工具的理论。在实践中(仍然用于外部工具的配置文件定义),您可以参考:

  • 如何使用msysgit/gitk设置diffmerge?说明了msysgit和gitk的diffmerge和winmerge的具体设置。
  • 如何设置编辑器在Windows上使用Git?用于将记事本++定义为外部编辑器。


要完成我以前的"diff.external"配置回答,请执行以下操作:

正如Jakub所提到的,Git1.6.3引入了Git Difftool,最初于2008年9月提出:

用法='[--tool=tool] [--commit=ref] [--start=ref --end=ref] [--no-prompt]

'。(见本答案最后一部分中的--extcmd)

$LOCAL包含起始版本的文件内容,$REMOTE包含结束版本的文件内容。$BASE包含WOR中文件的内容。

It's basically git-mergetool modified to operate on the git index/worktree.

The usual use case for this script is when you have either staged or unstaged changes and you'd like to see the changes in a side-by-side diff viewer (e.g. xxdiff, tkdiff, etc).

1
git difftool [<filename>*]

Another use case is when you'd like to see the same information but are comparing arbitrary commits (this is the part where the revarg parsing could be better)

1
git difftool --start=HEAD^ --end=HEAD [-- <filename>*]

最后一个用例是当您想将当前的工作树与head以外的其他东西(例如标记)进行比较时。

1
git difftool --commit=v1.0.0 [-- <filename>*]

注:由于Git2.5,所以git config diff.tool winmerge就足够了!参见"Git Mergetool WinMerge"

由于git 1.7.11,您可以选择--dir-diff,以便生成外部diff工具,在填充两个临时目录之后,一次可以比较两个目录层次结构,而不是每个文件对运行一次外部工具的实例。

Git 2.5之前:

使用自定义diff工具配置difftool的实际案例:

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

当winmerge.sh存储在路径的目录部分时:

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

如果您有另一个工具(kdiff3、p4diff,…),请创建另一个shell脚本和适当的difftool.myDiffTool.cmdconfig指令。然后您可以使用diff.tool配置轻松地切换工具。

你也有戴夫的这个博客条目来添加其他细节。(或者这个问题适用于winmergeu期权)

此设置的兴趣是winmerge.sh脚本:您可以根据特殊情况对其进行自定义。

例如,请参见下面的David Marble答案,以了解处理以下问题的示例:

  • 源文件或目标文件中的新文件
  • 已删除源文件或目标文件

正如Kem Mason在回答中提到的,您也可以使用--extcmd选项来避免任何包装:

1
--extcmd=<command>

Specify a custom command for viewing diffs. git-difftool ignores the configured defaults and runs $command $LOCAL $REMOTE when this option is specified.

例如,这就是gitk如何运行/使用任何diff工具。


在回答问题的精神上有点不同于被问到的问题。尝试此解决方案:

1
$ meld my_project_using_git

meld了解git,并提供有关最近更改的导航。


因为Git版本1.6.3,所以有"Git diff tool",您可以将其配置为使用您最喜欢的图形化diff工具。当前开箱即用支持的工具有kdiff3、kompare、tkdiff、meld、xxdiff、emerge、vimdiff、gvimdiff、ecmerge、diffuse和opendiff;如果要使用的工具不在此列表中,则可以始终使用"EDOCX1"〔0〕配置选项。

"git difftool"接受与"git diff"相同的选项。


使用新的git difftool,只需将其添加到.gitconfig文件中即可:

1
2
3
4
[diff]
    tool = any-name
[difftool"any-name"]
    cmd =""C:/path/to/my/ext/diff.exe" "$LOCAL" "$REMOTE""

还可以查看diffall,这是我编写的一个简单脚本,用于扩展串行打开每个文件时的恼人(imo)默认diff行为。


我还有一件事要做。我喜欢经常使用不受支持的diff应用程序作为默认工具(如万花筒),通过

1
git difftool -t

我还希望默认的diff只是常规命令行,所以设置GIT_EXTERNAL_DIFF变量不是一个选项。

您可以使用任意diff应用程序作为一次性命令:

1
git difftool --extcmd=/usr/bin/ksdiff

它只是将2个文件传递给您指定的命令,因此您可能也不需要包装器。


根据VONC的回答处理文件删除和添加,使用以下命令和脚本:

1
2
3
> git config --global diff.tool winmerge
> git config --global difftool.winmerge.cmd"winmerge.sh "$LOCAL" "$REMOTE" "$BASE""
> git config --global difftool.prompt false

这与在您的全球.gitconfig中输入相同:

1
2
3
4
5
6
[diff]
    tool = winmerge
[difftool"winmerge"]
    cmd = winmerge.bat"$LOCAL""$REMOTE""$BASE"
[difftool]
    prompt = false

然后把以下内容放到你必须要走的winmerge.sh中:

1
2
3
4
5
6
7
8
9
10
#!/bin/sh
NULL="/dev/null"
if ["$2" ="$NULL" ] ; then
    echo"removed: $3"
elif ["$1" ="$NULL" ] ; then
    echo"added: $3"
else
    echo"changed: $3"
   "C:/Program Files (x86)/WinMerge/WinMergeU.exe" -e -ub -dl"Base" -dr"Mine""$1""$2"
fi


Windows/MSYS Git解决方案

在阅读了答案之后,我发现了一种更简单的方法,只需更改一个文件。

  • 创建一个批处理文件来调用diff程序,参数为2和5。此文件必须位于您的路径中。(如果你不知道在哪里,把它放在c:windows中)。例如,称之为"gitdiff.bat"。我的是:

    1
    2
    3
    @echo off
    REM This is gitdiff.bat
    "C:\Program Files\WinMerge\WinMergeU.exe" %2 %5
  • 设置环境变量以指向批处理文件。例如:GIT_EXTERNAL_DIFF=gitdiff.bat。或者通过PowerShell键入git config --global diff.external gitdiff.bat

    重要的是不要使用引号,或者指定任何路径信息,否则它将不起作用。这就是为什么gitdiff.bat必须在你的路径中。

  • 现在,当您键入"git diff"时,它将调用外部diff查看器。


    如果您通过cygwin执行此操作,则可能需要使用cygpath:

    1
    2
    3
    4
    $ git config difftool.bc3.cmd"git-diff-bcomp-wrapper.sh \$LOCAL \$REMOTE"
    $ cat git-diff-bcomp-wrapper.sh
    #!/bin/sh
    "c:/Program Files (x86)/Beyond Compare 3/BComp.exe" `cygpath -w $1` `cygpath -w $2`


    在研究了其他一些外部差异工具之后,我发现Intellij Idea(和Android Studio)中的diff视图对我来说是最好的。

    步骤1-设置要从命令行运行的Intellij IDEA

    如果要使用intellij idea作为diff工具,应首先从命令行中按照以下说明设置要运行的intellij idea:

    在MacOS或Unix上:

  • 确保Intellij理念正在运行。
  • 在主菜单上,选择Tools | Create Command-line Launcher。将打开"创建启动程序脚本"对话框,其中包含建议的启动程序脚本路径和名称。您可以接受默认值,也可以指定自己的路径。注意它,因为你以后需要它。在intellij思想之外,将启动程序脚本的路径和名称添加到您的路径中。
  • 在Windows上:

  • 在PATH系统环境变量中指定Intellij IDEA可执行文件的位置。在这种情况下,您将能够从任何目录调用Intellij IDEA可执行文件和其他Intellij IDEA命令。
  • 步骤2-将Git配置为使用Intellij IDEA作为difftool

    按照此日志上的说明操作:

    猛击

    1
    2
    export INTELLIJ_HOME /Applications/IntelliJ\ IDEA\ CE.app/Contents/MacOS
    PATH=$IDEA_HOME $PATH

    1
    2
    set INTELLIJ_HOME /Applications/IntelliJ\ IDEA\ CE.app/Contents/MacOS
    set PATH $INTELLIJ_HOME $PATH

    现在将以下内容添加到Git配置中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [merge]
       tool = intellij
    [mergetool"intellij"]
       cmd = idea merge $(cd $(dirname"$LOCAL") && pwd)/$(basename"$LOCAL") $(cd $(dirname"$REMOTE") && pwd)/$(basename"$REMOTE") $(cd $(dirname"$BASE") && pwd)/$(basename"$BASE") $(cd $(dirname"$MERGED") && pwd)/$(basename"$MERGED")
       trustExitCode = true
    [diff]
       tool = intellij
    [difftool"intellij"]
       cmd = idea diff $(cd $(dirname"$LOCAL") && pwd)/$(basename"$LOCAL") $(cd $(dirname"$REMOTE") && pwd)/$(basename"$REMOTE")

    你可以用git difftoolgit difftool HEAD~1试试。


    这在Windows7上适用。不需要中间的sh脚本

    .gitconfig的内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
        [diff]
          tool = kdiff3

        [difftool]
           prompt = false

        [difftool"kdiff3"]
          path = C:/Program Files (x86)/KDiff3/kdiff3.exe
          cmd ="$LOCAL""$REMOTE"


    以上伟大答案的简短总结:

    1
    2
    3
    git difftool --tool-help
    git config --global diff.tool <chosen tool>
    git config --global --add difftool.prompt false

    然后通过键入(也可以指定文件名)来使用它:

    1
    git difftool


    介绍

    作为参考,我想在VONC的答案中加入我的变体。请记住,我正在使用修改过的路径的msys版本的git(此时为1.6.0.2),并从PowerShell(或cmd.exe)运行git本身,而不是bash shell。

    我引入了一个新的命令,gitdiff。运行此命令会暂时重定向git diff以使用您选择的可视化diff程序(而不是vonc的永久解决方案)。这允许我同时具有默认的Git Diff功能(git diff和可视的Diff功能(gitdiff)。这两个命令使用相同的参数,因此,例如,为了直观地区分特定文件中的更改,可以键入

    1
    gitdiff path/file.txt

    。安装程序

    注意,$GitInstall用作安装git的目录的占位符。

  • 创建一个新文件,$GitInstall\cmd\gitdiff.cmd

    1
    2
    3
    4
    5
    6
    7
    8
    @echo off
    setlocal
    for /F"delims=" %%I in ("%~dp0..") do @set path=%%~fI\bin;%%~fI\mingw\bin;%PATH%
    if"%HOME%"=="" @set HOME=%USERPROFILE%
    set GIT_EXTERNAL_DIFF=git-diff-visual.cmd
    set GIT_PAGER=cat
    git diff %*
    endlocal
  • 创建一个新文件,$GitInstall\bin\git-diff-visual.cmd(用您选择的diff程序的完整路径替换[visual_diff_exe]占位符)

    1
    2
    3
    4
    5
    6
    @echo off
    rem diff is called by git with 7 parameters:
    rem path old-file old-hex old-mode new-file new-hex new-mode
    echo Diffing"%5"
    "[visual_diff_exe]""%2""%5"
    exit 0

  • 你现在完成了。从Git存储库中运行gitdiff现在应该对更改的每个文件调用VisualDiff程序。


  • 如果您在Mac上安装了xcode,那么就安装了filemerge。终端命令是opendiff,所以您只需执行EDOCX1[8]


    这是一个适用于Windows的批处理文件-假定在默认位置安装了diffmerge,处理x64,必要时处理前向反斜杠替换,并且能够自行安装。应该很容易用您最喜欢的diff程序替换diffmerge。

    要安装:

    1
    gitvdiff --install

    gitvdiff.bat(吉特维迪夫.bat):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    @echo off

    REM ---- Install? ----
    REM To install, run gitvdiff --install

    if %1==--install goto install



    REM ---- Find DiffMerge ----

    if DEFINED ProgramFiles^(x86^) (
        Set DIFF="%ProgramFiles(x86)%\SourceGear\DiffMerge\DiffMerge.exe"
    ) else (
        Set DIFF="%ProgramFiles%\SourceGear\DiffMerge\DiffMerge.exe"
    )



    REM ---- Switch forward slashes to back slashes ----

    set oldW=%2
    set oldW=%oldW:/=\%
    set newW=%5
    set newW=%newW:/=\%


    REM ---- Launch DiffMerge ----

    %DIFF% /title1="Old Version" %oldW% /title2="New Version" %newW%

    goto :EOF



    REM ---- Install ----
    :install
    set selfL=%~dpnx0
    set selfL=%selfL:\=/%
    @echo on
    git config --global diff.external %selfL%
    @echo off


    :EOF


    对于如何在1.6.3之前的Git版本上配置diff工具的Linux版本(在Git中添加了1.6.3 diff tool),这是一个非常简明的教程,

    简而言之:

    步骤1:将此添加到.gitconfig中

    1
    2
    3
    4
    [diff]
      external = git_diff_wrapper
    [pager]
      diff =

    第二步:创建一个名为git diff-wrapper的文件,把它放在$path的某个地方。

    1
    2
    3
    #!/bin/sh

    vimdiff"$2""$5"


    安装meld

    1
     # apt-get install meld

    然后选择它作为difftool

    1
     $ git config --global diff.tool meld

    如果要在控制台上运行它,请键入:

    1
     $ git difftool

    如果要使用图形模式,请键入:

    1
     $ git mergetool

    输出将是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     'git mergetool' will now attempt to use one of the following tools:
     meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse
     diffmerge ecmerge p4merge araxis bc3 codecompare emerge vimdiff
     Merging:
     www/css/style.css
     www/js/controllers.js

     Normal merge conflict for 'www/css/style.css':
       {local}: modified file
       {remote}: modified file
     Hit return to start merge resolution tool (meld):

    所以只需按Enter键使用meld(默认),这将打开图形模式,进行magic save并按该键解决合并问题。这就是全部


    在Mac OS X上,

    1
    git difftool -t diffuse

    在Git文件夹中为我做这个工作。对于安装Diffuse,可以使用端口-

    1
    sudo port install diffuse


    您可以使用git difftool

    例如,如果已合并,可以通过以下方式编辑分支masterdevel

    1
    2
    git config --global diff.external meld
    git difftool master..devel


    以下内容可以从这里的其他答案中得到,但对我来说很困难(信息太多),所以这里是tkdiff的"只需输入"答案:

    1
    git difftool --tool=tkdiff <path to the file to be diffed>

    您可以将您最喜欢的diffing工具的可执行文件名替换为tkdiff。只要(例如tkdiff),(或您最喜欢的diffing工具)在您的路径中,它就会启动。


    我在这里尝试了一些新奇的东西(用tkdiff),但没有什么对我有用。所以我写了下面的脚本tkgitdiff。它做我需要它做的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $ cat tkgitdiff
    #!/bin/sh

    #
    # tkdiff for git.
    # Gives you the diff between HEAD and the current state of your file.
    #

    newfile=$1
    git diff HEAD -- $newfile > /tmp/patch.dat
    cp $newfile /tmp
    savedPWD=$PWD
    cd /tmp
    patch -R $newfile < patch.dat
    cd $savedPWD
    tkdiff /tmp/$newfile $newfile


    我在~/.gitconfig中使用这个位已经很长时间了:

    1
    2
    [diff]
        external = ~/Dropbox/source/bash/git-meld

    使用git-meld时:

    1
    2
    3
    4
    5
    6
    7
    #!/bin/bash
    if ["$DISPLAY" ="" ];
    then
        diff $2 $5
    else
        meld $2 $5
    fi

    但是现在我厌倦了在图形环境中使用meld,用这个设置调用普通的diff并不容易,所以我切换到这个:

    1
    2
    [alias]
        v = "!sh -c 'if [ $# -eq 0 ] ; then git difftool -y -t meld ; else git difftool -y $@ ; fi' -"

    有了这个设置,像这样的东西就可以工作了:

    1
    2
    3
    4
    git v
    git v --staged
    git v -t kompare
    git v --staged -t tkdiff

    我还得保留好的老东家。


    您可能需要尝试xd http://github.com/jiqingtang/xd,它是git/svn diff的GUI包装器。它本身不是diff工具。当你想运行git diffsvn diff时,你运行xd,它会显示一个文件列表、一个预览窗口,你可以启动任何你喜欢的diff工具,包括tkdiff、xxdiff、gvimdiff、emacs(ediff)、xemacs(ediff)、meld、diffuse、kompare和kdiff3。您还可以运行任何自定义工具。

    很遗憾,该工具不支持Windows。

    披露:我是这个工具的作者。


    如果您不是命令行的用户,那么如果您安装了Tortoise Git,您可以右键单击一个文件,以获得带有"diff later"选项的Tortoise Git子菜单。

    在第一个文件上选择此选项后,可以右键单击第二个文件,转到"TortoisGit"子菜单,然后选择"diff with==yourFileHere=="这将为结果提供TortoisGitmerge GUI。


    如果您碰巧已经有了与文件类型相关联的diff工具(例如,因为您安装了Diff查看器附带的Tortoissesvn),那么您可以将常规的git diff输出通过管道传输到"temp"文件,然后直接打开该文件,而无需了解查看器的任何信息:

    1
    git diff >"~/temp.diff" && start"~/temp.diff"

    将其设置为全局别名效果更好:git what

    1
    2
    [alias]
        what ="!f() { git diff >"~/temp.diff" && start"~/temp.diff"; }; f"


    我在Ubuntu上使用kompare:

    1
    sudo apt-get install kompare

    要比较两个分支:

    1
    git difftool -t kompare <my_branch> master