Git Cherry-pick-只把想要的 commit 併進來

很神奇的功能。

簡述

假設這是目前的紀錄:

example

我現在位於 master 上,然後有 dogcat 這兩個分支。現在我想要把 cat 的內容合併到 master,可是我只想要其中幾個 commit,不想要全部都併進去。

例如我只想要 add cat1 這筆紀錄的話,可以下這段指令:

1
git cherry-pick 1006eb2

這樣 master 就只會多出 add cat1 的紀錄:

example-result

不要幫我 commit

有時候你可能想額外加一些東西,所以不希望一下完指令後就直接 commit 出去,這時候可以加上 --no-commit

1
git cherry-pick 1006eb2 --no-commit

這樣子資料就會被放到「暫存區(Stage Area)」,等到全部修改完成後再自己 commit 就行囉。

example-no-commit

對 cherry-pick 的誤解

我剛開始學這個指令的時後發現我對它背後的含義有一點誤解,所以特別寫這一段來解釋一下。

先回憶一下剛剛的範例:

example

在前面的示範中我們是從 cat 中取出 add cat1 的記錄到 master 中,不過如果現在是取出 add cat3 呢?

1
git cherry-pick 63eeaa5

出來的結果就會變這樣子:

example2-result

看起來沒什麼問題啊?怎麼了嗎?

單從歷史紀錄來看的話確實是沒有什麼問題,但其實 cherry-pick 並不是幫你把 add cat3 給抓出來,而是把 add cat3 給合併

這樣子說可能聽不懂,所以我們來看一下 add cat3 修改了什麼:

example2-cat-changes

add cat3 只有新一行 Cat3 而已,接著來看一下併完後的 master

example2-master-changes

注意到了嗎?最後的內容並不是只有 add cat3 當下所做的改變,而是這個 commit 當下的所有檔案內容,換句話說就是整個合併進來。

所以這就跟我原本想的不太一樣,我以為它只會把「修改的內容」給抓出來而已,但實際上的意思是:

選擇我想要 merge 的位置,並且留下這個位置的 commit 訊息。

我舉幾個例子(這邊為了方便閱讀就不寫 hash 值了):

1
git cherry-pick 'add cat1'

意思是「把 add cat1 合併到 master,但只留下 add cat1 的提交紀錄」

1
git cherry-pick 'add cat2'

意思是「把 add cat2 合併到 master,但只留下 add cat2 的提交紀錄」

1
git cherry-pick 'add cat3'

意思是「把 add cat3 合併到 master,但只留下 add cat3 的提交紀錄」

你可以把上面這幾個範例想成這樣:

1
2
3
git merge 'add cat1' // 合併,但只保留 add cat1 的 commit 紀錄
git merge 'add cat2' // 合併,但只保留 add cat2 的 commit 紀錄
git merge 'add cat3' // 合併,但只保留 add cat3 的 commit 紀錄

總之你一定要記得:

  • cherry-pick 只是用另一種方式來做 merge
  • cherry-pick 只是用另一種方式來做 merge
  • cherry-pick 只是用另一種方式來做 merge

不管你選擇的位置是哪裡,只要想成你是在做 merge 就好了,跟那個 commit 修改的內容一點關係也沒有。

那什麼時候該用 cherry-pick?

如果有聽懂剛剛的解釋,就能理解 cherry-pick 比較像是「可以自由選擇 commit 紀錄的 merge」,而不是把你想要的修改內容抽出來,所以比較正確的用法大概會是像這樣,一樣是剛剛的例子:

example

1
git cherry-pick 63eeaa5 -x

這邊把 add cat3 合併進來並加上 -x-x 是用來讓 Git 自動幫我們產生「標準訊息」。

附註:因為 cherry-pick 併完後不會額外產生新的 commit,所以不仔細看的話可能不會知道這份紀錄是併過來的,所以才建議在 commit 內容中加上額外的訊息。

example3-standard-message

最後完成的結果就會像這樣:

example3-result

就跟剛剛說的一樣,這裡實際上是幫你合併所有在 cat 中的所有修改,但只有保留 add cat3 的 commit 紀錄。順道一提這段 commit 訊息應該要修改成 add cat1 ~ 3 才比較符合這個 commit 實際上做的事情,但這邊只是為了示範所以就沒特別做了。

總之用 cherry-pick 其實只是令外一種合併方式而已,它可以讓你很輕鬆的拿掉不必要的 commit 紀錄。

如果要用 merge 來產出相同的結果,步驟就會變比較麻煩:

1
git merge 63eeaa5

example4-merge1

1
git reset HEAD~3 // 取消最後 3 筆 commit 紀錄(但保留檔案)

example4-merge2

1
git commit -am 'add cat3' // 加入暫存區並提交

example4-merge3

所以兩種方法其實都行,端看你喜歡哪一種而已。

Vim 筆記 Git Rebase-以前做了一點修改,想合併到目前的紀錄
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×