git cherry-pick - 挑選 Commit
git cherry-pick 可以從其他分支挑選特定的 commit,套用到當前分支。當你只需要某個特定的變更,而不是整個分支時非常有用。
基本用法
git cherry-pick <commit-hash>
例如:
git cherry-pick a1b2c3d
這會把 a1b2c3d 這個 commit 的變更複製到當前分支,並建立一個新的 commit。
使用情境
情境一:把 Bug 修復套用到多個分支
# 在 develop 分支修復了一個 bug
git checkout develop
# 修復...
git commit -m "Fix critical bug"
# 這個修復也要套用到 main
git checkout main
git cherry-pick <fix-commit-hash>
# 也套用到 release 分支
git checkout release
git cherry-pick <fix-commit-hash>
情境二:從已廢棄的分支取回有用的 Commit
# 整個 feature 分支不要了,但其中有個 commit 想保留
git checkout main
git cherry-pick <useful-commit-hash>
情境三:誤 Commit 到錯誤的分支
# 發現 commit 應該在 feature 分支
git checkout feature
git cherry-pick <wrong-commit-hash>
# 從原分支移除
git checkout main
git reset --hard HEAD~1
Cherry-pick 多個 Commit
一次挑選多個
git cherry-pick <commit1> <commit2> <commit3>
挑選一個範圍
# 挑選從 A 到 B 的所有 commit(不含 A)
git cherry-pick A..B
# 包含 A
git cherry-pick A^..B
挑選連續的 Commit
# 從某個 commit 到分支頂端
git cherry-pick a1b2c3d..feature
常用選項
不自動 Commit
git cherry-pick -n <commit>
# 或
git cherry-pick --no-commit <commit>
變更會放到暫存區,讓你可以做額外修改或合併多個 cherry-pick:
git cherry-pick -n <commit1>
git cherry-pick -n <commit2>
git commit -m "Combined changes from commit1 and commit2"
編輯 Commit 訊息
git cherry-pick -e <commit>
# 或
git cherry-pick --edit <commit>
保留原本的作者資訊
預設 cherry-pick 會保留原作者,但會用你的資訊作為 committer。
如果想記錄是誰做的 cherry-pick:
git cherry-pick -x <commit>
這會在 commit 訊息中加入:
(cherry picked from commit a1b2c3d...)
附加原始 Commit 訊息
git cherry-pick --signoff <commit>
會加入:
Signed-off-by: Your Name <your@email.com>
處理衝突
Cherry-pick 也可能遇到衝突:
git cherry-pick a1b2c3d
# CONFLICT: 衝突發生
# 1. 解決衝突
code conflicted-file.js
# 2. 標記已解決
git add conflicted-file.js
# 3. 繼續 cherry-pick
git cherry-pick --continue
其他選項:
# 放棄這次 cherry-pick
git cherry-pick --abort
# 跳過這個 commit
git cherry-pick --skip
Cherry-pick Merge Commit
和 revert 一樣,cherry-pick merge commit 需要指定父 commit:
git cherry-pick -m 1 <merge-commit>
-m 1 表示從第一個父 commit 的角度 cherry-pick。
實際範例
從別人的分支拿取 Commit
# 查看別人的分支有哪些 commit
git log other-branch --oneline
# 挑選想要的
git cherry-pick <commit-hash>
只取部分變更
如果一個 commit 有多個檔案的變更,但你只要其中一些:
# 不自動 commit
git cherry-pick -n <commit>
# 取消不要的檔案
git restore --staged unwanted-file.js
git checkout -- unwanted-file.js
# commit 想要的
git commit -m "Partial cherry-pick"
把功能移植到舊版本
# 在 main 開發的功能
git log main --oneline
# a1b2c3d Add new feature
# b2c3d4e Feature setup
# 移植到 v1.x 維護分支
git checkout v1.x
git cherry-pick b2c3d4e a1b2c3d
Cherry-pick vs Merge vs Rebase
| 方式 | 用途 |
|---|---|
| Cherry-pick | 只需要特定幾個 commit |
| Merge | 需要整個分支的所有變更 |
| Rebase | 想要重新整理 commit 歷史 |
注意事項
重複的 Commit
Cherry-pick 會建立新的 commit(新的 hash),即使內容相同。如果之後 merge 那個分支,可能會看到重複的變更。
依賴關係
如果你 cherry-pick 的 commit 依賴於其他 commit,可能會遇到問題。確保 cherry-pick 所有相關的 commit。
追蹤 Cherry-pick
使用 -x 選項可以幫助追蹤哪些 commit 被 cherry-pick 過:
git cherry-pick -x <commit>
小技巧
查看哪些 Commit 可以 Cherry-pick
# 查看 feature 有但 main 沒有的 commit
git log main..feature --oneline
檢查 Commit 是否已經存在
# 查看 commit 的內容
git show <commit>
# 檢查這個變更是否已經在當前分支
git log --all --oneline -- <file-that-was-changed>