如何获得这两个git提交之间的差异?

2nc8po8w  于 2023-02-07  发布在  Git
关注(0)|答案(5)|浏览(176)

我试图在git中查看同一个提交的两个版本之间的差异。基本上,这是一个差异的差异。从我目前所读到的,这被称为“interdiff”。我读过一些关于如何创建git补丁的interdiff的教程,但我还没有能够让这些方法在我的特定情况下工作。
这里有两个分支,每个分支的提交略有不同:

* 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实用程序运行它们,但我得到的是这样的:
我不太明白那是什么意思,所以我现在有点卡住了。我该怎么办?
注意:我不是在这里寻找git diff old_commits new_commits,我不希望输出中包含提交1和2的修订。

vm0i2vca

vm0i2vca1#

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> )

描述

这个命令显示补丁系列的两个版本之间的差异,或者更一般地说,显示两个提交范围(忽略合并提交)。
为此,它首先从两个提交范围中找到相互对应的提交对。当两个提交的补丁之间的差异(即作者信息,提交信息和提交差异)与补丁的大小相比相当小时,这两个提交就被认为是对应的。
最后,匹配提交的列表按照第二个提交范围的顺序显示,不匹配的提交会在所有祖先提交显示之后插入。
因此,在您的情况下:

git range-diff base old_commits new_commits

会自动匹配old_commits分支中的提交和new_commits分支中的提交,并显示每个提交之间的差异摘要。
或者,如果你只想得到每个分支上一次提交的修改,你可以运行:

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

从Git 2.31开始,你可以使用更简洁的形式来描述单次提交:

git range-diff old_commits^! new_commits^!

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

7jmck4yq

7jmck4yq2#

也许是这样的:

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)
qqrboqgw

qqrboqgw3#

如果两个提交之间没有什么区别,那么比较删除的行和添加的行(即只比较以+或-开头的行)是有效的,它可以消除以@@开头的块边界或提交消息主体带来的噪音:

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`
 +   *
vyu0f0g1

vyu0f0g14#

你的两个补丁上的GNU相互差异失败了,因为它们没有直接的公共基础/父补丁。
git range-diff产生一个diffs的外部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

当然,合并冲突可能会在这里出现--由于缺乏真实的的直接公共父项,这(必然)会暴露与“虚拟公共库”的一种相互差异不兼容的更改。
可以创建一个(临时的)标签或分支来保存这个重定基的 * 比较提交 *(或提交范围)--例如,用于与其他用户讨论和工作。否则,临时的未引用的悬空提交很快就会被自动回收。

ldioqlga

ldioqlga5#

也许这会给予你想要的东西,但是如果提交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'

相关问题