ブログに戻る

git cherry-pick実践:複数コミット、ブランチ、コンフリクト

2026年9月12日

TL;DR: git cherry-pick <sha> は任意のブランチから1コミットを現在のブランチへコピーします——同じパッチ、新しいSHA、履歴は動かさない。 複数ならSHAを列挙するか範囲指定(git cherry-pick A..B)。ただし範囲は A を含まないので、含めたいなら A^..B と書きます。コンフリクトで止まったら、解消して git add、そして git cherry-pick --continue。cherry-pickは特定の修正を運ぶための道具です——相手ブランチの全部が要るなら、mergeかrebaseを使いましょう。

git cherry-pickは実際何をする?

cherry-pickは既存のコミットを取り、そのdiffを現在のブランチへ新しいコミットとして適用します。元のコミットは元の場所に留まり、コピーは新しいSHAを得ます。gitは何も「移動」しません——後になって「あのコミットがまだ古いブランチに見えるのはなぜ」と首をかしげる人は、まさにこれを見ています。

この「コピーであり移動ではない」モデルが、cherry-pickが正しい道具である場面を決めます:

  • フィーチャーブランチから1つの修正だけを今すぐ main に欲しい。残りはマージしない。
  • 間違ったブランチにコミットされたホットフィクスを、正しい側へ着地させたい。
  • main からは決してマージしないリリースブランチへ、パッチを再生したい。

補完的なスキルは、間違いだったコミットを取り消す方法です。その機構は git undo last commit: keep the changes で扱っています。

別ブランチからコミットをcherry-pickするには?

SHAを見つけ、対象ブランチに切り替え、ピックします:

# 1. ソースブランチ上でコミットを特定する
git log feature/payment-fix --oneline -5

# 2. 受け取る側のブランチへ切り替える
git switch main

# 3. 持ってくる
git cherry-pick 1a2b3c4

知っておくと便利な2つ:

  • git cherry-pick <branch> はそのブランチの先端コミットをピックします——便利ですが、「先端」が何かという頭の中の地図が古いままの手滑も起きやすい。
  • ピック後、git log -1 --stat で着地内容を確認。読むのは1秒、リバート1回を節約します。

コミット群は feature/payment-fix に留まります。ブランチは好きなときに消して構いません——main 上のピックされたコピーは独自のSHAを持ち、古い方には依存しません。

複数コミットをcherry-pickするには?

3つの形があります。使う頻度順に:

# 1. 明示リスト —— 列挙した順にピックされる
git cherry-pick 1a2b3c4 5d6e7f8

# 2. 範囲 —— A の後ろから B まで(B含む)
git cherry-pick A..B

# 3. A を含む範囲
git cherry-pick A^..B

A..BA^..B の違いは定番の驚きです: A..BA含みませんgit log で範囲を眺めて oldest..newest とピックすると、最古のコミットを黙ってスキップします。「最古の数コミットを順番に」が目的なら oldest^..newest と書けば、off-by-oneは消えます。

3回のピックを1コミットに折りたたむなら、-n / --no-commit でコミットせずにステージし、最後に1回コミットします:

git cherry-pick -n 1a2b3c4 5d6e7f8
git commit -m "Backport: payment retry fixes"

git cherry-pickが動かないのはなぜ?

頻度順に、実際の原因は4つです:

1. コンフリクトでピックが停止した。 gitはパッチを適用し、両ブランチで変わった行に当たると、シーケンスの途中で止まります:

# ファイルを解消してから:
git add <resolved-files>
git cherry-pick --continue   # または --abort でピック前の状態へ戻る

--continue は省略できませんし、暗黙にも走りません。実行するまで、あなたは一時停止中のcherry-pickシーケンスの中にいて、git status はそのことを言い続けます。

2. ピックが空(“The previous cherry-pick is now empty”)。 変更が既にこのブランチに存在します。前回のピックか、squashされたマージが原因のことが多い。git cherry-pick --skip で飛ばすか、マーカーが本当に要るなら --allow-empty で空コミットを強制します。

3. コミットがマージコミットだ。 マージには親が2つあるため「このdiffを適用しろ」は曖昧です——gitは推測ではなく拒否を選びます。どの親を基準にdiffするか告げます:

git cherry-pick -m 1 <merge-sha>   # 親1 = マージ*された*側のブランチ

4. 間違ったワーキングツリーかdetached HEAD。 ピックはHEADの指す先へ着地します。ピック前に git branch --show-current。何も出力しなければdetached HEADで、切り替えた瞬間にコミットは孤児になります。

cherry-pick vs merge vs rebase:いつどれを使う?

コマンド対象に着地するもの履歴使う場面
git cherry-pick <sha>指名したコミットのみコピー、新しいSHA特定の1修正を今すぐ運びたい
git merge <branch>ブランチ上の全部マージコミットかfast-forwardブランチ全体が要り、分岐は見せたい
git rebase <base>ブランチの全コミットを再生リニア、SHA書き換えブランチをきれいなリニア列として欲しい
git revert <sha>コミットの逆取り消しコミットを追加共有履歴上の着地済みコミットを取り消したい

一行でまとめると: cherry-pickは選択を動かし、mergeとrebaseは全部を動かす。 ブランチと「同期」するためにcherry-pickに手を伸ばすのは、実はマージが欲しいサインです——それがフォークの main 対 upstream なら、全手順は sync a fork with upstream, step by step にあります。

避けるべき習慣が1つ: 同じコミットを長期にわたって複数ブランチへピックし続けること。ソースブランチの今後の修正すべてに別のピックが要り、やがてブランチは漂流します。リリースブランチへのバックポートは普通のパターンです。恒久の並行宇宙は違います。

cherry-pickワークフロー、要点だけ

git log <source-branch> --oneline -5   # SHAを探す
git switch <target-branch>             # 正しい場所に着地
git cherry-pick A^..B                  # 範囲、リスト、単一SHAのいずれでも
# コンフリクト時: 解消 → git add → git cherry-pick --continue
git log -1 --stat                      # 着地内容を確認

探す、切り替える、ピックする、確認する。このコマンドには釣り合わない「危険」の評判があります——diffは適用されるか、止まって理由を告げるかのどちらかです。本当に破壊的な失敗は間違ったブランチへのピックだけで、push前の git log -1 をすればそれすら見逃しようがありません。

— mrsaynothing

Get the next one by email

One email per post. No spam, no algorithms.

self-hosted · no third parties · one-click unsubscribe

what is this?

cron vs systemdタイマー:どちらを使うべきか?

記事を楽しんでいただけましたか?私の本業はこのような構築です。 採用のご相談