本文主要記錄了分支的原理、分支的創建,刪除,合並、以及分支的使用策略。
分支在實際中的作用
假設你准備開發一個新功能,但是需要兩周才能完成,第一周你寫了50%的代碼,如果立刻提交,由於代碼還沒寫完,不完整的代碼庫會導致別人不能干活了。如果等代碼全部寫完再一次提交,又存在丟失每天進度的巨大風險。現在有了分支,就不用怕了。你創建了一個屬於你自己的分支,別人看不到,還繼續在原來的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到開發完畢后,再一次性合並到原來的分支上,這樣,既安全,又不影響別人工作。
分支的原理描述
在版本回退里,每次提交,Git都把它們串成一條時間線,這條時間線就是一個分支。開始的時候,只有一條時間線,在Git里,這個分支叫主分支,即master
分支。HEAD
嚴格來說不是指向提交,而是指向master
,master
才是指向提交的,所以,HEAD
指向的就是當前分支。
一開始的時候,master
分支是一條線,Git用master
指向最新的提交,再用HEAD
指向master
,就能確定當前分支,以及當前分支的提交點.
每次提交,master
分支都會向前移動一步,這樣,隨着你不斷提交,master
分支的線也越來越長:
當我們創建新的分支,例如dev
時,Git新建了一個指針叫dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示當前分支在dev
上.
這樣一個dev的分支就建成了,不過,從現在開始,對工作區的修改和提交就是針對dev
分支了,比如新提交一次后,dev
指針往前移動一步,而master
指針不變。
我們在dev上的工作完成了,就可以把dev合並到master上。最簡單的方法,就是直接把master指向dev的當前提交,就完成了合並。合並完分支后,就可以刪除無用的dev分支。刪除dev分支就是把dev指針給刪掉,刪掉后,我們就剩下了一條master分支。
分支的創建與刪除
ubuntu@myUbuntu:~/joe/learngit$ ls abc.c readme.txt ubuntu@myUbuntu:~/joe/learngit$ git status 位於分支 master //當前位於主分支 您的分支與上游分支 'origin/master' 一致。 無文件要提交,干凈的工作區 ubuntu@myUbuntu:~/joe/learngit$git checkout -b dev
//創建一個分支並切換到當前分支 切換到一個新分支 'dev' ubuntu@myUbuntu:~/joe/learngit$git branch
//查看所有分支,(當前的分支前會有*號) * dev master ubuntu@myUbuntu:~/joe/learngit$ ls abc.c readme.txt ubuntu@myUbuntu:~/joe/learngit$ vi readme.txt //在dev分支下修改文件 ubuntu@myUbuntu:~/joe/learngit$git status
//查看狀態,是在dev分支下 位於分支 dev 尚未暫存以備提交的變更: (使用 "git add <file>..." 更新要提交的內容) (使用 "git checkout -- <file>..." 丟棄工作區的改動) 修改: readme.txt 修改尚未加入提交(使用 "git add" 和/或 "git commit -a") ubuntu@myUbuntu:~/joe/learngit$ git add readme.txt ubuntu@myUbuntu:~/joe/learngit$git commit -m "new dev branch"
[dev 9409b92] new dev branch 1 file changed, 2 insertions(+), 1 deletion(-) ubuntu@myUbuntu:~/joe/learngit$git checkout master
//將dev分支下的工作提交以后,切換到主分支 切換到分支 'master' 您的分支與上游分支 'origin/master' 一致。 ubuntu@myUbuntu:~/joe/learngit$cat readme.txt
//主分支下查看文件發現文件內容並沒有修改 Git is a distributed version control system Git is free software distributed under the Are you ok? Yes,i am fine. What about you? ubuntu@myUbuntu:~/joe/learngit$git merge dev
//dev分支和master分支合並 更新 f10fe58..9409b92 Fast-
forward//cat readme.txtFast-forward
信息,Git告訴我們,這次合並是“快進模式”,也就是直接把master
指向dev
的當前提交,所以合並速度非常快。當然,也不是每次合並都能Fast-forward,就如下面的沖突
readme.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) ubuntu@myUbuntu:~/joe/learngit$
//合並以后,再次查看,文件內容已經修改 Git is a distributed version control system Git is free software distributed under the Are you ok? Yes,i am fine. What about you Create a branch is so quick. ubuntu@myUbuntu:~/joe/learngit$git branch -d dev
//刪除分株 已刪除分支 dev(曾為 9409b92)。 ubuntu@myUbuntu:~/joe/learngit$ git branch * master
//git checkout命令加上-b參數表示創建並切換,相當於以下兩條命令: $ git branch dev //創建分支 $ git checkout dev //切換分支 Switched to branch 'dev'
分支的沖突
ubuntu@myUbuntu:~/joe/learngit$ git status 位於分支 master 您的分支領先 'origin/master' 共 1 個提交。 (使用 "git push" 來發布您的本地提交) 無文件要提交,干凈的工作區 ubuntu@myUbuntu:~/joe/learngit$git checkout -b bran
//新建bran分支,修改文件內容並提交 切換到一個新分支 'bran' ubuntu@myUbuntu:~/joe/learngit$ vi abc.c ubuntu@myUbuntu:~/joe/learngit$ cat abc.c I am a new branch ubuntu@myUbuntu:~/joe/learngit$ git add abc.c ubuntu@myUbuntu:~/joe/learngit$git commit -m "new bran"
[bran 5aa28d8] new bran 1 file changed, 1 insertion(+), 1 deletion(-) ubuntu@myUbuntu:~/joe/learngit$git checkout master
//切換回主分支,修改同一個文件,並提交 切換到分支 'master' 您的分支領先 'origin/master' 共 1 個提交。 (使用 "git push" 來發布您的本地提交) ubuntu@myUbuntu:~/joe/learngit$ vi abc.c ubuntu@myUbuntu:~/joe/learngit$ cat abc.c I am not a branch ubuntu@myUbuntu:~/joe/learngit$ git add abc.c ubuntu@myUbuntu:~/joe/learngit$ gitcommit -m "not a branch"
[master fe42f3e] not a branch 1 file changed, 1 insertion(+), 1 deletion(-) ubuntu@myUbuntu:~/joe/learngit$git merge bran
//此時合並分支的時候,出現了沖突(2個分支都對文件做了修改,那么合並的時候應該合並哪一個呢?此時需要手動解決以后,才可以合並。) 自動合並 abc.c 沖突(內容):合並沖突於 abc.c 自動合並失敗,修正沖突然后提交修正的結果。 ubuntu@myUbuntu:~/joe/learngit$ git status 位於分支 master 您的分支領先 'origin/master' 共 2 個提交。 (使用 "git push" 來發布您的本地提交) 您有尚未合並的路徑。 (解決沖突並運行 "git commit") 未合並的路徑: (使用 "git add <file>..." 標記解決方案) 雙方修改: abc.c 修改尚未加入提交(使用 "git add" 和/或 "git commit -a") ubuntu@myUbuntu:~/joe/learngit$cat abc.c
//查看文件內容 <<<<<<< HEAD I am not a branch ======= I am a new branch >>>>>>> bran //Git用<<<<<<<,=======,>>>>>>>標記出不同分支的內容
ubuntu@myUbuntu:~/joe/learngit$
vi abc.c
//將其文件內容修改統一后,提交 ubuntu@myUbuntu:~/joe/learngit$ cat abc.c I am not a branch ubuntu@myUbuntu:~/joe/learngit$ git add abc.c ubuntu@myUbuntu:~/joe/learngit$git commit -m "conflict ok"
[master f73e798] conflict ok
ubuntu@myUbuntu:~/joe/learngit$
git log --graph --pretty=oneline --abbrev-commit
//查看分支歷史,形象的描寫了沖突的位置 * f73e798 conflict ok |\ | * 5aa28d8 new bran * | fe42f3e not a branch |/ * 9409b92 new dev branch * f10fe58 new abc * 0ad1dfe del ab.c * 7b6507e new ab.c * 020f927 del abc * 010726f del a line * c834e17 nothing * aa6b706 new abc.c * 82f4ed9 modify read * e32e92b del abc.c * ab22d92 test stage * d4e3943 understand how stage workd * 71038bf append GPL * 942f575 add distributed * b401faf joe's first txt ubuntu@myUbuntu:~/joe/learngit$git branch -
d bran
已刪除分支 bran(曾為 5aa28d8)。
分支管理策略
合並分支時,Git會用Fast forward
模式,但這種模式下,刪除分支后,會丟掉分支信息。
如果要強制禁用Fast forward
模式,Git就會在merge時生成一個新的commit,這樣,從分支歷史上就可以看出分支信息。
ubuntu@myUbuntu:~/joe/learngit$git checkout -b dev
//新建dev分支,修改文件並提交 切換到一個新分支 'dev' ubuntu@myUbuntu:~/joe/learngit$ vi abc.c ubuntu@myUbuntu:~/joe/learngit$ cat abc.c I like you!
ubuntu@myUbuntu:~/joe/learngit$ git add abc.c ubuntu@myUbuntu:~/joe/learngit$git commit -m "dev branch"
[dev cef4924] dev branch 1 file changed, 1 insertion(+), 1 deletion(-) ubuntu@myUbuntu:~/joe/learngit$ git checkout master 切換到分支 'master' 您的分支領先 'origin/master' 共 4 個提交。 (使用 "git push" 來發布您的本地提交) //合並dev分支,--no-ff參數,表示禁用Fast forward,本次合並要創建一個新的commit,所以加上-m參數,把commit描述寫進去 ubuntu@myUbuntu:~/joe/learngit$git merge --no-ff -m "merge with no-ff"
dev Merge made by the 'recursive' strategy. abc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) ubuntu@myUbuntu:~/joe/learngit$git log --graph --pretty=oneline --abbrev-
commit * 7877628 merge with no-ff |\ | * cef4924 dev branch |/ * f73e798 conflict ok |\ | * 5aa28d8 new bran * | fe42f3e not a branch |/ * 9409b92 new dev branch * f10fe58 new abc
使用fast forward的情況
ubuntu@myUbuntu:~/joe/learngit$git checkout -
b dev 切換到一個新分支 'dev' ubuntu@myUbuntu:~/joe/learngit$ vi abc.c ubuntu@myUbuntu:~/joe/learngit$ cat abc.c I don't like you!
ubuntu@myUbuntu:~/joe/learngit$ git add abc.c
ubuntu@myUbuntu:~/joe/learngit$
git commit -m "dev"
[dev b961f85] dev 1 file changed, 1 insertion(+), 1 deletion(-) ubuntu@myUbuntu:~/joe/learngit$ git checkout master 切換到分支 'master' 您的分支領先 'origin/master' 共 6 個提交。 (使用 "git push" 來發布您的本地提交) ubuntu@myUbuntu:~/joe/learngit$ git merge dev 更新 7877628..b961f85 Fast-forward abc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) ubuntu@myUbuntu:~/joe/learngit$git log --graph --pretty=oneline --abbrev-
commit
*
b961f85 dev * 7877628 merge with no-ff |\ //注意這2次分支的對比 | * cef4924 dev branch |/ * f73e798 conflict ok |\ | * 5aa28d8 new bran * | fe42f3e not a branch |/ * 9409b92 new dev branch * f10fe58 new abc * 0ad1dfe del ab.c
分支策略
- 首先,
master
分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面干活; - 干活都在
dev
分支上,dev
分支是不穩定的,新版本版本發布時,再把dev
分支合並到master
上,在master
分支發布新版本; - 每個人都在
dev
分支上干活,每個人都有自己的分支,時不時地往dev
分支上合並就可以了。