當前位置: 妍妍網 > 碼農

Linus 如何在 14 天內編寫出 Git?

2024-06-11碼農

作為一個強大的分布式版本控制系統,Git 的誕生使得多個開發人員能夠在同一個計畫上同時工作,也允許其跟蹤程式碼的所有更改。它不僅改變了開發和協作的方式,還提升了軟體開發的效率、品質和靈活性。掌握和熟練使用 Git 已成為現代軟體開發中不可或缺的一部份。

那麽,Git 究竟是怎麽開發出來的?又有哪些趣事?本文作者 Nicholas Yan 進行了詳細的回顧與分享。

原文連結:https://graphite.dev/blog/bitkeeper-linux-story-of-git-creation

作者 | Nicholas Yan 責編 | 夏萌

譯者 | 彎月

出品 | CSDN(ID:CSDNnews)

2005年4月3日,Linus釋出了Linux內核的一個候選版本2.6.12-rc2。Linus表示,這個釋出候選版本並不是太有趣,「diffstat (用於顯示檔差異統計資訊的工具) 輸出說明了一切:這是許多非常小的變更,融合了大量小的改進和錯誤修復」,但這個版本成為了一個重要的標誌,因為這是最後一個Linux內核的非Git版本。

BitKeeper

在使用BitKeeper(分布式版本控制系統)之前的十年裏,Linux內核的版本控制一直是Linus自己。

具體流程如下:開發人員將tarballs和修補程式送出給幾個Linus信任的助手。助手們透過稽核後,將修補程式發送給Linus。最後,Linus親手將它們合並到自己的原始碼樹中,然後釋出。

當然,Linus本人並不是一個「完美的版本控制服務」。1998年,知名程式設計師Larry McVoy透過Linux內核信件列表首次提出了BitKeeper的想法,他寫道:「很明顯,我們的領袖[Linus]目前有點超負荷,修補程式可能會遺失。」

盡管如今看來,這種手動的工作流程也未免太原始了,但在當時,Linus認為這種工作流程比其他選擇(主要是CVS)更好。

後來,2007年Linus在Google發表了關於Git的演講,他提到了他的一個核心設計原則:「 有什麽是CVS不會做的? 」當然,這種厭惡自然也延伸到了SVN,同樣是在那次演講中,他笑著說:「觀眾席中有Subversion使用者嗎?你們可以離席了。我非常討厭CVS,所以我認為Subversion是有史以來最沒有意義的計畫。有一段時間裏Subversion的整體口號是正確實作CVS。以這個口號為出發點,你將一事無成。因為CVS根本無法正確實作。」

Linus認為CVS的核心問題在於其集中化的性質。由於Linux開發人員有數百名之多,所以Linus認為每個人都擁有自己獨立的程式碼庫副本至關重要,因為只有這樣他們才能在自己的分支上開發。這不僅對線下的工作有幫助,而且對內部管理也很有幫助。每位開發人員都可以自由地向自己的程式碼庫送出任何程式碼,而且他們有機會說服社群他們的變更是有價值的。這樣可以防止擁有送出許可權的貢獻者成為唯一的程式碼庫的守門人。

BitKeeper與CVS截然不同。在前面提到的1998年關於BitKeeper的介紹中,Larry McVoy勾勒了一個系統,這個系統與如今我們所了解的原始碼控制非常相似,但在當時卻完全不同。Larry McVoy寫道:

支持所有這些操作的機制是一個分布式原始碼管理系統。該系統的主要特點是:

  • 每個人都有一個程式碼庫(相比之下,CVS只有一個程式碼庫)。

  • 程式碼變更可以作為「超級修補程式」(又稱為「變更集」)發送。變更集只是一個修補程式檔,包含以下內容:

  • 所有變更,按照修訂版本組織。

  • 一個識別元,表示修補程式應該套用在樹的哪個位置(如果你的更新落後於修補程式發送者,則修補程式將失敗)。

  • 所有變更的修訂歷史。

  • 後設資料,如路徑名變更,符號標簽(如 alpha2 或 linux-2.1.133)等。

  • 一個名為「開發線」(LOD)的新概念。從邏輯上講,它是一個分支,但不需要在分支上。修補程式可以(也將會)成為自己的 LOD。你可以在LOD上執行「將此套用於主分支」之類的操作。

  • 後來,Linus對BitKeeper表示了極大的贊賞,認為BitKeeper改變了他的看法,而Git的靈感也來源於此:「 BitKeeper不僅是第一個我覺得值得嘗試的版本控制系統,也讓我明白了使用這類系統的意義以及如何正確使用這類系統。所以,從技術的角度來看,Git的許多方面雖然與BitKeeper有很大的區別(這是另一個設計目標,因為我不希望Git成為BitKeeper的複制),但Git的許多工作流程都借鑒了BitKeeper。

    授權

    雖然Linus對BitKeeper的評價很高,但2002年在Linux內部使用該工具的問題上,他的決定引發了Linux內核信件列表上大規模的爭論。

    爭論源自何處?Larry McVoy在構建BitKeeper時,將其作為了一個商業的閉源計畫(BitMover)。盡管人們能夠使用BitKeeper的免費社群版本,但有一個限制性授權。

    根據維基百科記載:「社群版BitKeeper的授權允許開發人員在開源或自由軟體計畫中免費使用該工具,前提是這些開發人員在使用BitKeeper期間以及之後的一年內,不得參與競爭工具(如Concurrent Versions System、GNU arch、Subversion以及ClearCase)的開發。不論競爭工具是免費還是專有的,這條限制都適用。」

    自由軟體的宣傳者Richard Stallman也發表了意見:「BitKeeper授權掌握了控制權。實際上是在說,‘你沒有權利使用BitKeeper,只有臨時的使用授權,而我們可以隨時撤銷這個授權。我們允許你使用BitKeeper,你應該對此心存感激。不要做任何我們不喜歡的事情,否則我們可能會撤銷這些特權。自由軟體運動的產生正是源自大家對這種授權的憤怒。’」

    但Linus采取了更務實的觀點,從他的角度來看,他不過是需要最適合的工具,而不會在意這些工具源自何方。2007年,他曾表示:「盡管BitKeeper的授權有問題,但我仍然很高興,因為坦白說,對於我而言,我做開源是因為我認為開源才是構建軟體的唯一正確方式。但同時,我會使用最適合的工具,坦白說,BitKeeper就是我想要的工具。」

    然而,這段不安的聯姻無法持久。

    2005年,Linux內核開發人員Andrew Tridgell違反了授權,並實施了逆向工程。他能夠提取BitKeeper程式碼而不需要遵循BitKeeper授權。在Andrew Tridgell看來,這完全符合道德準則:「我在編寫這個工具時根本沒有使用BitKeeper,因此從未受過BitKeeper授權的約束。」

    然而Larry McVoy對此有不同的看法。最初,Linus是站在他這邊的:

    「如果有人編寫一個免費的替代品,Larry完全能接收……Larry不能接受的是,有人透過逆向工程他的程式碼編寫了一個免費的替代品。Larry的道德立場非常明確:‘你可以與我競爭,但你不能搭我的便車。自己解決問題,公平競爭。不要透過我的解決方案來競爭。’BitKeeper授權也正是為了表達這一點:‘少來搭我的便車,你這個愛占便宜的家夥。’而我[Linus]無法反駁這一點。」

    Linus充當了三個月的調停,但最終未能達成和解。

    2005年4月6日,Linus透過Linux內核信件列表發了一封主題為「內核SCM長篇故事……」的信件,開啟了一系列改變整個行業的事件:

    「可能部份人已知情,在過去的一兩個月裏,我們一直在努力解決BitKeeper的使用沖突。但並未取得成功,因此內核團隊正在尋找替代方案。」

    他開玩笑地談到了歷史:「並不是說我選擇BitKeeper完全沒有沖突」,並強調了他對BitKeeper團隊的感激之情。

    盡管如此,Linus回顧這段時光時仍然充滿了喜悅:

    事實上,BitKeeper從根本上改變了我們的做事方式。從細粒度的變更集跟蹤,到我最終信任次級維護者承擔更加重要的工作,我們無需再逐個出修補程式。因此,與BitKeeper的三年合作絕對沒有浪費,我相信我們改進了工作方式,而我正在考慮的事情之一就是確保這些方式持續有效。

    我想說,我個人對BitKeeper和Larry非常滿意。雖然我們的合作未能成功,但對Linux內核的開發產生了重大影響。我們必須找到一套工具來代替BitKeeper的功能。

    Linus去度假

    雖然4月6日Linus透過信件列表公布了雙方合作失敗的訊息,但實際上他已經展開了緊張的工作。就在2.6.12-rc2釋出的三天前,他停止了Linux內核的工作,並全力尋找BitKeeper的替代方案。

    Linus的目標是「在兩周內拿出可以投入使用的工具。」他在4月6日的信件中宣布:「我將離線一周(你可以認為‘Linus去度假了’),我請求繼續維護BitKeeper樹的人可以把結果作為(單獨的)修補程式發送給我,因為我也需要合並一部份程式碼。」

    很明顯,Linus的信件透漏出了緊迫感,Linux內核的下一個版本釋出受阻,他必須盡快解決這個問題。

    他甚至在4月7日的一封信件中提到了最壞打算,Linux內核可能會轉而使用集中式的版本控制系統:「請註意,我厭惡集中式的SCM模型,但如果事態嚴重,導致我們短時間內(一個月或兩個月)無法並列合並程式碼,我會透過一個信賴的網站搭建SVN之類的系統,允許少數幾個人送出程式碼,並將合並的工作分給幾個人,避免我自己成為瓶頸。」

    雖然事後來看,結果很明顯,但在當時,根據這些信件,編寫一個自訂的版本控制系統尚遙不可及。從4月6日的第一封信件到4月12日的最後一封信件,期間來往的信件多達205封,他們討論了許多其他開源替代方案,比如Monotone、GNU arch、Bazaar-ng、Darcs,其中一些工具的建立者也參與進來宣傳自己的計畫。

    主要考慮因素,尤其是從Linus的角度來看,是每個工具的總體效能。總的來說,205封信件涉及很多關於各種工具的效能和效率的討論。

    每個人心中最大的憂慮在於:現有工具中是否有一款適用於Linux內核這種規模的計畫?

    4月8日,距離最初的信件發出過去了兩天,也就是Linus全身心投入工作5天後,他分享了一個最新訊息:「由於monotone太慢,請各位在手頭的工作之余,試試看這個快速的挑戰:kernel.org:/pub/linux/kernel/people/torvalds/。」

    Git誕生了。

    Git的第一行程式碼

    有關Linus編寫初版Git僅用了兩周時間的傳聞,我們需要加上一則補充說明:如今我們所說的git主要是面向使用者的命令和整體工作流程,但當時的目標和任務有很大的不同,而且範圍非常有限。

    人們在信件列表上爭論各種工具和方法的優缺點時,有人粗略描述了他們的需求:「慢一點沒關系,只要不是慢得離譜。臨時解決方案的目的是建立線上的修補程式工作流程。」

    初版的Git更像是一個內容可尋址的檔案系統,算不上是一個完整的原始碼管理系統。Linus在另一封信件中解釋說:

    (*) 我稱之為「送出」,但實際上更簡單。實際上表明「這是我的<目錄的當前狀態>,我從<之前的目錄狀態集合>到達了這個狀態,其原因是<**>」。

    順便說一下,我的設計意圖就在於此。「git」並不在意合並之類的操作。你可以使用任何SCM合並程式碼。「git」所做的只是跟蹤目錄狀態(以及發展到該狀態的經過),僅此而已。git並不會執行合並操作,實際功能並不多。

    也就是說,你在Git存檔上「拉取」或「推播」時,就會得到所有目錄狀態的「聯合」。其中的HEAD就是指向「目錄狀態之海」的一個指標,但要想合並兩個目錄狀態,就必須使用其他工具。

    雖然來往的信件討論了各種工作流程和移動送出,但Linus構建的客戶端並沒有考慮這些操作。

    Linus表示:「實際上‘Git’非常簡單,僅用了4天就編寫完成了。大部份時間實際上並不是在編寫程式碼,而是思考數據結構。」

    這是他後來反復提及的感受,有時會被斷章取義,但確實Linus所編寫程式碼的新穎之處就在於數據結構的選擇。Linus分享了前幾次送出,但沒有關於工作流程的討論。

    少數人主張使用SQL來儲存變更。Linus在後來的對話(很符合他個人的發言風格)中表示:

    > 為什麽後端使用了目錄樹,而沒有使用sql?

    因為sql很糟糕?

    我可以想出幾百萬種方法來降低速度。請你提出提高速度的方法。

    —— Linus

    但也有一些人看好Git,並渴望使用Git。就在Linus請求大家檢視他的程式碼的同一天,有幾個人發回了一些指令碼,其中包含了在他的基礎之上構建的其他功能。

    在Linus投入真正的工作兩周後,即2005年4月17日,他發了一封信件:「第一次真正的內核Git合並!」

    未來的發展

    二十年後,再讀當初的那些信件,最令我開心的部份是看到當時的作者們未曾預料到的未來。

    一位使用者在評估原始碼控制替代產品monotone時表示:

    有點令人惱火的是,monotone似乎沒有網頁界面。我以前在追蹤bug時經常使用BitKeeper的網頁界面,開啟網頁瀏覽視窗檢視檔的修訂版本和簽入評論等操作真的很快。你們知道是否有人正在開發這樣的界面嗎?

    當時,原始碼控制和程式碼審查的網頁界面剛剛開始流行,Google,Guido van Rossum 正在開發他們的第一個基於網頁的專用程式碼審查工具Mondrian。而在兩年後,GitHub成立了。

    有關效能的討論也充滿了諷刺意味。

    關於如果Git後端使用基於網路的檔案系統效能會如何的討論,如今已被顛覆。Google(FUSE)和Meta(EdenFS)這類的大公司擁有龐大的單一程式碼庫,對於他們來說,這些基於網路的原始碼控制檔案系統是擴充套件原始碼控制和構建的關鍵。

    而最初激勵Linus編寫Git的核心問題(現有的版本控制替代產品無法支持Linux內核程式碼庫的大量歷史記錄和大規模的送出吞吐量)將在幾年後再次上演,Meta將主程式碼庫從Git遷移出去,也出自同一個原因。

    當然,當時參與討論的各位並不知道這一切。

    Git的建立是為了打破Linux內核釋出的阻礙,並非在全球重新發明所有原始碼管理。Linus的評論強調他認為原始碼管理是其他工具的領域,這些工具將成為Git的介面。

    在回顧歷史時,我們常常將其浪漫化為靈感突然迸發。然而,Git的建立說明了更加嚴酷的現實:圍繞授權的分歧逐漸升級;打破阻礙的緊急備選方案的需求;多年的打磨和叠代並非源自發明者,而是由社群推動。

    推薦閱讀:

    「如今馬斯克的 X,失去了唯一一位公關」