【Git】間違えて別ブランチで作業したときの復旧方法|cherry-pickとrebaseの活用

【Git】間違えて別ブランチで作業したときの復旧方法|cherry-pickとrebaseの活用 Git

ブランチを切り替え忘れて別ブランチにコミットしてしまった——実務で頻出するヒューマンエラーです。
本記事では、履歴を安全に移し替える考え方と、git cherry-pickおよびgit rebase --ontoを使った復旧手順を、
失敗しやすいポイントとともに解説します。箇条書きに頼らず、手順の流れを追えるよう段落で整理しました。

【Git】間違えて別ブランチで作業したときの復旧方法|cherry-pickとrebaseの活用

前提とゴール

本記事では、ブランチfeatureで作業すべきところを誤ってmainでコミットしてしまった状況を想定します。
目的は、誤って積んだコミットを正しいブランチへ移し、元のブランチからはそれらを取り除くことです。
作業前に現在の状態を把握し、取り返しが付く保険を必ず用意します。

復旧前の保険と現在地の確認

開始前に作業ツリーと履歴を確認して、影響範囲を把握します。
表示件数や装飾は任意ですが、ブランチや分岐が見やすいオプションを使うと安全です。

git status
git log --oneline --decorate --graph -n 30

誤コミットが載っているブランチ上でバックアップ用の退避ブランチを切り、
reflogで復元経路を確保します。誤操作で消えたように見えても、多くの場合reflogから戻せます。

git switch -c safety/backup-$(date +%Y%m%d-%H%M)
git reflog

アプローチ選定の考え方

コミットを順序を保ったまま別ブランチへ複製したいならcherry-pickが直感的です。
連続する複数コミットを丸ごと付け替えるならrebase --ontoが強力です。
既にリモートへpushしている場合は、履歴を書き換えない方針(取り消しコミットや内容の再適用)をまず検討し、
どうしても履歴修正が必要な場合のみチーム合意のうえで実行します。

ケースA:push前、少数のコミットを正しいブランチへ移す(cherry-pick)

正しい作業先のブランチを作成またはチェックアウトし、誤って積んだコミットを順に適用します。
元の順序で適用すると依存関係によるコンフリクトを減らせます。

# 正しいブランチへ移動(なければ作成)
git switch -c feature

# 例:3コミットを順番に移す
git cherry-pick <hash1> <hash2> <hash3>

# コンフリクト発生時は修正して続行
git add .
git cherry-pick --continue

移行後、誤ってコミットが載った側のブランチを安全な位置まで戻します。
push前であればハードリセットで巻き戻し可能です。

git switch main
git reset --hard <base-before-hash1>

ケースB:連続した誤コミットを一気に付け替える(rebase –onto)

誤ってmainへ積んだ連続コミットの先頭をA、末尾をB
本来のブランチをfeatureとします。
rebase --onto(A..B]のコミット列を切り出し、feature先端の上に再適用します。

git switch main
git rebase --onto feature A^ B

完了後にfeature側とmain側の履歴を確認し、期待どおり付け替わっているかを検証します。

git switch feature
git log --oneline --decorate --graph -n 20

ケースC:すでにリモートへpushしている場合の安全策

公開済み履歴の書き換えは混乱の原因になりやすいため、まずは履歴を残したまま是正する方法を選びます。
正しいブランチにはcherry-pickで変更を複製し、
誤って載せたブランチでは取り消しコミットで内容を戻します。

# 正しいブランチへ変更を複製
git switch feature
git cherry-pick <hash1> <hash2> ...

# 誤ブランチでは取り消しコミットを作成
git switch main
git revert <hash1> <hash2> ...
git push origin main

履歴をクリーンに保つ必要がある場合は、全員の合意と周知のうえで--force-with-leaseを使用します。
単純な--forceよりも安全性が高く、他者の更新を誤って消しにくくなります。

git push --force-with-lease origin main

ケースD:履歴ではなくファイル内容だけ取り出したい場合

コミットの再配置ではなく、特定ファイルの内容だけを正しいブランチへ持っていきたいときは、
誤コミットのハッシュからファイル単位で取り出し、改めてコミットします。

git switch feature
git checkout <wrong-commit-hash> -- path/to/fileA path/to/fileB
git add .
git commit -m "Pick files from wrong commit"

コンフリクト発生時の進め方と中断・撤回

cherry-pickrebase中にコンフリクトが起きたら、
マーカーを手掛かりに該当箇所を解消し、ステージして続行します。
作業をいったん取りやめたい場合は開始前に戻すサブコマンドを使います。

# 解消して続行
git add .
git cherry-pick --continue     # rebase中なら git rebase --continue

# 中断して開始前へ戻す
git cherry-pick --abort        # rebase中なら git rebase --abort

よくある失敗と避け方

コミットの適用順を入れ替えてしまい、依存関係が崩れてコンフリクトが連鎖することがあります。
元の順序で適用するのが基本方針です。
push後のreset --hardは原則避け、やむを得ず行う場合は--force-with-leaseを使い、
前提条件や手順をチーム内に周知してから実行します。
開始時の退避ブランチ作成とreflog確認の習慣化が、最悪時の復旧コストを大幅に下げます。

最小手順のまとめ

push前なら、正しいブランチでcherry-pickして誤ブランチをreset --hardで戻すのが最短です。
連続した変更はrebase --ontoで一括付け替えが効率的です。
push後は履歴を書き換えない戦略を優先し、必要に応じてrevertを使い、
履歴修正は合意と体制を整えたうえで--force-with-leaseを選びます。

付録:具体例に沿ったコマンド列

例として、誤ってmainC1C2C3の3コミットを積んだケースを考えます。
正しいブランチはfeatureです。
バックアップを作成し、featureへ切り替えてcherry-pickを行い、
その後mainを安全な位置へ戻します。

# 保険
git switch main
git switch -c safety/backup-$(date +%Y%m%d-%H%M)

# 移し替え
git switch -c feature
git cherry-pick C1 C2 C3

# 誤ブランチを巻き戻し(push前)
git switch main
git reset --hard <base-before-C1>

おわりに

ブランチ間違いは完全には防げませんが、適切な手順と復旧の型を知っていれば致命傷になりません。
バックアップとreflogで退路を確保しつつ、cherry-pickrebase --ontoを状況に応じて使い分けることで、
短時間で安全に復旧できます。