- Git
- 技術 💻
git cherry-pickの使い方|範囲指定・取り消し・コンフリクト・重複の対処
結論
git cherry-pick は、別ブランチの選んだコミットだけを今のブランチに新しいコミットとして写すコマンドです。取り込む側で git cherry-pick <ID> を実行します。
この記事でわかること
- 状況別15パターンの早見表(範囲指定・取り消し・PR)
- 範囲指定
A..BとA^..Bの実行結果の比較 - 同じ変更が2回入る仕組みと、エラー文12件の直し方
cherry-pick は feature のコミット C を残したまま、同じ変更の新しいコミット C' を main に作ります。
flowchart TD
subgraph F["feature(C は残る)"]
A["A"] --> C["C:修正"]
end
subgraph M["main"]
B["B"] --> C2["C':同じ変更<br>別の ID"]
end
C -- "git cherry-pick C" --> C2
| やりたいこと | コマンド | 補足 |
|---|---|---|
| 1つのコミットを取り込む | git cherry-pick <ID> |
新しい ID のコミットができる |
| 複数を取り込む | git cherry-pick <A> <B> |
書いた順に1つずつ適用 |
| 範囲で取り込む(A を含む) | git cherry-pick A^..B |
A から B まで |
| 範囲で取り込む(A を含まない) | git cherry-pick A..B |
A の次から B まで |
| コンフリクトを直した後 | git add <file> → git cherry-pick --continue |
エディタでメッセージ確認 |
| 全部やめて元に戻す | git cherry-pick --abort |
開始前の状態に戻る |
| 取り込んだ直後に取り消す(push 前) | git reset --hard HEAD~1 |
3件なら HEAD~3 |
| push 後に取り消す | git revert <作られたID> |
打ち消しコミットを足す |
| 今のコミットを飛ばす | git cherry-pick --skip |
残りは続行 |
| 取り込み元の ID を記録する | git cherry-pick -x <ID> |
メッセージに (cherry picked from commit …) |
| コミットせず変更だけ入れる | git cherry-pick -n <ID> |
複数を1コミットにまとめるとき |
| マージコミットを取り込む | git cherry-pick -m 1 <ID> |
-m なしはエラー |
| 同じ変更が入っているか調べる | git log --oneline --cherry main...feature |
= が取り込み済み |
| GitHub の PR から拾う | git fetch origin pull/7/head:pr-7 → git cherry-pick <ID> |
PR 番号 7 の例 |
| メッセージを直して取り込む | git cherry-pick -e <ID> |
エディタが開く |
確認環境:Git 2.43.0(Ubuntu 24.04、Linux)。使い捨てのリポジトリと、ローカルに作った bare リポジトリ(リモートの代わり)でこの記事のコマンドを実行し、出力を英語表示(LANG=C)のまま載せています。Git 2.45 で加わった --empty と、-x のコンフリクト後の動きは、ソースコードから構築した Git 2.56.0 でも実行しました。コミット ID は実行のたびに変わります。オプションの仕様は Git 公式マニュアル(2.56.0 版)、VS Code・IntelliJ IDEA・GitHub Desktop の操作は各公式ドキュメントで確かめました(確認日 2026年10月16日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「git cherry-pickの使い方|範囲指定・取り消し・コンフリクト・重複の対処」
git cherry-pick とは(図で仕組みを見る)
- 何をするか:指定したコミットが親に対して加えた差分(パッチ)を、今のブランチの先端に適用し、新しいコミットを作ります。
- 何が残るか:元のブランチのコミットはそのまま残ります。cherry-pick は「移動」ではなく「コピー」です。
- 何が変わるか:コミット ID は必ず変わります。変更内容・メッセージ・作者(Author)・作者の日時は引き継がれ、コミットした人(Committer)と日時は実行した人のものになります。
gitGraph
commit id: "initial"
branch release/1.0
checkout main
commit id: "feat-A"
commit id: "feat-B"
commit id: "fix-123"
checkout release/1.0
cherry-pick id: "fix-123"
commit id: "release-1.0.1"
図のように、main で直したバグ修正 fix-123 だけをリリースブランチへ写すのが典型的な使い方です。新機能 feat-A・feat-B は release/1.0 に入りません。
実際に写したコミットの中身を比べると、作者は元のまま、コミットした人だけが変わっています(後述の練習用リポジトリで、main の fix: round total を release/1.0 へ写した結果です)。
$ git log -n 1 --format='%h %s%n author: %an <%ae> %ad%n committer: %cn <%ce> %cd' main
386cf63 fix: round total
author: Taro Yamada <taro@example.com> Thu Oct 1 10:04:00 2026 +0900
committer: Taro Yamada <taro@example.com> Thu Oct 1 10:04:00 2026 +0900
$ git log -n 1 --format='%h %s%n author: %an <%ae> %ad%n committer: %cn <%ce> %cd' release/1.0
94cd2e1 fix: round total
author: Taro Yamada <taro@example.com> Thu Oct 1 10:04:00 2026 +0900
committer: Hanako Sato <hanako@example.com> Fri Oct 16 17:40:17 2026 +0900
ID は違っても「同じ変更」であることは git patch-id で確かめられます。patch-id は、差分から行番号を除いて計算した値で、Git が「取り込み済み」を判定するときにも使われます(後述の「同じ変更が2回入る問題」)。
$ git show 386cf63 | git patch-id --stable
cc1f0f78c7f221c1e034ea3592b73f6b2d35e93d 386cf6379edeaee5f144559f3df85f0e4a85273b
$ git show release/1.0 | git patch-id --stable
cc1f0f78c7f221c1e034ea3592b73f6b2d35e93d 94cd2e14b09805e865ef3a968b866d11eb8aaf35
左の値(patch-id)が一致しています。
使う場面と使わない場面(merge・rebase・revert との違い)
「何を」「どこへ」動かしたいかで選びます。
| コマンド | 何をする | 履歴への影響 | 向いている場面 |
|---|---|---|---|
cherry-pick |
選んだコミットの変更だけを複製 | 新しい ID のコミットが増える | 修正を別ブランチにも入れる、間違えたブランチのコミットを移す |
merge |
ブランチ全体を統合 | マージコミットで2本の流れが合流 | 機能ブランチをまるごと取り込む |
rebase |
ブランチのコミット群を別の起点に付け替え | コミット ID が書き換わる | push 前の自分のブランチを最新の main に追従させる |
revert |
指定コミットを打ち消す逆のコミットを作る | 打ち消しコミットが増える | 公開済みの変更を履歴を残して取り消す |
| 状況 | 選ぶもの | 理由 |
|---|---|---|
| main のバグ修正をリリースブランチにも入れたい | cherry-pick |
未リリースの機能を混ぜずに済む |
| 機能ブランチの全コミットを main に入れたい | merge(または PR) |
履歴がつながり、重複も生まれない |
| 機能ブランチを最新の main の上に載せ直したい | rebase |
全コミットを付け替えるのが目的 |
| main に push 済みのコミットを無かったことにしたい | revert |
履歴を書き換えない |
| 間違えて main にコミットした(push 前) | cherry-pick → 元を reset |
下の例 |
| 同じブランチを後で merge する予定がある | merge を先にできないか検討 |
cherry-pick すると同じ変更が2回入る(後述) |
merge と rebase の使い分けは関連記事「git mergeとrebaseの違い|使い分けとコンフリクト解消」で、revert は関連記事「git revertの使い方|resetとの違いとマージコミット取り消し手順」で扱っています。
例:間違えたブランチにコミットしたときの移し方
main に直接コミットしてしまった feat: add report page を feature/report に移します。
$ git log --oneline --graph --all
* adb78fb feat: add report page
* 739bfaf initial
$ git switch feature/report
Switched to branch 'feature/report'
$ git cherry-pick main
[feature/report 5e75adf] feat: add report page
Date: Fri Oct 16 10:05:00 2026 +0900
1 file changed, 1 insertion(+)
create mode 100644 report.py
$ git switch main
Switched to branch 'main'
$ git reset --hard HEAD~1
HEAD is now at 739bfaf initial
$ git log --oneline --graph --all
* 5e75adf feat: add report page
* 739bfaf initial
git cherry-pick main のようにブランチ名を書くと、そのブランチの先端のコミット1つを指します。main 側の取り消しは push 前なら reset、push 後なら revert です。詳しくは関連記事「git commit(コミット)の取り消し方|push前後の早見表・NG操作・復元」で扱っています。
練習用リポジトリの準備
手元で同じ結果を再現できるよう、最小のリポジトリを作ります。main に4つのコミットを積み、initial の時点から release/1.0 を切っておきます。
git init -b main demo && cd demo
printf 'version=1.0\n' > app.conf
printf 'def total(a, b):\n return a + b\n' > calc.py
git add . && git commit -m "initial"
git branch release/1.0
printf 'def tax(x):\n return x * 0.1\n' > tax.py && git add tax.py && git commit -m "feat: add tax"
echo "# log helper" > log.py && git add log.py && git commit -m "feat: add log helper"
echo "# util" > util.py && git add util.py && git commit -m "chore: add util"
printf 'def total(a, b):\n return round(a + b, 2)\n' > calc.py && git commit -am "fix: round total"
$ git log --oneline main
386cf63 fix: round total
8939a5f chore: add util
2bf627c feat: add log helper
991281e feat: add tax
ef90bce initial
$ git log --oneline release/1.0
ef90bce initial
この記事では main 側のコミットを別の人(Taro Yamada)が作ったことにしてあります。そのため cherry-pick の出力に Author: の行が出ます。自分のコミットを写したときは、この行は出ません。
基本の使い方:1つ・複数のコミットを取り込む
取り込むコミットの ID を探す
| 探し方 | コマンド |
|---|---|
| ブランチの履歴を一覧する | git log --oneline main |
| 相手のブランチにだけあるコミット | git log --oneline release/1.0..main |
| ファイルを変えたコミットだけ | git log --oneline main -- app.conf |
| メッセージで探す | git log --oneline --grep='timeout' main |
| 変更内容を見てから決める | git show <ID> |
git log の表示の整え方は関連記事「git logオプション一覧|見やすくするformat指定子とalias設定例」で扱っています。
1つのコミットを取り込む
取り込みたい側のブランチに切り替えてから、コミット ID を指定します。「どこから」ではなく「どこへ」のブランチにいることが大切です。
$ git switch release/1.0
Switched to branch 'release/1.0'
$ git cherry-pick 386cf63
[release/1.0 94cd2e1] fix: round total
Author: Taro Yamada <taro@example.com>
Date: Thu Oct 1 10:04:00 2026 +0900
1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --oneline
94cd2e1 fix: round total
ef90bce initial
$ git log --oneline main
386cf63 fix: round total
8939a5f chore: add util
2bf627c feat: add log helper
991281e feat: add tax
ef90bce initial
[release/1.0 94cd2e1] が新しくできたコミットです。元の 386cf63 は main に残ったままです。
複数のコミットをまとめて取り込む
ID をスペース区切りで並べると、書いた順に1つずつ適用されます。
$ git switch -c try-multi release/1.0
Switched to a new branch 'try-multi'
$ git cherry-pick 991281e 2bf627c
[try-multi e5b2412] feat: add tax
Author: Taro Yamada <taro@example.com>
Date: Thu Oct 1 10:01:00 2026 +0900
1 file changed, 2 insertions(+)
create mode 100644 tax.py
[try-multi 34e53ef] feat: add log helper
Author: Taro Yamada <taro@example.com>
Date: Thu Oct 1 10:02:00 2026 +0900
1 file changed, 1 insertion(+)
create mode 100644 log.py
$ git log --oneline -n 4
34e53ef feat: add log helper
e5b2412 feat: add tax
94cd2e1 fix: round total
ef90bce initial
先に作られたコミットから順に書くのが基本です。後のコミットが前のコミットの変更を前提にしている場合、逆順に書くとコンフリクトします。たとえば feature/export の先端 feat: export xlsx(export.py に1行追加)だけを、その前の feat: export csv(export.py を新規作成)より先に取り込もうとすると、次のように止まりました。
$ git cherry-pick feature/export
CONFLICT (modify/delete): export.py deleted in HEAD and modified in 5a14e4c (feat: export xlsx). Version 5a14e4c (feat: export xlsx) of export.py left in tree.
error: could not apply 5a14e4c... feat: export xlsx
範囲指定:A..B と A^..B の違い(実行して比較)
A..B は「A を含まず、A の次から B まで」、A^..B は「A を含めて B まで」です。 先頭の1コミットだけ入らなかった、というつまずきの原因はここにあります。
範囲指定の前に git log --oneline に同じ範囲を渡すと、対象が確かめられます。
$ git log --oneline 991281e..8939a5f
8939a5f chore: add util
2bf627c feat: add log helper
$ git log --oneline 991281e^..8939a5f
8939a5f chore: add util
2bf627c feat: add log helper
991281e feat: add tax
A..B(A は含まれない)
$ git switch -c try-range release/1.0
Switched to a new branch 'try-range'
$ git cherry-pick 991281e..8939a5f
[try-range 65ad598] feat: add log helper
Author: Taro Yamada <taro@example.com>
Date: Thu Oct 1 10:02:00 2026 +0900
1 file changed, 1 insertion(+)
create mode 100644 log.py
[try-range 8765b3c] chore: add util
Author: Taro Yamada <taro@example.com>
Date: Thu Oct 1 10:03:00 2026 +0900
1 file changed, 1 insertion(+)
create mode 100644 util.py
$ git log --oneline
8765b3c chore: add util
65ad598 feat: add log helper
94cd2e1 fix: round total
ef90bce initial
取り込まれたのは2つだけで、feat: add tax は入っていません。
A^..B(A も含まれる)
^ は「そのコミットの親」です。始点を1つ前にずらすことで、A そのものも範囲に入ります。A~1..B と書いても同じです。
$ git switch -c try-range2 release/1.0
Switched to a new branch 'try-range2'
$ git cherry-pick 991281e^..8939a5f
[try-range2 2834e5b] feat: add tax
(中略)
[try-range2 c3d20cd] feat: add log helper
(中略)
[try-range2 4d45f04] chore: add util
(中略)
$ git log --oneline
4d45f04 chore: add util
c3d20cd feat: add log helper
2834e5b feat: add tax
94cd2e1 fix: round total
ef90bce initial
| 書き方 | 取り込まれる範囲 | 今回の結果 |
|---|---|---|
991281e..8939a5f |
991281e の次 〜 8939a5f | 2コミット |
991281e^..8939a5f |
991281e 〜 8939a5f | 3コミット |
..main |
今のブランチに無い main のコミット全部 | 下の例 |
範囲指定の応用:..main と --stdin
..main は「今のブランチに無い、main のコミット全部」です。すでに取り込み済みの変更が範囲に入っていると、そのコミットは「空」になって止まります(後述の「空になるコミット」)。
$ git switch -c try-dots release/1.0
Switched to a new branch 'try-dots'
$ git log --oneline ..main
386cf63 fix: round total
8939a5f chore: add util
2bf627c feat: add log helper
991281e feat: add tax
$ git cherry-pick ..main
[try-dots 2834e5b] feat: add tax
(中略)
[try-dots 4d45f04] chore: add util
(中略)
The previous cherry-pick is now empty, possibly due to conflict resolution.
If you wish to commit it anyway, use:
git commit --allow-empty
Otherwise, please use 'git cherry-pick --skip'
特定のファイルを変えたコミットだけを拾うには、公式マニュアルの例にある --stdin が使えます。git rev-list --reverse で先に作られた順に ID を出し、パイプで渡します。
$ git log --oneline --reverse release/1.0..main -- export.py
0678be7 feat: export csv
5a14e4c feat: export xlsx
$ git rev-list --reverse release/1.0..main -- export.py | git cherry-pick --stdin
[try-stdin f9e4355] feat: export csv
(中略)
[try-stdin 710761b] feat: export xlsx
(中略)
zsh で EXTENDED_GLOB を有効にしている場合、^ がパターンとして解釈され zsh: no matches found: 991281e^..8939a5f になりました。'991281e^..8939a5f' のように引用符で囲むと通ります(既定の zsh では引用符なしでも通りました)。
オプション一覧:-n・-x・-e・-m・--allow-empty・-X
| オプション | 動き | 使う場面 |
|---|---|---|
-x |
メッセージ末尾に (cherry picked from commit <ID>) を追記 |
公開ブランチ間のバックポート |
-n, --no-commit |
コミットせず、変更をステージに入れて止まる | 複数を1コミットにまとめる、手直ししてからコミット |
-e, --edit |
コミット前にエディタでメッセージを編集 | リリース用の注記を足す |
-s, --signoff |
Signed-off-by: を追記 |
署名が必要なプロジェクト |
-m <n>, --mainline <n> |
マージコミットを「n 番目の親」基準で適用 | マージコミットを取り込む |
--ff |
HEAD が元コミットの親と同じなら fast-forward | 履歴が直線のとき |
--allow-empty |
もともと空のコミットを取り込む | 空コミット(CI 起動用など) |
--empty=drop・keep・stop |
取り込み先に同じ変更があり空になるコミットの扱い(Git 2.45 以降) | 範囲指定で重複が混ざるとき |
--keep-redundant-commits |
--empty=keep の非推奨の別名 |
2.45 より前の Git |
-X <opt>, --strategy-option |
マージ戦略のオプション(theirs・ours・patience など) |
自動解決したいとき |
--strategy=<name> |
マージ戦略の指定(既定は ort) |
通常は不要 |
-x:取り込み元のコミットを記録する
$ git cherry-pick -x 386cf63
[try-x 43cfee0] fix: round total
Author: Taro Yamada <taro@example.com>
Date: Thu Oct 1 10:04:00 2026 +0900
1 file changed, 1 insertion(+), 1 deletion(-)
$ git log -n 1 --format=%B
fix: round total
(cherry picked from commit 386cf6379edeaee5f144559f3df85f0e4a85273b)
公式マニュアルは「コンフリクトの無い cherry-pick でだけ付く」と説明していますが、Git 2.43.0 と 2.56.0 のどちらでも、コンフリクトを解消して --continue した後のコミットにも同じ行が付きました。 コンフリクト後は git log -n 1 --format=%B で確かめると確実です。マニュアルは、自分だけのブランチから写すときは -x を付けないよう案内しています(受け手にとって意味のない ID になるため)。
-n(--no-commit):変更だけ入れて、コミットは自分でする
$ git switch -c try-n release/1.0
Switched to a new branch 'try-n'
$ git cherry-pick -n 991281e 2bf627c
$ git status --short
A log.py
A tax.py
$ git commit -m "feat: add tax and log helper (backport)"
$ git log --oneline -n 3
e4eaa19 feat: add tax and log helper (backport)
94cd2e1 fix: round total
ef90bce initial
$ git log -n 1 --format='author=%an committer=%cn'
author=Hanako Sato committer=Hanako Sato
-n の実行後は何も表示されず、変更はステージ(インデックス)に入った状態で止まります。自分で git commit するため、作者も自分になり、元の作者の情報は残りません。 残したいなら -x を併用するか、メッセージに元の ID を書きます。
-e(--edit):メッセージを編集してから取り込む
通常はエディタが開きます。次の例では、エディタの代わりに sed で1行目の末尾に文字を足しています。
$ GIT_EDITOR="sed -i '1s/$/ [release-1.0]/'" git cherry-pick -e 8939a5f
[try-e eac6dfd] chore: add util [release-1.0]
Author: Taro Yamada <taro@example.com>
Date: Thu Oct 1 10:03:00 2026 +0900
1 file changed, 1 insertion(+)
create mode 100644 util.py
--ff:親が同じなら fast-forward する
HEAD が取り込むコミットの親と同じ位置にあるとき、--ff を付けると新しいコミットを作らず、元のコミット ID のままブランチが進みます。
$ git switch -c try-ff 991281e
Switched to a new branch 'try-ff'
$ git cherry-pick --ff 2bf627c
$ git log --oneline -n 2
2bf627c feat: add log helper
991281e feat: add tax
--ff なしで同じ操作をすると、同じ内容で別 ID(5c6b289)のコミットができました。
--mainline(-m 1):マージコミットを取り込む
マージコミットをそのまま指定すると止まります。親が2つあり、どちらから見た差分を取り込むかを Git が決められないためです。
$ git log --oneline --graph -n 5 main
* 23d973c Merge branch 'feature/export'
|\
| * 5a14e4c feat: export xlsx
| * 0678be7 feat: export csv
|/
* 0a97fba feat: add search
* 0bdb237 fix: add timeout setting
$ git switch release/1.0
Switched to branch 'release/1.0'
$ git cherry-pick 23d973c
error: commit 23d973c563a2e5c3f703625158f99d6c98120c37 is a merge but no -m option was given.
fatal: cherry-pick failed
-m 1 は「1番目の親(マージを受け入れた側=main の流れ)から見た差分」です。feature/export で加えた変更一式が、親が1つの通常コミットとして入ります。
$ git log -n 1 --format='%h parents: %p' main
23d973c parents: 0a97fba 5a14e4c
$ git cherry-pick -m 1 23d973c
[release/1.0 45f390f] Merge branch 'feature/export'
Author: Taro Yamada <taro@example.com>
Date: Sat Oct 3 11:02:00 2026 +0900
1 file changed, 2 insertions(+)
create mode 100644 export.py
$ cat export.py
# export csv
# export xlsx
-m 2 にすると「2番目の親(feature/export 側)から見た差分」、つまり main 側にあって feature に無かった変更を取り込むことになります。この例では、feature/export を切った後に main 側の変更が無かったため、差分が空と判定されて止まりました。
元の個々のコミットを残したいなら、マージコミットではなく中身を範囲で指定します。23d973c^1..23d973c^2 は「1番目の親に無く、2番目の親にあるコミット」です。
$ git log --oneline 23d973c^1..23d973c^2
5a14e4c feat: export xlsx
0678be7 feat: export csv
$ git cherry-pick 23d973c^1..23d973c^2
[try-indiv 4a58560] feat: export csv
(中略)
[try-indiv 24ea46b] feat: export xlsx
(中略)
Git 2.43.0 では、マージコミットでない通常のコミットに -m 1 を付けても、そのまま取り込まれました。
--allow-empty と --empty:空になるコミットの扱い
「空」には2種類あります。
| 種類 | 例 | 取り込むオプション |
|---|---|---|
| もともと空のコミット | git commit --allow-empty で作った CI 起動用コミット |
--allow-empty |
| 取り込み先に同じ変更があって空になる | 取り込み済みの修正をもう一度指定した | --empty=keep(2.45 以降)/--keep-redundant-commits |
どちらも既定では同じメッセージで止まります。
$ git cherry-pick 2111ac8
The previous cherry-pick is now empty, possibly due to conflict resolution.
If you wish to commit it anyway, use:
git commit --allow-empty
Otherwise, please use 'git cherry-pick --skip'
On branch release/1.0
You are currently cherry-picking commit 2111ac8.
(all conflicts fixed: run "git cherry-pick --continue")
(use "git cherry-pick --skip" to skip this patch)
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
nothing to commit, working tree clean
$ git cherry-pick --skip
$ git cherry-pick --allow-empty 2111ac8
[release/1.0 d87561d] chore: trigger CI
Date: Fri Oct 16 17:42:00 2026 +0900
もともと空のコミット 2111ac8 は --allow-empty で入りました。一方、取り込み済みの 386cf63(fix: round total)に --allow-empty を付けても同じメッセージで止まり、--keep-redundant-commits を付けると空のコミットとして入りました。
$ git cherry-pick --keep-redundant-commits 386cf63
[release/1.0 94cee52] fix: round total
Author: Taro Yamada <taro@example.com>
Date: Thu Oct 1 10:04:00 2026 +0900
$ git show --stat --oneline HEAD
94cee52 fix: round total
Git 2.45 で加わった --empty を Git 2.56.0 で実行した結果です。drop は何も作らずに次へ進み、keep は空コミットを残し、stop(既定)は上と同じメッセージで止まります。
$ git --version
git version 2.56.0
$ git cherry-pick --empty=drop 386cf63
dropping 386cf6379edeaee5f144559f3df85f0e4a85273b fix: round total -- patch contents already upstream
$ git cherry-pick --empty=keep 386cf63
[try-empty256 94cee52] fix: round total
Author: Taro Yamada <taro@example.com>
Date: Thu Oct 1 10:04:00 2026 +0900
| 状況 | 取る操作 |
|---|---|
| 取り込み済みなので要らない | git cherry-pick --skip(2.45 以降は最初から --empty=drop) |
| 「取り込んだ記録」として空コミットを残したい | --empty=keep(2.45 より前は --keep-redundant-commits) |
| もともと空のコミットを写したい | --allow-empty |
-X(--strategy-option):コンフリクトを片側で自動解決する
-X theirs は「取り込むコミット側」、-X ours は「今のブランチ側」を優先して衝突箇所を解決します。release/1.0(version=1.0)に、main 側で version=2.0 の下に timeout=30 を足したコミットを写す例です。
$ cat app.conf
version=1.0
$ git cherry-pick -X theirs 0bdb237
Auto-merging app.conf
[try-xtheirs 486230b] fix: add timeout setting
Author: Taro Yamada <taro@example.com>
Date: Fri Oct 2 09:02:00 2026 +0900
1 file changed, 2 insertions(+), 1 deletion(-)
$ cat app.conf
version=2.0
timeout=30
-X theirs は衝突した箇所を取り込むコミット側の内容で置き換えるため、リリースブランチの version=1.0 まで 2.0 に変わりました。 逆に -X ours では今のブランチ側が残り、結果として何も変わらないので「空」と判定されて止まりました。
$ git cherry-pick -X ours 0bdb237
Auto-merging app.conf
The previous cherry-pick is now empty, possibly due to conflict resolution.
(以下略)
$ cat app.conf
version=1.0
「version=1.0 のまま timeout=30 だけ足す」という結果は、どちらのオプションでも得られません。衝突の中身を見て手で直すのが基本で、-X は「衝突したら必ずこちら」と決められるときだけ使います。公式マニュアルの例にある -Xpatience は、文脈行の取り違えによる誤マージを減らす差分アルゴリズムの指定です(ort 戦略の既定は histogram)。
コンフリクトの解消手順(--continue・--skip・--abort)
取り込み先で同じ箇所が別の内容に変わっていると、コンフリクト(変更の衝突)で止まります。止まった後の分かれ道は4つです。
flowchart TD
A["git cherry-pick コミットID"] --> B{"自動で適用できた?"}
B -- "はい" --> C["新しいコミットができる<br/>(次のコミットへ)"]
B -- "いいえ" --> D["CONFLICT で停止<br/>(CHERRY_PICK_HEAD が残る)"]
D --> E["ファイルを直して git add"]
E --> F["git cherry-pick --continue"]
F --> C
D --> G["git cherry-pick --skip<br/>このコミットだけ飛ばす"]
G --> C
D --> H["git cherry-pick --abort<br/>開始前の状態に戻す"]
D --> I["git cherry-pick --quit<br/>記録だけ消し、作業ツリーは残す"]
| サブコマンド | 動き | 使う場面 |
|---|---|---|
--continue |
解消した内容でコミットし、残りがあれば続行 | コンフリクトを直して git add した後 |
--skip |
今のコミットだけ飛ばし、残りを続行 | そのコミットは要らないと判断したとき |
--abort |
すべて取り消し、開始前に戻す | いったん仕切り直したいとき |
--quit |
進行中の記録だけ消し、ここまでの結果と作業ツリーは残す | 途中までで確定させたいとき |
例:version を上げずに timeout の修正だけ写す
main で app.conf を version=2.0 に上げたあと timeout=30 を足した修正を、version=1.0 のままの release/1.0 に写します。
$ git switch release/1.0
Switched to branch 'release/1.0'
$ git cherry-pick 0bdb237
Auto-merging app.conf
CONFLICT (content): Merge conflict in app.conf
error: could not apply 0bdb237... fix: add timeout setting
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
$ git status
On branch release/1.0
You are currently cherry-picking commit 0bdb237.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --skip" to skip this patch)
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: app.conf
no changes added to commit (use "git add" and/or "git commit -a")
$ cat app.conf
<<<<<<< HEAD
version=1.0
=======
version=2.0
timeout=30
>>>>>>> 0bdb237 (fix: add timeout setting)
HEAD 側(上)が今のブランチの内容、下が取り込もうとしたコミットの内容です。マーカーの読み方は関連記事「Gitのコンフリクトの解消方法|マーカーの読み方から防ぎ方まで」で扱っています。ここでは「version=1.0 のまま、timeout=30 だけ足す」内容に直します。
version=1.0
timeout=30
直したら git add して --continue です。ターミナルではコミットメッセージの確認でエディタが開くので、そのまま保存して閉じます。
$ git add app.conf
$ git status --short
M app.conf
$ git cherry-pick --continue
[release/1.0 a76731d] fix: add timeout setting
Author: Taro Yamada <taro@example.com>
Date: Fri Oct 2 09:02:00 2026 +0900
1 file changed, 1 insertion(+)
$ git log --oneline -n 3
a76731d fix: add timeout setting
94cd2e1 fix: round total
ef90bce initial
$ cat app.conf
version=1.0
timeout=30
複数指定の途中で止まったときは --skip で飛ばせる
3つの範囲指定のうち、2つ目だけがコンフリクトする例です。--skip すると2つ目を飛ばして3つ目が適用されました。
$ git cherry-pick 7f9d75e^..0a97fba
[try-skip 8e27964] docs: add README
Author: Taro Yamada <taro@example.com>
Date: Fri Oct 2 09:01:00 2026 +0900
1 file changed, 1 insertion(+)
create mode 100644 README.md
Auto-merging app.conf
CONFLICT (content): Merge conflict in app.conf
error: could not apply 0bdb237... fix: add timeout setting
(hint は省略)
$ git status --short
UU app.conf
$ git cherry-pick --skip
[try-skip 5b6c487] feat: add search
Author: Taro Yamada <taro@example.com>
Date: Fri Oct 2 09:03:00 2026 +0900
1 file changed, 1 insertion(+)
create mode 100644 search.py
$ git log --oneline -n 4
5b6c487 feat: add search
8e27964 docs: add README
94cd2e1 fix: round total
ef90bce initial
迷ったら --abort で開始前に戻す
$ git cherry-pick 0bdb237
Auto-merging app.conf
CONFLICT (content): Merge conflict in app.conf
(中略)
$ git status --short
UU app.conf
$ git cherry-pick --abort
$ git status --short --branch
## try-abort
$ git log --oneline -n 1
94cd2e1 fix: round total
複数指定の途中で --abort すると、それまでに作られたコミットも含めて開始前に戻ります。「1つ目は残して2つ目でやめる」なら --quit です。
$ git cherry-pick 7f9d75e^..0a97fba
[try-quit 8e27964] docs: add README
(中略)
CONFLICT (content): Merge conflict in app.conf
(中略)
$ git cherry-pick --quit
$ git status --short --branch
## try-quit
UU app.conf
$ git log --oneline -n 3
8e27964 docs: add README
94cd2e1 fix: round total
ef90bce initial
--quit は進行中の記録を消すだけで、コンフリクトしたファイル(UU app.conf)は作業ツリーに残ります。要らなければ git reset --hard で捨てます。
cherry-pick の取り消し(直後/commit 後/push 後)
cherry-pick は merge や reset と違って ORIG_HEAD を残しません(実行後に git rev-parse ORIG_HEAD を試すと fatal: Needed a single revision でした)。戻す位置は HEAD~n か reflog で指定します。
| 状況 | 取り消し方 | 補足 |
|---|---|---|
| コンフリクトで止まっている | git cherry-pick --abort |
開始前に戻る |
| 取り込みが終わった直後(push 前) | git reset --hard HEAD~1 |
3件なら HEAD~3 |
-n で変更だけ入れた状態 |
git reset --hard |
他の作業中の変更があるなら git stash push --staged |
| push した後 | git revert <作られたID> |
打ち消しコミットを足して push |
| 取り消しを間違えた | git reflog → git reset --hard "HEAD@{n}" |
reflog に cherry-pick: の行が残る |
直後(push 前):reset --hard HEAD~n
$ git cherry-pick 991281e 2bf627c 8939a5f
[undo-demo c41caa2] feat: add tax
(中略)
[undo-demo 9b809c9] feat: add log helper
(中略)
[undo-demo e72a761] chore: add util
(中略)
$ git reflog -n 5
e72a761 HEAD@{0}: cherry-pick: chore: add util
9b809c9 HEAD@{1}: cherry-pick: feat: add log helper
c41caa2 HEAD@{2}: cherry-pick: feat: add tax
94cd2e1 HEAD@{3}: reset: moving to HEAD~1
272a025 HEAD@{4}: cherry-pick: chore: add util
$ git reset --hard HEAD~3
HEAD is now at 94cd2e1 fix: round total
$ git log --oneline -n 2
94cd2e1 fix: round total
ef90bce initial
reflog には1件ごとに cherry-pick: の行が残るので、何件戻すかはここで数えられます。戻しすぎたときは reflog から元に戻せます。
$ git reflog -n 3
94cd2e1 HEAD@{0}: reset: moving to HEAD~3
e72a761 HEAD@{1}: cherry-pick: chore: add util
9b809c9 HEAD@{2}: cherry-pick: feat: add log helper
$ git reset --hard "HEAD@{1}"
HEAD is now at e72a761 chore: add util
reset --hard は、コミットしていない作業中の変更も消します。復元の詳しい手順は関連記事「git reset --hardを取り消す方法|reflogで復元する手順」で扱っています。
-n で変更だけ入れた状態:reset --hard
$ git cherry-pick -n 8939a5f
$ git status --short
A util.py
$ git reset --hard
HEAD is now at 94cd2e1 fix: round total
$ git status --short
-n のときは CHERRY_PICK_HEAD が記録されないため、--abort は error: no cherry-pick or revert in progress になります。cherry-pick の前からあった作業中の変更(ステージしていないもの)を残したいときは、reset --hard ではなく git stash push --staged(Git 2.35 以降)で、ステージに入った取り込み分だけを退避して捨てます。
$ git status --short
M calc.py
A util.py
$ git stash push --staged -m "undo cherry-pick -n"
Saved working directory and index state On try-n-undo: undo cherry-pick -n
$ git status --short
M calc.py
$ git stash drop
Dropped refs/stash@{0} (bf1e7734e3ed1a99a79fdefc65cfafbdf53284be)
push 後:revert で打ち消す
push 済みのコミットは履歴を消さず、逆の変更を新しいコミットとして足します。
$ git cherry-pick 8939a5f
[undo-demo 272a025] chore: add util
(中略)
$ git push origin undo-demo
To <remote>
94cd2e1..272a025 undo-demo -> undo-demo
$ git revert --no-edit HEAD
[undo-demo 64659a4] Revert "chore: add util"
Date: Fri Oct 16 17:43:14 2026 +0900
1 file changed, 1 deletion(-)
delete mode 100644 util.py
$ git push origin undo-demo
To <remote>
272a025..64659a4 undo-demo -> undo-demo
push 後に reset で消して push すると拒否されます。ここで --force すると、その間に他の人が push したコミットまで消えることがあります。
$ git reset --hard HEAD~2
HEAD is now at 94cd2e1 fix: round total
$ git push origin undo-demo
To <remote>
! [rejected] undo-demo -> undo-demo (non-fast-forward)
error: failed to push some refs to '<remote>'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
強制 push で起きる事故と --force-if-includes は、関連記事「git commit(コミット)の取り消し方|push前後の早見表・NG操作・復元」で扱っています。
同じ変更が2回入る問題(rebase・merge 後の重複と検出)
cherry-pick で写したコミットは別 ID なので、あとで元のブランチを merge すると、同じ内容のコミットが履歴に2つ並びます。 rebase の場合は Git が重複を検出して落としますが、写した後に内容を変えていると落ちません。順に見ていきます。
feature/login の3コミットのうち、fix: add login timeout だけを main に cherry-pick した状態から始めます。
$ git log --oneline --graph --all
* 6bea9b3 fix: add login timeout
* 6926a33 docs: add docs
| * f4f4865 feat: login api
| * 66be61b fix: add login timeout
| * cc4d017 feat: login form
|/
* 25219e8 initial
取り込み済みのコミットを調べる:--cherry と git cherry
git log --cherry A...B は、B 側のコミットのうち A に同じ変更(patch-id が同じ)があるものに =、無いものに + を付けます。
$ git log --oneline --cherry main...feature/login
+ f4f4865 feat: login api
= 66be61b fix: add login timeout
+ cc4d017 feat: login form
--cherry は --right-only --cherry-mark --no-merges の省略形です。= を省いて「まだ main に無いものだけ」を出すには --cherry-pick --right-only を使います。
$ git log --oneline --cherry-pick --right-only --no-merges main...feature/login
f4f4865 feat: login api
cc4d017 feat: login form
両側を一度に見るなら --left-right --cherry-mark です。< が main だけ、> が feature/login だけ、= が両方にある変更です。
$ git log --oneline --left-right --cherry-mark main...feature/login
= 6bea9b3 fix: add login timeout
< 6926a33 docs: add docs
> f4f4865 feat: login api
= 66be61b fix: add login timeout
> cc4d017 feat: login form
git cherry コマンド(cherry-pick とは別のコマンド)も同じ判定をします。- が取り込み済み、+ が未取り込みです。
$ git cherry -v main feature/login
+ cc4d017365fad0dbe03e4d85b5442699e4838020 feat: login form
- 66be61b6a9470563f408b9325a026861be0621f9 fix: add login timeout
+ f4f4865c1caf101e793e6345e563c987e907f6c1 feat: login api
rebase すると重複は自動で落ちる
feature/login を main に rebase すると、取り込み済みの 66be61b は skipped previously applied commit として落とされました。公式マニュアルでは、--reapply-cherry-picks を付けない限り、git log --cherry-mark と同じ判定で「きれいに写されたコミット」を事前に落とすと説明されています。
$ git switch feature/login
Switched to branch 'feature/login'
$ git rebase main
warning: skipped previously applied commit 66be61b
hint: use --reapply-cherry-picks to include skipped commits
hint: Disable this message with "git config advice.skippedCherryPicks false"
Successfully rebased and updated refs/heads/feature/login.
$ git log --oneline --graph --all
* bb46cf7 feat: login api
* 2f97bdd feat: login form
* 6bea9b3 fix: add login timeout
* 6926a33 docs: add docs
* 25219e8 initial
merge すると同じ内容のコミットが2つ並ぶ
rebase せずに merge した場合です。内容が同じなのでコンフリクトはしませんが、fix: add login timeout が2つ残ります。
$ git merge --no-ff --no-edit feature/login
Merge made by the 'ort' strategy.
login.py | 1 +
login_api.py | 1 +
2 files changed, 2 insertions(+)
create mode 100644 login.py
create mode 100644 login_api.py
$ git log --oneline --graph
* c6102e1 Merge branch 'feature/login'
|\
| * f4f4865 feat: login api
| * 66be61b fix: add login timeout
| * cc4d017 feat: login form
* | 6bea9b3 fix: add login timeout
* | 6926a33 docs: add docs
|/
* 25219e8 initial
gitGraph
commit id: "initial"
branch feature/login
commit id: "login-form"
commit id: "fix-timeout"
commit id: "login-api"
checkout main
commit id: "docs"
cherry-pick id: "fix-timeout"
merge feature/login id: "merge"
これは cherry-pick の仕組み上の自然な結果で、git log に同じメッセージが2つ見えること自体は問題ではありません。-x の記録があれば、どれがどれの写しかを後からたどれます。
写した後に内容を変えると、rebase で止まる
cherry-pick した変更を取り込み先で手直しすると patch-id が変わり、Git は「別の変更」とみなします。LOGIN_TIMEOUT = 30 を main 側で 60 に直してコミットした後、feature/login を rebase した結果です。
$ git log --oneline --cherry main...feature/login
+ a1e6c84 feat: login api
+ 4cadfc4 fix: login timeout 30
$ git switch feature/login
Switched to branch 'feature/login'
$ git rebase main
Auto-merging settings.py
CONFLICT (content): Merge conflict in settings.py
error: could not apply 4cadfc4... fix: login timeout 30
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 4cadfc4... fix: login timeout 30
--cherry の表示が + のままなので、rebase の前に止まることが予想できます。この場合は git rebase --skip で元のコミットを飛ばすか、git rebase -i で drop します。手順は関連記事「git rebase -iでコミットをまとめる|squash・fixup早見表と復旧」で扱っています。
| 対策 | 内容 |
|---|---|
| 写した変更を取り込み先で手直ししない | 直すなら別コミットにする |
-x で元 ID を残す |
後から対応関係をたどれる |
merge 前に git log --cherry で確かめる |
+ のものだけが新しく入る |
| 後で merge する予定のブランチから cherry-pick すると重複が残る | feature ブランチを先に merge できないか検討する |
GitHub の PR からコミットを拾う
マージ前の PR(Pull Request)にある修正を先に取り込みたいときは、PR の参照を取得してから cherry-pick します。GitHub は PR ごとに refs/pull/<番号>/head という参照を公開しており、GitHub Docs は git fetch origin pull/ID/head:BRANCH_NAME で手元のブランチに取得する手順を案内しています。ローカルの bare リポジトリに同じ形の参照を作って実行しました。
$ git ls-remote origin 'refs/pull/*'
7900ccc9a8b957a3e81fb2fca2996f69ff789420 refs/pull/7/head
$ git fetch origin pull/7/head:pr-7
From <remote>
* [new ref] refs/pull/7/head -> pr-7
$ git log --oneline main..pr-7
7900ccc fix: trim whitespace in csv parser
1220eb8 feat: csv export
$ git cherry-pick -x 7900ccc
[main 9306217] fix: trim whitespace in csv parser
Author: Taro Yamada <taro@example.com>
Date: Tue Oct 6 09:02:00 2026 +0900
1 file changed, 2 insertions(+)
create mode 100644 parser.py
$ git log -n 1 --format=%B
fix: trim whitespace in csv parser
(cherry picked from commit 7900ccc9a8b957a3e81fb2fca2996f69ff789420)
ブランチを作らずに取得するなら git fetch origin pull/7/head で、取得したコミットは FETCH_HEAD から参照できます。
$ git fetch origin pull/7/head
From <remote>
* branch refs/pull/7/head -> FETCH_HEAD
$ git log --oneline main..FETCH_HEAD
7900ccc fix: trim whitespace in csv parser
1220eb8 feat: csv export
| 方法 | コマンド | 向いている場面 |
|---|---|---|
| PR をブランチとして取得 | git fetch origin pull/7/head:pr-7 |
複数のコミットから選ぶ |
| PR を一時的に取得 | git fetch origin pull/7/head → FETCH_HEAD |
1回だけ拾う |
| GitHub CLI で PR を checkout | gh pr checkout 7 |
PR 全体を手元で確かめてから選ぶ |
| 他のリポジトリ(fork)のコミット | git remote add <名前> <URL> → git fetch <名前> |
fork 側の修正を取り込む |
コミット ID は、PR の「Commits」タブからコピーできます。gh の使い方は関連記事「GitHub CLI(gh)の使い方|逆引きコマンド一覧とjqレシピ」で扱っています。cherry-pick 元が別のリポジトリでも、git fetch でコミットを手元に取得すれば同じ手順です。
VS Code・IntelliJ・GitHub Desktop での操作
各ツールの公式ドキュメントに載っている操作です。
| ツール | 操作 | 対応する Git の操作 |
|---|---|---|
| VS Code | Source Control Graph でコミットを右クリック →「Cherry Pick」 | git cherry-pick <ID> |
| VS Code | コマンドパレット「Git: Cherry Pick...」で ID を入力 | git cherry-pick <ID> |
| VS Code | コマンドパレット「Git: Abort Cherry Pick」 | git cherry-pick --abort |
| IntelliJ IDEA | Git ツールウィンドウの Log でコミットを選び「Cherry-pick」ボタン | git cherry-pick <ID> |
| IntelliJ IDEA | Commit Details でファイルを選び「Cherry-Pick Selected Changes」 | 一部のファイルだけを取り込む |
| IntelliJ IDEA | VCS ウィジェットの「Abort Cherry-Pick」「Continue Cherry-Pick」 | --abort / --continue |
| GitHub Desktop | History でコミットを右クリック →「Cherry pick commit」→ 取り込み先のブランチを選ぶ | git cherry-pick <ID> |
| GitHub Desktop | History のコミットを「Current Branch」の一覧へドラッグ&ドロップ | 同上 |
- VS Code:公式ドキュメントでは、Source Control Graph のコミットを右クリックして「Cherry Pick」を選ぶと、そのコミットの変更が今のブランチに適用されると説明されています。Git 拡張のコマンド名は「Cherry Pick...」(ID を入力)と「Abort Cherry Pick」です。
- IntelliJ IDEA:公式ヘルプでは、先に取り込み先のブランチを checkout し、Log タブでコミットを選んで「Cherry-pick」ボタンを押す手順です。コンフリクトが起きると、変更は Commit ツールウィンドウに残り、後からコミットできます。設定「Add the 'cherry-picked from ' suffix when picking commits pushed to protected branches」を有効にすると、保護ブランチからの cherry-pick に
-xと同じ記録が付きます。 - GitHub Desktop:公式ドキュメントでは、History タブでコミットを選び(Ctrl または Shift で複数選択)、右クリックの「Cherry pick commit」か、ブランチ一覧へのドラッグ&ドロップで取り込み先を選びます。実行後は取り込み先のブランチに切り替わります。
よくあるエラーと直し方
| エラー文(原文) | 原因 | 直し方 |
|---|---|---|
fatal: bad revision 'abc1234' |
ID やブランチ名が存在しない(打ち間違い、まだ fetch していない別リポジトリのコミット、メッセージを指定した) | git log で ID を確かめる。別リポジトリなら先に git fetch |
error: your local changes would be overwritten by cherry-pick. |
ステージ済みの変更がある | git commit するか git stash で退避 |
error: Your local changes to the following files would be overwritten by merge: |
取り込むコミットが変えるファイルに、未コミットの変更がある | git stash → cherry-pick → git stash pop |
error: The following untracked working tree files would be overwritten by merge: |
取り込むコミットが作るファイルと同名の未追跡ファイルがある | ファイルを移動または削除 |
The previous cherry-pick is now empty, possibly due to conflict resolution. |
取り込み先に同じ変更が入っている、または元が空コミット | --skip。残すなら --empty=keep/--allow-empty |
error: commit … is a merge but no -m option was given. |
マージコミットを指定した | -m 1 を付ける |
error: Cherry-picking is not possible because you have unmerged files. |
前の cherry-pick がコンフリクトで止まったまま | 解消して --continue、または --abort |
error: Committing is not possible because you have unmerged files. |
git add せずに --continue した |
直したファイルを git add してから --continue |
fatal: cannot switch branch while cherry-picking |
進行中のままブランチを切り替えた | --continue・--abort・--quit のどれかで終える |
error: no cherry-pick or revert in progress |
進行中でないのに --continue/--abort した |
すでに終わっているので操作は不要 |
error: empty commit set passed |
範囲の向きが逆(B..A)で対象が0件 |
git log --oneline A^..B で範囲を確かめる |
git: 'cherrypick' is not a git command. |
ハイフンの打ち忘れ | git cherry-pick(ハイフンあり) |
実行例です。ステージ済みの変更があるときと、取り込むコミットと同じファイルに未コミットの変更があるときで、メッセージが変わります。
$ git status --short
M calc.py
$ git cherry-pick 8939a5f
error: your local changes would be overwritten by cherry-pick.
hint: commit your changes or stash them to proceed.
fatal: cherry-pick failed
$ git status --short
M app.conf
$ git cherry-pick 0bdb237
error: Your local changes to the following files would be overwritten by merge:
app.conf
Please commit your changes or stash them before you merge.
Aborting
fatal: cherry-pick failed
取り込むコミットが変えないファイルの未コミットの変更(ステージしていないもの)があっても、cherry-pick はそのまま通りました。退避の手順は関連記事「git stashの使い方|全コマンド実行結果つきで退避と復元を解説」で扱っています。
$ git cherry-pick 0bdb237
(コンフリクトで停止)
$ git cherry-pick 8939a5f
error: Cherry-picking is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: cherry-pick failed
$ git switch main
fatal: cannot switch branch while cherry-picking
Consider "git cherry-pick --quit" or "git worktree add".
$ git cherry-pick --continue
error: Committing is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.
U app.conf
$ git cherrypick 386cf63
git: 'cherrypick' is not a git command. See 'git --help'.
The most similar command is
cherry-pick
よくある質問
Q. git cherry pick(git cherry-pick)とは何ですか? A. 別のブランチにある特定のコミットの変更だけを、今のブランチに新しいコミットとして写すコマンドです。元のコミットは残り、写したコミットは別の ID になります。仕組みは「git cherry-pick とは」の節で図にしています。
Q. cherry pick の読み方と意味は?
A. 「チェリーピック」と読みます。さくらんぼを1粒ずつ選んで摘むように、コミットを1つずつ選んで取り込むことからの名前です。コマンドはハイフンあり(git cherry-pick)で、git cherrypick と打つと 'cherrypick' is not a git command になります。
Q. git cherry-pick --continue はいつ使いますか?
A. コンフリクトで止まった後、ファイルを直して git add してから実行します。解消した内容でコミットが作られ、範囲指定で残りがあれば続きが適用されます。git add を忘れると Committing is not possible because you have unmerged files. になります。
Q. 複数のコミットをまとめて cherry-pick するには?
A. git cherry-pick <A> <B> <C> と並べるか、git cherry-pick A^..C の範囲指定です。A..C と書くと A が入りません。1つのコミットにまとめたいなら -n を付けてから git commit します。
Q. cherry-pick を取り消すには?
A. コンフリクトで止まっているなら git cherry-pick --abort、終わった直後で push 前なら git reset --hard HEAD~1、push 後なら git revert <作られたID> です。
Q. cherry-pick すると元のブランチからコミットは消えますか?
A. 消えません。cherry-pick は変更を複製するだけです。移動させたいときは、取り込んだ後に元のブランチで git reset(push 前)か git revert(push 後)を行います。
Q. cherry-pick と rebase の違いは? A. cherry-pick は「選んだコミット」を今のブランチに写します。rebase は「ブランチのコミット全部」を別の起点に付け替えます。rebase は内部で cherry-pick と同じ適用を繰り返しており、取り込み済みの変更は自動で落とします。
Q. 別のリポジトリ(fork)のコミットも cherry-pick できますか?
A. できます。git remote add で相手を登録し、git fetch でコミットを手元に取得すれば、その ID を指定して cherry-pick できます。GitHub の PR なら git fetch origin pull/<番号>/head:<ブランチ名> です。
Q. マージコミットを cherry-pick するとエラーになります。
A. error: commit … is a merge but no -m option was given. は、親が2つあるためです。git cherry-pick -m 1 <ID> で「マージを受け入れた側」から見た変更一式が入ります。元の個々のコミットを残すなら <ID>^1..<ID>^2 の範囲指定です。
まとめ
- cherry-pick は選んだコミットの変更を新しいコミットとして複製する。 元は残り、ID は変わり、作者は引き継がれる
- 範囲指定は
A..Bだと A を含まず、A^..Bで A を含む。 先にgit log --oneline A^..Bで確かめる -xで元 ID を記録、-nでまとめてコミット、-eでメッセージ編集、マージコミットは-m 1- 空になったら
--skip。残すなら--empty=keep(2.45 以降)/--keep-redundant-commits、もともと空なら--allow-empty - コンフリクトは 直して
git add→--continue。飛ばすなら--skip、戻すなら--abort - 取り消しは push 前
git reset --hard HEAD~n、push 後git revert。cherry-pick はORIG_HEADを残さない - あとで merge すると 同じ変更が2つ並ぶ。rebase は自動で落とすが、写した後に手直しした変更は落ちない。
git log --cherry A...Bで事前に確かめる - GitHub の PR は
git fetch origin pull/<番号>/head:<ブランチ>で取得してから cherry-pick
参考・出典
確認日はいずれも 2026年10月16日です。
- Git 公式マニュアル git-cherry-pick:https://git-scm.com/docs/git-cherry-pick
- Git 公式マニュアル git-log(--cherry-pick・--cherry-mark・--cherry・--left-right):https://git-scm.com/docs/git-log
- Git 公式マニュアル git-cherry:https://git-scm.com/docs/git-cherry
- Git 公式マニュアル git-patch-id:https://git-scm.com/docs/git-patch-id
- Git 公式マニュアル git-rebase(--reapply-cherry-picks):https://git-scm.com/docs/git-rebase
- Git 公式マニュアル git-merge(MERGE STRATEGIES、-X ours/theirs/diff-algorithm):https://git-scm.com/docs/git-merge
- Git 公式マニュアル git-revert:https://git-scm.com/docs/git-revert
- Git 公式マニュアル git-stash(--staged):https://git-scm.com/docs/git-stash
- Git 公式マニュアル git-config(advice.skippedCherryPicks・advice.mergeConflict):https://git-scm.com/docs/git-config
- Git 2.45.0 リリースノート(cherry-pick --empty):https://www.kernel.org/pub/software/scm/git/docs/RelNotes/2.45.0.adoc
- Git 2.35.0 リリースノート(stash --staged):https://www.kernel.org/pub/software/scm/git/docs/RelNotes/2.35.0.adoc
- GitHub Docs「Checking out pull requests locally」:https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally
- GitHub Docs「Cherry-picking a commit in GitHub Desktop」:https://docs.github.com/en/desktop/managing-commits/cherry-picking-a-commit-in-github-desktop
- VS Code Docs「View source control history」:https://code.visualstudio.com/docs/sourcecontrol/history
- VS Code Git 拡張のコマンド名(extensions/git/package.nls.json):https://github.com/microsoft/vscode/blob/main/extensions/git/package.nls.json
- IntelliJ IDEA Help「Apply changes from one branch to another」:https://www.jetbrains.com/help/idea/apply-changes-from-one-branch-to-another.html
- IntelliJ IDEA Help「Version Control | Git」(設定):https://www.jetbrains.com/help/idea/settings-version-control-git.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「git cherry-pickの使い方|範囲指定・取り消し・コンフリクト・重複の対処」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。