Git詳解(四) 分支整合

上一篇:Git詳解(三) 項目協作

cherry-pick

cherry-pick 是日本一家做互聯網服務的公司,坐落於東京澀谷區:

不好意思,拿錯稿子了。

cherry-pick 是 Git 的一個指令,作用是改寫提交。具體是什麼意思呢?它可以將某個分支上的指定提交,追加到當前所在分支上。

相信你應該有過這樣的體驗:在 bug 修復分支上的修改通過測試之後,需要將 bug 修復分支合併到主分支上,即使 bug 修復分支只做了一次提交。如下圖:

在這種情況下,如果我們不想對整個分支進行合併,而只是想將某一次提交合入到當前所在分支上,那麼就可以使用 cherry-pick 指令。

cherry-pick 使用起來十分簡單,指令如下:

git cherry-pick <SHA-1>

首先,我們需要獲取要改寫提交記錄的 SHA-1 值:

要改寫提交記錄的 SHA-1 值爲 ae0fb8909,將此次提交追加到 master 分支上:

查看 master 分支的提交歷史:

可以看到 master 分支上多出一次提交,但是新增提交記錄的 SHA-1 值爲 34ee24f,和改寫提交記錄的 SHA-1 值不一樣。因此需要明確的是,改寫後的提交記錄和改寫前的提交記錄內容雖然是完全一樣的,但是本質上是兩次提交,而非同一個提交記錄。

如果你不想使用原來的提交信息,可以使用 -e 參數編輯提交說明:

git cherr-pick -e <SHA-1>

執行該指令後,改寫後提交記錄的作者、提交時間也會被修改。 

如果不想 cherry-pick 自動合併,可以使用 -n 參數:

git cherry-pick -n <SHA-1>

執行該指令後,指定提交記錄不會被直接追加到 master 分支上:

當然,使用 cherry-pick 並不總是一帆風順,追加提交記錄有時會出現衝突。

此時如果要繼續 cherry-pick 操作,需要先解決衝突,然後使用 --continue 參數繼續執行 cherry-pick 指令:

如果要中斷此次 cherry-pick 操作,可以使用 --quit 參數,這種情況下當前分支中衝突的內容依然會保留:

如果要取消此次 cherry-pick 操作,可以使用 --abort 參數,這種情況下當前分支會恢復到 cherry-pick 前的狀態:

從 Git 1.7.2 版本開始,cherry-pick 支持批量操作,也就是可以一次性將一個連續時間序列內的提交記錄進行 cherry-pick 操作:

git cherry-pick <start-SHA-1>...<end-SHA-1>

例如,此時 bugfix 分支上存在以下 3 條提交記錄:

將這 3 條提交記錄追加到 master 分支上:

從上圖可以看到,<start-SHA-1>...<end-SHA-1> 是一個左開右閉的區間,它並不會包含開始的提交記錄。如果想要包含開始的提交記錄,需要使用 ^ 標記一下,使之成爲一個左閉右閉的區間:

git cherry-pick <start-SHA-1>^...<end-SHA-1>

 

rebase

在 Git 中整合來自不同分支的修改主要有兩種方法,一種是我們熟悉的 merge,另一種則本小節要介紹的 rebase(變基)。

在介紹變基之前,一定要記住一個前提:不要企圖對任何公共倉庫中的提交變基。爲了加深你的印象,附上 Git 官網的原話

呃,奇妙的變基也並非完美無缺,要用它得遵守一條準則:

如果提交存在於你的倉庫之外,而別人可能基於這些提交進行開發,那麼不要執行變基。

如果你遵循這條金科玉律,就不會出差錯。 否則,人民羣衆會仇恨你,你的朋友和家人也會嘲笑你,唾棄你。

首先我們回顧一下之前我們是如何整合分支的。現在本地倉庫中存在 master 和 newb 兩個分支:

通過 merge 指令,我們可以很輕鬆的將 newb 分支合併到 master 分支上。它會把兩個分支的最新提交(C2 和 C3)以及二者最近的共同祖先提交(C1)進行三方合併,合併的結果是生成一個新的提交(C4),並將 C4 提交到 master 分支:

而變基給我們提供了一種新的思路:提取 C3 的修改作爲一個補丁(C3'),然後將這個補丁應用到 C2 上:

它的原理是先找到當前所在分支(newb)和變基操作的目標基底分支(master)的最近共同祖先提交(C1),然後對比當前所在分支相對於該祖先提交的歷次提交,提取相應的修改並存爲臨時文件(補丁),接着將當前分支指向目標基底(C2),最後依次將之前的補丁應用。 

簡單來說,rebase 操作的作用就是將某一分支上的所有修改都移至另一分支上。變基指令如下:

git rebase <topic_branch> <source_branch>

現有本地倉庫 master 分支和 newb 分支提交信息如下:

   

將 newb 分支變基到 master 分支,由於當前所在分支就是 source_branch,因此可以省略:

再次查看 master 分支和 newb 分支的提交記錄:

  

由於變基後的提交是重新生成的,可以看到原本 newb 分支上的最新提交 SHA-1 值爲 ef031cb,變基後的最新提交 SHA-1 值爲 5d770af。

此時將 newb 分支合併到 master 分支上,會觸發 fast-forward 合併,我們就能得到一個乾淨、簡潔的 master 分支: 

通過上面的舉例,你可以發現 rebase 和 cherry-pick 有很多相似的地方。只是 cherry-pick 更多的是針對單一提交的操作,而 rebase 更多的是面向一組提交的操作。

和 cherry-pick 操作一樣,rebase 操作也會面臨衝突。出現衝突時,你可以在解決衝突之後通過 --continue 參數繼續變基操作,或者通過 --quit/ --abort 退出變基操作。

 

補充:

Git詳解(補1) Git 對象

 

參考:

[Git] Git整理(五) git cherry-pick的使用

Cherry-Pick | 一日一 Git

Git 分支 - 變基

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章