7. 高階主題¶
到目前為止,希望您已經掌握了開發流程的運作方式。然而,仍有更多內容需要學習!本節將介紹一些對希望成為 Linux 核心開發流程常客的開發者有用的主題。
7.1. 使用 Git 管理補丁¶
核心的分散式版本控制始於2002年初,當時 Linus 首次試用專有的 BitKeeper 應用程式。儘管 BitKeeper 備受爭議,但它所體現的軟體版本管理方法無疑並非如此。分散式版本控制使得核心開發專案得以立即加速。目前,BitKeeper 有多種免費替代方案。無論好壞,核心專案已選擇 Git 作為其首選工具。
使用 Git 管理補丁可以大大簡化開發者的工作,尤其是在補丁數量增加時。Git 也有其粗糙之處並帶來某些風險;它是一個年輕而強大的工具,仍在被其開發者不斷完善。本文件不會嘗試教讀者如何使用 Git;那本身就足以寫成一篇長篇文件。相反,本文的重點將放在 Git 如何特別是如何融入核心開發流程中。希望快速掌握 Git 的開發者可以在以下網址找到更多資訊:
以及網路上各種教程。
首要任務是閱讀上述網站並對 Git 的工作原理有一個紮實的理解,然後才能嘗試使用它向他人提供補丁。使用 Git 的開發者應該能夠獲取主線倉庫的副本,探索修訂歷史,向樹提交更改,使用分支等。理解 Git 用於重寫歷史的工具(如 rebase)也很有用。Git 帶有其自己的術語和概念;Git 的新使用者應該瞭解引用(refs)、遠端分支、索引(index)、快進合併(fast-forward merges)、推送(pushes)和拉取(pulls)、分離頭(detached heads)等。這一切在開始時可能有點令人生畏,但只要稍加學習,這些概念並不難掌握。
在熟悉 Git 的過程中,使用 Git 生成透過電子郵件提交的補丁是一個很好的練習。
當你準備好上傳 Git 樹供他人檢視時,你當然需要一個可以從中拉取(pull)的伺服器。如果你有一個可以訪問網際網路的系統,使用 git-daemon 設定這樣的伺服器相對簡單。否則,免費的公共託管網站(例如 GitHub)正在網際網路上出現。經驗豐富的開發者可以在 kernel.org 上獲得賬戶,但這並不容易獲得;請參閱 https://kernel.linux.club.tw/faq/ 獲取更多資訊。
正常的 Git 工作流程涉及大量分支的使用。每條開發線都可以分離到一個單獨的“主題分支”中並獨立維護。Git 中的分支成本低廉,沒有理由不自由使用它們。無論如何,你不應該在你打算讓其他人從中拉取(pull)的任何分支中進行開發。公開可用的分支應謹慎建立;當開發分支中的補丁完整並準備就緒時才合併它們——而不是在此之前。
Git 提供了一些強大的工具,可以讓你重寫開發歷史。一個不便的補丁(例如,一個導致二分查詢失敗或有其他明顯錯誤)可以在原地修復或完全從歷史中移除。一個補丁系列可以被重寫,就好像它是基於今天的主線編寫的,即使你已經為此工作了數月。更改可以透明地從一個分支轉移到另一個分支。諸如此類。明智地利用 Git 修正歷史的能力有助於建立問題較少的乾淨補丁集。
然而,過度使用此功能可能會導致其他問題,而不僅僅是對建立完美專案歷史的簡單執著。重寫歷史將重寫該歷史中包含的更改,將一個經過測試(希望如此)的核心樹變成一個未經測試的樹。但除此之外,如果開發者對專案歷史沒有共同的看法,他們就無法輕鬆協作;如果你重寫了其他開發者已經拉取到他們倉庫中的歷史,你將使那些開發者 laborious。因此,這裡適用一個簡單的經驗法則:已經匯出給其他人的歷史之後通常應被視為不可變。
因此,一旦你將一系列更改推送到你的公共伺服器,這些更改就不應該被重寫。如果你嘗試推送不會導致快進合併(即不共享相同歷史的更改)的更改,Git 將嘗試強制執行此規則。可以覆蓋此檢查,並且有時可能需要重寫匯出的樹。例如,在樹之間移動更改集以避免 linux-next 中的衝突。但此類操作應該很少見。這就是為什麼開發應該在私有分支中進行(如有必要可以重寫),並且只有在達到相當成熟的狀態時才將其移動到公共分支的原因之一。
隨著主線(或基於一系列更改的其他樹)的推進,人們很容易傾向於與該樹合併以保持領先地位。對於私有分支,rebase 是一種跟上另一個樹的簡單方法,但 rebase 不再是選項一旦樹被匯出到外部。一旦發生這種情況,就必須進行完整合並。偶爾合併很有意義,但過於頻繁的合併可能會不必要地使歷史變得混亂。在這種情況下,建議的技術是少合併,並且通常只在特定的釋出點(例如主線 -rc 釋出)進行合併。如果你對特定更改感到不安,你始終可以在私有分支中執行測試合併。Git 的“rerere”工具在這種情況下會很有用;它會記住合併衝突是如何解決的,這樣你就不必重複相同的工作了。
關於像 Git 這樣的工具,最常見的抱怨之一是:補丁從一個倉庫大規模移動到另一個倉庫,使得未經審查或不當的更改很容易潛入主線。核心開發者看到這種情況發生時往往會感到不高興;上傳包含未經審查或跑題補丁的 Git 樹可能會影響你未來獲取樹的能力。引用 Linus 的話:
You can send me patches, but for me to pull a git patch from you, I
need to know that you know what you're doing, and I need to be able
to trust things *without* then having to go and check every
individual change by hand.
(https://lwn.net/Articles/224135/)。
為了避免這種情況,請確保給定分支中的所有補丁都與相關主題緊密相關;一個“驅動程式修復”分支不應該修改核心記憶體管理程式碼。最重要的是,不要使用 Git 樹來繞過審查流程。定期向相關列表釋出樹的摘要,並在適當的時候,請求將該樹包含在 linux-next 中。
如果或當其他人開始傳送補丁以包含到您的樹中時,請不要忘記審查它們。同時確保您維護正確的作者資訊;Git 的“am”工具在這方面盡力而為,但如果補丁是透過第三方轉發給您的,您可能需要向補丁新增“From:”行。
當請求拉取(pull)時,請務必提供所有相關資訊:你的樹在哪裡,要拉取哪個分支,以及拉取將導致哪些更改。Git 的 `request-pull` 命令在這方面很有幫助;它將按照其他開發者期望的格式化請求,並且還會檢查你是否記得將這些更改推送到公共伺服器。
7.2. 審查補丁¶
有些讀者肯定會反對將本節歸入“高階主題”,理由是即使是初級核心開發者也應該審查補丁。確實,學習如何在核心環境中程式設計的最佳方式莫過於檢視其他人釋出的程式碼。此外,審查者總是供不應求;透過檢視程式碼,你可以為整個流程做出重大貢獻。
審查程式碼可能是一個令人生畏的前景,特別是對於那些可能對公開質疑經驗更豐富的人釋出的程式碼感到緊張的新核心開發者。然而,即使是最有經驗的開發者編寫的程式碼也可以改進。也許對審查者(所有審查者)最好的建議是:將審查意見表述為問題而不是批評。提問“此路徑中鎖是如何釋放的?”總是比宣告“這裡的鎖機制是錯誤的”效果更好。
在出現分歧時,另一個有用的技巧是請其他人發表意見。如果討論在幾次交流後陷入僵局,那麼請其他審查者或維護者發表意見。通常,那些同意審查者意見的人除非被要求,否則會保持沉默。多人的意見具有指數級的更大權重。
不同的開發者會從不同的角度審查程式碼。有些人主要關注編碼風格以及程式碼行是否有尾隨空格。另一些人則主要關注補丁整體實現的更改是否對核心有利。還有一些人會檢查是否存在問題鎖、過度堆疊使用、可能的安全問題、與其他地方程式碼的重複、足夠的文件、對效能的不利影響、使用者空間 ABI 更改等。所有型別的審查,如果能使進入核心的程式碼變得更好,都是受歡迎和有價值的。
沒有嚴格要求使用像 Reviewed-by 這樣的特定標籤。事實上,即使提供了標籤,也更鼓勵用簡單英語進行的審查,因為它們資訊量更大,例如“我查看了此提交的 A、B 和 C 方面,我認為它看起來不錯。” 某種形式的審查訊息或回覆顯然是必要的,否則維護者將根本不知道審查者是否查看了補丁!
最後但同樣重要的是,補丁審查可能會變成一個負面過程,只專注於指出問題。請時不時地給予一些讚揚,特別是對於新手!