Git三大特色之Branch(分支)

段淺淺兒發表於2019-02-28

我習慣每篇部落格都有個開篇

還記得 Git 系列第一篇 Git 自我介紹的話嗎?其中有 Git 自己都贊同的三大特色

cheap local branching, convenient staging areas, and multiple workflows

輕量的本地分支, 方便的暫存,以及多工作流。其中因為有分支的存在,才構成了多工作流的特色,所以 Branch 不愧為 Git 的王牌特色。這篇部落格,主要和大家一起學習一下輕若鴻毛,帥到炸裂的分支兒。

Branch 的概念

分支的概念,在我看來,分兩個版本:

從使用場景上解釋,是這麼個概念

Git 的分支,就是開發過程中,要選擇的一條路,你可以選擇和其他小夥伴一起走同一條路,也可以自己走一條路,路與路之間相互沒有影響,作為路的主人,你也隨時可以讓兩條路合併。

簡筆畫 Git 分支

深入一點的話,是這麼個概念

Git 的分支,其實本質上僅僅是指向提交物件的可變指標,這個可變指標,指向路的終點。同時,還有一個比較特別的 HEAD 指標,用於記錄當前工作的位置,借用上面的例子,這個 HEAD 指標等於在路上走的你自己,你在哪,指標就在哪,你在哪個分支,HEAD 指標就指向哪個分支的指標。

深層次的分支概念圖

實際上,當我們使用 Git 的時候,我們就使用了分支,因為 Git 的預設分支名字是 master,如果你有心的話,會發現執行 git init後,命令列的輸出頭部已經預設在 master 分支了。 但是這個時候,還並未建立 master 分支,只有當有一個提交的時候,才會建立 master 分支。原因在於,分支的指標要指向提交的呀,突然明白了,當初看 Android Studio 的教程,為什麼每個都讓有一個初步提交了呢。

無圖無真相,不信的看下面:

git 預設分支 master

玩轉 Branch 必備技能

有關分支的命令不多,無非是換著花樣的增刪改查,掌握好以下基本的命令,以後就可以在 Branch 的草原上策馬奔騰瀟瀟灑灑啦

建立分支

 git branch <name>
複製程式碼

這個命令看起來,似乎簡單到你只需要想個分支的名字就好了。
但是在建立分支的時候,要想下,是否要從當前分支的內容基礎上去開闢一條新分支。

檢視分支

三個命令,讓你想看什麼分支就看什麼分支,就是這麼方便

 git branch //檢視本地分支
 git branch -r //檢視遠端分支
 git branch -a //檢視本地和遠端的所有分支
複製程式碼

刪除分支

當本地分支刪除後,推動到遠端倉庫後,遠端倉庫並不能自動刪除遠端分支(原因,下回分解)。所以,分支的完全刪除是分兩個部分的,一個是本地,一個是遠端。

本地刪除操作需要加上 -d或者 -D 引數,引數的名稱來自英語 delete的縮寫,Remember it so easy!

兩者的區別在於-D-d要粗暴一點。當被刪除分支有新內容沒有被合併的時候,使用-D,會直接刪除, 使用-d,會提示該分支有新內容沒有被合併,不執行刪除。刪除需謹慎,建議非特殊情況下,使用溫柔的-d要好一點,以免小手一抖,眼淚長流。

 git branch -d <name>
 git branch -D <name> //強制刪除

複製程式碼

刪除遠端分支需要 push 操作。

git push origin :<name>
複製程式碼

重新命名分支

其實,這是個偽命題。

但是有很多人,包括我,都有過對分支名稱不滿意想該修改一下的想法,所以,就有了這個偽命題的存在。

事實上,分支不存在重新命名,沒有 rename 的這個命令。如果你起的名字不滿意,想重新起的話,那隻要建立一個和要修改分支內容一樣的分支,起上你喜歡的名字,然後再把之前的給刪掉。

檢出分支

這個檢出分支的“檢出”二字,算是個關於 Git 分支的專業術語了,你可以理解為切換當前分支。
本質上, checkout 操作是移動 HEAD 指標,將 HEAD 指標指向要切換的分支的指標處。

使用場景有兩個:

  1. 已經存在的分支,現在要切換過去。
 git checkout <name>
複製程式碼
  1. 建立一個新分支,並切換到新分支,這個一步到位的話需要 -b 引數。

    以當前分支為基礎,建立一個新分支

    git checkout -b <branch name>
    複製程式碼

    以指定的某一個提交,建立一個新分支

    git checkout -b <branch name> <SHA1>
    複製程式碼

合併分支

以上,是分支的增刪改查獨立操作,但是 Git 創造這個分支,並不只是為了讓它們自個兒和自個兒玩的,還需要它們之間的相互協作和配合。 就像寫專案的時候,分好開發任務,你和你的小夥伴新建了兩個分支,你寫你的 Anglela,他寫他的 baby,到開發完成之後,肯定要合在一起,才能成就 Anglelababy。合的這個動作,就涉及到了分支合併的概念。

分支合併使用到的命令是

git merge <branch name>
複製程式碼

分支合併相對分支的其他操作,是相對要複雜一點的,怎麼說也是多分支操作,至少要對得起它一聽就比較高階的名字吧,於是我決定把分支的合併作為一個大標題。

Branch 合併是大事

git 的兩種合併模式

分支的合併是非常智慧的,目前有兩種模式,兩種模式的選擇,不需要我們參與,而是 Git 根據分支情況不同,自行判斷選擇的。在我使用 Git 的過程中,執行分支合併,有時需要輸入提交資訊,有時不需要,作為小白的我懵的不知所以然,後來才知道是因為合併模式的問題。

兩種模式是:

  1. Fast-Forward(快進式)(PS:這個名字是官方的)
  2. Recursive Strategy Merge(策略合併式)(PS:這個名字非官方,我自己起的,有時也叫三方合併式)
  • Fast-Forward(快進式)

Git三大特色之Branch(分支)

如圖,有兩個分支,master 分支和 feature 分支。當這兩個分支處於上面的關係時,當進行合併操作時,就會出現 fast-forward。

原因是;由於當前 master 分支所指向的提交是 feature 分支的直接上游,所以 Git 只是簡單的將指標向前移動。 換句話說,當你試圖合併兩個分支時,如果順著一個分支走下去能夠到達另一個分支,那麼 Git 在合併兩者的時候,只會簡單的將指標向前推進(指標右移),因為這種情況下的合併操作沒有需要解決的分歧——這就叫做 “快進(fast-forward)”。

合併後的分支指標位置如下:

Git三大特色之Branch(分支)

  • Recursive Strategy Merge(策略合併式)

這個合併方式,是為補充 fast-forward 而出現的,因為你知道,在專案開發過程中,很多人開發的情況下,出現 fast-forward 的情況並不是很多,很多是類似下面這種。提交歷史是分叉的,無法滿足執行 fast-forward 的條件:

Git三大特色之Branch(分支)

因為,master 分支所在提交併不是 feature 分支所在提交的直接祖先,Git 不得不做一些額外的工作。 出現這種情況的時候,Git 會使用兩個分支的末端所指的快照(C4 和 C5)以及這兩個分支的工作祖先(C3),做一個簡單的三方合併,生成一個新的提交(C6)。

Git三大特色之Branch(分支)

實戰演練一下

說起來就是一堆理論,我自己都記不住,找個例子演示一下:

//建立一個資料夾,並初始化 Git
mkdir GitDemo
git init

//初次提交,建立 master 分支
touch master.txt
git add.
git commit -m '新增master檔案'

//從master分支末尾,建立並切換 featureA 分支,並建立一個提交
git checkout -b featureA
touch A.txt
git add.
git commit -m '新增A檔案'

//從master分支末尾,建立並切換 featureB 分支,並建立一個提交
git checkout master
git checkout -b featureB
touch B.txt
git add.
git commit -m '新增B檔案'

//切換 master 分支
git checkout master

//master 合併 featureA 分支
git merge featureA

//master 合併featureA 後再合併 featureB 分支
git merge featureB

複製程式碼

博主不想給你說話,並向你投擲了一大串命令,快去敲敲看啊,會看到兩種合併模式的!

master 分支合併 featureA 時,是快進式合併:

Git三大特色之Branch(分支)

master 分支合併 featureA 後, 再合併 featureB 時,已經不滿足快進式條件了,此時合併會觸發一個三方合併,產生一個新的提交。所以,執行合併命令,會跳到下面的頁面,讓我們編輯這個新提交的提交資訊,預設提交資訊是“Merge branch 'branch name'”. 按 i編輯提交資訊, :wq!儲存並退出頁面。

Git三大特色之Branch(分支)

合併成功後的提示資訊:

Git三大特色之Branch(分支)

畫出上面小例子的分支合併,示意圖,如下:

master 合併 featureA

master 合併 featureB

和平解決 Branch 合併衝突

有人在的地方就有江湖,有分支在的地方,就有衝突。有時候合併操作不會如此順利。 如果你在兩個不同的分支中,對同一個檔案的同一個部分進行了不同的修改,Git 就沒法乾淨的合併它們,於是就會發生衝突。

如下,分別在 master 和 featureA ,在 master.txt 檔案第一行新增一句話,然後兩個分支合併,就會發生衝突。

Git三大特色之Branch(分支)

衝突提示資訊中,指明衝突檔案為 master.txt。同時,也可以通過 git status 命令,檢視衝突的詳細資訊

Git三大特色之Branch(分支)

需要說明的是,如果遇到衝突的話,git 就無法自動合併了,接下來要靠我們自己手動解決衝突,方法是:

  1. 檢視造成衝突的檔案,修改衝突部分
  2. 對修改後衝突檔案,執行 git add操作
  3. 建立一個修改衝突的提交。

先知道一下思路,有個簡單的概念在腦子裡,接下來,一步一步仔細看~

第一步:檢視造成衝突的檔案,修改衝突部分

衝突檔案 master.txt 如下,git 雖然無法解決衝突, 但是已經幫我們幫到最後了,使用簡單的三個符號,標明瞭衝突的地方,以及衝突的兩個分支在該地方發生衝突內容。

Git三大特色之Branch(分支)

符號 意義
======= 分隔符
<<<<<<< HEAD 至 ======= master 分支中該地方的內容
======= 至 >>>>>>> featureA featureA 分支中該地方為內容

接下來編輯 master.txt 檔案,完成合並,確認之後,把 git 衝突識別符號號給刪除掉即可。

第二步 & 第三步:修改後衝突檔案,add && commit

Git三大特色之Branch(分支)

分支回滾, 有後悔路可以走

現實中,難免有些時候,你會有後悔的念頭。例如每天我遲到的時候,都會後悔為什麼第一遍鬧鐘響的時候沒有起床,但是這個世界,沒有後悔路可以走,我只能努力做到明天早起。

但是,Git 中有!因為神奇的 reset 和 revert 命令~,兩個命令都可以達到回滾的效果,兩者之間的區別以後會專門說,這裡我們使用 reset 。

提前宣告:回滾之前,不要忘記做好備份,有備無患吶。

本地分支回滾:

確定回滾到哪個提交,找到該提交的 commit id,執行以下命令,就好了

git reset --hard commit id
複製程式碼

遠端分支回滾

依舊是個偽命題。遠端分支不存在什麼回滾,要想達到回滾的效果,就是刪除之前的遠端分支,然後把本地回滾好的本地分支,push 到遠端。

git reset --hard commit id //本地分支回滾
git push origin :<name> //刪除遠端分支
git push origin <name> //用回滾後的本地分支重新建立遠端分支
複製程式碼

我習慣每篇部落格都有個結束語

這篇部落格用了我不少洪荒之力,希望對大家理解 Git 分支有所幫助,不對之處還請指出。
最近 Git 系列走起,下篇部落格見!


歡迎關注博主的微信公眾號,快快加入哦,期待與你一起成長!

歡迎關注博主的微信公眾號,快快加入哦,期待與你一起成長!

相關文章