こんにちは、さるまりんです。
ブランチが長く育ってくると、「この修正だけ main に持っていきたい」という場面が必ず訪れます。 ですが、普通に git cherry-pick すると、関係ないファイルまで一緒に取り込まれてコンフリクト祭りに……。 今回は、特定ファイルだけを安全に適用する“パス限定 cherry-pick” という方法です。 実際に自分の環境でやってみて、「スクリプト実行 → コンフリクト → 手動解決 → 最終確認」までたどり着いた記録をメモとして残します。
🔧 通常の cherry-pick ではうまくいかない
git cherry-pick は便利ですが、ファイル単位で指定できません。 複雑なブランチでは:
- 意図しない修正まで混ざる
 - コンフリクトが増える
 - 差分を追うのが難しい
 
ということが起こります。 これを避けるために、git diff と git apply を組み合わせて「必要なファイルだけ」移植しました。
🚀 パス限定 cherry-pick の考え方
コミットごとの差分を抽出し、その中の「特定ファイル」だけを安全に git apply --3way で当てていきます。
git diff --binary <commit>^! -- path/to/file.js | git apply --3way --index
ポイントはgitコマンドのオプションです。それぞれ
--binary:画像や非テキストファイルも安全に扱える--3way:コンフリクト検出あり--index:ステージに直接反映
です。
手順①:対象コミットの取得
対象コミットを並べるため、まず変数にまとめます。
COMMITS="a1b2c3d e4f5g6h i7j8k9l"
ORDERED=$(echo "$COMMITS" | xargs git rev-list --reverse --topo-order)
ところが…ここで macOS の Terminal に直接貼り付けたらエラー! 改行やクォートの扱いがうまくいかず、スクリプトが途中で止まってしまいました。
手順②:/tmp にスクリプトを保存して実行
ターミナル直貼りではうまくいかないので、次のように `/tmp/port_patches.sh` を作って実行する形にしました。
#!/bin/bash
set -e
ORDERED=(a1b2c3d e4f5g6h i7j8k9l)
for c in "${ORDERED[@]}"; do
  echo "=== apply $c ==="
  git diff --binary "$c^!" -- path/to/file1.js path/to/file2.js \
    | git apply --3way --index || {
      echo "⚠️ コンフリクト発生: $c"
      exit 1
    }
done
# 実行
bash /tmp/port_patches.sh
set -e にしておくと、途中でエラーが出た時点で安全に停止できます。
手順③:マージコミットに遭遇
途中でマージコミットに当たり、`git diff` がエラーを出しました。
error: No valid patches in input (allow with "--allow-empty")
この場合、マージの親が2つあるので、どちらの差分を取るかを手動で判断します。
git diff <commit>^1 <commit> -- path/to/file.js
git diff <commit>^2 <commit> -- path/to/file.js
今回は 親2側(^2) の変更を採用。 以降は自動スクリプトを使わず、同じ形式で 手動実行 することに切り替えました。
手順④:コンフリクトの解消
<<<<<<< ours
 methodA(); 
=======
 this.methodA(); 
>>>>>>> theirs
残したい方(今回は theirs)を選んで編集後、git add。
手順⑤:コミット前の最終確認
git --no-pager diff --stat --cached
--no-pager を付けると出力が less に流れず、即時確認できて便利です。 差分内容まで見たい場合は:
git diff --cached
これで変更範囲をすべて確認してから、まとめてコミットします。
git commit -m "Port selected fixes using path-limited cherry-pick"
🧩 結果と学び
最終的に目的のファイルだけを安全に main に反映できました。 途中のスクリプト化やマージ対応で得たポイントは以下の通りです。
| 課題 | 解決策 | 
| xargs展開エラー | 配列として ORDERED を定義 | 
| macターミナルで途中停止 | /tmp にスクリプト保存して実行 | 
| マージコミットでエラー | 親2(^2)側の差分を手動適用 | 
| コミット前の確認 | git --no-pager diff --stat --cached | 
⚙️ まとめ
この“パス限定 cherry-pick”手法は、「特定のファイルだけを取り込みたい」という状況で使えます。 コンフリクトの発生箇所も明確にしつつ、差分の追跡もしやすいです。自動でも、手動かは臨
今回のようにスクリプトを /tmp/ に置いて何度も再実行できる形にしておくと、安心して試行錯誤ができます。 ブランチが複雑に絡み合っても、1ファイルずつ丁寧に適用していくアプローチで、安全かつ確実に作業できます。バージョン管理ってミスすると怖いイメージがずっとありますが、何をやっているかわかってると自信を持ってcommitやpushができると思います。 大きなマージや古いブランチの整理に悩んだときは、この“パス限定 cherry-pick”をよかったら試してみてください。
読んでくださってありがとうございました。 それではまた!