Git三大特色之Branch(分支)

NO IMAGE

我習慣每篇博客都有個開篇

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

cheap local branching, convenient staging areas, and multiple workflows

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

Branch 的概念

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

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

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

Git三大特色之Branch(分支)

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

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

Git三大特色之Branch(分支)

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

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

Git三大特色之Branch(分支)

玩轉 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(分支)

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

Git三大特色之Branch(分支)

Git三大特色之Branch(分支)

和平解決 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 分支中該地方的內容
======= 至 >>>>>>> featureAfeatureA 分支中該地方為內容

接下來編輯 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 系列走起,下篇博客見!


Git三大特色之Branch(分支)

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

相關文章

Git三大特色之WorkFlow(工作流)

Git三大特色之Stage(暫存區)

Android少年,快拔掉你的數據線

Android巧妙利用CompoundDrawables