处理混乱的拉取请求差异统计
子系统维护者通常在将工作发送到上游的过程中使用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的更改中实际发生了什么。
维护者通常尝试通过重新基于分支或在将其推送到上游之前执行另一个合并来解决这个问题,然后重新创建拉取请求。这种方法往往不会在接收拉取请求的一方带来愉快的回应;在推送到上游之前进行变基和/或合并是一种众所周知的导致不满的方式。
那么应该怎么办呢?当面对这种情况时,最好的反应确实是与你打算将你的工作合并到的分支进行合并,但要将其作为一种耻辱的来源进行私下处理。创建一个新的、一次性的分支,并在那里进行合并:
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN | | | | +-- c1 --- c2 --- ... --- cN | | / | | +-- x1 --- x2 --- x3 +------------+-- TEMP
合并操作解决了由多个起始点导致的所有复杂性,产生了一个只包含与主线分支的差异的连贯结果。现在可以使用所需信息生成差异统计:
$ git diff -C --stat --summary linus..TEMP SCSS 复制 全屏
保存此命令的输出,然后简单地删除TEMP分支;绝对不要将其暴露给外界。将保存的差异统计输出编辑到混乱的拉取请求中,得到一个真实反映正在发生的情况的结果。然后可以将该请求发送到上游。