微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何 git diff 分歧分支 TL;DR长ish有趣的范围

如何解决如何 git diff 分歧分支 TL;DR长ish有趣的范围

我在我的分支上重写了一些提交历史,所以我的分支与远程分支不同:

Switched to branch 'dev'
Your branch and 'origin/dev' have diverged,and have 3 and 3 different commits each,respectively.

是否有一种简单的方法可以在不同版本(即我的本地分支和远程分支)之间git diff

我知道我可以使用 git diff commit1..commit2 来区分 2 个提交,但在这种情况下,我想区分我分支上的三个本地提交和三个远程提交。

解决方法

使用 git fetch 获取后

git diff <mainbranch_path> <remotebranch_path>

例如git diff develop origin/develop

,

TL;DR

使用 git range-diff——在本例中为 git range-diff origin/dev...dev(注意这里的三个点)。

长(ish)

首先,让我们绘制设置。以下是两组提交,如在您自己的存储库中所见:

          F'-G'-H'  <-- dev
         /
...--D--E
         \
          F--G--H   <-- origin/dev

提交 FGH——这里的字母代表真实的哈希 ID,它们太大太丑了,无法打扰——是之前的三个你做了你的工作;他们新改进的替代品分别是 F-prime、G-prime 和 H-prime。

通过仅比较这两个提交来比较最终结果非常容易:git diff dev origin/devgit diff origin/dev dev 将比较提交 HH'dev 选择 H'origin/dev 选择 H)。但这不是你想要的,不是真的:

  • 您想先比较 FF';然后
  • 您想比较 GG';最后
  • 您想比较 HH'

单个 git diff 命令只能生成这三个中的最后一个。

暴力解决方案是自己运行三个 git diff,一次一个。要命名提交 F',您可以编写 dev~2;要命名提交 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,因为用两点 .. 表示法表示的范围在数学上是半开区间:它们包括最终提交,但不包括开始提交。 (在心理上,您可以将其视为想要在结果中进行 3 次提交,因此 X~3..X。事实是 (X~3 .. X] 当然很重要,因为 [X~3 .. X ) 会忽略范围的错误结束,但无论哪种方式,半开区间都会补偿通常的 fencepost error。) 再次参见 gitrevisions

在这种情况下更容易,不过,我们可以使用 -dot 表示法,git range-diff 稍微特殊处理。如 gitrevisions 文档中所述,三点表示法意味着在集合论方面的对称差运算,因此:

git range-diff origin/dev...dev

暗示该命令应该检查由要么 origin/dev 可访问的提交——即,在后面提交H—— dev ,即在背面提交 H';但应该检查可从两个名称访问的提交,即提交 E 及更早。因此,这正好选择了所需的两组提交:F-G-HF'-G'-H'

有趣的范围

剩下的问题是:

  1. 这是如何工作的?为什么我们不必在任何地方提及 X~3,对于某些 X

  2. 这些顺序是否正确?如果不正确,您将得到一个范围差异,它描述了从新的和改进的提交中向后的情况——可能是由于 rebase ——致那些又老又烂的人。

让我们先解决问题 1,然后解决问题 2。我们实际上已经回答了问题 1,但只是借助了一些人可能不熟悉的集合论。

Symmetric difference 是根据集合定义的:它是联合减去交集。给定两个集合AB,对称差A⊖BAΔ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

因此,我们可以使用 dev~3..dev 代替 origin/dev..dev 向后去除 E 中的提交。当然,origin/dev 需要输入 10 个字符,而 dev~3 只有 5 个字符,所以我们在这里没有真正获得任何东西。

问题是,出于同样的原因,我们可以编写 dev..origin/dev 以从向后从 H 提交中排除向后提交 E。这次它确实节省了一些输入,而且——甚至更好——如果我们有某种符号让我们只需输入AB 在这里,我们只需键入每个名称一次。 这是我们的对称差分符号,因此我们可以只输入 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 范围的提交放在第一位, 范围的提交放在第二位。如果我们运行:

git range-diff origin/dev...dev

那么 <rev2>dev,所以“相当于”部分变成:

git range-diff dev..origin/dev origin/dev..dev

这使用了第 1 项中的技巧来制作两个单独的范围表达式,并确保 second 范围表达式(确定哪些提交是“新的”)以指定的 second 结尾rev,即dev。所以 origin/dev...dev 是正确的顺序。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。