還記得 Git 系列第一篇 Git 自我介紹的話嗎?其中有 Git 本身都贊同的三大特點git
cheap local branching, convenient staging areas, and multiple workflowsbash
輕量的本地分支, 方便的暫存,以及多工做流。其中由於有分支的存在,才構成了多工做流的特點,因此 Branch 不愧爲 Git 的王牌特點。這篇博客,主要和你們一塊兒學習一下輕若鴻毛,帥到炸裂的分支兒。微信
分支的概念,在我看來,分兩個版本:學習
從使用場景上解釋,是這麼個概念spa
Git 的分支,就是開發過程當中,要選擇的一條路,你能夠選擇和其餘小夥伴一塊兒走同一條路,也能夠本身走一條路,路與路之間相互沒有影響,做爲路的主人,你也隨時可讓兩條路合併。命令行
深刻一點的話,是這麼個概念:3d
Git 的分支,其實本質上僅僅是指向提交對象的可變指針,這個可變指針,指向路的終點。同時,還有一個比較特別的 HEAD 指針,用於記錄當前工做的位置,借用上面的例子,這個 HEAD 指針等於在路上走的你本身,你在哪,指針就在哪,你在哪一個分支,HEAD 指針就指向哪一個分支的指針。 指針
實際上,當咱們使用 Git 的時候,咱們就使用了分支,由於 Git 的默認分支名字是 master,若是你有心的話,會發現執行 git init
後,命令行的輸出頭部已經默認在 master 分支了。 可是這個時候,還並未建立 master 分支,只有當有一個提交的時候,纔會建立 master 分支。緣由在於,分支的指針要指向提交的呀,忽然明白了,當初看 Android Studio 的教程,爲何每一個都讓有一個初步提交了呢。code
無圖無真相,不信的看下面:cdn
有關分支的命令很少,無非是換着花樣的增刪改查,掌握好如下基本的命令,之後就能夠在 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 指針指向要切換的分支的指針處。
使用場景有兩個:
git checkout <name>
複製代碼
建立一個新分支,並切換到新分支,這個一步到位的話須要 -b
參數。
以當前分支爲基礎,建立一個新分支
git checkout -b <branch name>
複製代碼
以指定的某一個提交,建立一個新分支
git checkout -b <branch name> <SHA1>
複製代碼
以上,是分支的增刪改查獨立操做,可是 Git 創造這個分支,並不僅是爲了讓它們自個兒和自個兒玩的,還須要它們之間的相互協做和配合。 就像寫項目的時候,分好開發任務,你和你的小夥伴新建了兩個分支,你寫你的 Anglela,他寫他的 baby,到開發完成以後,確定要合在一塊兒,才能成就 Anglelababy。合的這個動做,就涉及到了分支合併的概念。
分支合併使用到的命令是
git merge <branch name>
複製代碼
分支合併相對分支的其餘操做,是相對要複雜一點的,怎麼說也是多分支操做,至少要對得起它一聽就比較高端的名字吧,因而我決定把分支的合併做爲一個大標題。
分支的合併是很是智能的,目前有兩種模式,兩種模式的選擇,不須要咱們參與,而是 Git 根據分支狀況不一樣,自行判斷選擇的。在我使用 Git 的過程當中,執行分支合併,有時須要輸入提交信息,有時不須要,做爲小白的我懵的不知因此然,後來才知道是由於合併模式的問題。
兩種模式是:
如圖,有兩個分支,master 分支和 feature 分支。當這兩個分支處於上面的關係時,當進行合併操做時,就會出現 fast-forward。
緣由是;因爲當前 master 分支所指向的提交是 feature 分支的直接上游,因此 Git 只是簡單的將指針向前移動。 換句話說,當你試圖合併兩個分支時,若是順着一個分支走下去可以到達另外一個分支,那麼 Git 在合併二者的時候,只會簡單的將指針向前推動(指針右移),由於這種狀況下的合併操做沒有須要解決的分歧——這就叫作 「快進(fast-forward)」。
合併後的分支指針位置以下:
這個合併方式,是爲補充 fast-forward 而出現的,由於你知道,在項目開發過程當中,不少人開發的狀況下,出現 fast-forward 的狀況並非不少,不少是相似下面這種。提交歷史是分叉的,沒法知足執行 fast-forward 的條件:
由於,master 分支所在提交併非 feature 分支所在提交的直接祖先,Git 不得不作一些額外的工做。 出現這種狀況的時候,Git 會使用兩個分支的末端所指的快照(C4 和 C5)以及這兩個分支的工做祖先(C3),作一個簡單的三方合併,生成一個新的提交(C6)。
提及來就是一堆理論,我本身都記不住,找個例子演示一下:
//建立一個文件夾,並初始化 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 時,是快進式合併:
master 分支合併 featureA 後, 再合併 featureB 時,已經不知足快進式條件了,此時合併會觸發一個三方合併,產生一個新的提交。因此,執行合併命令,會跳到下面的頁面,讓咱們編輯這個新提交的提交信息,默認提交信息是「Merge branch 'branch name'」. 按 i
編輯提交信息, :wq!
保存並退出頁面。
合併成功後的提示信息:
畫出上面小例子的分支合併,示意圖,以下:
有人在的地方就有江湖,有分支在的地方,就有衝突。有時候合併操做不會如此順利。 若是你在兩個不一樣的分支中,對同一個文件的同一個部分進行了不一樣的修改,Git 就無法乾淨的合併它們,因而就會發生衝突。
以下,分別在 master 和 featureA ,在 master.txt 文件第一行添加一句話,而後兩個分支合併,就會發生衝突。
衝突提示信息中,指明衝突文件爲 master.txt。同時,也能夠經過 git status
命令,查看衝突的詳細信息
須要說明的是,若是遇到衝突的話,git 就沒法自動合併了,接下來要靠咱們本身手動解決衝突,方法是:
git add
操做先知道一下思路,有個簡單的概念在腦子裏,接下來,一步一步仔細看~
衝突文件 master.txt 以下,git 雖然沒法解決衝突, 可是已經幫咱們幫到最後了,使用簡單的三個符號,標明瞭衝突的地方,以及衝突的兩個分支在該地方發生衝突內容。
符號 | 意義 |
---|---|
======= | 分隔符 |
<<<<<<< HEAD 至 ======= | master 分支中該地方的內容 |
======= 至 >>>>>>> featureA | featureA 分支中該地方爲內容 |
接下來編輯 master.txt 文件,完成合並,確認以後,把 git 衝突標識符號給刪除掉便可。
現實中,不免有些時候,你會有後悔的念頭。例如天天我遲到的時候,都會後悔爲何第一遍鬧鐘響的時候沒有起牀,可是這個世界,沒有後悔路能夠走,我只能努力作到明天早起。
可是,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 系列走起,下篇博客見!