幾乎所有的版本控制系統(tǒng)都以某種形式支持分支。 使用分支意味著你可以把你的工作從開(kāi)發(fā)主線(xiàn)上分離開(kāi)來(lái),以免影響開(kāi)發(fā)主線(xiàn)。 在很多版本控制系統(tǒng)中,這是一個(gè)略微低效的過(guò)程——常常需要完全創(chuàng)建一個(gè)源代碼目錄的副本。對(duì)于大項(xiàng)目來(lái)說(shuō),這樣的過(guò)程會(huì)耗費(fèi)很多時(shí)間。
有人把 Git 的分支模型稱(chēng)為它的“必殺技特性”,也正因?yàn)檫@一特性,使得 Git 從眾多版本控制系統(tǒng)中脫穎而出。 為何 Git 的分支模型如此出眾呢? Git 處理分支的方式可謂是難以置信的輕量,創(chuàng)建新分支這一操作幾乎能在瞬間完成,并且在不同分支之間的切換操作也是一樣便捷。 與許多其它版本控制系統(tǒng)不同,Git 鼓勵(lì)在工作流程中頻繁地使用分支與合并,哪怕一天之內(nèi)進(jìn)行許多次。 理解和精通這一特性,你便會(huì)意識(shí)到 Git 是如此的強(qiáng)大而又獨(dú)特,并且從此真正改變你的開(kāi)發(fā)方式。
為了真正理解 Git 處理分支的方式,我們需要回顧一下 Git 是如何保存數(shù)據(jù)的。
或許你還記得起步的內(nèi)容,Git 保存的不是文件的變化或者差異,而是一系列不同時(shí)刻的文件快照。
在進(jìn)行提交操作時(shí),Git 會(huì)保存一個(gè)提交對(duì)象(commit object)。知道了 Git 保存數(shù)據(jù)的方式,我們可以很自然的想到——該提交對(duì)象會(huì)包含一個(gè)指向暫存內(nèi)容快照的指針。 但不僅僅是這樣,該提交對(duì)象還包含了作者的姓名和郵箱、提交時(shí)輸入的信息以及指向它的父對(duì)象的指針。首次提交產(chǎn)生的提交對(duì)象沒(méi)有父對(duì)象,普通提交操作產(chǎn)生的提交對(duì)象有一個(gè)父對(duì)象,而由多個(gè)分支合并產(chǎn)生的提交對(duì)象有多個(gè)父對(duì)象。
為了說(shuō)得更加形象,我們假設(shè)現(xiàn)在有一個(gè)工作目錄,里面包含了三個(gè)將要被暫存和提交的文件。 暫存操作會(huì)為每一個(gè)文件計(jì)算校驗(yàn)和(使用我們?cè)?起步 中提到的 SHA-1 哈希算法),然后會(huì)把當(dāng)前版本的文件快照保存到 Git 倉(cāng)庫(kù)中(Git 使用 blob 對(duì)象來(lái)保存它們),最終將校驗(yàn)和加入到暫存區(qū)域等待提交:
$ git add README test.rb LICENSE
$ git commit -m 'The initial commit of my project'
當(dāng)使用git commit進(jìn)行提交操作時(shí),Git 會(huì)先計(jì)算每一個(gè)子目錄(本例中只有項(xiàng)目根目錄)的校驗(yàn)和,然后在 Git 倉(cāng)庫(kù)中這些校驗(yàn)和保存為樹(shù)對(duì)象。 隨后,Git 便會(huì)創(chuàng)建一個(gè)提交對(duì)象,它除了包含上面提到的那些信息外,還包含指向這個(gè)樹(shù)對(duì)象(項(xiàng)目根目錄)的指針。如此一來(lái),Git 就可以在需要的時(shí)候重現(xiàn)此次保存的快照。
現(xiàn)在,Git 倉(cāng)庫(kù)中有五個(gè)對(duì)象:三個(gè) blob 對(duì)象(保存著文件快照)、一個(gè)樹(shù)對(duì)象(記錄著目錄結(jié)構(gòu)和 blob 對(duì)象索引)以及一個(gè)提交對(duì)象(包含著指向前述樹(shù)對(duì)象的指針和所有提交信息)。

做些修改后再次提交,那么這次產(chǎn)生的提交對(duì)象會(huì)包含一個(gè)指向上次提交對(duì)象(父對(duì)象)的指針。

Git 的分支,其實(shí)本質(zhì)上僅僅是指向提交對(duì)象的可變指針。 Git 的默認(rèn)分支名字是master。 在多次提交操作之后,你其實(shí)已經(jīng)有一個(gè)指向最后那個(gè)提交對(duì)象的master分支。 它會(huì)在每次的提交操作中自動(dòng)向前移動(dòng)。
Git 的 “master” 分支并不是一個(gè)特殊分支。 它就跟其它分支完全沒(méi)有區(qū)別。 之所以幾乎每一個(gè)倉(cāng)庫(kù)都有 master 分支,是因?yàn)?git init 命令默認(rèn)創(chuàng)建它,并且大多數(shù)人都懶得去改動(dòng)它。

上面的理論比較全面,如果還不理解下面有一個(gè)比較簡(jiǎn)單的解釋
分支就是科幻電影里面的平行宇宙,當(dāng)你正在電腦前努力學(xué)習(xí)Git的時(shí)候,另一個(gè)你正在另一個(gè)平行宇宙里努力學(xué)習(xí)SVN。
如果兩個(gè)平行宇宙互不干擾,那對(duì)現(xiàn)在的你也沒(méi)啥影響。不過(guò),在某個(gè)時(shí)間點(diǎn),兩個(gè)平行宇宙合并了,結(jié)果,你既學(xué)會(huì)了Git又學(xué)會(huì)了SVN!

分支在實(shí)際中有什么用呢?假設(shè)你準(zhǔn)備開(kāi)發(fā)一個(gè)新功能,但是需要兩周才能完成,第一周你寫(xiě)了50%的代碼,如果立刻提交,由于代碼還沒(méi)寫(xiě)完,不完整的代碼庫(kù)會(huì)導(dǎo)致別人不能干活了。如果等代碼全部寫(xiě)完再一次提交,又存在丟失每天進(jìn)度的巨大風(fēng)險(xiǎn)。
現(xiàn)在有了分支,就不用怕了。你創(chuàng)建了一個(gè)屬于你自己的分支,別人看不到,還繼續(xù)在原來(lái)的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到開(kāi)發(fā)完畢后,再一次性合并到原來(lái)的分支上,這樣,既安全,又不影響別人工作。
其他版本控制系統(tǒng)如SVN等都有分支管理,但是用過(guò)之后你會(huì)發(fā)現(xiàn),這些版本控制系統(tǒng)創(chuàng)建和切換分支比蝸牛還慢,簡(jiǎn)直讓人無(wú)法忍受,結(jié)果分支功能成了擺設(shè),大家都不去用。
但Git的分支是與眾不同的,無(wú)論創(chuàng)建、切換和刪除分支,Git在1秒鐘之內(nèi)就能完成!無(wú)論你的版本庫(kù)是1個(gè)文件還是1萬(wàn)個(gè)文件。