【问题标题】:How do I get the interdiff between these two git commits?如何获得这两个 git 提交之间的差异?
【发布时间】:2013-07-22 16:30:01
【问题描述】:

我正在尝试查看 git 中同一提交的两个修订版之间的差异。差异的差异,基本上。从我目前所读到的,这被称为“interdiff”。我已经阅读了几个关于如何创建 git 补丁的 interdiffs 的教程,但我无法让这些方法在我的特定情况下工作。

所以这是设置。我有两个不同的分支,每个分支都有略微不同的提交:

* 29e734f - (origin/feature_branch, new_commits) New commit 3 (69 minutes ago) <Ajedi32>
* b22ebea - New commit 2 (89 minutes ago) <Ajedi32>
* 09d42c2 - New commit 1 (2 hours ago) <Ajedi32>
| * 467e08f - (old_commits) Old commit 3 (4 weeks ago) <Ajedi32>
| * f2bf1cb - Old commit 2 (4 weeks ago) <Ajedi32>
| * 34a2187 - Old commit 1 (4 weeks ago) <Ajedi32>
|/  
*   1b05a4a - (origin/base, base) Base commit (5 weeks ago) <Ajedi32>

在这个例子中,我想找到“旧提交 3”和“新提交 3”之间的差异。我尝试从这两个提交创建一个补丁文件并通过interdiff 实用程序运行它们,但我得到的只是:

1 out of 2 hunks FAILED -- saving rejects to file /tmp/interdiff-1.Kgwx8u.rej
interdiff: Error applying patch1 to reconstructed file

我不太确定这意味着什么,所以我现在有点卡住了。我从这里去哪里?

注意:我不是在这里寻找git diff old_commits new_commits。我不希望输出中包含对提交 1 和 2 的修订。

【问题讨论】:

  • 哦,根据 OP 试图询问的内容,这可能与 this question 有关。
  • 出于好奇,diff 的 diff 能为您带来什么?
  • @Shahbaz 你的意思是它有什么用?我使用它是为了让审查我的代码的人更容易看到我在响应之前的审查时所做的更改。 This page 是我遵循的教程之一。它在页面顶部附近有一个很好的解释为什么 interdiffs 是有用的。
  • @Shahbaz 或者你问如果我通过diff 命令运行差异内容会发生什么?在那种情况下,我不确定,但我怀疑它会很漂亮。
  • @mnagel 来自原始问题:“注意:我不是在这里寻找git diff old_commits new_commits。我不希望输出中包含对提交 1 和 2 的修订。”因此,如果“旧提交 1”和“新提交 1”之间存在一些细微差别,我不希望包含这些更改。我在区分补丁,而不是仓库的状态。

标签: git


【解决方案1】:

Git 2.19 引入了一个新命令,git range-diff,它执行此操作:

git-range-diff - 比较两个提交范围(例如,一个分支的两个版本)

git range-diff [--color=[<when>]] [--no-color] [<diff-options>] [--no-dual-color]
               [--creation-factor=<factor>]\
               ( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> )

说明

此命令显示补丁的两个版本之间的差异 系列,或更一般地说,两个提交范围(忽略合并提交)。

为此,它首先从两个提交范围中找到提交对 是相互对应的。据说两个提交是对应的 当他们的补丁之间的差异(即作者信息, 提交消息和提交差异)与 补丁的大小。详情请见下方Algorithm

最后,匹配的提交列表按顺序显示 第二个提交范围,之后插入不匹配的提交 他们所有的祖先都被展示出来了。

所以,在你的情况下:

git range-diff base old_commits new_commits

会自动将old_commits 分支中的提交与new_commits 分支中的提交进行匹配,并显示每个提交之间差异的摘要。

或者,如果您只想要每个分支中上次提交的更改,您可以运行:

git range-diff old_commits~..old_commits new_commits~..new_commits

有关范围差异的更多信息,请参阅the official documentation

【讨论】:

    【解决方案2】:

    大概是这样的:

    git log -p -1 new_commits > patch.new
    git log -p -1 old_commits > patch.old
    diff patch.old patch.new
    

    或者对于一个简洁的单行代码(bash):

    diff <(git log -p -1 old_commits) <(git log -p -1 new_commits)
    

    【讨论】:

    • 用于单行的 bash 语法是 process substitution
    • 是否有理由使用git log 而不是git show,例如diff &lt;(git show old_commits) &lt;(git show new_commits)
    • @doak 好点 - 似乎输出是相同的,至少在我目前使用的 git 版本上......不过,情况可能总是如此,也可能并不总是如此。 ..
    • @talberg,我很确定这至少在 10 年和至少在接下来的 20 年都是如此;)来自man git show:“对于提交,它显示日志消息和文本差异。”
    • 单行似乎实际上符合 posix 标准
    【解决方案3】:

    如果两次提交之间几乎没有差异,则比较删除的行和添加的行(即仅以 + 或 - 开头的行)是有效的。它消除了以@@ 开头的大块边界或不重要的提交消息正文引入的噪音:

    diff -u --ignore-matching-lines '^[^+-]' \
        <(git show 1d9e4ac) <(git show 7b8e5c9)
    

    样本输出为:

    --- /dev/fd/63  2015-02-13 13:27:08.612683558 +0100
    +++ /dev/fd/62  2015-02-13 13:27:08.616683527 +0100
    @@ -62,13 +57,24 @@
      }
    
     diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h
    -index 0113662..282cbeb 100644
    +index 3b2e6e6..0a633a5 100644
     --- a/src/crush/CrushWrapper.h
     +++ b/src/crush/CrushWrapper.h
    -@@ -874,6 +874,25 @@ public:
    -     return false;
    +@@ -863,6 +863,36 @@ public:
    +     if (!crush) return -1;
    +     return crush_find_rule(crush, ruleset, type, size);
        }
    - 
    ++
    ++  bool ruleset_exists(int const ruleset) const {
    ++    for (size_t i = 0; i < crush->max_rules; ++i) {
    ++     if (crush->rules[i]->mask.ruleset == ruleset) {
    ++       return true;
    ++     }
    ++    }
    ++
    ++    return false;
    ++  }
    ++
     +  /**
     +   * Return the lowest numbered ruleset of type `type`
     +   *
    

    【讨论】:

      【解决方案4】:

      您的 2 个补丁上的 GNU interdiff 失败,因为它们没有直接的公共基础/父级。

      虽然git range-diff 产生差异的外部差异(通常难以阅读;不知道/不一致关于先前提交中已使用/合并的更改;不是适用的补丁格式),您可以获得有效且易读的 interdiff通过将一个提交的副本合并到另一个(最好是较新的)提交的父级上。有几种方法。

      在您的示例中将&lt;New commit 1&gt;&lt;Old commit 1&gt; 进行比较是很简单的,因为它们已经有一个直系共同父母

      diff NC1 OC1
      

      进一步远离共同基础,根据您的实际问题,我们得到它例如这样:

      # move to the parent of NC3 - entering detached HEAD state
      git checkout NC3~1
      # merge-rebase the single patch <Old-commit-3> onto here
      git cherry-pick OC3
      # show the diff or reverse diff (or diff in gitk GUI)
      git diff -R NC3
      # back to feature_branch
      git checkout feature_branch
      

      当然,这里可能会出现合并冲突——然后(必然)暴露出与“虚拟公共基础”的一种 interdiff 不兼容的更改,因为缺少真正的直接公共父级。

      可以创建一个(临时)标签或分支来保存这个重新设置的比较提交(或提交范围)——例如与其他用户讨论和工作。否则临时未引用的悬空提交将很快被自动回收。

      【讨论】:

        【解决方案5】:

        也许这会给你想要的东西。但是如果提交 1-2-3 非常依赖,它将失败。

        $ git checkout 'old commit 2'
        $ git cherry-pick -n 'new commit 3'
        $ git diff 'old commit 3'
        
        $ git checkout 'new commit 2'
        $ git cherry-pick -n 'old commit 3'
        $ git diff 'new commit 3'
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-04-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多