1. 程式人生 > >Git知識總覽(四) git分支管理之rebase 以及 cherry-pick相關操作

Git知識總覽(四) git分支管理之rebase 以及 cherry-pick相關操作

上篇部落格聊了《》,本篇部落格我們主要來看一下 rebase 變基相關的操作。rebase 操作和 merge 操作最終都可以達到合併程式碼的效果,不過其對分支的影響不同。上篇部落格中我們聊到了 merge操作。簡單的說merge操作就是將兩個commit進行合併,然後在這兩個分支合併的基礎上建立一個新的commit。而變基操作簡單的說是改變提交的父類,在改變父類時進行合併操作。合併就可能產生衝突,所以rebase時也會產生衝突,下方會介紹到。

聊完rebase,下方還聊如何進行cherry-pickcherry-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的相關的內容。