Git 版本控制管理(二)

Git 分支管理

1. 概念

咱們來抽象的理解,分支就是科幻電影裏面的平行宇宙,當你正在電腦前努力學習Git的時候,另外一個你正在另外一個平行宇宙裏努力學習SVN。若是兩個平行宇宙互不干擾,那對如今的你也沒啥影響。不過,在某個時間點,兩個平行宇宙合併了,結果,你既學會了git又學會了SVN!git

那麼分支在實際中有什麼用呢?假設你準備開發一個新功能,可是須要兩週才能完成,第一週你寫了50%的代碼,若是馬上提交,因爲代碼還沒寫完,不完整的代碼庫會致使別人不能幹活了。若是等代碼所有寫完再一次提交,又存在丟失天天進度的巨大風險。vim

如今有了分支,就不用怕了。你建立了一個屬於你本身的分支,別人看不到,還繼續在原來的分支上正常工做,而你在本身的分支上幹活,想提交就提交,直到開發完畢後,再一次性合併到原來的分支上,這樣,既安全,又不影響別人工做。安全

2.建立與合併分支

git把咱們以前每次提交的版本串成一條時間線,這條時間線就是一個分支。截止到目前只有一條時間線,在git裏,這個分支叫主分支,即master分支。HEAD嚴格來講不是指向提交,而是指向master,master纔是指向提交的,因此,HEAD指向的就是當前分支。bash

1) 一開始的時候,master分支是一條線,git用master指向最新的提交,再用HEAD指向master,就能肯定當前分支,以及當前分支的提交點:學習

每次提交,master分支都會向前移動一步,這樣,隨着你不斷提交,master分支的線也愈來愈長。this

2)當咱們建立新的分支,例如dev時,git新建了一個指針叫dev,指向master相同的提交,再把HEAD指向dev,就表示當前分支在dev上:spa

git建立一個分支很快,由於除了增長一個dev指針,改變HEAD的指向,工做區的文件都沒有任何變化。3d

3)不過,從如今開始,對工做區的修改和提交就是針對dev分支了,好比新提交一次後,dev指針往前移動一步,而master指針不變:指針

 

4)假如咱們在dev上的工做完成了,就能夠把dev合併到master上。git怎麼合併呢?最簡單的方法,就是直接把master指向dev的當前提交,就完成了合併:code

git合併分支也很快,就改改指針,工做區內容也不變。

5)合併完分支後,甚至能夠刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉後,咱們就剩下了一條master分支:

實戰案例演示:

執行以下命令能夠查看當前有幾個分支,而且看到在哪一個分支下工做

[root@kai git_test]# git branch
* master
[root@kai git_test]#

下面建立一個分支dev並切換到其上進行工做。

[root@kai git_test]# git branch
* master
[root@kai git_test]# git checkout -b dev
Switched to a new branch 'dev'
[root@kai git_test]# git branch
* dev
  master
[root@kai git_test]#

下面咱們修改code.txt內容,在裏面添加一行,並進行提交。

[root@kai git_test]# echo "add one line" >> code.txt 
[root@kai git_test]# cat code.txt 
this is the first line
this is the second line
this is the third line
this is the forth line
add one line
[root@kai git_test]# git add code.txt 
[root@kai git_test]# git commit -m "dev_branch_submit"
[dev b63902b] dev_branch_submit
 1 file changed, 1 insertion(+)
[root@kai git_test]#

dev分支的工做完成,咱們就能夠切換回master分支:

[root@kai git_test]# git commit -m "dev_branch_submit"
[dev b63902b] dev_branch_submit
 1 file changed, 1 insertion(+)
[root@kai git_test]# git checkout master
Switched to branch 'master'
[root@kai git_test]# git branch
  dev
* master
[root@kai git_test]#

master分支查看code.txt,發現添加的內容沒有了。由於那個提交是在dev分支上,而master分支此刻的提交點並無變:

[root@kai git_test]# cat code.txt 
this is the first line
this is the second line
this is the third line
this is the forth line
[root@kai git_test]# 

如今,咱們把dev分支的工做成果合併到master分支上:

[root@kai git_test]# git merge dev
Updating f25e944..b63902b
Fast-forward
 code.txt | 1 +
 1 file changed, 1 insertion(+)
[root@kai git_test]# cat code.txt 
this is the first line
this is the second line
this is the third line
this is the forth line
add one line
[root@kai git_test]#

注意到上面的Fast-forward信息,Git告訴咱們,此次合併是「快進模式」,也就是直接把master指向dev的當前提交,因此合併速度很是快。

合併完成後,就能夠放心地刪除dev分支了,刪除後,查看branch,就只剩下master分支了。

[root@kai git_test]# git branch -d dev
Deleted branch dev (was b63902b).
[root@kai git_test]# git branch
* master
[root@kai git_test]#

小結:
查看分支:git branch
建立分支:git branch <name>
切換分支:git checkout <name>
建立+切換分支:git checkout -b <name>
合併某分支到當前分支:git merge <name>
刪除分支:git branch -d <name>

3. 解決衝突

合併分支每每也不是一路順風的。

再建立並切換一個新分支dev,修改code.txt內容,並進行提交。

[root@kai git_test]# git checkout -b dev
Switched to a new branch 'dev'
[root@kai git_test]# git branch
* dev
  master
[root@kai git_test]# echo "add two line" >> code.txt 
[root@kai git_test]# cat code.txt 
this is the first line
this is the second line
this is the third line
this is the forth line
add one line
add two line
[root@kai git_test]# git add code.txt 
[root@kai git_test]# git commit -m "dev_branch_submit"
[dev 7da47b4] dev_branch_submit
 1 file changed, 1 insertion(+)
[root@kai git_test]# 

切換回master分支,在master的code.txt添加一行內容並進行提交。

[root@kai git_test]# git checkout master
Switched to branch 'master'
[root@kai git_test]# echo "add two line in master" >> code.txt 
[root@kai git_test]# cat code.txt
this is the first line
this is the second line
this is the third line
this is the forth line
add one line
add two line in master
[root@kai git_test]# git add code.txt 
[root@kai git_test]# git commit -m "matser_branch_submit"
[master e57c158] matser_branch_submit
 1 file changed, 1 insertion(+)
[root@kai git_test]# 

如今,master分支和dev分支各自都分別有新的提交,變成了這個樣子:

這種狀況下,git沒法執行「快速合併」,只能試圖把各自的修改合併起來,但這種合併就可能會有衝突。

執行以下命令嘗試將dev分支合併到master分支上來。

[root@kai git_test]# git merge dev
Auto-merging code.txt
CONFLICT (content): Merge conflict in code.txt
Automatic merge failed; fix conflicts and then commit the result.
[root@kai git_test]# 

git告訴咱們,code.txt文件存在衝突,必須手動解決衝突後再提交。

git status也能夠告訴咱們衝突的文件:

[root@kai git_test]# git status
# On branch master
# You have unmerged paths.
#   (fix conflicts and run "git commit")
#
# Unmerged paths:
#   (use "git add <file>..." to mark resolution)
#
#	both modified:      code.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
[root@kai git_test]# 

查看code.txt的內容。

[root@kai git_test]# cat code.txt 
this is the first line
this is the second line
this is the third line
this is the forth line
add one line
<<<<<<< HEAD
add two line in master
=======
add two line
>>>>>>> dev
[root@kai git_test]#

git用<<<<<<<,=======,>>>>>>>標記出不一樣分支的內容,咱們修改以下後保存,再次提交:

[root@kai git_test]# cat code.txt 
this is the first line
this is the second line
this is the third line
this is the forth line
add one line
add two line in master
add two line
[root@kai git_test]# git add code.txt 
[root@kai git_test]# git commit -m "resolve_the_conflict"
[master b46a32f] resolve_the_conflict
[root@kai git_test]#

如今,master分支和dev分支變成了下圖所示:

用帶參數的git log也能夠看到分支的合併狀況:

[root@kai git_test]# git commit -m "resolve_the_conflict"
[master b46a32f] resolve_the_conflict
[root@kai git_test]# git log --graph --pretty=oneline
*   b46a32ff94fb7cf4b61ce9af466c5433b0469fb2 resolve_the_conflict
|\  
| * 7da47b4af8476b1c42b03bf04b7d3f103b16da0d dev_branch_submit
* | e57c158c60697955a4179ab87244957967419f70 matser_branch_submit
|/  
* b63902b3874dd3e0a3e0b1ae3e0eb0f30cd616d4 dev_branch_submit
* f25e944f3e23532ecc3d2837c32057826920474b delete_code2.txt
* 66a9c996749285bdb5e2010b992483e8a1a1771c version4
* f18f0ccadc62b83fa4c6e2222956ba2f2a0e5230 version3
* 6280fa584403809ac2078a81120acf33e6bec836 version2
* 020bf021ec6d1b77836db4e96541d3659251714e version1
[root@kai git_test]#

最後工做完成,能夠刪除dev分支。

[root@kai git_test]# git branch -d dev
Deleted branch dev (was 7da47b4).
[root@kai git_test]# git branch
* master
[root@kai git_test]#

 4. 分支管理策略

一般,合併分支時,若是可能,git會用fast forward模式,可是有些快速合併不能成功並且合併時沒有衝突,這個時候會合並以後並作一次新的提交。但這種模式下,刪除分支後,會丟掉分支信息。

 

建立切換到dev分支下,新建一個文件code3.txt編輯內容以下,並提交一個commit。

[root@kai git_test]# git checkout -b dev
Switched to a new branch 'dev'
[root@kai git_test]# echo "this is the first line" >> code3.txt 
[root@kai git_test]# cat code3.txt 
this is the first line
[root@kai git_test]# git add code3.txt 
[root@kai git_test]# git commit -m "create_new_code3"
[dev a1f6ad6] create_new_code3
 1 file changed, 1 insertion(+)
 create mode 100644 code3.txt
[root@kai git_test]#

切換回master分支,編輯code.txt並進行一個提交。

[root@kai git_test]# git checkout master
Switched to branch 'master'
[root@kai git_test]# ls
code.txt
[root@kai git_test]# echo "add three line" >> code.txt 
[root@kai git_test]# git add code.txt 
[root@kai git_test]# git commit -m "add_new_line"
[master f4f5dd0] add_new_line
 1 file changed, 1 insertion(+)
[root@kai git_test]# 

合併dev分支的內容到master分支。出現以下提示,這是由於此次不能進行快速合併,因此git提示輸入合併說明信息,輸入以後合併內容以後git會自動建立一次新的提交。

[root@kai git_test]# git merge dev
Merge branch 'dev'

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
~                                                                                                                                    
~                                                                                                                                    
~                                                                                                                                                                                                                                                                        
".git/MERGE_MSG" 7L, 246C
# 保存退出便可!
Merge made by the 'recursive' strategy.
 code3.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 code3.txt
[root@kai git_test]# 

使用分支命令查看分支信息。

[root@kai git_test]# git log --graph --pretty=oneline
*   f6807c155cbb5aa59a04a6eb354d1df14d641c3c Merge branch 'dev'
|\  
| * a1f6ad699c62782ddf3cd2c6fc36773f7e55a365 create_new_code3
* | f4f5dd02154451492b799d9ce8346361e3898b00 add_new_line
|/  
*   b46a32ff94fb7cf4b61ce9af466c5433b0469fb2 resolve_the_conflict
|\  
| * 7da47b4af8476b1c42b03bf04b7d3f103b16da0d dev_branch_submit
* | e57c158c60697955a4179ab87244957967419f70 matser_branch_submit
|/  
* b63902b3874dd3e0a3e0b1ae3e0eb0f30cd616d4 dev_branch_submit
* f25e944f3e23532ecc3d2837c32057826920474b delete_code2.txt
* 66a9c996749285bdb5e2010b992483e8a1a1771c version4
* f18f0ccadc62b83fa4c6e2222956ba2f2a0e5230 version3
* 6280fa584403809ac2078a81120acf33e6bec836 version2
* 020bf021ec6d1b77836db4e96541d3659251714e version1
[root@kai git_test]#

刪除dev分支。

[root@kai git_test]# git branch -d dev
Deleted branch dev (was a1f6ad6).
[root@kai git_test]#

若是要強制禁用fast forward模式,git就會在merge時生成一個新的commit,這樣,從分支歷史上就能夠看出分支信息。

禁用fast forward模式:

建立並切換到dev分支,修改code.txt內容,並提交一個commit。

[root@kai git_test]# git checkout -b dev
Switched to a new branch 'dev'
[root@kai git_test]# echo "add new line" >> code.txt 
[root@kai git_test]# git add code.txt 
[root@kai git_test]# git commit -m "add_nwe_line"
[dev 5952b2f] add_nwe_line
 1 file changed, 1 insertion(+)
[root@kai git_test]#

切換回master分支,準備合併dev分支,請注意--no-ff參數,表示禁用Fast forward:

[root@kai git_test]# git merge --no-ff -m 'forbid_fastforward_merge' dev
Merge made by the 'recursive' strategy.
 code.txt | 1 +
 1 file changed, 1 insertion(+)
[root@kai git_test]# 

由於本次合併要建立一個新的commit,因此加上-m參數,把commit描述寫進去。

合併後,咱們用git log看看分支歷史:

能夠看到,不使用Fast forward模式,merge後就像這樣:

[root@kai git_test]# git log --graph --pretty=oneline
*   aa22465083e104bf61d7a5c1b8190fe48557adf7 forbid_fastforward_merge
|\  
| * 5952b2f6b216ca88484ab92aafc636077c30c9a3 add_nwe_line
|/  
*   f6807c155cbb5aa59a04a6eb354d1df14d641c3c Merge branch 'dev'
|\  
| * a1f6ad699c62782ddf3cd2c6fc36773f7e55a365 create_new_code3
* | f4f5dd02154451492b799d9ce8346361e3898b00 add_new_line
|/  
*   b46a32ff94fb7cf4b61ce9af466c5433b0469fb2 resolve_the_conflict
|\  
| * 7da47b4af8476b1c42b03bf04b7d3f103b16da0d dev_branch_submit
* | e57c158c60697955a4179ab87244957967419f70 matser_branch_submit
|/  
* b63902b3874dd3e0a3e0b1ae3e0eb0f30cd616d4 dev_branch_submit
* f25e944f3e23532ecc3d2837c32057826920474b delete_code2.txt
* 66a9c996749285bdb5e2010b992483e8a1a1771c version4
* f18f0ccadc62b83fa4c6e2222956ba2f2a0e5230 version3
* 6280fa584403809ac2078a81120acf33e6bec836 version2
* 020bf021ec6d1b77836db4e96541d3659251714e version1
[root@kai git_test]#

5. Bug分支

軟件開發中,bug就像屢見不鮮同樣。有了bug就須要修復,在git中,因爲分支是如此的強大,因此,每一個bug均可以經過一個新的臨時分支來修復,修復後,合併分支,而後將臨時分支刪除。

 

當你接到一個修復一個代號001的bug的任務時,很天然地,你想建立一個分支bug-001來修復它,可是,等等,當前正在dev上進行的工做尚未提交:

[root@kai git_test]# echo "this line is writing...." >> code.txt 
[root@kai git_test]# git status
# On branch dev
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   code.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
[root@kai git_test]# 

並非你不想提交,而是工做只進行到一半,還無法提交,預計完成還需1天時間。可是,必須在兩個小時內修復該bug,怎麼辦?

git還提供了一個stash功能,能夠把當前工做現場「儲藏」起來,等之後恢復現場後繼續工做:

[root@kai git_test]# git stash
Saved working directory and index state WIP on dev: 5952b2f add_nwe_line
HEAD is now at 5952b2f add_nwe_line
[root@kai git_test]#

首先肯定要在哪一個分支上修復bug,假定須要在master分支上修復,就從master建立臨時分支:

[root@kai git_test]# git checkout master
Switched to branch 'master'
[root@kai git_test]# git checkout -b bug-001
Switched to a new branch 'bug-001'
[root@kai git_test]#

如今模擬修復bug,把 add new line刪掉,而後提交。

[root@kai git_test]# vim code.txt 
[root@kai git_test]# cat code.txt 
this is the first line
this is the second line
this is the third line
this is the forth line
add one line
add two line in master
add two line
add three line
[root@kai git_test]# git add code.txt 
[root@kai git_test]# git commit -m "repair_bug"
[bug-001 f52de9b] repair_bug
 1 file changed, 1 deletion(-)

修復完成後,切換到master分支,並完成合並,最後刪除bug-001分支。

[root@kai git_test]# git checkout master
Switched to branch 'master'
[root@kai git_test]# git merge --no-ff -m "repair_bug" bug-001
Merge made by the 'recursive' strategy.
 code.txt | 1 -
 1 file changed, 1 deletion(-)
[root@kai git_test]# git branch -d bug-001
Deleted branch bug-001 (was f52de9b).
[root@kai git_test]#

如今bug-001修復完成,是時候接着回到dev分支幹活了!

[root@kai git_test]# git checkout dev
Switched to branch 'dev'
[root@kai git_test]# git status
# On branch dev
nothing to commit, working directory clean
[root@kai git_test]#

工做區是乾淨的,剛纔的工做現場存到哪去了?用git stash list命令看看:

[root@kai git_test]# git stash list
stash@{0}: WIP on dev: 5952b2f add_nwe_line
[root@kai git_test]#

工做現場還在,git把stash內容存在某個地方了,可是須要恢復一下

[root@kai git_test]# git stash pop
# On branch dev
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   code.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (ff39e6e47ea948b97d2587f2205c465fa789c5e9)
[root@kai git_test]# git status
# On branch dev
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   code.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
[root@kai git_test]#

小結:修復bug時,咱們會經過建立新的bug分支進行修復,而後合併,最後刪除;當手頭工做沒有完成時,先把工做現場git stash一下,而後去修復bug,修復後,再git stash pop,恢復工做現場。

相關文章
相關標籤/搜索