什么是分支
在玩劇情類游戲時,不同的選擇會觸發不同的劇情路線,每條劇情路線都會獨立發展,最終走向不同的結局。
Git中所謂的“分支(branch)”就如同游戲中的劇情路線,用戶可以為項目建立不同的分支,使得項目能在不同的分支里獨立進行,並且互不干預。
當用戶初始化一個倉庫時,Git會自動為其建立一條主分支,默認稱其為master。若用戶沒有創建其他分支,那么項目發展的各個版本就默認存儲在這條 master 分支上。
分支指令介紹
分支的新建和切換
假設你正在項目上工作,並且在 master 分支上已經有了如下的提交。
對應的圖即為如下:
master 指針指向該分支上最新的提交; HEAD 指針指向的是當前所在分支。
此時你發現了項目中有一個代號為#11的bug需要你解決。你決定專門新建一個分支,在那條分支上把該問題解決。於是你敲入了新建分支的指令。
上面兩行命令可以僅用一條命令替代:$ git branch -b bug#11。
當我們在創建新的分支時,實際上是創建一個新的指針。它會指向 master 此時指向的提交。當我們切換到分支 bug#11時,HEAD 指針就會指向 bug#11,如下圖所示。
此外,我們可以用如下命令查看了目前倉庫中存在的分支。
可以看到目前共存在2個分支,其中帶*號的是目前所在分支:master。
分支的作用
於是你開始在 bug#11 這條分支上工作,並作出了如下的提交(commit)。
於是 bug#11 指針往前移動了一步,而 master 指針還是留在原地。
這時,當你用 $ git checkout master 命令切換回 master 分支時,你發現剛才在 bug#11 分支上新建的 log.txt 文件不見了,當前的工作目錄和你開始在 bug#11 分支工作前一模一樣。
這就是分支的好處,它將工作切分開來,讓工作多線獨立發展。
合並分支
我們將介紹在合並分支時會遇到的3種情況。
Fast-Forward
此時,你已經把 #bug11 修復完畢,你決定把這項修復合並到主線 master 中。於是,你使用了 $ git merge 命令來實現這個目的。
在合並的時候,你注意到了“快進(Fast-forward)”這個詞。當你試圖合並兩個分支時, 如果順着一個分支走下去能夠到達另一個分支,那么 Git 在合並兩者的時候, 只會簡單的將指針向前推進,因為這種情況下的合並操作沒有需要解決的分歧——這就叫做 “快進(fast-forward)”,如圖所示。
此時合並完成,所以你也不再需要 bug#11 分支了。你可以使用帶 -d 選項的 $ git branch 命令來刪除分支:
'recursive' strategy
此時,你又發現了項目中有一個代號為 bug#31 的漏洞需要修復,於是你先用 $ git branch bug#31 命令新建了一個分支。
現在的你還在 master 這條分支上工作:你將 Scheduling.txt 的文件內容修改為 Project Scheduling - 85% Done., 然后commit這次的修改。
此時,對應的圖為如下:
現在的你感到心滿意足,決心切換到 bug#31 分支上開始修復 bug#31。於是你先用 $ git checkout bug#31 命令切換到了該分支。
接着你辛辛苦苦了一整天,總算把 bug#31 修復完了。於是你修改了 log.txt 文件里的內容,加上了一行Fixed bug#31. ,並commit這次的修改,此時的圖對應如下:
現在,你決定把對 bug#31 的修復應用到 master 分支中來,於是你切換回 master 分支,然后再次調用了 $ git merge 命令:
你發現這次提示的和之前在合並 bug#11 分支時提示的不太一樣。因為此時,你想合並的 bug#31 指向的最新提交 C4 並不是 master 指向的最新提交 C3 的直接后繼(換句話說,C3 不能順着一條路走到 C4)。所以Git沒法再那么通過簡單的移動指針來完成合並了。
Git會找到 C3 和 C4 的共同祖先 C2,然后做一個三方合並。
那么什么是三方合並呢?
例子1:A是B和C的共同祖先。B相對A的改動是刪掉了3,C相對A的改動是增加了1。那么B和C合並的結果就是123。
例子2:A是B和C的共同祖先。B相對A的改動是刪掉了1,C相對A的改動是增加了3。那么B和C合並的結果就是23。
所以簡單來說,三方合並就是把B方和C方相對於共同祖先A方的改動分別應用到合並結果上。
剛才,C3 相對於 C2 的改動是修改了 Scheduling.txt 文件的內容,而 C4 相對於 C2 的改動是修改了 log.txt 文件里的內容,將這兩項改動都應用到合並結果中,就得到了一個既修改了 Scheduling.txt 又修改了 log.txt 的 C5 。
遇到沖突時的合並
有時候合並操作不會如此順利。 如果你在兩個不同的分支中,對同一個文件進行了不同的修改,Git 就沒法干凈的合並它們。
例如:你在 bug#31 分支中在 README.md 文件中添加了一行 I like Git.;在 master 分支中對 README.md 文件添加了一行 Git is good.,然后再執行 $ git merge 命令:
在兩個分支中,你都對 README.md 文件進行了修改,因此就會產生合並沖突。
打開 README.md 文件會看到如下內容,其中 <<<<<<< HEAD 到 ======= 之間的內容是 HEAD 指向分支里的內容,即 master;======= 到 >>>>>>> bug#31 之間的是 bug#31 分支里的內容。
你手動修改了這個文件,修改后的內容如下。
在Git輕松入門1:本地倉庫篇,我們提到過,文件修改后,需要執行 $ git add 和 $ git commit 兩個步驟。所以現在,你同樣需要執行這兩個步驟,而當你敲完命令,你會發現提示合並成功。
總結
總結一下今天出現過的幾個Git命令:
# 列出該倉庫存在的分支,當前分支的前面會帶有*號
$ git branch
# 創建分支
$ git branch [branch-name]
# 切換分支
$ git checkout [branch-name]
# 創建分支並立刻切換到該分支下
$ git checkout -b [branch-name]
# 刪除分支
$ git branch -d [branch-name]
# 合並分支
$ git merge [branch-name]
分支的作用在於將工作切分開來,使得工作可以多線獨立發展。以上是本講關於分支命令的概括。此外,本講還介紹了Git采取的3種合並策略:Fast-forward(直接移動指針),recursive strategy(采取三方合並)以及merge conflict(手動修改存在沖突的文件)。
參考
- http://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging
- https://www.zhihu.com/question/30200228
- https://www.liaoxuefeng.com/wiki/896043488029600/900003767775424
- https://www.runoob.com/git/git-branch.html
有問題歡迎大家在評論區留言,轉載請注明出處。
