卷2:第6章 Git

2018-02-24 15:55 更新

作者:Susan Potter,翻譯:張吉

原文:http://www.aosabook.org/en/git.html

6.1 Git概述

Git能夠讓不同的協(xié)作者通過一個點對點的倉庫網(wǎng)絡(luò)對數(shù)據(jù)內(nèi)容(通常是代碼,當(dāng)然不僅限于代碼)進行維護。它支持分布式的工作流程,能夠讓數(shù)據(jù)內(nèi)容臨時分離,并最終合并到一起。

本章將闡述Git的內(nèi)部實現(xiàn)是如何提供以上功能的,以及它和其他版本控制系統(tǒng)(VCS)的區(qū)別。

6.2 Git起源

為了更好地理解Git的設(shè)計思想,我們有必要先了解一下Git項目的發(fā)源地——Linux內(nèi)核開發(fā)社區(qū)——所面臨的問題。

Linux內(nèi)核開發(fā)與其他商業(yè)軟件項目有很大不同,因為它的開發(fā)者眾多,且每個開發(fā)者的參與程度和對Linux內(nèi)核代碼的理解有很大差異。多年以來,內(nèi)核代碼一直都是以Tar壓縮文件以及補丁的形式維護的,而當(dāng)時的核心開發(fā)團隊一直在尋找一個能夠滿足他們各方面需求的版本控制系統(tǒng)。

Git就是在這樣的背景下于2005年作為一款開源軟件誕生的。當(dāng)時,Linux內(nèi)核代碼通過兩種版本控制系統(tǒng)進行維護,BitKeeper和CVS,分別由兩組核心開發(fā)團隊使用。BitKeeper相較于當(dāng)時頗為流行的CVS,提供了一種不同的歷史展示方式。

當(dāng)BitKeeper的所有者BitMover決定收回Linux內(nèi)核開發(fā)人員的使用許可時,Linux Torvalds緊急開啟了一個項目,也就是后來的Git。一開始,他通過編寫一組Shell腳本來幫助他將郵件中的補丁按順序應(yīng)用到代碼中。這組原始腳本能夠在代碼合并過程中迅速中斷,讓維護者能夠進行人工干預(yù),修改代碼,然后繼續(xù)合并。

從項目開始之初,Torvalds就為Git制定了一個目標(biāo)——要和CVS的做法完全相反——同時還包含了以下三條設(shè)計目標(biāo):

  • 支持分布式的協(xié)作流程,類似BitKeeper
  • 預(yù)防代碼錯亂
  • 高性能

這些設(shè)計目標(biāo)都被實現(xiàn)了,我會在下文中通過解析Git的各種做法來闡述,包括在內(nèi)容管理中使用有向無環(huán)圖(DAG),頭指針引用,對象模型,遠(yuǎn)程協(xié)議,以及Git如何追蹤合并樹。

雖然Git設(shè)計之初受到了很多BitKeeper的影響,但是兩者還是有根本上的區(qū)別的,如Git提供了更多分布式和本地開發(fā)流程,這點是BitKeeper做不到的。Monotone,2003年啟動的一個開源分布式版本控制系統(tǒng),也對Git的早期開發(fā)產(chǎn)生了影響。

分布式版本控制系統(tǒng)在提供更靈活的工作流程的同時,往往會增加它的復(fù)雜程度。分布式模型的獨特優(yōu)點有:

  • 能夠線下進行增量提交
  • 開發(fā)者可以決定自己的代碼何時能夠開放出來
  • 能夠線下瀏覽歷史
  • 可以將工作成果發(fā)布到不同的倉庫,以不同的分支、不同的提交粒度展現(xiàn)出來

在Git項目的開發(fā)期間,誕生了其他三個開源分布式版本控制系統(tǒng)(其中Mercurial可以參見《開源軟件架構(gòu)》的第一卷)。這些分布式版本控制系統(tǒng)(dVCS)都提供了非常靈活的工作流程,這是先前的集中式版本控制系統(tǒng)做不到的。注意:Subversion有一款插件名為SVK,由不同的開發(fā)者維護,提供了服務(wù)器之間的同步功能。

目前流行的dVCS包括Bazaar, Darcs, Fossil, Git, Mercurial, 以及Veracity。

6.3 版本控制系統(tǒng)的設(shè)計

現(xiàn)在讓我們回過頭來看看Git之外的其他版本控制系統(tǒng)是如何設(shè)計的。通過比較他們和Git之間的區(qū)別,可以幫助我們?nèi)ダ斫釭it在架構(gòu)設(shè)計中的選擇。

版本控制系統(tǒng)通常有三項核心功能(需求):

  • 保存內(nèi)容
  • 記錄變更歷史(包括具體的合并信息)
  • 向協(xié)作者分發(fā)內(nèi)容和變更歷史

注意:第三項并不是所有版本控制系統(tǒng)的核心功能。

保存內(nèi)容

在VCS中保存內(nèi)容,最普遍的做法是保存增量的修改,或使用有向無環(huán)圖(DAG)。

增量修改可以反映出兩個版本之間的內(nèi)容差異,以及一些額外的信息。使用有向無環(huán)圖保存內(nèi)容則是將特定對象構(gòu)造成一種樹狀結(jié)構(gòu),作為某一次提交的快照保存下來(樹狀結(jié)構(gòu)中未發(fā)生變化的對象是可以重用的)。Git使用有向無環(huán)圖來保存內(nèi)容,它所使用的不同對象類型會在本文的“對象數(shù)據(jù)庫”一節(jié)中有所描述。

提交和合并的歷史

在保存歷史、記錄變化方面,大部分VCS使用以下方式之一:

  • 線性歷史
  • 有向無環(huán)圖

Git使用的還是有向無環(huán)圖,這次則是用來保存歷史。每次提交包含了它父節(jié)點的元信息——Git中的一次提交可以擁有0個或多個父節(jié)點(理論上沒有個數(shù)限制)。例如,Git倉庫的第一次提交就沒有父節(jié)點,而一次三頭合并則有三個父節(jié)點。

Git和SVN線性提交的另一個重要區(qū)別是Git可以直接進行分支的創(chuàng)建,并記錄下大部分合并歷史。

libgit2。一開始它并不流行,直到一個名叫Vincent Marti的學(xué)生在谷歌編程夏令營中使用了它。從那以后,Vincent和Github持續(xù)對libgit2類庫貢獻代碼,并為其他語言編寫了相應(yīng)類庫,包括Ruby,Python,PHP,.NET,Lua,Object-C等。

Shawn Pearce還開啟了一個名為JGit的BSD項目,使用純Java語言實現(xiàn),能夠?qū)it版本庫進行基本的操作。該類庫現(xiàn)在由Eclipse基金會維護,用于Eclipse IDE的Git插件中。

還有其他一些有趣的周邊項目,帶有實驗性質(zhì),使用各類數(shù)據(jù)源來保存Git對象,如:

  • jgit_cassandra?使用Apache Cassandra作為Git對象數(shù)據(jù)庫。它是一種混合型的數(shù)據(jù)源,提供了動態(tài)的BigTable式的數(shù)據(jù)模型。
  • jgit_hbase?能夠?qū)it對象保存在HBase中,一種KV型分布式數(shù)據(jù)庫。
  • libgit2-backends?由libgit2項目衍生而來,致力于提供其他種類的數(shù)據(jù)源,如Memcached,Redis,SQLite,MySQL。

以上這些都是獨立于Git核心工具包之外的項目。

如你所見,我們可以用各種方式來使用Git,它的表現(xiàn)形式不再只有命令行這一種了,而是成為一種版本控制系統(tǒng)的協(xié)議。

在本文撰寫之時,這些項目都還沒有發(fā)布穩(wěn)定版本,所以還是有很多工作要做,但整體看來未來是光明的。

6.10 經(jīng)驗教訓(xùn)

在軟件設(shè)計中,任何一個決定都有正反兩面。作為一個在日常工作中大量使用Git,并且還為Git對象數(shù)據(jù)庫開發(fā)了周邊軟件的程序員,我覺得Git目前的組織方式非常棒。因此,下文提到的“經(jīng)驗教訓(xùn)”更多的是來自其他開發(fā)者對于Git目前設(shè)計方式的不滿,主要歸咎于Git核心開發(fā)者當(dāng)初做出的決定。

最常見的問題在于Git相較于其他CVS不能很好地和IDE進行整合,因為Git是基于工具包設(shè)計的,整合起來會比較具有挑戰(zhàn)性。

早期Git的實現(xiàn)是采用shell腳本的方式,不能很好地跨平臺,特別是對于Windows操作系統(tǒng)。雖然我相信Git開發(fā)者不會因為這個問題而寢食難安,但這的確阻礙了Git在大型公司內(nèi)的推廣。現(xiàn)在,有一個名為Git for Windows的項目由志愿者發(fā)起,及時地將最新的Git開發(fā)成果移植到Windows平臺上。

Git工具包的設(shè)計方式所帶來的另一個間接影響是,他的底層命令繁多,會讓初學(xué)者陷入困境,難以理解Git出錯時拋出的異常信息,最后無可適從。這就使得Git在某些開發(fā)團隊中的推廣受到阻礙。

即便如此,我仍然對Git核心項目以及其周邊項目的開發(fā)充滿信心。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號