【问题标题】:How do I diff the same file between two different commits on the same branch?如何在同一分支上的两个不同提交之间区分同一文件?
【发布时间】:2021-11-13 20:12:44
【问题描述】:

在 Git 中,我如何在同一分支(例如 master)上的两个不同提交(不连续)之间比较同一文件?

我正在寻找一种 比较 功能,例如 Visual SourceSafe (VSS) 或 Team Foundation Server (TFS) 中的功能。
在 Git 中可以吗?

【问题讨论】:

  • 如果您需要在 GitHub 中执行此操作 - check this

标签: git git-diff


【解决方案1】:

来自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

【讨论】:

  • .. 不是必需的,尽管它可以使用它(也许在相当旧的版本中除外)。如果两个提交相距甚远,您还可以使用git loggitk 来查找要使用的SHA1。 gitk 在其上下文菜单中还有一个“diff selected -> this”和“diff this -> selected”。
  • 即使在 2 次提交之间修改了文件名,这也能正常工作吗?
  • 那么“--”的目的是什么
  • @user64141 -- 很有用,例如当您有一个名为 -p 的文件时。非常适合在脚本中使用,仅在实践中需要的极少数情况下使用。
  • 注意:您需要使用相对于 repo 根目录的路径。相对于当前工作目录的路径将不起作用。
【解决方案2】:

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

git diff &lt;<em>revision_1</em>&gt;:&lt;<em>file_1</em>&gt; &lt;<em>revision_2</em>&gt;:&lt;<em>file_2</em>&gt;

【讨论】:

  • 请注意,如果 &lt;file_1&gt;&lt;file_2&gt; 在当前目录中,而不是在顶级 git 托管目录中,则必须在 Unix 上添加 ./&lt;revision_1&gt;:./filename_1
  • :可以省略,因此您可以与尚未提交的文件进行比较。
  • 请注意,在 Windows 上,文件路径必须使用“/”,而不是“\”。
  • 有没有办法执行这个差异,使得两个文件之一是本地的? IE。当您的 difftool 打开时,该文件不是临时目录中的副本。与git diff HEAD..HEAD~1git diff HEAD~1 之间的区别相同
【解决方案3】:

如果你已经配置了“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 [这是我首选的 diff 和合并工具]

[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 Enterprise 或 Community Edition - 它是 3 路合并的最佳工具之一。

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • 如果您想要特定文件的差异,请在命令末尾添加路径。
    • 如果两个提交跨越不同的分支,也可以执行“git pull”来下载完整的树信息。否则你会得到一个“fatal: bad object”错误。
    • git diff (sha-id-one) (sha-id-two) -- filename.ext 没有文件名,它将列出这两个提交中 所有 文件的差异。
    【解决方案5】:

    如果您想逐个提交查看两次提交之间文件的所有更改,您也可以这样做

    git log -u $start_commit..$end_commit -- path/to/file

    【讨论】:

    • 什么是“$start_commit”和“$end_commit”?它们是字面意思吗?如果不是,你能举个例子吗?
    • 这些是包含开始和结束修订的 shell 变量,可以改为 sha1 文字或 refs
    【解决方案6】:

    这是一个 Perl 脚本,它为 Git 日志命令中的给定文件打印出 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;
    }
    

    【讨论】:

      【解决方案7】:

      如果您有多个文件或目录并且想要比较非连续提交,您可以这样做:

      创建一个临时分支("revision" 在这个例子中)

      git checkout -b revision
      

      回退到第一个提交目标

      git reset --hard <commit_target>
      

      挑选那些感兴趣的提交

      git cherry-pick <commit_interested> ...
      

      应用差异

      git diff <commit-target>^
      

      完成后

      git branch -D revision
      

      【讨论】:

      • 感谢您的解决方案。它适用于我的用例。我唯一要更新的是,当你完成后,你不能删除分支,直到你关闭它。
      【解决方案8】:

      如果你想对多个文件进行 diff,使用@mipadi 指定的方法:

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

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

      这将递归搜索您的 your_search_folder/ 以查找所有 .coffee 文件,并在它们和它们的 master 版本之间进行区分。

      【讨论】:

        【解决方案9】:

        使用 Git 的另一种方式...

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

        【讨论】:

        • 我从这个答案中定义了一个别名,适用于 bash:difftool-file = "!git difftool HEAD@{\"$2\"} HEAD \"$1\" #"
        【解决方案10】:

        所有其他回复都更完整,因此请点赞。 这只是为了记住,您可以避免知道最近提交的 id。通常,我将自己设置在要比较的分支中,并在知道旧的提交 uid 的情况下运行差异工具(您可以使用其他符号):

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

        此外,请在此处检查此其他响应以设置您希望 git 打开的工具以比较文件: Configuring diff tool with .gitconfig 要了解有关 difftool 的更多信息,go to the difftool doc

        【讨论】:

        • 您不能使用 HEAD 作为最近提交 ID 的别名吗? HEAD^ 表示之前的那个,HEAD^^ 表示之前的那个,等等?还是我误会了?
        • ^^ 不起作用。但是在祖先选择下检查这个git-scm.com/book/en/v2/Git-Tools-Revision-Selection :)
        【解决方案11】:

        如果您想在 Windows 上进行简单的视觉比较,例如可以在 Visual SourceSafeTeam Foundation Server (TFS) 中获取,请尝试以下操作:

        • 在文件资源管理器中右键单击文件
        • 选择“Git 历史”

        注意:升级到 Windows 10 后,我丢失了 Git 上下文菜单选项。但是,您可以在命令窗口中使用“gitk”或“gitk 文件名”来实现相同的目的。

        调用“Git History”后,Git GUI 工具将启动,文件的历史记录显示在左上窗格中。选择您要比较的版本之一。然后右键单击第二个版本并选择任一

        区分这个 -> 选择

        选择差异 -> 这个

        颜色编码的差异将出现在左下方的窗格中。

        【讨论】:

        • 请注意:这是一个简单的解决方案,易于实施并解决了 OP 的问题。它适用于 OP 明确使用的 Windows(请参阅问题中对 TFS 和 VSS 的引用)。
        猜你喜欢
        • 1970-01-01
        • 2017-08-19
        • 2011-12-29
        • 2023-03-18
        • 1970-01-01
        • 2016-12-04
        • 2019-12-31
        相关资源
        最近更新 更多