rebase と履歴整理
git rebase(通常・interactive)と git cherry-pick を使って、コミット履歴をきれいに整理する方法を演習問題で学びます。
このチュートリアルでは、コミット履歴を整理するための git rebase と git cherry-pick を演習形式で学びます。プルリクエストを出す前に履歴をきれいにする、といった実務でよくある作業を扱います。
⚠️ 共有ブランチへの rebase は禁止です
git rebaseはコミットのハッシュを書き換えます。mainやdevelopなど、他の人と共有しているブランチに対して rebase を行うと、他の人のローカル履歴と食い違いが生じ、混乱の原因になります。rebase は自分だけが使っているローカルの feature ブランチに限定してください。 共有ブランチの変更を取り込みたいだけなら、素直にgit mergeを使いましょう。
演習 1:フィーチャーブランチを main に rebase する
feature/login ブランチで作業している間に、main に新しいコミットが追加されたとします。
問題: feature/login ブランチのコミットを、最新の main の先端に付け替える(rebase する)コマンドを書いてください。
答えを見る
git switch feature/login
git rebase main【rebase 前】
main: A → B → C
feature/login: ↘
D → E
【rebase 後】
main: A → B → C
feature/login: ↘
D' → E'feature/login のコミット(D, E)が main の最新コミット(C)の先に付け替えられ、履歴が一直線になります。コンフリクトがなければ自動的に完了します。
演習 2:rebase 中のコンフリクトを解決する
rebase の途中で、main 側と feature/login 側が同じ箇所を変更していてコンフリクトが起きたとします。
問題: コンフリクトが発生した状態から、ファイルを修正してコンフリクトを解消し、rebase を再開するまでの手順を書いてください。
答えを見る
git rebase main
# CONFLICT (content): Merge conflict in src/auth.js
# Resolve all conflicts manually, mark them as resolved with
# "git add/rm <conflicted_files>", then run "git rebase --continue".# 1. コンフリクトマーカーを開いて手動で解消する
# 2. 解消したファイルをステージング
git add src/auth.js
# 3. rebase を再開
git rebase --continue複数のコミットで順にコンフリクトが起きる場合、この手順をコミットの数だけ繰り返します。うまくいかない場合はやり直せます。
git rebase --abort--abort は rebase 開始前の状態に完全に戻すので、行き詰まったら遠慮なく使いましょう。
演習 3:interactive rebase でコミットを squash する
「作業中の小さなコミット」が何個も積まれてしまい、プルリクエスト前に1つにまとめたいとします。
問題: 直近3つのコミットをインタラクティブに編集する画面を開くコマンドを書いてください。
答えを見る
git rebase -i HEAD~3エディタが開き、以下のようなリストが表示されます。
pick a1b2c3d ログイン画面の雛形を追加
pick e4f5g6h バリデーション処理を追加
pick i7j8k9l タイポ修正2つ目・3つ目のコミットを1つ目に統合したい場合、pick を squash(または短縮形 s)に変更します。
pick a1b2c3d ログイン画面の雛形を追加
squash e4f5g6h バリデーション処理を追加
squash i7j8k9l タイポ修正保存してエディタを閉じると、3つのコミットメッセージをまとめた新しいコミットメッセージの編集画面が開きます。内容を整えて保存すると、3つのコミットが1つに統合されます。
演習 4:interactive rebase でコミットメッセージを reword する
すでにコミットしたメッセージに誤字があった、あるいは内容が分かりづらかったとします(直前のコミットでなく、2つ前など、途中のコミットが対象)。
問題: 直近3コミットのうち、2つ前のコミットメッセージだけを書き直す手順を書いてください。
答えを見る
git rebase -i HEAD~3リストで対象のコミットの pick を reword(短縮形 r)に変更します。
reword a1b2c3d ログイン画面の雛形を追加 ← ここを reword に変更
pick e4f5g6h バリデーション処理を追加
pick i7j8k9l タイポ修正保存してエディタを閉じると、a1b2c3d のコミットメッセージを編集する画面が開きます。修正して保存すれば、そのコミットだけメッセージが更新されます(直前のコミットのメッセージだけでよい場合は git commit --amend の方が手軽です)。
演習 5:git cherry-pick で特定コミットだけを別ブランチに持ち込む
feature/experiment ブランチで作った複数のコミットのうち、1つだけをすぐに main に取り込みたいとします。
問題: feature/experiment にあるコミット f9e8d7c だけを、現在の main ブランチに取り込むコマンドを書いてください。
答えを見る
git switch main
git cherry-pick f9e8d7c【取り込み前】
main: A → B
feature/experiment: A → B → C → D
【git cherry-pick D 実行後】
main: A → B → D'
feature/experiment: A → B → C → DD' は D と同じ内容を持つ新しいコミットとして main に追加されます。feature/experiment 側の履歴には影響しません。
まとめ
自分のブランチだけ整理したい → git rebase <base>
直近のコミットを対話的に整理したい → git rebase -i HEAD~N
└ 統合したい → squash / fixup
└ メッセージを直したい → reword
特定のコミットだけ別ブランチに持ち込みたい → git cherry-pick <hash>
いずれの操作もコミットハッシュを書き換えるため、push 済みで他の人と共有しているコミットに対しては使わないのが原則です。ローカルの整理が終わってから push しましょう。