用Git進行多人協做開發時,必然會合並代碼,解決衝突。然而合併代碼也是須要點技巧的,若是對一些關鍵命令沒有理解去使用的話,git的版本演進路線就會變得很亂,從而形成了往後維護的一些麻煩。html
Git上合併代碼有git merge 以及 git rebase 兩種方式。下面將深刻二者的用法以及對二者的適用場景做個總結。git
有了以上知識點,咱們能夠了解通常團隊開發都是基於feature分支進行開發,而後把feature分支合併到develop分支的。接着咱們模擬以下一個實際開發場景。github
如今在develop開發分支上,而後你建立了一個feature分支開發新功能,如今團隊中另外一個成員在develop分支上添加了新的提交。以下圖所示安全
如今,若是develop中新的提交和你的工做是相關的。爲了將新的提交併入你的分支,你有兩個選擇:merge或rebase。測試
將develop分支合併到feature分支最簡單的辦法就是用下面這些命令:spa
git checkout feature
git merge develop
或者,你也能夠把它們壓縮在一行裏。(我的仍是喜歡上面的寫法)3d
git merge develop feature
feature分支中新的合併提交(merge commit)將兩個分支的歷史連在了一塊兒。你會獲得下面這樣的分支結構:code
Merge好在它是一個安全的操做。現有的分支不會被更改,避免了rebase潛在的缺點(後文會講)。可是這一樣意味着每次合併上游更改時feature分支都會引入一個外來的合併提交。若是master很是活躍的話,這或多或少會污染你的分支歷史。htm
默認狀況下,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 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。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)。
參考文獻: