处理混乱的拉取请求差异统计信息¶
子系统维护者通常使用 git request-pull
作为向上游发送工作的一部分。通常,结果会包含一个漂亮的差异统计信息,显示哪些文件将被修改以及每个文件将被修改多少。但是,偶尔,一个开发历史相对复杂的存储库会产生一个包含大量不相关工作的巨大差异统计信息。结果看起来很糟糕,并掩盖了拉取请求实际在做什么。本文档描述了正在发生的事情以及如何解决问题;它源自 Linus Torvalds 的智慧,可以在 Linus1 和 Linus2 中找到。
Git 开发历史以一系列提交的形式进行。简单来说,主线内核开发看起来像这样
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
如果想查看两个点之间发生了什么变化,可以使用如下命令
$ git diff --stat --summary vN-rc2..vN-rc3
这里,历史中有两个清晰的点;Git 本质上会从结束点“减去”起始点,并显示由此产生的差异。请求的操作是明确的,并且很容易理解。
当子系统维护者创建分支并向其中提交更改时,最简单的情况是历史看起来像这样
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
|
+-- c1 --- c2 --- ... --- cN
如果该维护者现在使用 git diff
来查看主线分支(我们称之为“linus”)和 cN 之间发生了什么变化,仍然有两个清晰的端点,结果如预期。因此,使用 git request-pull
生成的拉取请求也将如预期。但是现在考虑一个稍微复杂的开发历史
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
| |
| +-- c1 --- c2 --- ... --- cN
| /
+-- x1 --- x2 --- x3
我们的维护者在 vN-rc1 和 vN-rc2 处分别创建了一个分支;然后将这两个分支合并到 c2 中。现在为 cN 生成的拉取请求可能确实会很混乱,开发人员经常会想知道为什么。
这里发生的事情是 git diff
操作不再有两个清晰的端点可以使用。最终在 cN 中进行的开发从两个不同的地方开始;为了生成差异统计信息,git diff
最终不得不选择其中一个并寄希望于最好的结果。如果差异统计信息从 vN-rc1 开始,它可能最终会包括从那里到第二个起始端点 (vN-rc2) 之间的所有更改,这肯定不是我们的维护者所希望的。在差异统计信息中包含所有这些额外的垃圾后,可能无法分辨出导致 cN 的更改中实际发生了什么。
维护者通常会尝试通过以下方式解决此问题:例如,对分支进行变基或与 linus 分支执行另一次合并,然后重新创建拉取请求。这种方法往往不会让拉取请求的接收端感到高兴;在推送到上游之前进行变基和/或合并是众所周知的获得坏脾气响应的方法。
那么应该怎么做呢?在这种情况下,最好的响应确实是与您打算将工作拉入的分支进行合并,但要私下进行,仿佛它是耻辱的源头。创建一个新的、一次性的分支,并在那里进行合并
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
| | |
| +-- c1 --- c2 --- ... --- cN |
| / | |
+-- x1 --- x2 --- x3 +------------+-- TEMP
合并操作解决了由多个起始点导致的所有复杂问题,产生了一个只包含与主线分支差异的连贯结果。现在可以生成包含所需信息的差异统计信息
$ git diff -C --stat --summary linus..TEMP
保存此命令的输出,然后简单地删除 TEMP 分支;绝对不要将其暴露给外界。获取保存的差异统计信息输出,并将其编辑到混乱的拉取请求中,从而产生一个显示实际情况的结果。然后可以将该请求发送到上游。