?Welcome to 9ilk's Code World
? ? ? ?
(??? ? ???)?個人主頁:? ? ? ?9ilk
(??? ? ???)?文章專欄:? ? ?Git
? ?本篇博客我們來介紹Git的一個重要功能之一 ---- 分支。我們將講解關于分支的各種操作,以及如何幫助我們進行開發。
🏠 理解分支
假設你處于一個平行宇宙,主時間線里你按部就班的學者C++,OS,另一個時間線的里學著Java,到達某一個時間點時兩個時空合并,此時相當于你在一段時間掌握的技能增加了,這里平行時空2相當于是在當前分支基礎上創建一個新分支,到達某一個時間點,我們再將兩個分支合并。
head與master
在版本回退里,每次提交,Git都會把他們串成一條時間線,這條時間線可以理解為是一個分支。截止到目前,我們只有一條時間線,在Git里,這個分支叫主分支,即master分支。
再來理解一下,HEAD指針嚴格來說不是指向提交,而是指向master,master才是指向提交的,所以HEAD(默認)指向的是當前分支。
每次提交,master分支都會向前移動一步,隨著你的不斷提交,master分支的線也越來越長,而HEAD只要一直指向master分支即可指向當前分支。通過查看當前的版本庫,我們也能清晰的觀察:拿到master分支,我們就能通過parent依次拿到該分支下之前的一個個提交。
🏠 創建、切換、合并分支
當我們創建本地倉庫時,Git會自動給我們創建master分支,如果我們想查看本地有哪些分支,我們可以使用 git branch 命令
- * 表示當前正在master分支工作。
- HEAD不僅可以指向master分支,也可以指向其他分支,其中被HEAD指向的分支就是我們當前的工作分支。
創建分支
git branch + 分支名
創建完一個新的分支之后,我們可以使用git branch驗證一下是否創建了新分支:
還可以在.git目錄樹上驗證:
由于我們創建dev分支是基于master分支創建的,所以創建出來之后會指向最近的一次提交:
時間線圖如下:
切換分支
我們之前說HEAD所指向分支為當前工作分支,那如何切換當前工作分支呢?我們可以使用命令git checkout + 分支名
git checkout + 分支名
使用git branch操作驗證下是否切換成功:
切換后的時間線如圖:
合并分支
由于當前dev分支只是剛基于master分支創建,合并沒什么意義,我們對dev分支做一次提交
修改ReadMe文件:
兩板斧提交:
zhuang@VM-8-14-ubuntu:~/gitcode$ git add ReadMe
zhuang@VM-8-14-ubuntu:~/gitcode$ git commit -m "md ReadMe"
[dev 3165a96] md ReadMe1 file changed, 2 insertions(+), 1 deletion(-)
zhuang@VM-8-14-ubuntu:~/gitcode$ git status
On branch dev
nothing to commit, working tree clean
此時我們切換到master分支觀察變化:
此時我們切換到dev分支:
為什么切換到master分支下我們沒有觀察到變化,而在dev分支上內容還在呢??
這是因為我們是在dev分支上提交的,而master分支此刻的提交點沒有變,即沒有在master分支上master進行提交,時間線不會延長,此時狀態如圖:
當切換到master分支時,HEAD指向了master,此時自然看不到提交。
此時如果我們想讓我們之前修改的信息能在master分支上能查看到,此時需要合并兩個分支,但是注意master合并dev,需要先切換到master,再合并
git checkout + 要合并到的分支
git merge + 要合并的分支
此時我們就能在master分支上查看到我們之前修改的信息了:
- Fast-forward表示快進模式(快速提交),直接把master的指向指向dev的最新提交,合并起來很快
合并后的時間線圖如下:
合并之后如果我們在master分支下再進行一次提交會發生什么?
合并之后并不是指dev分支等同于master分支了,而是將dev時間線的各個版本與master分支進行合并,往后他們各自還是獨立的:
🏠 刪除分支
將master分支和dev分支合并完之后,dev的使命基本結束了,此時我們需要把它刪除,那怎么刪除一個分支呢?
git branch -d + 要刪除的分支名
注意:要刪除一個分支時,需要先切換到其他分支,否則會報錯
因為創建、合并和刪除分支非常快,所以Git鼓勵你使用分支完成某個任務,合并后再刪掉分支,這和直接在master分支上工作效果是一樣的,但過程更安全。
🏠 合并沖突
合并分支不是說能隨便合并的,合并時也可能出現沖突:
假設master分支上已經有aaa on branch的提交,我們模擬剩下的內容:
(1)在dev分支上提交 ccc on branch
zhuang@VM-8-14-ubuntu:~/gitcode$ git checkout -b dev1
Switched to a new branch 'dev1'
補充選項:git checkout的-b選項幫我們完成兩件事:先幫我們創建新分支,再切換到新分支上
zhuang@VM-8-14-ubuntu:~/gitcode$ vim ReadMe
zhuang@VM-8-14-ubuntu:~/gitcode$ git add ReadMe
zhuang@VM-8-14-ubuntu:~/gitcode$ git commit -m "bb ReadMe"
[dev1 700c7b6] bb ReadMe1 file changed, 1 insertion(+), 1 deletion(-)
(2)在master分支上提交ccc on branch
zhuang@VM-8-14-ubuntu:~/gitcode$ git checkout master
Switched to branch 'master'
zhuang@VM-8-14-ubuntu:~/gitcode$ vim ReadMe
zhuang@VM-8-14-ubuntu:~/gitcode$ git add ReadMe
zhuang@VM-8-14-ubuntu:~/gitcode$ git commit -m "cc ReadMe"
[master a5c1371] cc ReadMe1 file changed, 1 insertion(+), 1 deletion(-)
(3)合并分支
我們打開ReadMe文件查看沖突內容,Git會用<<<<<<<,=======, >>>>>>>來標記出不同分支的沖突內容:
此時我們需要自己決策,手動調整沖突代碼,并需要再次提交修正后的結果!
此時的時間線圖如下:
如果我們想查看分支的合并情況,也可以使用git log命令帶上 --graph? --abrev-commit選項
🏠 合并模式
Fast-forward 模式
這里我們創建新分支dev2,提交一次之后與master分支進行合并,我們git log看看結果:
在這種Fast forward模式下,刪除分支之后,查看分支歷史時,會丟掉分支信息,看不出來最新提交到底時merge進來的還是正常提交的。
no-ff模式
在合并沖突部分,我們也看到通過解決沖突問題,會再進??次新的提交,得到的最終狀態為:
那么這就不是 Fast forward 模式了,而是no-ff模式,這樣的好處是,從分?歷史上就可以看出分?信息。例如我們現在已經刪除了在合并沖突部分創建的 dev1 分?,但依舊能看到master其實是由其他分?合并得到。
Git?持我們強制禁? Fast forward 模式(帶上--no-ff選項),那么就會在merge時?成?個新的 commit ,這樣,從分?歷史上就可以看出分?信息:
在dev2分支上提交:
使用no-ff模式,此時需要一次新的提交,需要帶上-m選項:
用git log查看:
此時時間線圖如下:
🏠 分支策略
在實際開發中,我們應該按照幾個基本原則進行分支管理:
首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是說,dev分支是不穩定的,到某個時候,比如1.0版本發布
時,再把dev分支合并到master上,在master分支發布1.0版本;(類似王者榮耀更新版本);你和你的小伙伴們每個人都在dev分支上干活,每個人都有自己的分支,時不時地往dev分支上合并就可以了。所以,團隊合作的分支看起來就像這樣:
🏠 Bug分支
線上環境不是百分百穩定,master主分支也可能有bug,我們應該單獨創建一個專門修復master分支bug的分支再合并,不能直接在master分支上修改bug有可能改出一個更大bug
我們要模擬的場景如下:
(1)dev2分支正在開發(I am coding)
(2) 暫存dev2分支工作區內容
由于dev2分支開發時只是對工作區進行修改并未提交所以會影響master,此時我們可以使用git stash命令先將工作區內容暫存起來
此時我們發現在.git目錄下多了個stash分區:
注意 git stash命令只能存儲之前被追蹤管理過的文件內容
(3) 創建bug分支修改分支
假設bug為:
創建fix_bug分支修改bug提交之后然后與master分支合并:
(4)?修復完bug切回dev2分支繼續開發
git stash list展示stash里存了什么
git stash pop將stash內容放出來
我們將內容恢復然后在dev2分支上進行提交
此時我們注意到,bug修復的內容在dev2分支上沒有顯示,這是因為master分支目前最新的提交,是要領先于新建dev2時基于的master分支的提交的。
我們最終目的是讓master合并dev2分支,但是這樣是有風險的,這是因為在合并分支時可能會有沖突,而代碼沖突需要我們手動解決(在master分支上解決),我們無法保證對于沖突問題可以正確地一次性解決,實際開發中,代碼沖突不只一行兩行那么簡單,解決過程出錯難免,導致錯誤的代碼合并到master分支上。此時狀態為:
解決這個問題的一個好的建議就是:最好在自己的分支上(dev2)合并下master,再讓master去合并dev2,這樣做的目的是有沖突可以在本地分支解決并進行測試,而不影響master。此時的狀態為:
演示:
dev2合并master
再將dev2合并到master
最后刪除fix_bug和dev2
zhuang@VM-8-14-ubuntu:~/gitcode$ git branchdev2fix_bug
* master
zhuang@VM-8-14-ubuntu:~/gitcode$ git branch -d dev2 fix_bug
Deleted branch dev2 (was 1714a31).
Deleted branch fix_bug (was dffd15d).
🏠 強制刪除分支
我們之前git branch -d刪除分支的前提是merge,git認為只要你創建分支不能隨便刪,此時我們確定該分支可以刪,只需改選項-D表示強行刪除
git branch -D 分支名
總結分支相關操作:
1. 創建分支 : git branch
2. 切換分支 : git checout?
3. 創建 + 切換分支 : git checkout -b?
4. 合并分支 : git merge?
5. 刪除分支 : git branch -d?
6. 查看分支情況 : git log?--graph? --abrev-commit
7. no-ff模式合并 : git merge --no-ff -m "message"?