Git版本管理系統學習之Git分支——分支簡介

3.1 Git 分支 - 分支簡介

幾乎所有的版本控制系統都以某種形式支持分支。 使用分支意味着你可以把你的工作從開發主線上分離開來,以免影響開發主線。 在很多版本控制系統中,這是一個略微低效的過程——常常需要完全創建一個源代碼目錄的副本。對於大項目來說,這樣的過程會耗費很多時間。

有人把 Git 的分支模型稱爲它的`‘必殺技特性’',也正因爲這一特性,使得 Git 從衆多版本控制系統中脫穎而出。 爲何 Git 的分支模型如此出衆呢? Git 處理分支的方式可謂是難以置信的輕量,創建新分支這一操作幾乎能在瞬間完成,並且在不同分支之間的切換操作也是一樣便捷。 與許多其它版本控制系統不同,Git 鼓勵在工作流程中頻繁地使用分支與合併,哪怕一天之內進行許多次。 理解和精通這一特性,你便會意識到 Git 是如此的強大而又獨特,並且從此真正改變你的開發方式。

分支簡介

爲了真正理解 Git 處理分支的方式,我們需要回顧一下 Git 是如何保存數據的。

或許你還記得 起步 的內容,Git 保存的不是文件的變化或者差異,而是一系列不同時刻的文件快照。

在進行提交操作時,Git 會保存一個提交對象(commit object)。知道了 Git 保存數據的方式,我們可以很自然的想到——該提交對象會包含一個指向暫存內容快照的指針。 但不僅僅是這樣,該提交對象還包含了作者的姓名和郵箱、提交時輸入的信息以及指向它的父對象的指針。首次提交產生的提交對象沒有父對象,普通提交操作產生的提交對象有一個父對象,而由多個分支合併產生的提交對象有多個父對象,

爲了更加形象地說明,我們假設現在有一個工作目錄,裏面包含了三個將要被暫存和提交的文件。 暫存操作會爲每一個文件計算校驗和(使用我們在 起步 中提到的 SHA-1 哈希算法),然後會把當前版本的文件快照保存到 Git 倉庫中(Git 使用 blob 對象來保存它們),最終將校驗和加入到暫存區域等待提交:

$ git add README test.rb LICENSE
$ git commit -m 'The initial commit of my project'

當使用 git commit 進行提交操作時,Git 會先計算每一個子目錄(本例中只有項目根目錄)的校驗和,然後在 Git 倉庫中這些校驗和保存爲樹對象。 隨後,Git 便會創建一個提交對象,它除了包含上面提到的那些信息外,還包含指向這個樹對象(項目根目錄)的指針。如此一來,Git 就可以在需要的時候重現此次保存的快照。

現在,Git 倉庫中有五個對象:三個 blob 對象(保存着文件快照)、一個樹對象(記錄着目錄結構和 blob 對象索引)以及一個提交對象(包含着指向前述樹對象的指針和所有提交信息)。

首次提交對象及其樹結構。

Figure 9. 首次提交對象及其樹結構

做些修改後再次提交,那麼這次產生的提交對象會包含一個指向上次提交對象(父對象)的指針。

提交對象及其父對象。

Figure 10. 提交對象及其父對象

Git 的分支,其實本質上僅僅是指向提交對象的可變指針。 Git 的默認分支名字是 master。 在多次提交操作之後,你其實已經有一個指向最後那個提交對象的 master 分支。 它會在每次的提交操作中自動向前移動。

Note

Git 的 “master” 分支並不是一個特殊分支。 它就跟其它分支完全沒有區別。 之所以幾乎每一個倉庫都有 master 分支,是因爲 git init 命令默認創建它,並且大多數人都懶得去改動它。

分支及其提交歷史。

Figure 11. 分支及其提交歷史

分支創建

Git 是怎麼創建新分支的呢? 很簡單,它只是爲你創建了一個可以移動的新的指針。 比如,創建一個 testing 分支, 你需要使用 git branch 命令:

$ git branch testing

這會在當前所在的提交對象上創建一個指針。

兩個指向相同提交歷史的分支。

Figure 12. 兩個指向相同提交歷史的分支

那麼,Git 又是怎麼知道當前在哪一個分支上呢? 也很簡單,它有一個名爲 HEAD 的特殊指針。 請注意它和許多其它版本控制系統(如 Subversion 或 CVS)裏的 HEAD 概念完全不同。 在 Git 中,它是一個指針,指向當前所在的本地分支(譯註:將 HEAD 想象爲當前分支的別名)。 在本例中,你仍然在 master分支上。 因爲 git branch 命令僅僅 創建 一個新分支,並不會自動切換到新分支中去。

HEAD 指向當前所在的分支。

Figure 13. HEAD 指向當前所在的分支

你可以簡單地使用 git log 命令查看各個分支當前所指的對象。 提供這一功能的參數是 --decorate

$ git log --oneline --decorate
f30ab (HEAD, master, testing) add feature #32 - ability to add new
34ac2 fixed bug #1328 - stack overflow under certain conditions
98ca9 initial commit of my project

正如你所見,當前 “master” 和 “testing” 分支均指向校驗和以 f30ab 開頭的提交對象。

分支切換

要切換到一個已存在的分支,你需要使用 git checkout 命令。 我們現在切換到新創建的 testing 分支去:

$ git checkout testing

這樣 HEAD 就指向 testing 分支了。

HEAD 指向當前所在的分支。

Figure 14. HEAD 指向當前所在的分支

那麼,這樣的實現方式會給我們帶來什麼好處呢? 現在不妨再提交一次:

$ vim test.rb
$ git commit -a -m 'made a change'

HEAD 分支隨着提交操作自動向前移動。

Figure 15. HEAD 分支隨着提交操作自動向前移動

如圖所示,你的 testing 分支向前移動了,但是 master 分支卻沒有,它仍然指向運行 git checkout時所指的對象。 這就有意思了,現在我們切換回 master 分支看看:

$ git checkout master

檢出時 HEAD 隨之移動。

Figure 16. 檢出時 HEAD 隨之移動

這條命令做了兩件事。 一是使 HEAD 指回 master 分支,二是將工作目錄恢復成 master 分支所指向的快照內容。 也就是說,你現在做修改的話,項目將始於一個較舊的版本。 本質上來講,這就是忽略 testing 分支所做的修改,以便於向另一個方向進行開發。

Note

分支切換會改變你工作目錄中的文件

在切換分支時,一定要注意你工作目錄裏的文件會被改變。 如果是切換到一個較舊的分支,你的工作目錄會恢復到該分支最後一次提交時的樣子。 如果 Git 不能幹淨利落地完成這個任務,它將禁止切換分支。

我們不妨再稍微做些修改並提交:

$ vim test.rb
$ git commit -a -m 'made other changes'

現在,這個項目的提交歷史已經產生了分叉(參見 項目分叉歷史)。 因爲剛纔你創建了一個新分支,並切換過去進行了一些工作,隨後又切換回 master 分支進行了另外一些工作。 上述兩次改動針對的是不同分支:你可以在不同分支間不斷地來回切換和工作,並在時機成熟時將它們合併起來。 而所有這些工作,你需要的命令只有 branchcheckout 和 commit

項目分叉歷史。

Figure 17. 項目分叉歷史

你可以簡單地使用 git log 命令查看分叉歷史。 運行 git log --oneline --decorate --graph --all ,它會輸出你的提交歷史、各個分支的指向以及項目的分支分叉情況。

$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) made other changes
| * 87ab2 (testing) made a change
|/
* f30ab add feature #32 - ability to add new formats to the
* 34ac2 fixed bug #1328 - stack overflow under certain conditions
* 98ca9 initial commit of my project

由於 Git 的分支實質上僅是包含所指對象校驗和(長度爲 40 的 SHA-1 值字符串)的文件,所以它的創建和銷燬都異常高效。 創建一個新分支就相當於往一個文件中寫入 41 個字節(40 個字符和 1 個換行符),如此的簡單能不快嗎?

這與過去大多數版本控制系統形成了鮮明的對比,它們在創建分支時,將所有的項目文件都複製一遍,並保存到一個特定的目錄。 完成這樣繁瑣的過程通常需要好幾秒鐘,有時甚至需要好幾分鐘。所需時間的長短,完全取決於項目的規模。而在 Git 中,任何規模的項目都能在瞬間創建新分支。 同時,由於每次提交都會記錄父對象,所以尋找恰當的合併基礎(譯註:即共同祖先)也是同樣的簡單和高效。 這些高效的特性使得 Git 鼓勵開發人員頻繁地創建和使用分支。

接下來,讓我們看看你爲什麼應該這樣做。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章