-
1. 起步
-
2. Git 基礎
-
3. Git 分支
-
4. 伺服器上的 Git
- 4.1 協議
- 4.2 在伺服器上部署 Git
- 4.3 生成 SSH 公鑰
- 4.4 架設伺服器
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 第三方託管服務
- 4.10 小結
-
5. 分散式 Git
-
A1. 附錄 A: Git 在其他環境
- A1.1 圖形介面
- A1.2 Visual Studio 中的 Git
- A1.3 Visual Studio Code 中的 Git
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git
- A1.5 Sublime Text 中的 Git
- A1.6 Bash 中的 Git
- A1.7 Zsh 中的 Git
- A1.8 PowerShell 中的 Git
- A1.9 小結
-
A2. 附錄 B: 在應用程式中嵌入 Git
-
A3. 附錄 C: Git 命令
3.1 Git 分支 - 分支概覽
幾乎所有的版本控制系統都支援某種形式的分支。分支意味著你可以脫離主開發線,繼續進行開發而不影響主線。在許多版本控制工具中,這是一個相對昂貴的過程,通常需要你建立一個原始碼目錄的全新副本,這對於大型專案來說可能非常耗時。
有些人將 Git 的分支模型稱為其“殺手級特性”,它無疑使 Git 在版本控制社群中脫穎而出。為什麼它如此特別?Git 分支的實現方式非常輕量級,使得分支操作幾乎瞬時完成,而且在分支之間切換也通常一樣快。與其他許多版本控制系統不同,Git 鼓勵經常進行分支和合並的工作流程,甚至一天內進行多次。理解並掌握這個特性會給你一個強大而獨特的工具,並可能徹底改變你的開發方式。
分支概覽
為了真正理解 Git 的分支工作方式,我們需要退一步,審視 Git 是如何儲存其資料的。
正如你可能還記得 Git 是什麼? 中提到的,Git 儲存資料的方式不是一系列變更集或差異,而是一系列快照。
當你提交時,Git 會儲存一個提交物件,其中包含指向你暫存內容快照的指標。該物件還包含作者姓名和電子郵件地址、你輸入的提交資訊,以及指向該提交之前一個或多個提交的指標(其父提交):對於初始提交為零個父提交,對於普通提交為一個父提交,而對於合併兩個或多個分支產生的提交則有多個父提交。
為了視覺化這一點,我們假設你有一個包含三個檔案的目錄,並將它們全部暫存然後提交。暫存檔案會計算每個檔案的校驗和(我們在 Git 是什麼? 中提到的 SHA-1 雜湊),將該檔案的版本儲存在 Git 倉庫中(Git 將它們稱為blob),並將該校驗和新增到暫存區。
$ git add README test.rb LICENSE
$ git commit -m 'Initial commit'
當你透過執行 git commit 來建立提交時,Git 會校驗每個子目錄(在本例中,只有根專案目錄),並將它們作為樹物件儲存在 Git 倉庫中。然後,Git 會建立一個提交物件,該物件包含元資料以及指向根專案樹的指標,以便在需要時重新建立該快照。
你的 Git 倉庫現在包含五個物件:三個blob(每個代表三個檔案之一的內容)、一個tree(列出目錄內容並指定哪些檔名對應哪些 blob),以及一個commit(指向該根樹幷包含所有提交元資料)。
如果你進行一些更改並再次提交,下一個提交會儲存一個指向其緊前面提交的指標。
Git 中的分支只是一個指向這些提交之一的、可移動的輕量級指標。Git 中的預設分支名稱是 master。當你開始進行提交時,會有一個指向你最新提交的 master 分支。每次提交時,master 分支指標會自動向前移動。
|
注意
|
Git 中的“master”分支並非特殊分支。它與其他任何分支完全相同。幾乎每個倉庫都有一個的原因是 |
建立新分支
當你建立新分支時會發生什麼?嗯,這樣做會建立一個新的指標供你移動。假設你想建立一個名為 testing 的新分支。你可以透過 git branch 命令來實現
$ git branch testing
這會建立一個指向你當前所在提交的新指標。
Git 如何知道你當前在哪個分支上?它會維護一個特殊的指標,稱為 HEAD。請注意,這與你在其他版本控制系統(如 Subversion 或 CVS)中可能習慣的 HEAD 概念大不相同。在 Git 中,它是指向你當前所在本地分支的指標。在這種情況下,你仍然在 master 分支上。git branch 命令僅僅建立了一個新分支,並沒有切換到該分支。
你可以透過執行簡單的 git log 命令來輕鬆檢視這一點,該命令會顯示分支指標指向何處。此選項稱為 --decorate。
$ git log --oneline --decorate
f30ab (HEAD -> master, testing) Add feature #32 - ability to add new formats to the central interface
34ac2 Fix bug #1328 - stack overflow under certain conditions
98ca9 Initial commit
你可以看到 master 和 testing 分支都指向 f30ab 提交。
切換分支
要切換到現有分支,請執行 git checkout 命令。讓我們切換到新的 testing 分支
$ git checkout testing
這會將 HEAD 移動到指向 testing 分支。
這有什麼意義呢?嗯,讓我們再進行一次提交
$ vim test.rb
$ git commit -a -m 'Make a change'
這很有趣,因為現在你的 testing 分支已經向前移動了,而你的 master 分支仍然指向你在執行 git checkout 切換分支時所在的提交。讓我們切換回 master 分支
$ git checkout master
|
注意
|
git log 不會總是顯示所有分支如果你現在執行 分支並沒有消失;Git 只是不知道你對該分支感興趣,它試圖顯示它認為你感興趣的內容。換句話說,預設情況下, 要顯示所需分支的提交歷史,你必須顯式指定它: |
該命令執行了兩項操作。它將 HEAD 指標移回指向 master 分支,並將工作目錄中的檔案恢復到 master 指向的快照。這也意味著你從現在開始所做的更改將與舊版本專案分道揚鑣。它基本上是回滾了你在 testing 分支中所做的工作,以便你可以朝不同的方向前進。
|
注意
|
切換分支會更改工作目錄中的檔案
重要的是要注意,當你切換 Git 中的分支時,工作目錄中的檔案會發生變化。如果你切換到較舊的分支,你的工作目錄將恢復到上一次在該分支提交時的樣子。如果 Git 無法乾淨地執行此操作,它將不允許你切換。 |
讓我們進行一些更改並再次提交
$ vim test.rb
$ git commit -a -m 'Make other changes'
現在你的專案歷史已經分叉(請參見 分叉歷史)。你建立了一個分支並切換到它,在該分支上進行了一些工作,然後切換回你的主分支並進行了其他工作。這些更改都隔離在不同的分支中:你可以在分支之間來回切換,並在準備好時將它們合併。所有這些都透過簡單的 branch、checkout 和 commit 命令完成。
你也可以透過 git log 命令輕鬆地看到這一點。如果你執行 git log --oneline --decorate --graph --all,它將打印出你的提交歷史,顯示你的分支指標在哪裡以及你的歷史如何分叉。
$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) Make other changes
| * 87ab2 (testing) Make a change
|/
* f30ab Add feature #32 - ability to add new formats to the central interface
* 34ac2 Fix bug #1328 - stack overflow under certain conditions
* 98ca9 Initial commit of my project
由於 Git 中的分支實際上是一個包含其指向的提交的 40 位 SHA-1 校驗和的簡單檔案,因此建立和銷燬分支的成本很低。建立一個新分支就像向一個檔案寫入 41 位元組(40 個字元和一個換行符)一樣快速簡單。
這與大多數舊版本控制工具的分支方式形成了鮮明對比,它們通常涉及將專案的所有檔案複製到第二個目錄中。根據專案大小,這可能需要幾秒鐘甚至幾分鐘,而在 Git 中,這個過程總是瞬時的。此外,由於我們在提交時記錄了父提交,因此查詢合適的合併基礎進行合併會自動完成,並且通常非常容易。這些特性有助於鼓勵開發人員頻繁建立和使用分支。
讓我們看看為什麼你應該這樣做。
|
注意
|
同時建立新分支並切換到該分支
通常情況下,你會建立一個新分支並立即想切換到該新分支——這可以透過一個操作完成,即使用 |
|
注意
|
從 Git 版本 2.23 開始,你可以使用
|