Git分支合併選擇

   用Git進行多人協做開發時,必然會合並代碼,解決衝突。然而合併代碼也是須要點技巧的,若是對一些關鍵命令沒有理解去使用的話,git的版本演進路線就會變得很亂,從而形成了往後維護的一些麻煩。html

   Git上合併代碼有git merge 以及 git rebase 兩種方式。下面將深刻二者的用法以及對二者的適用場景做個總結。git

前置知識點

  • 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分支的。接着咱們模擬以下一個實際開發場景。github

場景

如今在develop開發分支上,而後你建立了一個feature分支開發新功能,如今團隊中另外一個成員在develop分支上添加了新的提交。以下圖所示安全

如今,若是develop中新的提交和你的工做是相關的。爲了將新的提交併入你的分支,你有兩個選擇:merge或rebase。測試

merge

git merge

將develop分支合併到feature分支最簡單的辦法就是用下面這些命令:spa

git checkout feature
git merge develop 

或者,你也能夠把它們壓縮在一行裏。(我的仍是喜歡上面的寫法)3d

git merge develop feature

feature分支中新的合併提交(merge commit)將兩個分支的歷史連在了一塊兒。你會獲得下面這樣的分支結構:code

Merge好在它是一個安全的操做。現有的分支不會被更改,避免了rebase潛在的缺點(後文會講)。可是這一樣意味着每次合併上游更改時feature分支都會引入一個外來的合併提交。若是master很是活躍的話,這或多或少會污染你的分支歷史。htm

git merge --no-ff

默認狀況下,Git執行"快進式合併"(fast-farward merge),會直接將develop分支指向feature分支。如git merge裏的圖所示。使用--no-ff參數後,會執行正常合併,在develop分支上生成一個新節點。爲了保證版本演進的清晰,咱們但願採用這種作法。關於合併的更多解釋,請參考Benjamin Sandofsky的《Understanding the Git Workflow》blog

 

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

能夠看到,使用了git merge --no-ff 命令後的git 演進路線是清晰的,命令歸納以下:

git checkout feature
git merge --no-ff develop

 

----------------- 分割線 ------------------- 

git merge --no-ff 在每次合併都會產生一個新的合併記錄; git merge 的話只有解決衝突的時候纔會產生一個新的合併記錄。隨着本身的實踐, 會對現有文章產生一些 修正補充

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爲原分支上每個提交建立一個新的提交,重寫了項目歷史,而且不會帶來合併提交。

rebase最大的好處是你的項目歷史會很是整潔。首先,它不像git merge 那樣引入沒必要要的合併提交。其次,如上圖所示,rebase致使最後的項目歷史呈現出完美的線性。這讓你更容易使用git log來查看項目歷史。

不過,這種簡單的提交歷史會帶來兩個後果:安全性和可跟蹤性。若是你違反了Rebase黃金法則,重寫項目歷史可能會給你的協做工做流帶來災難性的影響。此外,rebase不會有合併提交中附帶的信息——你看不到feature分支中併入了上游的哪些更改。

> git merge --no-ff 在每次合併都會產生一個新的合併記錄; git merge 的話只有解決衝突的時候纔會產生一個新的合併記錄。

rebase的黃金法則

當你理解rebase是什麼的時候,最重要的就是何時 不能 用rebase。git rebase 的黃金法則即是,毫不要在公共的分支上使用它

好比說,若是你在develop分支上,rebase到你的feature分支上會發生什麼:

此次rebase將develop分支上的全部提交都移到了feature分支後面。問題是它只發生在你的代碼倉庫中,其餘全部的開發者還在原來的develop上工做。由於rebase引發了新的提交,Git會認爲你的develop分支和其餘人的develop已經分叉了。

同步兩個develop分支的惟一辦法是把它們merge到一塊兒,致使一個額外的合併提交和兩堆包含一樣更改的提交。不用說,這會讓人很是困惑。

因此重要的再強調一遍,毫不要在公共的分支上使用它。在你運行git rebase 以前,必定要問問你本身「有沒有別人正在這個分支上工做?」。若是答案是確定的,從新找到一個無害的方式(如git revert)來提交你的更改。否則的話,你能夠爲所欲爲地重寫歷史。

總結

若是你想要一個乾淨的、線性的提交歷史,沒有沒必要要的合併提交,你應該使用git rebase 而不是git merge 來併入其餘分支上的更改。

另外一方面,若是你想要保存項目完整的歷史,而且避免重寫公共分支上的commit, 你可使用git merge (--no-ff)。

 

參考文獻:

相關文章
相關標籤/搜索