相信大部分使用 Git 的朋友都會碰見相同的疑問,而且也從網上搜索了很多資料。那麼,爲何我還要寫這篇文章呢?由於我想嘗試從本身的角度解釋這個問題,若是能給到你們靈光一閃的感悟,便善莫大焉啦。估計點進來的朋友也對 merge 和 rebase 有了必定了解,因此我也就不浪費篇幅再去詳細介紹 merge 和 rebase,讓咱們直入主題吧。html
如今假設咱們有一個主分支 master 及一個開發分支 deve,倉庫歷史就像這樣:git
如今若是在 master 分支上 git merge deve
:Git 會自動根據兩個分支的共同祖先即 e381a81
這個 commit 和兩個分支的最新提交即 8ab7cff
和 696398a
進行一個三方合併,而後將合併中修改的內容生成一個新的 commit,即下圖的 78941cb
。hexo
rebase 是什麼狀況呢?仍是一個初始的倉庫歷史圖:fetch
若是是在 master 分支上 git rebase deve
:Git 會從兩個分支的共同祖先 3311ba0
開始提取 master 分支(當前所在分支)上的修改,即 85841be
、a016f64
與 e53ec51
,再將 master 分支指向 deve 的最新提交(目標分支)即 35b6708
處,而後將剛剛提取的修改依次應用到這個最新提交後面。操做會捨棄 master 分支上提取的 commit,同時不會像 merge 同樣生成一個合併修改內容的 commit,至關於把 master 分支(當前所在分支)上的修改在 deve 分支(目標分支)上原樣複製了一遍,操做完成後的版本歷史就像這樣:spa
能夠看見 master 分支從 deve 分支最新提交 35b6708
開始依次提交了本身的三個 commit(因爲是提取修改後從新依次提交,故 commit 的 hash 碼與上面的85841be
、a016f64
、e53ec51
不一樣)。code
rebase 操做加上 -i
選項能夠更直觀的看見被提取的 commit 信息。htm
仍然在 master 分支上 rebase deve 分支,不過此次要加上 -i
選項,即 git rebase -i deve
,而後咱們能夠獲得這樣一個文本信息框blog
A 區域內的信息說明了此次 rebase 操做提取了哪些 commit 記錄(f9a7673
與 edb2ba2
),會鏈接到目標分支的哪一個 commit (9c86a5c
)後面。能夠根據 B 區域中的命令說明修改 pick
爲其餘命令,對該次提取出來的 commit 作額外的操做ip
B 區域內說明了本次 rebase 操做能夠選用的命令開發
經過 :wq
保存退出後,就會按照剛剛在 A 區域內設定的命令處理 commit 並 rebase。
merge 碰見衝突後會直接中止,等待手動解決衝突並從新提交 commit 後,才能再次 merge
rebase 碰見衝突後會暫停當前操做,開發者能夠選擇手動解決衝突,而後 git rebase --continue
繼續,或者 --skip
跳過(注意此操做中當前分支的修改會直接覆蓋目標分支的衝突部分),亦或者 --abort
直接中止該次 rebase 操做
merge 是一個合併操做,會將兩個分支的修改合併在一塊兒,默認操做的狀況下會提交合並中修改的內容
merge 的提交歷史忠實地記錄了實際發生過什麼,關注點在真實的提交歷史上面
rebase 並無進行合併操做,只是提取了當前分支的修改,將其複製在了目標分支的最新提交後面
rebase 的提交歷史反映了項目過程當中發生了什麼,關注點在開發過程上面
merge 與 rebase 都是很是強大的分支整合命令,沒有優劣之分,使用哪個應由項目和團隊的開發需求決定
merge 和 rebase 還有不少強大的選項,可使用 git help <command>
查看
使用 merge 時應考慮採用默認操做,仍是 --no-ff
或 --ff-only
的方式
rebase 操做會丟棄當前分支已提交的 commit,故不要在已經 push 到遠程,和其餘人正在協做開發的分支上執行 rebase 操做
與遠程倉庫同步時,使用 pull 命令默認進行了 git fetch + git merge
兩個操做,能夠經過加上 --rebase
命令將 fetch 後的 merge 操做改成 rebase 操做,或者僅僅 'git fetch remoteName',而後才思考採起哪一種整合策略 git merge(or rebase) origin/master
開發與 commit 時注意本身此時在哪一個分支上
當有修改未 commit 時,不能進行 rebase 操做,此時能夠考慮先用 git stash
命令暫存