天天看點

Git分支合并選擇

   用Git進行多人協作開發時,必然會合并代碼,解決沖突。然而合并代碼也是需要點技巧的,如果對一些關鍵指令沒有了解去使用的話,git的版本演進路線就會變得很亂,進而造成了日後維護的一些麻煩。

   Git上合并代碼有git merge 以及 git rebase 兩種方式。下面将深入兩者的用法以及對兩者的适用場景作個總結。

前置知識點

  • Master分支:首先,代碼庫應該有一個、且僅有一個主分支。所有提供給使用者使用的正式版本,都在這個主分支上釋出。這個分支被稱為Master分支;
  • Develop分支:主分支隻用來分布重大版本,日常開發應該在另一條分支上完成。我們把開發用的分支,叫做Develop分支。這個分支可以用來生成代碼的最新隔夜版本(nightly)。如果想正式對外釋出,就在Master分支上,對Develop分支進行"合并"(merge)。
  • 臨時性分支:除了常設分支以外,還有一些臨時性分支,用于應對一些特定目的的版本開發。臨時性分支主要有三種:    
    • 功能(feature)分支:它是為了開發某種特定功能,從Develop分支上面分出來的。開發完成後,要再并入Develop。它的命名,可以采用feature-*的形式。
    • 預釋出(release)分支:它是指釋出正式版本之前(即合并到Master分支之前),我們可能需要有一個預釋出的版本進行測試。預釋出分支是從Develop分支上面分出來的,預釋出結束以後,必須合并進Develop和Master分支。它的命名,可以采用release-*的形式。
    • 修補bug分支:軟體正式釋出以後,難免會出現bug。這時就需要建立一個分支,進行bug修補。修補bug分支是從Master分支上面分出來的。修補結束以後,再合并進Master和Develop分支。它的命名,可以采用fixbug-*的形式。

有了以上知識點,我們可以了解一般團隊開發都是基于feature分支進行開發,然後把feature分支合并到develop分支的。接着我們模拟如下一個實際開發場景。

場景

現在在develop開發分支上,然後你建立了一個feature分支開發新功能,現在團隊中另一個成員在develop分支上添加了新的送出。如下圖所示

Git分支合并選擇

現在,如果develop中新的送出和你的工作是相關的。為了将新的送出并入你的分支,你有兩個選擇:merge或rebase。

merge

git merge

将develop分支合并到feature分支最簡單的辦法就是用下面這些指令:

git checkout feature
git merge develop       

或者,你也可以把它們壓縮在一行裡。(個人還是喜歡上面的寫法)

git merge develop feature      

feature分支中新的合并送出(merge commit)将兩個分支的曆史連在了一起。你會得到下面這樣的分支結構:

Git分支合并選擇

Merge好在它是一個安全的操作。現有的分支不會被更改,避免了rebase潛在的缺點(後文會講)。但是這同樣意味着每次合并上遊更改時feature分支都會引入一個外來的合并送出。如果master非常活躍的話,這或多或少會污染你的分支曆史。

git merge --no-ff

預設情況下,Git執行"快進式合并"(fast-farward merge),會直接将develop分支指向feature分支。如git merge裡的圖所示。使用--no-ff參數後,會執行正常合并,在develop分支上生成一個新節點。為了保證版本演進的清晰,我們希望采用這種做法。關于合并的更多解釋,請參考Benjamin Sandofsky的

《Understanding the Git Workflow》

Git演進圖如下圖所示。(如有錯誤歡迎指正)

Git分支合并選擇

可以看到,使用了git merge --no-ff 指令後的git 演進路線是清晰的,指令概括如下:

git checkout feature
git merge --no-ff develop      

git rebase

先提個問題吧,git rebase 和 git reset 有什麼差別? 如果不知道的話,可以在回顧一下在什麼場景下用git merge以及git rebase的,而git reset則僅僅是在目前的分支(一個分支)的版本切換。

接着來講git rebase。作為merge的替代選擇,你可以像下面這樣将feature分支并入master分支:

git checkout feature
git rebase develop      

它會把整個feature分支移動到develop分支的後面,有效地把所有develop分支上新的送出并入過來。但是,rebase為原分支上每一個送出建立一個新的送出,重寫了項目曆史,并且不會帶來合并送出。

Git分支合并選擇

rebase最大的好處是你的項目曆史會非常整潔。首先,它不像

git merge

 那樣引入不必要的合并送出。其次,如上圖所示,rebase導緻最後的項目曆史呈現出完美的線性。這讓你更容易使用git log來檢視項目曆史。

不過,這種簡單的送出曆史會帶來兩個後果:安全性和可跟蹤性。如果你違反了Rebase黃金法則,重寫項目曆史可能會給你的協作工作流帶來災難性的影響。此外,rebase不會有合并送出中附帶的資訊——你看不到feature分支中并入了上遊的哪些更改。

rebase的黃金法則

當你了解rebase是什麼的時候,最重要的就是什麼時候 不能 用rebase。

git rebase

 的黃金法則便是,絕不要在公共的分支上使用它。

比如說,如果你在develop分支上,rebase到你的feature分支上會發生什麼:

Git分支合并選擇

這次rebase将develop分支上的所有送出都移到了feature分支後面。問題是它隻發生在你的代碼倉庫中,其他所有的開發者還在原來的develop上工作。因為rebase引起了新的送出,Git會認為你的develop分支和其他人的develop已經分叉了。

同步兩個develop分支的唯一辦法是把它們merge到一起,導緻一個額外的合并送出和兩堆包含同樣更改的送出。不用說,這會讓人非常困惑。

是以重要的再強調一遍,絕不要在公共的分支上使用它。在你運作

git rebase

 之前,一定要問問你自己“有沒有别人正在這個分支上工作?”。如果答案是肯定的,重新找到一個無害的方式(如

git revert

)來送出你的更改。不然的話,你可以随心所欲地重寫曆史。

總結

如果你想要一個幹淨的、線性的送出曆史,沒有不必要的合并送出,你應該使用

git rebase

 而不是

git merge

 來并入其他分支上的更改。

另一方面,如果你想要儲存項目完整的曆史,并且避免重寫公共分支上的commit, 你可以使用

git merge (--no-ff)。

參考文獻:

作者:

牧雲雲

出處:

http://www.cnblogs.com/MuYunyun/"

本文版權歸作者和部落格園所有,歡迎轉載,轉載請标明出處。

如果您覺得本篇博文對您有所收獲,請點選右下角的 [推薦],謝謝!