Git で履歴を整える:rebase の基本とインタラクティブ rebase
前回はブランチを作ってマージする基本的な流れを学びました。
今回は git rebase を取り上げます。merge とは別のアプローチでブランチを統合しつつ、コミット履歴を直線的に保つ強力な機能です。
rebase とは何か
rebase は、ブランチの「分岐元」を別のコミットに付け替える操作です。 文字通り「ベース(base)を付け替え(re)する」という意味です。
merge との違いを理解するために、まず両者の挙動を比較してみましょう。
【共通の出発点】
main: A → B → C
feature: → D → E
merge の場合:mainとfeatureの両方の変更を取り込むマージコミット M が作られます。
main: A → B → C → M
↗
feature: → D → E
rebase の場合:feature ブランチの分岐元を C に付け替え、コミットが C の上に積み直されます。
main: A → B → C → D' → E'
rebase 後の D' E' は元のコミット D E とハッシュが異なります。同じ変更内容を持つ新しいコミットとして作り直されているからです。結果として、マージコミットのない一直線の履歴が得られます。
git rebase main の流れ
フィーチャーブランチを最新の main の上に載せ替えるのが、rebase の最もよくある使い方です。
# feature ブランチで作業中
git switch feature/add-login
# main の最新を取得してから rebase
git fetch origin
git rebase main
git rebase main を実行すると、Git は次の手順を自動で行います。
featureとmainの共通の祖先(分岐点)を探すfeatureにのみあるコミットを一時的に退避するfeatureのベースをmainの先端に移す- 退避したコミットを順番に再適用する
リモートリポジトリから最新を取り込む git pull にも --rebase オプションがあります。
git pull --rebase origin main
こちらは git fetch + git rebase を一度に行います。git pull(fetch + merge)の代わりにこれを使う習慣をつけると、無駄なマージコミットが減り履歴がすっきりします。
merge vs rebase の使い分け
どちらが「正しい」というものではなく、状況によって使い分けます。
merge を選ぶとき
- ブランチの合流という事実を履歴に残したい
- チームでの PR マージなど、「このブランチを取り込んだ」という記録が重要な場合
rebase を選ぶとき
- 手元の作業ブランチを最新の
mainに追随させたい - プッシュ前にコミット履歴を整理してレビューしやすくしたい
- マージコミットのない直線的な履歴を保ちたいチームポリシーの場合
ただし、後述するrebase の黄金律を先に頭に入れておくことが大切です。
インタラクティブ rebase でコミットを整理する
git rebase -i(インタラクティブ rebase)は、過去のコミット群を対話的に編集できる機能です。
「細かくコミットしたけれどプッシュ前にまとめたい」「コミットメッセージを直したい」という場面で重宝します。
直近3件のコミットを対象にする場合は HEAD~3 を指定します。
git rebase -i HEAD~3
エディタが起動し、次のような画面が表示されます。
pick a1b2c3d Add login form
pick b4c5d6e Fix typo in login
pick c7d8e9f Add password validation
各行の先頭の pick を別のキーワードに変えることで操作を指定します。
| キーワード | 省略形 | 動作 |
|---|---|---|
pick | p | そのまま使用(デフォルト) |
squash | s | 直前のコミットに統合(メッセージを結合) |
fixup | f | 直前のコミットに統合(メッセージは捨てる) |
reword | r | コミットメッセージを書き直す |
drop | d | そのコミットを削除する |
edit | e | 一時停止してコミット内容を修正する |
例えば「Addログインフォーム」と「Fixタイポ」を1つにまとめたい場合は次のようにします。
pick a1b2c3d Add login form
fixup b4c5d6e Fix typo in login
pick c7d8e9f Add password validation
ファイルを保存してエディタを閉じると、指定した操作が順番に実行されます。
rebase 中のコンフリクトと対処法
rebase はコミットを一つずつ再適用するため、コンフリクトが起きた場合はその時点で処理が止まります。
git rebase main
# CONFLICT (content): Merge conflict in auth.py
# error: could not apply b4c5d6e... Fix typo in login
# hint: Resolve all conflicts manually, ...
対処の流れは次のとおりです。
# 1. コンフリクトしたファイルを確認する
git status
# 2. エディタでコンフリクトマーカーを解消する(次回詳解)
# ファイルを編集してマーカーを取り除く
# 3. 解消したファイルをステージングする
git add auth.py
# 4. rebase を続ける
git rebase --continue
コミットが複数ある場合は、次のコミットを再適用する際にまた同様の処理が必要になることがあります。 一方、「やっぱり rebase を中止したい」という場合は次のコマンドで元の状態に戻せます。
git rebase --abort
--abort を使うと、rebase 開始前の状態にきれいに戻ります。
rebase の黄金律:push 済みブランチは rebase しない
rebase で最も重要なルールが**「他の人と共有したブランチは rebase しない」**です。
なぜかを理解するため、次のシナリオを考えます。
あなたが feature ブランチをリモートにプッシュし、同僚がそのブランチを git pull して作業を始めたとします。
ここであなたが feature ブランチを rebase してリモートへ強制プッシュ(git push --force)すると、同僚が手元に持っているコミット履歴と、リモートの履歴が完全に食い違います。
rebase はコミットを「作り直す」操作なので、同じ変更でもハッシュが変わります。
その結果、同僚が次に git pull しようとすると大量のコンフリクトや重複コミットが生じ、リポジトリの履歴が壊れた状態になります。
安全な使い方の境界線はシンプルです。
- 手元にしかない(まだ push していない)ブランチ → rebase OK
- リモートに push 済み、あるいは他のメンバーが使っているブランチ → rebase しない
自分だけの作業ブランチであっても、リモートに push した後は事情が変わります。
やむを得ず rebase して --force-with-lease で上書きする場合は、必ずチームに事前に共有してください。
実践的なコツ
プル時に rebase を使う
git pull --rebase
これを常用すると、git pull で生まれがちな「マージコミット」を防げます。
グローバルに設定することもできます。
git config --global pull.rebase true
インタラクティブ rebase の前に作業ブランチをバックアップする
git rebase -i を使い慣れていない間は、rebase 前にブランチのバックアップを作っておくと安心です。
git branch backup/feature-login feature/add-login
万一 rebase が意図通りにいかなくてもバックアップブランチから復旧できます。
git log --oneline --graph で履歴の形を確認する
git log --oneline --graph --all
rebase の前後でどのようにグラフの形が変わったか視覚的に確認できます。
--all をつけるとすべてのブランチが表示されるので全体像が把握しやすいです。
まとめ
- rebase はブランチの分岐元を付け替えて、コミット履歴を直線的に整える操作
git rebase mainでフィーチャーブランチを最新の main の上に乗せ直せる- merge がマージコミットを作るのに対し、rebase はマージコミットを作らない
git rebase -i HEAD~Nでコミットのまとめ・メッセージ修正・削除ができる- rebase 中のコンフリクトは
git rebase --continue、中止はgit rebase --abort - push 済みの共有ブランチを rebase してはいけない(黄金律)
git pull --rebaseを使うと日常的なプルのマージコミットを減らせる
次回はコンフリクト(マージ競合)を取り上げます。 コンフリクトマーカーの読み方と、焦らず手順通りに解消する方法を詳しく解説します。