Git進階系列 | 7. Git中的Cherry-pick提交

語言: CN / TW / HK

Git是最流行的程式碼版本控制系統,這一系列文章介紹了一些Git的高階使用方式,從而幫助我們可以更好的利用Git的能力。本系列一共8篇文章,這是第7篇。原文:Cherry-Picking Commits in Git [1]

在本系列的第5部分中,討論了rebase和merge。雖然 git mergegit rebase 之間有一些不同,但這兩個命令的目標是相同的: 將一個分支的更改整合到另一個分支。

今天我們來看看 git cherry-pick ,理解它是怎樣允許我們將任何分支中被選中的、單獨的提交整合到當前的 HEAD 分支中。這與 git mergegit rebase 有很大的區別,兩者都只能整合來自指定分支的所有新提交。

那麼為什麼要從一個分支中只選擇一個提交整合到另一個分支呢?當然會有不同的原因,但其中一個特別的原因是撤消變更。假設我們不小心在錯誤的分支上做了一個提交,使用cherry-pick處理就不會有什麼大問題。我們可以切換到正確的分支,然後cherry-pick對應的提交。

Git進階系列:

  1. 建立完美的提交

  2. Git中的分支策略

  3. 基於Pull Request實現更好的協作

  4. 合併衝突

  5. Rebase vs Merge

  6. 互動式Rebase

  7. Git中的Cherry-pick提交(本文)

  8. 用Reflog恢復丟失的提交

在看例項之前,先警告一下: 不要對cherry-pick太過興奮。你的主要目標應該是在分支級別工作, git mergegit rebase 都是為此構建的。cherry pick只是為了特殊場合,而不是為了代替merge和rebase。

將提交移到另一個分支

我們通過一個真實的場景來解釋什麼時候cherry pick才是正確的。假設我們向 master 分支提交了一些本打算用於 feature/newsletter 的內容。現在怎麼辦?需要打電話給團隊成員或老闆來解釋這個“錯誤”嗎?

下面的截圖顯示了這個問題,以及在 master 分支上意外提交的 26bf1b48

或者,如果在終端輸入 git log ,可以在命令列看到這一情況:

$ git log
commit 26bf1b4808ba9783e4fabb19ec81e7a4c8160194 (HEAD -> master)
Author: Tobias Günther
Date: Fri Oct 5 09:58:03 2018 +0200

Newsletter signup page

可以看到,ID為 26bf1b48 的提交最終合併到了 master 中,但其實應該提交到分支 feature/newsletter 中。我們需要選擇特定的提交併將其移到正確的分支。首先切換分支,然後選擇提交:

$ git checkout feature/newsletter
Switched to branch 'feature/newsletter'
$ git status
On branch feature/newsletter
nothing to commit, working tree clean
$ git cherry-pick 26bf1b48
[feature/newsletter 7fb55d0] Newsletter signup page
Author: Tobias Günther <[email protected]>
Date: Fri Oct 5 09:58:03 2018 +0200
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 signup.html

再次執行 git log ,可以在 feature/newsletter 分支上看到新的提交:

$ git log
commit 7fb55d06a8e70fdce46921a8a3d3a9de7f7fb8d7 (HEAD -> feature/newsletter)
Author: Tobias Günther <[email protected]>
Date: Fri Oct 5 09:58:03 2018 +0200

Newsletter signup page

這背後發生了什麼?Git在 feature/newsletter 分支上建立了一個具有相同更改的提交副本以及相同的提交資訊。然而,這是一個有著新ID的全新提交。那麼最初的提交呢?

清理其他分支

如果檢查 master 分支,仍然可以看到“錯誤的”提交。這意味著cherry pick不會從原來的分支“移動”被選中的提交,而只是建立一個副本,不會影響原始檔案。

現在,為了清理和撤銷提交,可以使用 git reset

$ git checkout master
Switched to branch 'master'
$ git reset --hard HEAD~1
HEAD is now at 776f8ca Change about title and delete error page

就像什麼都沒發生過一樣。

如果使用像Tower這樣的GUI應用,整個過程是這樣的:

用於特殊情況的工具,而不是日常的整合

只要可以使用傳統的merge或rebase,就應該這樣做。Cherry pick應該只在 git mergegit rebase 沒用的情況下才用,比方說想要從一個分支把某個提交移到另一個。記住, git cherry-pick 建立了“重複”的提交,應該在之後進行清理。

如果想更深入瞭解高階Git工具,可以免費檢視“Advanced Git Kit [3] ”: 這是關於分支策略、互動式Rebase、Reflog、子模組等主題的短視訊集合。

References:[1] Cherry-Picking Commits in Git: https://css-tricks.com/cherry-picking-commits-in-git/

你好,我是俞凡,在Motorola做過研發,現在在Mavenir做技術工作,對通訊、網路、後端架構、雲原生、DevOps、CICD、區塊鏈、AI等技術始終保持著濃厚的興趣,平時喜歡閱讀、思考,相信持續學習、終身成長,歡迎一起交流學習。

微信公眾號:DeepNoMind

- END -