上篇部落格聊了《Git知識總覽(三) 分支的建立、删除、切換、合并以及沖突解決》,本篇部落格我們主要來看一下 rebase 變基相關的操作。rebase 操作和 merge 操作最終都可以達到合并代碼的效果,不過其對分支的影響不同。上篇部落格中我們聊到了 merge操作。簡單的說merge操作就是将兩個commit進行合并,然後在這兩個分支合并的基礎上建立一個新的commit。而變基操作簡單的說是改變送出的父類,在改變父類時進行合并操作。合并就可能産生沖突,是以rebase時也會産生沖突,下方會介紹到。
聊完rebase,下方還聊如何進行cherry-pick。cherry-pick的本質其實也是合并,隻不過是可以将任意分支,任意送出合并到相關分支。當然隻要是合并操作,都有可能産生沖突,下方會給出cherry-pick操作的基本使用以及如何解決cherry-pick時産生的沖突。
一、merge 與 rebase 的簡單對比
下方是我們做操作之前的分支狀态,共有 bugFix、side 、another 三個分支。現在我們要做的是分别使用 merge 和 rebase 将分支 side 中的内容合并到master分支。

首先我們先來看一下 merge 操作。上篇部落格中已經詳細的聊了merge的相關操作,再次就不做過多的展示了,下方隻做了簡單的展示。
首先切換到master分支
然後在master分支上執行 git merge side 操作,将side分支上的内容合并到master分支上。
最後如果需要的話,在将side分支的指針指向master分支即可。
然後我們再看一下 rebase 下的相關操作。
首先切換到 side 分支。
然後在 side 分支上執行 git rebase master 操作,将其變基到master分支上。
二、rebase的基本操作
首先我們來看一下在git分支管理中如何使用rebase, 以及rebase的後會起什麼作用。下方會根據一系列的示例來看一下rebase操作的實際效果。首先我們先來看一下做rebase操作之前的分支狀态,如下所示。目前除了master主分支外,還有其他三個分支,分别為bugfix01、bugfix02、bugfix03。
現在要做的事情是在 bugfix01 的分支上執行rebase操作,将其變基到master分支上。
下方是在 bugfix01分支上執行的 git rebase master 将bugfix01分支變基到master分支上,下方是變基後的分支狀态。從下方的分支中不難看出,之前在 master 分支後方的 bugfix01現在跑到了master分支的後方,并且 bigfix01 分支上的兩個送出(3cc582b、f47d2ac)不見了。取而代之的是基于master分支的兩個新的送出(d6d82d8、14bc685)。這兩個新的送出不但包含了3cc582b、f47d2ac這兩個舊的送出的内容,而且還包含了master分支目前指向的分支(b79aa11)送出上的内容。
上面的表達也許有點抽象,下面我們可以話一張圖來表示上述的關系。根據上面的分支關系,簡單的畫了一下上面的 rebase 操作所對應的關系圖。rebase 操作完後,下方畫紅框的分支就被廢棄掉了。然後bugfix01會指向rebase後的commit上。
接着上面的操作,可以切換到master分支,然後執行 git merge bugfix01 指令,将master分支快速移動到bugfix01分支上所指向的内容上。下方就是快速移動後的結果。經過這步後,就完成了一次rebase操作。從rebase操作的結果來看,其對 git 的分支進行了整理,換句話說,rebase操作可以将其他分支上的内容合并到主分支上,合并後之前的分支的指針的指向也會随之變化,變化後之前的送出就會被抛棄掉。
變基是存在一定風險的,在 ProGit上有一句話:Do not rebase commits that exist outside your repository. 大概意思就是說:不要在你的倉庫在其他地方存在副本的情況下,對分支執行變基。也就是說,你從遠端Clone下來代碼,然後對之前的操作進行了rebase, 并且強推到遠端。如果别人也clone的相關倉庫,在其分支上做了相關操作。在push之前執行pull時,因為之前的分支被你rebase了,也就是有了新的送出,在pull時,就會進行merge操作。這樣一來,分支就會更加複雜。如果出現上述問題 就使用rebase 來解決問題,即使用 git pull --rebase 來執行。
這一塊具體的東西還是參考ProGit上的内容來的比較直覺,在此就不做過多贅述了。
三、rebase的沖突解決
為了看rebase沖突的解決方式,我們故意的制造了下方的沖突,然後去執行rebase操作。從下方的操作中不難看出,在rebase的過程中産生了沖突,需要我們去解決。解決沖突後将相關問題件進行commit, 然後使用 git rebase --continue 操作來繼續rebase。
因為rebase時會合并多個送出,在多個送出合并時會産生多個沖突,所有在一個沖突解決并送出後,進行git rebase --continue繼續合并接下來的點。繼續後仍然有可能産生沖突,産生沖突即解決沖突,直到rebase結束為止。
四、cherry-pick的基本操作
接下來我們來看一下git中比較實用的一個指令:cherry-pick。這個指令的名字是比較形象的,cherry-pick即“摘櫻桃”,使用該指令可以将任意的commit通過其commit号将其合并到你想要的分支上。接下來我們就來看一個例子。
下方就示範了cherry-pick指令的使用方法。在 master 分支上,執行 git cherry-pick <一些commit的哈希值> 然後将這些送出合并到master分支上。這些分支會根據cherry-pick的順序進行merge,每次merge都會形成一個新的送出。與rebase指令不同,雖然會産生一個新的送出,而之前的送出是不變的。具體如下所示:
接下來我們來看一下具體在終端上cherry-pick的操作指令。下方是目前分支的狀态,并且處于master分支上。現在我們要做的事情是将 d98ff43 這個commit 拿到master上。
下方就是我們執行cherry-pick的指令,如下所示。下方執行cherry-pick時是非常順利的,沒有産生沖突。當送出進行合并時會産生沖突,就不是這個樣子了,稍後會示範到。
下方就是順利的cherry-pick後的樣子。
五、cherry-pick的沖突解決
在cherry-pick時遇到沖突是避免的,下方特地搞了一個cherry-pick沖突的例子。為了更進一步的了解沖突的解決方式,下方cherry-pick了多個送出,而且這多個送出在merge時都會有沖突。下方我們會對這些沖突進行解決。
首先我們在master分支上通過 git cherry-pick <一系列送出的哈希值>來将 4f8e019、dbe9e8a、5c52520這三個送出摘到master分支上。
然後我們會先看到在cherry-pick 4f8e019 這個送出時産生了沖突,報了一個Error:提升不能将cherry-pick指令應用于4f8e019。并且下方給了一系列的提示(解決此錯誤可以通過正确的方式解決沖突,然後通過git add 或者 git rm将更改的檔案進行追蹤,最後可以使用 git commit進行送出)
解決一個沖突并commit後,使用 git cherry-pick --continue可以進一步的進行下一個送出的cherry-pick。下方再次執行git cherry-pick --continue時,又出現了沖突,此刻我們還是按照上述的步驟對沖突進行解決,解決完畢後接着git cherry-pick --continue。直到所有的commit被合并完畢即可。具體操作步驟如下所示:
下方是上述操作的最終結果,cherry-pick了三個commit,沖突了三次,解決了三次。如下所示:
下篇部落格會繼續聊Git的相關的内容。
作者:青玉伏案
出處:http://www.cnblogs.com/ludashi/
本文版權歸作者和共部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。
如果文中有什麼錯誤,歡迎指出。以免更多的人被誤導。
收履歷:某網際網路公司,招聘iOS/Android靠譜工程師,入職後,可内部聯系樓主,有小禮品贈送,有意者可郵箱投遞履歷:[email protected]