cherry-pick と rebase の実践テクニック
コミットの整理・移動・救済など、日常的に使える実践パターン集
前提
rebase と cherry-pick はコミットハッシュが変わる操作
プッシュ済みのコミットに対して実行すると force push が必要になり、チームメンバーの履歴と不整合を起こします。
このページのテクニックは未プッシュのコミットが前提
まだプッシュしていないローカルのコミットに対して使うことを想定しています。
多くの場面では merge だけで十分
詳しくは きれいな履歴にこだわりすぎない を参照してください。
interactive rebase でコミットを整理する
git rebase -i では、エディタで各コミットに対して以下のコマンドを指定できます。
| コマンド | 意味 |
|---|---|
pick |
そのまま使う |
reword |
メッセージのみ変更 |
squash |
前のコミットと統合してメッセージを編集 |
fixup |
前のコミットと統合してメッセージは破棄 |
drop |
コミットを削除 |
PR前にコミットを整理するのが定番の使い方です。
fixup! プレフィックス付きコミットと --autosquash を組み合わせると、自動で対象コミットの直後に配置されるので効率的です。
# PR前にコミットを整理する
git rebase -i origin/main
# エディタで pick/squash/fixup/reword/drop を指定
# fixup コミットを作る → 後で自動整理
git commit --fixup=abc1234
git rebase -i --autosquash origin/main
# 直近5コミットを整理
git rebase -i HEAD~5間違ったブランチにコミットした場合の救済
間違ったコミットのハッシュをメモ
git log --onelineで対象のコミットハッシュを確認してメモしておきます。作業中に位置がずれても戻せるように、必ず最初に記録します。正しいブランチに移動して cherry-pick
git switchで目的のブランチに切り替え、git cherry-pick <hash>でコミットを取り込みます。複数コミットならgit cherry-pick A..Bの範囲指定も使えます。元のブランチから reset でコミットを消す
元のブランチに戻り、
git reset --hard HEAD~Nで不要なコミットを削除します。既にプッシュ済みの場合は影響があるため、git revertを検討してください。
# 1. まず間違ったコミットのハッシュを確認
git log --oneline -3
# abc1234 間違えてmainにコミットした変更
# 2. 正しいブランチに移動してcherry-pick
git switch feature/correct-branch
git cherry-pick abc1234
# 3. 元のブランチからコミットを消す
git switch main
git reset --hard HEAD~1
# 複数コミットを一括で移す
git switch feature/correct-branch
git cherry-pick abc1234..def5678リリースブランチへのホットフィックス適用
本番で見つかったバグを修正してリリースブランチにも反映するパターンです。
hotfix ブランチを作り、修正後に main とリリースブランチの両方に merge するのが安全です。
cherry-pick でも同じことはできますが、ハッシュが変わるため merge のほうがトラブルが少なくなります。
# hotfix ブランチを作成して修正
git switch -c hotfix/login-npe main
git commit -m "fix: ログイン時のNPEを修正"
# main にマージ
git switch main
git merge hotfix/login-npe
# リリースブランチにもマージ
git switch release/v2.0
git merge hotfix/login-npe
# 不要になった hotfix ブランチを削除
git branch -d hotfix/login-nperebase --onto で特定範囲を付け替え
feature/api から分岐した feature/api-test を、main に直接付け替えたい場合に rebase --onto を使います。
構文は git rebase --onto <新しいベース> <古いベース> <対象ブランチ> です。
feature/api の変更を含めずに feature/api-test のコミットだけを main に移せます。
ブランチの依存関係を変更したいときに重宝します。
# feature/api-test を main に直接付け替え
# (feature/api の変更は含めない)
git rebase --onto main feature/api feature/api-test
# 特定範囲のコミットを別ブランチに移す
git rebase --onto main HEAD~3 feature/newコンフリクト対処の実践
対象ファイルを修正して
git addエディタでコンフリクトマーカー(
<<<<<<<=======>>>>>>>)を解消し、修正後のファイルをステージングします。--continueで再開git rebase --continueまたはgit cherry-pick --continueで次のコミットに進みます。残りのコミットでも同じ手順を繰り返します。どうしても解決できないときは
--abortgit rebase --abort/git cherry-pick --abortで操作前の状態に安全に戻れます。繰り返すコンフリクトには rerere を有効化
git config --global rerere.enabled trueで一度解決したコンフリクトが記録され、次回以降自動で再適用されます。
# コンフリクト発生時の基本手順
git rebase origin/main
# CONFLICT が発生
# 1. ファイルを修正して add
git add src/app.ts
# 2. rebase を続行
git rebase --continue
# 諦めて撤退する場合
git rebase --abort
# rerere を有効にしてコンフリクト解決を記憶させる
git config --global rerere.enabled true
Git Ready