前情提要:Git應用詳解第二講:Git刪除、修改、撤銷操做html
分支是git
最核心的操做之一,瞭解分支的基本操做可以大大提升項目開發的效率。這一講就來介紹一些分支的常見操做及其基本原理。git
在開發當中,每每須要分工合做。好比:小紅開發A
功能,小明開發B
功能,小剛開發C
功能。如何才能作到三者並行開發呢?git
爲咱們提供的分支功能就能實現這一需求,以下圖所示:vim
在實際的開發過程當中,master
分支是用來發布項目穩定版本的。新的功能每每是在一個新建的分支上進行開發,等到新功能開發完畢並通過測試,表現穩定後,纔會合併到master
分支上進行版本更新。這樣就能夠在保持一款軟件發行的同時,同步進行新功能的開發。less
一般來講,遠程倉庫的Git
分支會有以下幾種:master
分支、test
分支、develop
分支,除此以外可能還有緊急修復bug
的hotfix
分支;可是,本地的分支能夠有不少;本文主要介紹Git
本地分支的內容。編輯器
git branch
查看當前版本庫中的全部分支:工具
其中的 *
表示當前處於的分支,可見當前處於master
分支;測試
使用git init
初始化git
倉庫時,git
會自動建立一個master
分支。可是,若是沒有在master
分支上進行任何提交就切換到其餘分支,那麼在切換分支的時候master
分支會被銷燬。而且,沒法查看沒有提交記錄的分支,以下圖所示:命令行
git branch -a
查看全部本地分支,包括本地分支和本地遠程分支:指針
git branch -v
查看全部本地分支上最近一次的提交記錄:code
可是,該指令沒法查看本地遠程分支:
git branch -r
-r
參數用於單獨查看本地遠程分支:
git branch -av
該指令不只能夠顯示全部的本地分支,包括本地遠程分支,以及對應分支上的最新提交信息:
git branch -vv
-vv
參數表示查看全部本地分支與遠程分支的關聯狀況。如圖所示,本地master
分支有本地遠程分支origin/master
與之關聯,說明它已與遠程master
分支創建了關聯;
至於上面提到的本地遠程分支,將在下一講中詳細介紹。
git branch <branch_name>
可經過上述命令建立新分支new_branch
:
因爲是在master
分支上建立的new_branch
分支,因此new_branch
分支與master
分支有着部分共同的提交歷史;因此,master
分支上的文件,new_branch
分支上都有。可是,在new_branch
分支上添加的new_branch
文件,不會存在於master
分支上:
此時兩分支的狀態爲:
git branch -b <branch_name>
經過上述命令可建立並切換到new_branch
分支:
如圖所示,原本所在分支爲master
,而且沒有new_branch
分支。執行上述命令後,建立並切換到了new_branch
分支上。
git checkout <branch_name>
好比切換到new_branch
分支:
git checkout -
切換回上次操做的分支:
git branch -m <oldName> <newName>
以下圖所示,將本地分支master
重命名爲master2
:
git branch -d new_branch
刪除new_branch
分支:
注意點:
不能刪除當前所處的分支;
當須要刪除的分支上有master
分支沒有的內容,而且刪除前沒有進行合併(merge
)時,會報錯:
此時能夠經過git branch -D new_branch
使用參數D
,在不合並的狀況下強制刪除分支;
注意:這裏所講的分支指的是有公共提交節點的分支,以下圖中的dev
與master
分支所示,提交節點A
爲它們的公共提交節點:
當兩分支沒有公共提交節點,以下圖所示,應採用rebase
進行合併,後面會詳細介紹:
git merge <branch_name>
首先,建立並切換到新分支dev
中,併爲test.txt
文件添加內容dev1
:
注意:要將dev
分支上的這一修改提交到版本庫,才能進行後續合併。由於合併的是提交對象鏈,詳情見後面講解的合併原理:
而後,切換回master
分支,經過git merge dev
指令,將dev
分支中的內容合併到當前所處的master
分支中;合併後master
分支與dev
分支上test.txt
文件的內容達到了同步:
git
分支的合併採用的是三方合併的原則:找到兩分支最新提交A
和B
的公共父節點C
,在這三個節點的基礎上合併爲節點D
。這個節點D
就包含了兩個分支上的全部內容:
分支:指向一條commit
對象鏈或一條工做記錄線的指針;
快照A~D
分別表示四次提交(commit
),注意提交的順序爲:A -> B -> C -> D
:
從圖中能夠看到每一次提交的對象內都會保存上一次提交的commit id
,由此能夠從後往前把全部的提交(commit
)串起來造成一條鏈(相似單向鏈表),這條鏈就組成了一條完整的分支信息:
當版本庫中只有一條分支:該分支的最新提交就包含了整條分支的全部內容,表明版本庫的當前狀態。如上圖的快照D
,裏面包含了快照A~C
中的全部內容,此時快照D
中的內容就是整個版本庫中的內容:
當版本庫中有多條分支:每條分支上的最新提交包含了所處分支的所有內容,將各個分支的最新提交進行合併。合併的節點就包含了全部分支的內容,也就是現階段的版本庫自己;以下圖中的d1
、m2
、t3
分別包含了dev
、master
、test
分支上的全部內容:
==
指針情景一:
從圖中能夠看到:
HEAD
爲一個指針:指向當前分支;
master
也爲一指針:指向提交;
情景二:
上圖中,dev
爲master
分支上建立的新分支,可知:
git
在建立新分支時,文件自己不變化,只須要建立一個表明新分支,並指向當前分支的指針;如圖中的dev
與master
指向同一個提交,文件沒有發生任何變化;HEAD
指向dev
分支,表示當前所處分支爲dev
,至關於執行了:git checkout -b dev
後的狀態;相信你已經發現:
HEAD
是一個始終指向當前分支的指針;
HEAD
標識符HEAD
文件是一個指向當前所在分支的引用標識符,也能夠理解爲一個指針,它與分支之間的關係是這樣的:
HEAD
HEAD
文件中並不包含SHA1
值(每次提交的commit ID
),而是包含一個指向另一個引用的指針。咱們能夠查看.git
目錄下的HEAD
文件:
可見HEAD
指向的是當前所在的master
分支;
當咱們經過git checkout -b dev
建立並切換到dev
分支後,再次進入.git
文件夾查看HEAD
,會發現此時HEAD
指向了dev
:
由此證實了HEAD
始終指向當前分支;
當執行git commit
命令時,git
會建立一個commit
對象(好比下圖D
)。而且將這個commit
對象的parent
指針指向HEAD
所指向的引用(master
)指向的提交(也就是C
),這樣就能造成一條提交鏈:
咱們對於HEAD
修改的任何操做,都會被git reflog
完整記錄下來:
可是手動地修改HEAD
文件,這些信息就不會被記錄下來,因此十分不建議手動修改git
相關的配置文件,而是應該儘可能採用命令行的方式來修改。
HEAD
實際上,咱們能夠經過git
的底層命令symbolic-ref
來實現對HEAD
文件內容的修改;
git
中的命令可分爲兩類:高級命令和底層命令;以前介紹的git add
等都是高級命令;
讀取:
寫入:
要注意格式:refs/heads/develop
;
查看ORIG_HEAD
文件:
裏面是一個SHA1
值,查看當前的提交信息:
能夠發現,ORIG_HEAD
裏面的SHA1
值就是最新一次提交的SHA1
值。
查看FETCH_HEAD
文件:
裏面有兩個信息,一個是最新提交的commit ID
,另外一個是提交信息。
因此,對於git
而言commit ID
是十分重要的信息,經過這個SHA1
值能夠回溯或查找須要的提交。
git merge
原理在新分支上進行提交操做
上圖表示在dev
分支上進行了一次提交,此時:
master
的提交記錄由:A
、B
和C
組成;dev
的提交歷史則由:A
、B
、C
和D
組成;對兩分支進行合併操做
在master
分支上執行:git merge dev
將dev
分支的內容合併到了master
分支上;這種合併方式叫作:Fast-forward
,沒有衝突,改變的只是master
指針的指向;
在執行合併操做前:
master
分支上查看該分支的提交記錄:dev
分支上查看該分支的提交記錄:能夠看到dev
分支只是比master
分支多進行了一次提交(dev1
),兩分支狀態以下圖所示:
執行合併操做:
先切換到master
分支,而後執行git merge dev
合併dev
分支:
能夠看到使用了Fast-forward
方式進行合併,合併後兩分支狀態以下圖所示:
合併後,HEAD
同時指向了master
和dev
分支;而且master
和dev
分支的提交歷史徹底一致;這就說明了:使用Fast-forward
(快進合併)方式進行分支合併,只會改變master
分支指針的指向;
Fast-forward
git
會使用Fast-forward
模式;--no-ff
參數會禁止使用Fast-forward
方式,這樣會多出一次提交記錄;
ff
表示Fast-forward
。
具體演示以下:
Fast-forward
首先,查看master
分支上最新的3
次提交:
此時兩分支的狀態爲:
隨後在dev
分支上新增一次提交:dev2
。查看dev
分支上最新的3
次提交:
此時兩個分支的狀態爲:
切換回master
分支,經過git merge dev
合併dev
分支,此時默認採用Fast-forward
方式:
能夠看到合併後,master
直接指向了dev
的最新提交,並無產生新的提交。合併後兩分支的狀態以下所示:
由此驗證了Fast-forward
方式只會改變分支指針的指向。
Fast-forward
合併時能夠經過:
git merge --no-of dev
禁用Fast-forward
模式。
繼續在dev
分支新增一次提交:dev3
。而後查看dev
分支上最新的3
次提交:
不修改master
分支,查看其最新的3
次提交:
此時兩個分支的狀態爲:
而後,在master
分支上不使用Fast-forward
方式合併dev
分支。合併命令採用:
git merge --no-ff dev
執行後進入以下的vim
編輯器界面,要求咱們填寫提交註釋:
這說明不使用Fast-forward
方式合併分支,會觸發了一次提交。填寫提交註釋後完成提交操做,合併完成後,查看master
分支的提交記錄:
能夠發現禁用了Fast-forward
模式的合併會比dev
分支多產生一次提交:Merge branch 'dev'
,即便合併後的內容是同樣的。此時兩分支的狀態爲:
由此驗證了,禁用Fast-forward
方式合併,會多出一個表示合併的提交記錄。
合併的兩分支只有一條分支發生了改變,而且其中一分支是基於另外一分支建立的。好比上述的master
與dev
分支,兩分支沒有分岔,此時不會出現合併衝突;git
會經過Fast-forward
方式自動完成合並操做;
可是,當合並的兩分支都發生改變時,即分支出現分岔,以下圖所示。此時就須要解決衝突後手動合併分支了:
具體演示以下:
首先,分別對兩分支上的test.txt
文件進行修改,並分別將修改提交到各自的分支;
master
分支上進行新的提交:mas3
,而後查看文件test.txt
內容和分支提交記錄:dev
分支上進行新的提交:dev1
,而後查看文件test.txt
內容和分支提交記錄:可見兩分支的提交記錄只有最新一次提交不同:
在master
分支上,經過git merge dev
合併dev
分支時,會在共同修改的test.txt
文件中出現合併衝突,以下圖所示:
出現衝突的緣由爲:兩個分支都對同一個文件test.txt
進行了修改,git
合併時並不知道以哪一個分支的修改成標準。因此不能採用Fast-forward
方式自動合併,須要解決衝突,手動合併。
手動合併操做須要分以下三步進行:
此時進入發生合併衝突的test.txt
文件:
會出現典型的衝突呈現方式(此時HEAD
指向的是master
分支),其中:
<<<HEAD
與>>>dev
之間的內容表示:兩分支上test.txt
文件的不一樣之處;
<<<HEAD
與===
之間的內容表示:當前分支master
對test.txt
文件的修改;
===
與>>>dev
之間的內容表示:dev
分支對test.txt
文件的修改;
此時只須要在test.txt
中保留想要的內容便可,例如:將兩分支對test.txt
的修改都進行保存,刪除三、五、7
行多餘的內容:
除此以外,還能夠經過git mergetool
指令,調用vimdiff
工具進入vim
編輯器,來解決test.txt
文件的衝突:
在實際開發中,咱們不多手動進行合併,而是藉助於一些工具來實現。
git add test.txt
將手動解決衝突時對test.txt
的修改提交到暫存區;編輯完畢後,能夠看到此時仍然處於合併過程當中(MERGING
)。經過git status
查看狀態,發現手動解決衝突時對test.txt
文件的修改操做還在工做區中,須要經過git add test.txt
將這一修改歸入暫存區,繼續進行合併:
git commit -m '合併註釋'
將手動解決衝突時對test.txt
的修改進行提交,完成合並操做;若是須要填寫較多的合併註釋,能夠經過git commit
進入vim
編輯器編輯。提交後,完成整個手動合併過程。
完成手動合併分支後,查看兩分支的提交歷史:
master
分支上的提交歷史:dev
分支上的提交歷史:能夠發現此時兩分支轉變爲了能夠經過Fast forward
方式合併的形式了,如圖所示:
手動解決衝突後:
若想將dev
和master
分支上的內容進行同步,只須要在dev
分支中經過git merge master
合併master
分支便可。此時就可使用Fast-forward
方式進行合併了,合併結果以下圖所示:
驗證:
合併後,查看dev
分支的提交歷史:
能夠看到HEAD
同時指向dev
與master
,即三個指針都指向了最新的一次提交,符合上述分析得出的結論;
通過上面的討論,不難看出:合併分支的實質就是不一樣提交的合併,以及HEAD
和分支指針的移動;
以上就是今天介紹的本地分支重要操做,相信看到這裏的你已經對
git
本地分支的操做了如指掌了。在下一講中將介紹git
最神奇的功能:版本回退。俗話說得好:世上沒有後悔藥。可是在git
中,就存在所謂的"後悔藥"!那麼咱們下一節再見。