简体中文 ▾ 主题 ▾ 最新版本 ▾ git-range-diff 最后更新于 2.52.0

名称

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

概要

git range-diff [--color=[<when>]] [--no-color] [<diff-options>]
	[--no-dual-color] [--creation-factor=<factor>]
	[--left-only | --right-only] [--diff-merges=<format>]
	[--remerge-diff]
	( <range1> <range2> | <rev1>…​<rev2> | <base> <rev1> <rev2> )
	[[--] <path>…​]

描述

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

当存在 <path> 参数时,这些提交范围将相应地受到限制。

为此,它首先找到两个提交范围中相互对应的提交对。当两个提交之间的补丁差异(即作者信息、提交消息和提交差异)与补丁大小相比足够小时,这两个提交就被认为是对应的。有关详细信息,请参阅下面的“算法”。

最后,匹配提交的列表会按照第二个提交范围的顺序显示,未匹配的提交会在其所有祖先都显示之后插入。

有三种方法可以指定提交范围

  • <range1> <range2>:任一提交范围都可以是 <base>..<rev><rev>^!<rev>^-<n> 的形式。有关更多详细信息,请参阅 gitrevisions[7] 中的 指定范围

  • <rev1>...<rev2>。这等同于 <rev2>..<rev1> <rev1>..<rev2>

  • <base> <rev1> <rev2>:这等同于 <base>..<rev1> <base>..<rev2>

选项

--no-dual-color

当提交差异不同时,git range-diff 会重新创建原始差异的着色,并添加外部的 -/+ 差异标记,背景为红色/绿色,以便更容易看到例如添加了哪些确切行的更改。

此外,仅存在于第一个提交范围中的提交差异行会显示为“变暗”(可以使用 color.diff.<slot> 配置设置覆盖,其中 <slot>contextDimmedoldDimmednewDimmed 之一),而仅存在于第二个提交范围中的提交差异行会显示为粗体(可以使用 color.diff.<slot> 配置设置覆盖,其中 <slot>contextBoldoldBoldnewBold 之一)。

这被称为 range-diff 的“双重着色”。使用 --no-dual-color 可恢复为根据外部差异标记着色所有行(并在考虑颜色时完全忽略内部差异)。

--creation-factor=<percent>

将创建/删除成本的调整因子设置为 <percent>。默认为 60。如果 git range-diff 错误地将一项大更改视为完全重写(删除一个提交并添加另一个),则尝试使用较大的值;反之,则使用较小的值。有关为什么需要此设置的说明,请参阅下面的“算法”部分。

--left-only

抑制在指定的第一个范围(或使用 <rev1>...<rev2> 格式时的“左范围”)中缺失的提交。

--right-only

抑制在指定的第二个范围(或使用 <rev1>...<rev2> 格式时的“右范围”)中缺失的提交。

--diff-merges=<format>

代替忽略合并提交,使用 git-log[1] 的相应 --diff-merges=<format> 选项为它们生成差异,并将它们包含在比较中。

注意:在常见情况下,remerge 模式将是最自然的选择,因为它仅显示 Git 的合并机制将产生的差异之上的差异。换句话说,如果一个合并提交是非冲突的 git merge 的结果,remerge 模式将用空差异来表示它。

--remerge-diff

便捷选项,等同于 --diff-merges=remerge

--notes[=<ref>]
--no-notes

此标志将传递给生成补丁的 git log 程序(请参阅 git-log[1])。

<range1> <range2>

比较由两个范围指定的提交,其中 <range1> 被视为 <range2> 的旧版本。

<rev1>…​<rev2>

等同于传递 <rev2>..<rev1><rev1>..<rev2>

<base> <rev1> <rev2>

等同于传递 <base>..<rev1><base>..<rev2>。请注意,<base> 不需要是分支的确切分叉点。例如:在 rebase 分支 my-topic 后,git range-diff my-topic@{u} my-topic@{1} my-topic 将显示 rebase 引入的更改。

git range-diff 也接受常规的 diff 选项(请参阅 git-diff[1]),最值得注意的是 --color=[<when>]--no-color 选项。这些选项在生成“补丁之间的差异”时使用,即比较对应旧/新提交的作者、提交消息和差异。目前没有办法调整传递给 git log 以生成这些补丁的大多数 diff 选项。

输出稳定性

range-diff 命令的输出可能会发生变化。它旨在成为人类可读的 porcelain 输出,而不是可以在不同 Git 版本之间使用以获得文本上稳定的 range-diff(与 git-patch-id[1]--stable 选项相反)。也没有 range-diffgit-apply[1] 的等效项,其输出不适合机器读取。

这尤其适用于传递 diff 选项时。目前,某些选项(如 --stat)可能会产生对 range-diff 上下文而言几乎无用的输出。未来版本的 range-diff 可能会学会以 range-diff 特有的方式解释这些选项(例如,对于 --stat,生成人类可读的输出,总结 diffstat 如何改变)。

配置

此命令使用 diff.color.*pager.range-diff 设置(后者默认启用)。请参阅 git-config[1]

示例

当 rebase 需要解决合并冲突时,请立即使用以下命令比较 rebase 引入的更改:

$ git range-diff @{u} @{1} @

git range-diff 的典型输出如下所示:

-:  ------- > 1:  0ddba11 Prepare for the inevitable!
1:  c0debee = 2:  cab005e Add a helpful message at the start
2:  f00dbal ! 3:  decafe1 Describe a bug
    @@ -1,3 +1,3 @@
     Author: A U Thor <author@example.com>

    -TODO: Describe a bug
    +Describe a bug
    @@ -324,5 +324,6
      This is expected.

    -+What is unexpected is that it will also crash.
    ++Unexpectedly, it also crashes. This is a bug, and the jury is
    ++still out there how to fix it best. See ticket #314 for details.

      Contact
3:  bedead < -:  ------- TO-UNDO

在此示例中,有 3 个旧提交和 3 个新提交,其中开发人员删除了第 3 个,在前面两个之前添加了一个新提交,并修改了第 2 个提交的消息及其差异。

当输出到终端时,默认情况下它是带颜色的,就像常规的 git diff 输出一样。此外,第一行(添加提交)是绿色的,最后一行(删除提交)是红色的,第二行(完美匹配)是黄色的,就像 git show 的输出的提交头一样,第三行则将旧提交染成红色,新提交染成绿色,其余的与 git show 的提交头一样。

然而,对差异进行天真的着色实际上有点难以阅读,因为它将整行染成红色或绿色。例如,在旧提交中添加“What is unexpected”的行完全是红色的,即使旧提交的目的是添加某些内容。

为了帮助解决这个问题,range 默认使用 --dual-color 模式。在这种模式下,差异的差异将保留原始的差异颜色,并在行前加上 -/+ 标记,其 **背景** 为红色或绿色,以更清楚地表明它们描述了差异本身如何变化。

算法

总体的思想是:我们生成两个提交范围中提交之间的成本矩阵,然后解决最小成本分配问题。

成本矩阵的填充方式如下:对于每对提交,都会生成两个差异,然后生成“差异的差异”,包含 3 行上下文,然后使用该差异的行数作为成本。

为了避免误报(例如,当一个补丁被删除,而一个不相关的补丁在同一补丁系列的两个迭代之间被添加时),成本矩阵已扩展为允许这种情况,通过为整体删除/添加添加固定成本条目。

示例:假设提交 1--2 是补丁系列的第一迭代,而 A--C 是第二迭代。假设 A2 的 cherry-pick,而 C1 的 cherry-pick,但有一个小的修改(例如,修复了一个拼写错误)。将提交可视化为二分图:

    1            A

    2            B

		 C

我们正在寻找一个“最佳”的解释,用旧的来解释新的系列。我们可以将一个“解释”表示为图中的一条边:

    1            A
	       /
    2 --------'  B

		 C

这个解释是“免费”的,因为没有变化。同样,C 可以用 1 来解释,但这会产生一些成本 c>0,因为有修改:

    1 ----.      A
	  |    /
    2 ----+---'  B
	  |
	  `----- C
	  c>0

用数学术语来说,我们正在寻找一种最小成本二分匹配;1 以某种成本匹配到 C,等等。底层图实际上是一个完整的二分图;我们为每条边关联的成本是两个提交的补丁之间的差异大小。为了解释新的提交,我们在两侧引入了虚拟节点:

    1 ----.      A
	  |    /
    2 ----+---'  B
	  |
    o     `----- C
	  c>0
    o            o

    o            o

o--C 的成本是 C 的差异大小,并由一个调整因子修改,该因子应小于 100%。边 o--o 的成本是免费的。调整因子是必需的,因为即使 1C 没有共同之处,它们也可能共享一些空行等,这可能导致分配 1--Co--o 的成本略低于 1--oo--C,即使 1C 没有共同之处。有了调整因子,我们需要更大的共同部分才能认为补丁是对应的。

计算此算法所需的总时间是计算 n+m 个提交差异所需的时间,再加上 n*m 个补丁差异的差异,再加上计算 n 和 m 个差异之间的最小成本分配所需的时间。Git 使用 Jonker-Volgenant 算法的实现来解决分配问题,该算法具有三次运行时间复杂度。在这种情况下找到的匹配将如下所示:

    1 ----.      A
	  |    /
    2 ----+---'  B
       .--+-----'
    o -'  `----- C
	  c>0
    o ---------- o

    o ---------- o

另请参阅

GIT

Git[1] 套件的一部分