處理混亂的拉取請求差異統計¶
子系統維護者通常會使用 git request-pull 作為向上遊提交工作流程的一部分。通常,結果會包含一個清晰的差異統計 (diffstat),顯示哪些檔案將被修改以及每個檔案修改了多少。然而,偶爾,一個開發歷史相對複雜的倉庫會產生一個巨大的差異統計 (diffstat),其中包含大量不相關的工作。結果看起來很難看,並且掩蓋了拉取請求實際的作用。本文件描述了這種情況發生的原因以及如何解決;它源自 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 的開發始於兩個不同的地方;為了生成差異統計 (diffstat),git diff 最終不得不選擇其中一個,然後聽天由命。如果差異統計 (diffstat) 從 vN-rc1 開始,它可能最終會包含從那裡到第二個原始終點 (vN-rc2) 之間的所有更改,這肯定不是我們的維護者所希望的。由於差異統計 (diffstat) 中包含所有這些額外的“垃圾”,可能無法判斷在導致 cN 的更改中實際發生了什麼。
維護者通常會嘗試解決這個問題,例如,透過對分支進行變基操作,或者與 linus 分支進行另一次合併,然後重新建立拉取請求。這種方法往往不會讓拉取請求的接收方感到高興;在向上遊推送之前進行變基和/或合併是一種眾所周知的會招致不滿回應的方式。
那麼該怎麼做呢?當遇到這種情況時,最好的回應確實是與你打算將工作拉入的分支進行合併,但要私下進行,彷彿這是一件見不得人的事情。建立一個新的、臨時的分支,並在那裡進行合併
... vM --- vN-rc1 --- vN-rc2 --- vN-rc3 --- ... --- vN-rc7 --- vN
| | |
| +-- c1 --- c2 --- ... --- cN |
| / | |
+-- x1 --- x2 --- x3 +------------+-- TEMP
合併操作解決了由多個起始點引起的所有複雜問題,從而產生了一個只包含與主線分支差異的連貫結果。現在就可以生成包含所需資訊的差異統計 (diffstat) 了
$ git diff -C --stat --summary linus..TEMP
儲存此命令的輸出,然後簡單地刪除 TEMP 分支;千萬不要將其暴露給外界。將儲存的差異統計 (diffstat) 輸出編輯到混亂的拉取請求中,從而產生一個顯示實際情況的結果。然後就可以將該請求傳送到上游了。