5. 釋出補丁

遲早,您的工作將準備好提交給社群進行審查,並最終納入主線核心。不出所料,核心開發社群已經發展出一套用於釋出補丁的慣例和程式;遵循這些慣例和程式將使所有相關人員的工作變得更加輕鬆。本文件將嘗試詳細涵蓋這些期望;更多資訊還可以在檔案 Documentation/process/submitting-patches.rstDocumentation/process/submit-checklist.rst 中找到。

5.1. 何時釋出

總有一種誘惑,想等到補丁完全“準備好”再發布。對於簡單的補丁,這沒什麼問題。然而,如果正在進行的工作很複雜,那麼在工作完成之前從社群獲得反饋將受益匪多。因此,您應該考慮釋出正在進行的工作,甚至公開一個 git 樹,以便感興趣的開發人員可以隨時瞭解您的工作進展。

在釋出尚未準備好納入的程式碼時,最好在釋出內容中明確說明。還要提及任何尚未完成的主要工作以及任何已知問題。知道補丁不成熟的人會較少關注,但那些關注的人會抱著幫助您將工作引向正確方向的想法。

5.2. 建立補丁之前

在考慮向開發社群傳送補丁之前,有一些事情應該做。其中包括

  • 儘可能測試程式碼。利用核心的除錯工具,確保核心能以所有合理的配置選項組合進行構建,使用交叉編譯器為不同架構進行構建等。

  • 確保您的程式碼符合核心編碼風格指南。

  • 您的更改是否對效能有影響?如果是,您應該執行基準測試,顯示您的更改的影響(或益處);結果摘要應包含在補丁中。

  • 確保您有權釋出程式碼。如果此工作是為僱主完成的,僱主可能對該工作擁有權利,並且必須同意在 GPL 下發布。

一般來說,在釋出程式碼之前多花一點心思,幾乎總能很快得到回報。

5.3. 補丁準備

準備釋出補丁可能是一項出乎意料的工作量,但再一次強調,即使短期內,試圖在此處節省時間通常也是不明智的。

補丁必須針對特定版本的核心準備。一般來說,補丁應該基於 Linus 的 git 樹中當前的主線版本。當基於主線時,應從一個眾所周知的釋出點(如穩定版或 -rc 版本)開始,而不是從主線的任意位置分支。

不過,為了促進更廣泛的測試和審查,可能需要針對 -mm、linux-next 或子系統樹製作版本。根據您的補丁所涉及的領域以及其他地方正在發生的事情,基於這些其他樹的補丁可能需要大量工作來解決衝突和處理 API 更改。

只有最簡單的更改應該格式化為單個補丁;其他所有更改都應該製作成一個邏輯上的系列。拆分補丁是一門藝術;一些開發人員花很長時間才弄清楚如何以社群期望的方式進行。然而,有一些經驗法則可以提供很大幫助

  • 您釋出的補丁系列幾乎肯定不會是您工作版本控制系統中找到的更改系列。相反,您所做的更改需要以最終形式進行考慮,然後以有意義的方式進行拆分。開發人員感興趣的是離散的、獨立的更改,而不是您達到這些更改所採取的路徑。

  • 每個邏輯上獨立的更改都應該格式化為單獨的補丁。這些更改可以很小(“為此結構新增一個欄位”)或很大(例如,新增一個重要的新驅動程式),但它們在概念上應該很小,並且能夠用一行描述。每個補丁都應該進行一個特定的更改,可以獨立審查並驗證其確實如其所說。

  • 重申上述指導原則:不要在同一個補丁中混合不同型別的更改。如果一個補丁同時修復了一個關鍵安全漏洞、重新排列了一些結構並重新格式化了程式碼,那麼它很有可能被忽略,重要的修復將丟失。

  • 每個補丁都應該生成一個能夠正確構建和執行的核心;如果您的補丁系列中途被中斷,結果仍然應該是一個可工作的核心。當使用“git bisect”工具查找回歸時,部分應用補丁系列是一個常見場景;如果結果是損壞的核心,您將使那些從事追蹤問題這項崇高工作的開發人員和使用者的生活更加艱難。

  • 但是不要過度。一位開發人員曾將一個檔案的編輯作為 500 個單獨的補丁釋出——這一行為並沒有讓他成為核心郵件列表上最受歡迎的人。只要單個補丁仍然包含一個邏輯上的更改,它就可以合理地大。

  • 引入一個全新基礎設施並將其作為一系列補丁新增,但直到系列中最後一個補丁才啟用整個功能,這可能很誘人。如果可能,應避免這種誘惑;如果該系列引入了迴歸,二分查詢會將最後一個補丁識別為導致問題的補丁,即使真正的錯誤在其他地方。只要可能,新增新程式碼的補丁應該立即啟用該程式碼。

在“真正的工作”完成後,努力建立完美的補丁系列可能是一個令人沮喪的過程,需要花費相當多的時間和思考。然而,如果做得好,這些時間是值得的。

5.4. 補丁格式和變更日誌

現在您有了一系列完美的補丁可以釋出,但工作還沒有完全完成。每個補丁都需要格式化成一條訊息,以便快速清晰地向外界傳達其目的。為此,每個補丁將由以下部分組成

  • 可選的“From”行,指明補丁的作者。此行僅在您透過電子郵件轉發他人補丁時才需要,但如有疑問,新增它也無妨。

  • 補丁作用的單行描述。這條訊息應該足以讓讀者在沒有其他上下文的情況下弄清楚補丁的範圍;它是在“簡短形式”變更日誌中顯示的行。此訊息通常以相關子系統名稱開頭,後跟補丁的目的。例如

    gpio: fix build on CONFIG_GPIO_SYSFS=n
    
  • 一個空行,後面是補丁內容的詳細描述。此描述可以根據需要儘可能長;它應該說明補丁的作用以及為什麼應該將其應用於核心。

  • 一個或多個標籤行,其中至少包含補丁作者的 Signed-off-by: 行。標籤將在下面更詳細地描述。

上述各項共同構成了補丁的變更日誌。編寫良好的變更日誌是一項至關重要但常被忽視的藝術;值得花時間再討論一下這個問題。編寫變更日誌時,您應該記住會有許多不同的人閱讀您的文字。其中包括需要決定補丁是否應被納入的子系統維護者和審查員、試圖決定補丁是否應回溯到其他核心的發行商和其他維護者、懷疑補丁是否是他們正在追蹤的問題原因的漏洞獵人、想知道核心如何更改的使用者等等。一個好的變更日誌以最直接和簡潔的方式向所有這些人傳達所需的資訊。

為此,摘要行應儘可能在單行限制內描述更改的效果和動機。詳細描述可以隨後闡述這些主題並提供任何所需的額外資訊。如果補丁修復了一個錯誤,如果可能,請引用引入該錯誤的提交(在引用提交時請同時提供提交 ID 和標題)。如果問題與特定的日誌或編譯器輸出相關聯,請包含該輸出以幫助其他人尋找相同問題的解決方案。如果更改旨在支援後續補丁中的其他更改,請說明。如果內部 API 發生更改,請詳細說明這些更改以及其他開發人員應如何響應。總的來說,您越能設身處地為將閱讀您的變更日誌的每個人著想,該變更日誌(以及整個核心)就會越好。

毋庸置疑,變更日誌應該是將更改提交到版本控制系統時使用的文字。它後面將是

  • 補丁本身,採用統一(“-u”)補丁格式。使用 diff 的 “-p” 選項會將函式名與更改關聯起來,使生成的補丁更易於他人閱讀。

上面已經簡要提及的標籤用於提供補丁是如何產生的見解。它們在 Documentation/process/submitting-patches.rst 文件中詳細描述;下面是簡要總結。

一個標籤用於引用引入補丁所修復問題的早期提交

Fixes: 1f2e3d4c5b6a ("The first line of the commit specified by the first 12 characters of its SHA-1 ID")

另一個標籤用於連結包含額外背景或詳細資訊的網頁,例如導致該補丁的早期討論,或由該補丁實現規範的文件

Link: https://example.com/somewhere.html  optional-other-stuff

許多維護者在應用補丁時也會新增此標籤,以連結到補丁的最新公開審查釋出;這通常由 b4 等工具或像‘配置 Git’中所述的 git 鉤子自動完成。

如果 URL 指向補丁正在修復的公開錯誤報告,請使用“Closes:”標籤代替

Closes: https://example.com/issues/1234  optional-other-stuff

一些錯誤跟蹤系統能夠在應用帶有此類標籤的提交時自動關閉問題。一些監控郵件列表的機器人也可以跟蹤此類標籤並採取某些行動。禁止使用私有錯誤跟蹤系統和無效 URL。

另一種標籤用於記錄誰參與了補丁的開發。每種標籤都使用這種格式

tag: Full Name <email address>  optional-other-stuff

常用標籤有

  • Signed-off-by: 這是開發人員證明其有權提交補丁以納入核心的宣告。它是一份對《開發者原始貢獻證書》的認可,其全文可在 Documentation/process/submitting-patches.rst 中找到。沒有適當簽名的程式碼不能合併到主線中。

  • Co-developed-by: 表明該補丁由多位開發人員共同建立;當多人協作一個補丁時,它用於向共同作者(除了 From: 標籤歸屬的作者之外)致謝。每個 Co-developed-by: 後面必須緊跟著相應的共同作者的 Signed-off-by:。詳細資訊和示例可在 Documentation/process/submitting-patches.rst 中找到。

  • Acked-by: 表示另一位開發人員(通常是相關程式碼的維護者)同意該補丁適合納入核心。

  • Tested-by: 表明指定人員已測試該補丁並發現其正常工作。

  • Reviewed-by: 指定的開發人員已審查補丁的正確性;更多詳情請參閱 Documentation/process/submitting-patches.rst 中的審查員宣告。

  • Reported-by: 指明報告了此補丁所修復問題的一位使用者;此標籤用於表彰那些測試我們的程式碼並在程式碼不正確時告知我們的(常被低估的)人。請注意,除非報告在網上不可用,否則此標籤後面應跟一個指向該報告的 Closes: 標籤。如果補丁修復了所報告問題的一部分,則可以使用 Link: 標籤代替 Closes:。

  • Suggested-by: 標籤表明補丁的想法是由指定人員提出的,並確保將功勞歸於該想法的提出者。這有望激勵他們在未來再次幫助我們。

  • Cc: 指定人員收到了補丁的副本並有機會對其發表評論。

在您的補丁中新增上述標籤時請務必小心,因為除 Cc:、Reported-by: 和 Suggested-by: 外,所有標籤都需要獲得指定人員的明確許可。對於這三個標籤,如果該人員根據 lore 檔案或提交歷史記錄使用該姓名和電子郵件地址為 Linux 核心做出了貢獻——並且在 Reported-by: 和 Suggested-by: 的情況下是在公開場合進行的報告或建議——那麼隱式許可就足夠了。請注意,bugzilla.kernel.org 在此意義上是一個公共場所,但那裡使用的電子郵件地址是私有的;因此,除非該人員在早期的貢獻中使用了這些地址,否則不要在標籤中公開它們。

5.5. 傳送補丁

在您傳送補丁之前,還有幾件事需要注意

  • 您確定您的郵件客戶端不會損壞補丁嗎?那些被郵件客戶端隨意新增空格或進行換行的補丁將無法在另一端應用,並且通常不會被詳細檢查。如果存有任何疑問,請將補丁傳送給自己,並確認它完整無損地顯示。

    Documentation/process/email-clients.rst 包含一些關於如何使特定郵件客戶端適用於傳送補丁的有用提示。

  • 您確定您的補丁沒有愚蠢的錯誤嗎?您應該始終使用 scripts/checkpatch.pl 檢查補丁並解決它提出的問題。請記住,checkpatch.pl 雖然體現了對核心補丁外觀的相當多的思考,但它並不比您聰明。如果修復 checkpatch.pl 的抱怨會使程式碼變差,請不要這樣做。

補丁應始終以純文字形式傳送。請不要以附件形式傳送;那樣會使審閱者在回覆中引用補丁的某些部分變得更加困難。相反,只需將補丁直接放入您的訊息中。

郵寄補丁時,重要的是將副本傳送給任何可能對其感興趣的人。與其他一些專案不同,核心鼓勵人們寧可多發也不要少發;不要以為相關人員會在郵件列表中看到您的釋出。特別是,副本應傳送給

  • 受影響子系統的維護者。如前所述,MAINTAINERS 檔案是查詢這些人的首選之地。

  • 一直在同一領域工作的其他開發人員——特別是那些現在可能正在那裡工作的開發人員。使用 git 檢視還有誰修改了您正在處理的檔案會有所幫助。

  • 如果您正在回覆錯誤報告或功能請求,請也抄送原發帖人。

  • 傳送一份副本到相關的郵件列表,或者,如果沒有其他適用的,傳送到 linux-kernel 列表。

  • 如果您正在修復一個錯誤,請考慮該修復是否應該包含在下一個穩定更新中。如果是,stable@vger.kernel.org 應該收到一份補丁副本。此外,在補丁本身的標籤中新增“Cc: stable@vger.kernel.org”;這將在您的修復進入主線時通知穩定團隊。

在選擇補丁接收者時,最好有一個您認為最終會接受併合並該補丁的人。雖然可以直接將補丁傳送給 Linus Torvalds 並讓他合併,但通常不會這樣做。Linus 很忙,並且有子系統維護者負責核心的特定部分。通常您會希望該維護者合併您的補丁。如果沒有明確的維護者,Andrew Morton 常常是最後的補丁目標。

補丁需要好的主題行。補丁行的規範格式如下所示

[PATCH nn/mm] subsys: one-line description of the patch

其中“nn”是補丁的序號,“mm”是系列中的補丁總數,“subsys”是受影響子系統的名稱。顯然,對於單個獨立的補丁,可以省略 nn/mm。

如果您有大量補丁系列,通常會發送一個介紹性描述作為第零部分。不過,這種慣例並非普遍遵循;如果您使用它,請記住介紹中的資訊不會進入核心變更日誌。因此,請確保補丁本身具有完整的變更日誌資訊。

一般來說,多部分補丁的第二部分及後續部分應作為對第一部分的回覆傳送,以便它們在接收端全部串聯起來。像 git 和 quilt 這樣的工具具有傳送帶有正確執行緒的補丁集的命令。但是,如果您有一個很長的系列並且正在使用 git,請避免使用 --chain-reply-to 選項,以免建立異常深的巢狀。