为什么`git diff`不会调用外部的diff工具?

35

在我的代码库里,如果我输入

$ git diff some-file
或者
$ git difftool some-file

我得到了终端内的差异显示。我认为这不应该发生,因为我已经设置了一个外部的差异工具,就像 git config -l 的输出所示:

$ git config -l
user.name=blah blah
user.email=blah blah
http.sslverify=true
diff.external=/home/daniel/bin/git-diff  <--This is the important line
push.default=simple
core.filemode=false
core.editor=gedit
alias.tree=log --all --graph --decorate=short --color --format=format:'%C(bold blue)%h%C(reset) %C(auto)%d%C(reset)
         %C(black)[%cr]%C(reset)  %x09%C(black)%an: %s %C(reset)'
core.repositoryformatversion=0
core.filemode=false
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
remote.origin.url=https://daniel@skynet/git/pyle.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master
branch.daniel.remote=origin
branch.daniel.merge=refs/heads/daniel

diff.external 行中引用的 git-diff 文件看起来像这样:

#!/bin/bash

meld $2 $5

为什么git diff没有调用meld?

如果我使用git config -l设置以下行,我会得到相同的行为:

diff.tool = meld
或者
diff.external = usr/bin/meld

注意:我电脑上的其他代码库没有这个问题。

相关但不相等的Stack Overflow问题:

  1. git diff 和 git difftool 有什么区别?
  2. 无法使用diff.external作为外部diff工具使git diff生效

你为什么要使用第二个和第五个参数? - merlin2011
@merlin2011:我的理解是git diff将七个参数传递给外部diff工具,而meld只需要其中的两个。 - DanielSank
3个回答

23
我看到了终端中的差异显示。这不应该发生,因为我已经设置了一个外部的差异工具。
是的,它应该发生:diff.external用于“在终端中显示差异”。
(来自git config man page
diff.external

如果设置了此配置变量,则不使用内部差异机制执行差异生成,而是使用给定的命令进行差异生成。可以使用GIT_EXTERNAL_DIFF环境变量覆盖。按照git(1)中“git Diffs”中描述的参数调用该命令。注意:如果您想仅在文件的子集上使用外部差异程序,则可能希望改用gitattributes(5)question you link解释了为什么meld无法扮演“外部差异”的角色。
使用其他工具进行可视化差异比较的方法如下: Viewing a diff visually with another tool
git difftool --dir-diff shaOfHisCheckIn^!
git difftool --tool=meld --dir-diff shaOfHisCheckIn^!
git difftool -t meld -d shaOfHisCheckIn^!

"meld" 可以在 Windows 上配置为差异工具:请参见 "Git Diff and Meld on Windows"。
如果您想为git diff配置meld,则可以(在Ubuntu上)使用diff.external,但需要一个包装脚本

create a file called git-diff.sh, using the following content:

#!/bin/bash
meld "$2" "$5" > /dev/null 2>&1

Save this to a location such as /usr/local/bin, giving it executable rights:

$ sudo mv git-diff.sh /usr/local/bin/
$ sudo chmod +x /usr/local/bin/git-diff.sh

The final step is to open your $HOME/.gitconfig file and add the following few lines:

[diff]
        external = /usr/local/bin/git-diff.sh

The next time you type git diff in a Git project with changes, Meld will be launched showing you a split-pane diff viewer.
Note that you are required to close the open instance of meld before the next diff viewer is opened.


will评论中注释:

That wrapper script works great on my Ubuntu system.

I did discover a gottcha: I detached the meld command as so:

meld "$2" "$5" > /dev/null 2>&1 &

Kept failing to open the $2 file (tempory file).
What happens? Well, git removes $2 once the wrapper exits.
My suggestion, if you wish to detach copy the tmp file, invoke meld and remove tmp file yourself.

将会提议使用gist-meld.bash,并使用meld --newtab,如seen here所示:

#!/bin/bash
#  * expects meld to be on your default PATH
#
function detach_meld()
{
    local f1="/tmp/mld1-$(basename "$1")"
    local f2="/tmp/mld2-$(basename "$2")"
    
##  echo "f1 = ${f1}"
##  echo "f2 = ${f2}"

    cp "$1" "${f1}"
    cp "$2" "${f2}"
#
    (meld  --newtab  "${f1}" "${f2}" ; rm  "${f1}"  "${f2}" ) > /dev/null 2>&1  &    
}

detach_meld  "$2"  "$5"

4
git difftool 似乎是解决方案。我尝试使用包装脚本,但由于某些原因它不起作用。 - DanielSank
那个包装脚本在我的Ubuntu系统上运行得很好。我发现了一个问题。我将meld命令分离如下:meld "$2" "$5" > /dev/null 2>&1 &。一直无法打开$2文件(临时文件)。发生了什么?当包装器退出时,git会删除$2。我的建议是,如果您希望分离,请复制临时文件,调用meld并自己删除临时文件。 - will
@will 感谢你的反馈。我已将您的评论包含在答案中以提高其可见性。 - VonC
1
我发布了一个代码片段:git-meld.bash。如果你真的要比较分支,请准备好许多meld窗口弹出,每个文件都会有一个窗口。如果您知道如何在meld中将文件打开为选项卡,请留下评论。 - will
@will 或许可以使用meld的 --newtab 选项?在这里bzr的上下文中看到:https://askubuntu.com/a/1058344/5470:看看能否将其适应于git difftool选项。 - VonC
显示剩余3条评论

16

看起来,git diff(至少在 git 版本 1.7.12.4 之后)将不会对处于“both modified”状态的文件运行除内部控制台差异以外的任何内容。git mergetool 可以处理这样的文件。


3
即使在git版本1.9.1中仍然是正确的,这真让人心烦!我刚刚浪费了一个小时试图弄清楚为什么我的git difftool配置设置突然停止工作了。 - Die in Sente
2
仍然适用于 git version 2.5.4 (Apple Git-61)。控制台的三方合并工作流程是一个相当大的痛点。真的缺乏能力强的控制台本地差异工具。我相信我将采取的方法是允许git将冲突标记转储到文件中,然后使用我编写的简单工具来处理这些内容以生成可读的差异输出。 - Steven Lu
2
啊哈!@trebor-rude,你刚刚挽救了我的理智,因为我想知道为什么我的所有difftool选择都无法工作。 - jaygooby

2

我通常只想检查我要提交的更改是否正确,所以我遵循了这里建议的步骤(类似于VonC提到的步骤)。然而,运行git difftool仍然没有打开meld。然后我创建了一个别名:

alias git-diff='git difftool $(git rev-parse HEAD)'

将以下代码保存在您的.bashrc或.zshrc配置文件中,或者适当的shell配置文件中。这将比较分支状态与分支上先前提交的状态。
使用git-diff命令逐个文件查看更改内容,或者使用git-diff --dir查看整个目录的所有更改。

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