Git
简体中文 ▾ Topics ▾ Latest version ▾ git-range-diff last updated in 2.43.0

名称

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

概述

git range-diff [--color=[<when>]] [--no-color] [<diff-options>]
	[--no-dual-color] [--creation-factor=<factor>]
	[--left-only | --right-only]
	( <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`会重现原始差异的颜色,并添加外层的 -/+ 差异标记,背景 为红/绿色,以便于查看,例如,当具体添加了哪些行时。

此外,只出现在第一个提交范围内的提交差异行会显示为 "dimmed"(这可以使用 color.diff. <slot> 配置设置,其中 <slot> 是`contextDimmed`、oldDimmednewDimmed 中的一个),而仅出现在第二个提交范围内的提交差异行以粗体显示(这可以通过配置设置 color.diff.<slot> 来覆盖,其中 <slot>contextBoldoldBoldnewBold 中的一个)。

这在 range-diff 中被称为 "双重着色"。使用 --no-dual-color 可以还原为根据外部差异标记对所有线条着色(在着色时完全忽略内部差异)。

--creation-factor=<百分比>

Set the creation/deletion cost fudge factor to <percent>. Defaults to 60. Try a larger value if git range-diff erroneously considers a large change a total rewrite (deletion of one commit and addition of another), and a smaller one in the reverse case. See the ``Algorithm`` section below for an explanation of why this is needed.

--left-only

忽略第一个指定范围(或使用 <rev1>...<rev2> 格式时的 "左侧范围")中丢失的提交。

--right-only

忽略第二个指定范围(或使用 <rev1>...<rev2> 格式时的 "右侧范围")中丢失的提交。

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

这个标志将传递给生成补丁的 git log 程序(参见 git-log[1])。

<range1> <range2>

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

<rev1>…​<rev2>

相当于传递 <rev2>...<rev1><rev1>...<rev2>

<base> <rev1> <rev2>

等同于传递 <base>...<rev1><base>...<rev2>。 注意 <base> 不需要是分支的确切分支点。例如: 在重定向分支 my-topic 之后, git range-diff my-topic@{u} my-topic@{1} my-topic 将显示重定向带来的差异。

git range-diff 也接受常规的 diff 选项 (参见 git-diff[1]),特别是 --color=[<when>]--no-color 选项。这些选项用于生成 “补丁间的差异”,即比较新旧提交的作者、提交信息和差异。目前还没有办法调整生成补丁时传递给 git log 的大部分 diff 选项。

输出稳定性

range-diff 命令的输出可能会改变。它的目的是提供人类可读的上层命令输出,而不是可以在不同版本的 Git 中使用以获得文本稳定的 range-diff (与 git-patch-id[1]--stable 选项不同)。对于 range-diff 来说,也没有与 git-apply[1] 等价的东西,其输出不是机器可读的。

当传递 diff 选项时尤其如此。目前,一些选项,例如 --stat,会在 range-diff 的上下文中产生无用的输出。未来版本的 range-diff 可能会学习如何以 range-diff 特有的方式来解释这些选项 (例如, --stat 产生人类可读的输出,总结了 diffstat 的变化情况)。

配置

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

实例

当重置需要解决合并冲突时,直接比较重置后引入的更改,使用 :

$ 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.

    -+出乎意料的是,它也会崩溃。
    ++出乎意料的是,它也会崩溃。这是一个bug,陪审团还在讨论如何最好地修复它。
    ++如何最好地修复它,还没有定论。详见 #314 号记录。

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

In this example, there are 3 old and 3 new commits, where the developer removed the 3rd, added a new one before the first two, and modified the commit message of the 2nd commit as well as its diff.

当输出到终端时,默认是用颜色编码的,就像普通的 git diff 输出一样。此外,第一行(添加提交)是绿色的,最后一行(删除提交)是红色的,第二行(完全匹配)是黄色的,就像 git show 输出的提交头一样,第三行旧提交是红色的,新提交是绿色的,其余的就像 git show 的提交头一样。

不过,用颜色编码的原 diff 实际上有点难读,因为它会把整行都染成红色或绿色。例如,在旧提交中添加了 "What is unexpected" 的那行就完全是红色的,即使旧提交的意图是添加一些东西。

为了解决这个问题,range 默认使用 --dual-color 模式。在这种模式下,diffs 的 diff 将保留原始的 diff 颜色,并在行的前缀加上 -/+ 标记,其 背景 为红色或绿色,以便更明显地描述 diff 本身是如何改变的。

算法

总体思路是这样的:我们在两个提交范围内的提交之间生成一个成本矩阵,然后求解最小成本分配。

成本矩阵是这样填充的:对于每一对提交,生成两个差异,并生成 “差异的差异”,其中包含 3 行上下文,然后将差异中的行数作为成本。

为了避免假阳性(例如,当一个补丁被删除,而在同一补丁系列的两次迭代之间又添加了一个不相关的补丁),成本矩阵通过为整体删除/添加添加固定成本条目进行扩展,以考虑到这一点。

示例: 假设 1--2 是补丁系列的第一次迭代,A--C`是第二次迭代。假设 `A`是从 `2 中挑选出来的,而 C 是从 1 中挑选出来的,但做了一点修改(比如,一个固定的错别字)。将提交可视化为一个二元图:

    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--C, o--o1--o, o--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] 文档

scroll-to-top