9

我正在尝试查看 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 的修订。

4

5 回答 5

11

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

有关 range-diff 的更多信息,请参阅官方文档

于 2018-09-11T14:49:44.210 回答
5

也许是这样的:

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

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

diff <(git log -p -1 old_commits) <(git log -p -1 new_commits)
于 2013-07-22T17:41:08.380 回答
1

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

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`
 +   *
于 2015-02-13T12:40:40.447 回答
1

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

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

在您的示例中进行比较是微不足道<New commit 1>的,<Old commit 1>因为它们已经有一个直接的共同父母

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 不兼容的更改,因为缺少真正的直接公共父级。

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

于 2020-10-27T00:25:56.410 回答
0

也许这会给你一些你想要的东西。但如果提交 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'
于 2013-07-22T16:45:45.770 回答