如何在同一分支的两个不同提交之间对相同文件进行差异比较?

1431
在Git中,我如何比较同一分支(例如主分支)上两个不相邻提交之间的相同文件?
我正在寻找像Visual SourceSafe(VSS)或Team Foundation Server(TFS)中的“比较”功能。 Git是否支持这种功能?

4
如果你需要在GitHub中进行这个操作 - 查看这个链接 - Pankaj Singhal
12个回答

1803

git-diff手册中得知:

git diff [--options] <commit> <commit> [--] [<path>...]

例如,要查看文件“main.c”在现在和两个提交之前的差异,以下是三个等效的命令:

$ git diff HEAD^^ HEAD main.c
$ git diff HEAD^^..HEAD -- main.c
$ git diff HEAD~2 HEAD -- main.c

50
.. 并不是必需的,但如果使用它也可以(除了一些相对老的版本可能不支持)。如果两个提交之间的距离很远,你也可以使用 git loggitk 找到要使用的 SHA1 值。gitk 的上下文菜单中还有一个 "diff selected -> this" 和 "diff this -> selected" 选项,可以进行差异比较。 - Cascabel
21
如果在两次提交之间修改了文件名,这个方法仍然有效吗? - reubenjohn
34
“--”的目的是什么? - user64141
51
-- 在有文件名为 -p 的情况下非常有用,尤其是在脚本中使用,实践中只在极少数情况下需要使用。 - Palec
24
注意:您需要使用相对于存储库根目录的路径。相对于当前工作目录的路径将无法正常工作。 - Kevin Wheeler
显示剩余8条评论

366
您还可以比较两个不同版本中的两个不同文件,如下所示:

git diff <revision_1>:<file_1> <revision_2>:<file_2>

(注:此翻译为保留原文 HTML 标签的前提下进行的。)

29
请注意,如果<file_1><file_2>在当前目录中,而不是在顶级Git管理的目录中,则需要在Unix系统上加上./前缀:<revision_1>:./filename_1 - Andre Holzner
7
<revision> 可以省略,这样你就可以将其与尚未提交的文件进行比较。 - Yaroslav Nikitenko
2
请注意,在Windows上,文件路径必须使用“/”而不是“\”。 - Niko Pasanen
有没有一种方法可以执行这种差异,使其中一个文件是本地的?也就是说,在打开您的差异工具时,该文件不是在临时目录中的副本。与git diff HEAD..HEAD~1git diff HEAD~1之间的差异类似。 - Gregory Kuhn

109

如果你已经配置了"difftool",你可以使用

git difftool revision_1:file_1 revision_2:file_2

示例:比较同一分支上文件的最后一次提交和上一次提交:

假设您在项目根目录中

$git difftool HEAD:src/main/java/com.xyz.test/MyApp.java HEAD^:src/main/java/com.xyz.test/MyApp.java

你的 ~/.gitconfig 或者 project/.git/config 文件中应该包含以下条目。安装p4merge。

[merge]
    tool = p4merge
    keepBackup = false
[diff]
    tool = p4merge
    keepBackup = false
[difftool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
[mergetool]
    keepBackup = false
[difftool]
    keepBackup = false
[mergetool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
    cmd = p4merge.exe \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"

注意:如果你使用的是Intellij企业版或社区版,它有一个很好的工具可以在合并/变基时进行三方合并。

对于简单的差异比较,您可以右键单击->Git->与修订版本比较

输入图像说明

选择您感兴趣的修订版本。

输入图像说明

Intellij将显示差异。

输入图像说明

82

检查$ git log, 复制两个不同提交的SHA-1 ID,并使用这些ID运行git diff命令。例如:

$ git diff (sha-id-one) (sha-id-two)

35
如果您想要特定文件的差异,可以在命令结尾添加该文件的路径。 - hBrent
如果两个提交跨越不同的分支,请执行“git pull”以下载完整的树信息。否则,您将收到“fatal: bad object”错误。 - user238607
9
git diff (sha-id-one) (sha-id-two) -- filename.ext 如果不加文件名,它将列出这两个提交中所有文件的差异。 - SherylHohman

44
如果您想逐个提交地查看两个提交之间文件的所有更改,您还可以执行以下操作: git log -u $start_commit..$end_commit -- path/to/file

"$start_commit"和"$end_commit"是什么?它们是字面意思吗?如果不是,你能提供一个例子吗? - Peter Mortensen
1
这些是包含起始和结束修订版本的shell变量,它们可以替换为sha1文字或引用。 - cxreg

23

以下是一个Perl脚本,它可以根据Git log命令中给定的文件打印出Git diff命令。

例如:

git log pom.xml | perl gldiff.pl 3 pom.xml

生成:

git diff 5cc287:pom.xml e8e420:pom.xml
git diff 3aa914:pom.xml 7476e1:pom.xml
git diff 422bfd:pom.xml f92ad8:pom.xml

然后可以将其剪切并粘贴到shell窗口会话中,或者通过管道传输到/bin/sh

注:

  1. 数字(在本例中为3)指定要打印的行数。
  2. 文件(在本例中为pom.xml)必须在两个位置上保持一致(您可以将其包装在shell函数中,在两个位置上提供相同的文件),或者将其放在二进制目录中作为shell脚本。

代码:

# gldiff.pl
use strict;

my $max  = shift;
my $file = shift;

die "not a number" unless $max =~ m/\d+/;
die "not a file"   unless -f $file;

my $count;
my @lines;

while (<>) {
    chomp;
    next unless s/^commit\s+(.*)//;
    my $commit = $1;
    push @lines, sprintf "%s:%s", substr($commit,0,6),$file;
    if (@lines == 2) {
        printf "git diff %s %s\n", @lines;
        @lines = ();
    }
    last if ++$count >= $max *2;
}

16

如果你有多个文件或目录,并且想要比较非连续的提交,可以按照以下步骤操作:

创建一个临时分支(在此示例中称为"revision"

git checkout -b revision

回溯到第一个提交目标

git reset --hard <commit_target>

只挑选那些有兴趣的提交记录。

git cherry-pick <commit_interested> ...

应用差异

git diff <commit-target>^

当你完成时

git branch -D revision

2
谢谢您提供的解决方案。它对我的使用情况非常有效。唯一需要更新的是,当您完成后,除非您切换到其他分支,否则无法删除该分支。 - Steven Dix

15

如果您想使用 @mipadi 指定的方法对多个文件进行差异比较:

例如,在 HEAD 和您的 master 之间查找所有 .coffee 文件:

git diff master..HEAD -- `find your_search_folder/ -name '*.coffee'`

这将递归搜索您的 your_search_folder/ 中的所有 .coffee 文件,并对它们和它们的 master 版本进行差异比较。


13

只是另一种使用Git强大功能的方式...

git difftool HEAD HEAD@{N} /PATH/FILE.ext

1
我定义了一个别名,可以在bash中使用,其内容来自于这个答案: difftool-file = "!git difftool HEAD@{\"$2\"} HEAD \"$1\" #" - blueogive

11

其他的回答更为完整,所以请给它们点赞。 这个回答只是提醒你可以避免了解最近提交的id。通常,我会将自己设置在要进行比较的分支上,并运行diff工具,知道旧的提交uid(您也可以使用其他标识符):

git checkout master
git difftool 6f8bba my/file/relative/path.py

另外,查看这里的其他响应,设置您想要比较文件的git工具: 使用.gitconfig配置差异工具 要了解有关差异工具的更多信息,请转到difftool文档


你不能使用HEAD作为最近提交ID的别名吗?HEAD^表示前一个,HEAD^^表示再前一个,以此类推?还是我理解有误? - SherylHohman
^^ 不起作用。但请查看此链接 https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection 在祖先选择下 :) - Raúl Martín

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