咱們在平常開發中使用 Git 作分支合併的時候有兩種方式:merge 和 rebase。merge 是最經常使用的,rebase 使用的沒有 merge 這麼多,那麼 rebase 和 merge 有什麼區別呢?何時使用 rebase?使用 rebase 的時候有什麼注意事項呢?接下來我來介紹下這三個問題。git
首先咱們先了解下 merge 和 rebase 的運行機制有什麼不一樣。假設咱們有兩個分支(master 和 feature)。feature 是基於 master 的 C1 節點創建的分支,而後開發人員分別在兩個分支各自開發:spa
如今咱們想要把 feature 分支開發的內容合併到 master,使用 merge 命令:指針
$ git checkout master $ git merge feature
Git 會把 C2 和 C3 的內容合併一下產生一個新的修改 C4,把 C4 提交到 master 分支。那麼 master 就有了全部最新的代碼(紅色是 master 分支線,藍色是 feature 分支線)。code
咱們回到仍是未合併以前的狀態,看看使用 rebase 合併會有什麼效果。使用 rebase 有兩種用法,先看第一種:圖片
$ git checkout master $ git rebase feature
Git 把 C2 備份成 C2',刪除 C2,而後把 C2' 追加到 C3 後面,把 master 指向 C2'。看圖上紅線,成爲了新的 master,這條線上一樣有全部的最新代碼,起到的做用也是合併了兩個分支。那麼和 merge 有什麼區別呢?就是歷史時間線的區別。merge 保留了你全部的操做記錄,而 rebase 把提交的修改節點變成了線性的時間線。若是分支 merge 不少的話,時間線會錯綜複雜,這個時候 rebase 的好處就出現了,對人肉追溯比較友好。開發
咱們再看下合併兩個分支 rebase 的第二種用法:同步
$ git checkout feature $ git rebase master $ git checkout master $ git merge feature
前兩條命令咱們先在 feature 上 rebase on master,產生的效果和第一種方法相似,只是把 feature 分支的改動追加到了 master 分支後面(紅色是 master 分支線,藍色是 feature 分支線)。it
後兩條命令是把 feature 分支 merge 到 master 分支。因爲 Git 發現不須要合併代碼,只須要移動頭指針就能夠了,因此快速移動(fast forward)頭指針到最前面,master 分支這時就有全部最新代碼,一樣起到了合併分支的做用。ast
那麼第一種和第二種有什麼區別呢?直觀的看就是時間線上 C2,C3 順序的區別,對於咱們合併分支最終的意圖是沒有什麼區別的。class
若是你是一人開發,且只有本地倉庫,那麼上面 rebase 用哪一種問題都不會太大。可是若是你是多人協做且有遠程倉庫,那麼區別就巨大了。由於你合併完分支以後還須要 push 到遠程倉庫供別人使用,當你使用第一種方法後,C2 被放到了 C3 後面,你本地的 master 時間線變成了 C1 - C3 - C2',而遠程倉庫 master 的時間線是 C1 - C2。雖然 C2 和 C2' 是同樣的,可是二者時間線歷史徹底不同了,Git 認爲你這是兩個不同的分支,不容許你 push。這個時候只能用 $ git push --force
強迫提交,用本地的 master 覆蓋遠程倉庫的 master。可是 master 分支別人還在用啊,他們也須要同步 master 分支。可是別人本地的 master 分支並不知道你 rebase 過了遠程倉庫的 master,因此當他們 pull master 的時候,變成了以下時間線:
其餘人本地的 master 時間線上會出現兩個 C2(C2 和 C2'),而後若是這人把上圖的 master 再 push 到遠程倉庫,會帶上上圖全部的歷史,多來幾回之後整個倉庫就沒有辦法看了。而第二種 rebase 的方法是把新的 commit 不斷的追加到 master 後面,只要全部人在往 master 上合併代碼的時候都遵循第二種方法,那麼就不會產生極其混亂的時間線。
按咱們上面看到的,在現實的開發過程當中,嚴格禁止在公共分支上 rebase on 其餘分支(譬如不容許在 master 分支上直接運行 git rebase branchname)。使用 merge 是最保險的合併分支方式,若是你對時間線清晰度要求不是那麼高的話。可是若是你對時間線的清晰程度有比較高的要求,那麼在合併分支的時候按第二種方法 rebase 就能幫助造成清晰的線性時間線,可是 rebase 的壞處是丟失了一部分提交操做歷史。
除了合併不一樣分支這種狀況,還有一個十分常見的狀況,多人在同一個分支上開發,如何保證同一條分支具備清晰的時間線。咱們假設有三我的在開發 feature 分支,一般開發習慣是:
按上述步驟,咱們看下時間線示意圖:
先是第1,第2步
用戶1執行3,4步
用戶2執行3,4步
用戶3執行3,4步
由於 pull 默認是經過 merge 遠程倉庫和本地倉庫實現同步的,因此每次 pull 都會多出一個提交記錄。可是咱們能夠經過指定參數來指定 pull 的時候使用 rebase 策略:$ git pull --rebase
。讓咱們看下每次執行第3步的時候使用 pull rebase 那麼會是什麼樣子。
用戶1執行3,4步
用戶2執行3,4步
用戶3執行3,4步
經過圖示咱們看到,若是使用 pull 的 rebase 模式,那麼多人協做同一個分支也能夠作到時間線清晰。最後再經過以前提到的 rebase 方式把 feature 合併到 master 分支上。那麼整個開發過程時間線就呈現出清晰的時間線。