TL;DR
使用git range-diff——在本例中为git range-diff origin/dev...dev(注意此处的三个点)。
长(ish)
首先,让我们绘制设置。以下是两组提交,如您自己的存储库中所示:
F'-G'-H' <-- dev
/
...--D--E
\
F--G--H <-- origin/dev
提交F、G 和H——这里的字母代表真正的哈希ID,它们太大太丑了——是你工作之前的原始三个;它们新的和改进的替代品分别是 F-prime、G-prime 和 H-prime。
通过仅比较这两个提交来比较最终结果非常容易:git diff dev origin/dev 或 git diff origin/dev dev 将比较提交 H 和 H'(dev 选择 H' , origin/dev 选择 H)。但这不是你想要的,不是真的:
- 您想先比较
F 和F';那么
- 您想比较
G 与G';最后
- 您想比较
H 与 H'。
单个git diff 命令只能生成这三个命令中的最后一个。
蛮力解决方案是自己运行三个git diffs,一次一个。要命名提交F',可以写dev~2;要命名 commit G',你可以写成 dev~1(或 dev~ 或 dev^——所有这些都有效;有关更多信息,请参阅 the gitrevisions documentation)。要将提交命名为F,请使用origin/dev~2,依此类推。
不过,从 Git 2.19 开始,就有一个新命令可以为您执行此操作。如上面的 TL;DR 中所述,这是 git range-diff。
range-diff 命令需要知道要比较的两个范围。您可以明确地将它们提供给它:
git range-diff origin/dev~3..origin/dev dev~3..dev
我们在这里使用~3,而不是~2,因为用两点.. 表示法表示的范围在数学上是半开区间:它们包括最终提交,但不包括开始提交。 (在心理上,你可以认为这需要在结果中提交三个提交,因此 X~3..X。这是 (X~3 .. X] 的事实当然很重要,因为 [X~3 .. X ) 将忽略范围的错误结束,但无论哪种方式,半开间隔都会补偿通常的 fencepost error。)再次,请参阅 gitrevisions。
不过,在这种情况下更简单的是,我们可以使用 三个-点表示法,git range-diff 会稍微特别处理它。如gitrevisions 文档中所述,三点符号表示集合论方面的对称差分操作,因此:
git range-diff origin/dev...dev
暗示该命令应该检查可通过或者origin/dev 访问的提交——即,在后面提交H——或 dev,即,提交@987654368 @ 背面;但应该不检查可从两个名称访问的提交,即提交E 和更早的时间。所以这会准确选择所需的两组提交:F-G-H 和 F'-G'-H'。
范围的乐趣
那么,剩下的问题是:
-
这是如何工作的? 为什么我们不必在任何地方提及X~3,对于某些X?
-
这些顺序是否正确?如果不是,您将获得一个范围差异,描述从您的新提交和改进提交(可能是由 rebase 产生)到旧的和糟糕的。
让我们先解决问题 1,然后解决问题 2。我们实际上已经回答了问题 1,但只是求助于集合论,这对某些人来说可能并不熟悉。
Symmetric difference 是根据集合定义的:它是并集减去交集。给定两个集合 A 和 B,对称差 A⊖B 或 AΔB 可以计算为A∖B (读作“A 排除 B”)和 B∖A 的并集(或等效地,作为从 中减去交集的结果 em> 工会,这是我自己通常的想法,并在此先声明)。
在上面,我们写道:从dev 可到达的所有提交的集合,不包括从dev~3 可到达的所有提交的集合。那是我们的dev~3..dev。这是从E 开始的每个提交并向后工作 从H' 开始的每个提交并向后工作的非常精确的方法 .但毕竟我们不必那么精确。我们可以偷懒,说:从H' 开始的每个提交并向后工作,剥离从H 开始的每个提交并向后工作。而F-G-H 不在中 那个集合,要求把它们从那个集合中剥离出来是无害的:A∖B 不需要 B 中的东西在 A 首先。
因此,我们可以使用origin/dev..dev 来代替dev~3..dev,从E 向后删除提交。当然origin/dev 需要输入十个字符,而dev~3 只有五个字符,所以我们在这里并没有什么收获。
问题是,出于同样的原因,我们可以写 dev..origin/dev 以从向后提交的 H 中排除 E 的 commits-backwards-from。这一次它确实节省了一些输入,而且——更好的是——如果我们有某种符号让我们只需输入 A 和 B 在这里,我们只需键入每个名称一次。 这是我们的对称差分符号,因此我们可以只输入origin/dev...dev(三个点)或dev...origin/dev(仍然是三个点)。
现在让我们解决问题 2,获得正确的顺序。我们现在咨询the git range-diff documentation,上面写着:
<rev1>...<rev2>
相当于通过<rev2>..<rev1>和<rev1>..<rev2>。
现在,我最初建议:
git range-diff origin/dev~3..origin/dev dev~3..dev
也就是说,我们将 old 范围的提交放在第一位,new 范围的提交放在第二位。如果我们运行:
git range-diff origin/dev...dev
那么<rev2>就是dev,所以“等价于”部分就变成了:
git range-diff dev..origin/dev origin/dev..dev
这使用了第 1 项中的技巧来制作两个单独的范围表达式,并确保 second 范围表达式——它确定哪些提交是“新的”——以指定的 秒结束rev,即dev。所以origin/dev...dev 是正确的顺序。