Rebaseは、あるブランチから別のブランチの先端にコミットを移動し、不要なマージコミットのない線形の履歴を作成するGitの操作です。マージとは異なり、rebaseは履歴を書き換えます。各移動コミットは、親が変更されるため新しいハッシュを取得します。Gitドキュメント(2026年)によると、rebaseはプルリクエストを作成する前にフィーチャーブランチをmainの最新状態と同期させるために使用されます。git rebaseコマンドは、Git Flowを使用するプロジェクトでクリーンな履歴を維持するための主要なツールの一つです。
ポイント
Rebaseは、現在のブランチを指定されたブランチにリベースするGitコマンドです。現在のブランチからすべてのコミットを取得し、一時的に保存し、ブランチポインタをターゲットコミットに移動し、保存されたコミットをその上に順次適用します。結果として、開発者がターゲットブランチの最新コミットから直接作業したかのような履歴になります。
基本的な構文:git rebase main — フィーチャーブランチにいる状態で、このコマンドはすべてのフィーチャーコミットをmainの先端に移動します。Gitは各コミットごとに個別にスリーウェイマージ戦略を使用します。コミットAがターゲットブランチに既に存在する場合(ハッシュで判断)、Gitは自動的にそれをスキップし、重複する変更を回避します。
Rebaseはコミットのサブセットを移動するためのontoモードもサポートしています:git rebase --onto target start end — この形式は、あるブランチからコミットの範囲を抽出し、別のブランチの上に適用することができます。例えば、git rebase --onto main feature~3 featureは、フィーチャーブランチの最後の3つのコミットをmainの上に移動します。
# Switch to feature branch
git checkout feature
# Rebase feature onto main
git rebase main
# After successful rebase — history is linear
git log --oneline --graph
# Move last 3 commits to main
git rebase --onto main HEAD~3 HEAD
Rebaseとmergeは同じタスク(異なるブランチからの変更の結合)を解決しますが、根本的に異なる方法で行います。Mergeは2つの親を持つマージコミットを作成して完全なマージ履歴を保持します。Rebaseは履歴を書き換え、線形にします。どちらを選ぶかは、チームのワークフローとリポジトリ管理ルールに依存します。
主な違いはマージの記録方法です。Mergeは「この時点でフィーチャーをmainにマージした」を保持します — これはプロジェクト履歴にとって有益ですが、頻繁なマージでログが乱雑になります。Rebaseは「フィーチャーコミットはmainの最新状態から順次作成された」を示します — これはクリーンですが、開発が並行して行われた事実を隠します。
2つ目の違いは競合処理です。Mergeでは、競合は一度解決され、その解決策はマージコミットに記録されます。Rebaseでは、移動するコミットごとに競合が発生する可能性があり、それぞれ個別の解決が必要です。これはより手間がかかりますが、最終バージョンにどの変更が含まれるかをより正確に制御できます。
| 基準 | Rebase | Merge |
|---|---|---|
| 履歴 | 線形、マージコミットなし | 非線形、マージコミットあり |
| コミットハッシュ | 書き換え(新しい) | 元のまま保持 |
| 競合 | 各コミットごとに個別 | マージコミットで一度 |
| 公開ブランチ | 禁止 | 許可 |
| 取り消しコマンド | git rebase --abort | git merge --abort |
インタラクティブrebase(git rebase -i)は、Gitがコミットのリストと各コミットに使用可能なアクションを含むエディタを開くモードです。開発者はリモートリポジトリにプッシュする前に履歴を書き換えることができます。これはフィーチャーブランチでクリーンなコミットを維持するための主要なツールです。
インタラクティブモードで使用可能なコマンド:pick(コミットをそのまま保持)、reword(コミットメッセージを変更)、edit(変更のために停止)、squash(前のコミットと結合、両方のメッセージを保持)、fixup(結合、メッセージを破棄)、drop(コミットを削除)。各コマンドは、開かれたエディタでコミットハッシュの前に配置されます。
Squashとfixupはコミットを結合するために最も頻繁に使用されるコマンドです。開発者が作業中に5つの小さな修正コミットを行った場合、squashはそれらを意味のあるメッセージを持つ1つの論理コミットにマージします。Fixupはタイプミスの修正に便利です。変更は独自のメッセージを保持せずに前のコミットに取り込まれます。
# Open editor for last 4 commits
git rebase -i HEAD~4
# Editor will show:
pick a1b2c3d Add authentication
pick e4f5g6h Fix typo in login
squash i6j7k8l Additional login fixes
pick m9n0o1p Add auth tests
# After saving — Git performs rebase
# and opens editor for squashed commit message
# Auto-squash without opening editor
git rebase -i HEAD~4 --autosquash
--autosquashフラグは、fixup!またはsquash!で始まるメッセージを持つコミットに対して自動的にfixup/squashを配置します。開発者が後で結合するために事前にコミットにマークを付ける場合、作業が高速化されます。--committer-date-is-author-dateフラグは、リベース時に元のコミット日付を保持します — 履歴の時系列順を維持するのに役立ちます。
Rebase中の競合は、ターゲットブランチの変更との矛盾によりGitが移動したコミットを自動的に適用できない場合に発生します。Mergeでは競合が一度解決されるのとは異なり、rebaseでは各コミットが競合を引き起こす可能性があり、最も古いコミットから最も新しいコミットまで順次解決する必要があります。
競合が発生すると、Gitはrebaseを一時停止し、どのコミットが問題を引き起こしたかを報告します。開発者は競合するファイルを開き(Gitは競合領域を<<<<<<<、=======、>>>>>>>マーカーでマークします)、編集し、インデックスに追加し(git add)、git rebase --continueでrebaseを続行します。解決策が見つからない場合 — git rebase --abortでrebaseを完全にキャンセルします。
ヒント:複数の競合がある場合、競合解決のためにビジュアルエディタを開くgit mergetoolを使用する方が効率的です。問題のあるコミットをスキップすることもできますが(git rebase --skip)、最終的な履歴からその変更が削除されるため、正しい判断になることは稀です。
# Start rebase with conflict
git rebase main
# Auto-merging file.txt
# CONFLICT (content): Merge conflict in file.txt
# Check status
git status
# both modified: file.txt
# Edit conflicted sections → git add → continue
git add file.txt
git rebase --continue
# If uncertain — abort
git rebase --abort
Rebaseの黄金律:すでにリモートリポジトリにプッシュされ、他の開発者が利用できるコミットは決してリベースしてはいけません。Rebaseはコミットハッシュを書き換えるため、同僚が同期しようとすると競合が発生します — ローカル履歴が書き換えられたリモート履歴と異なります。
Rebaseが完全に禁止されている状況:誰かがすでにあなたのコミットに基づいてブランチを作成している場合(例えば、同僚があなたのフィーチャーからブランチを作成した場合)、履歴を書き換えるとその作業が壊れます。そのような場合はmergeを使用してください。また、締め切りの直前にrebaseを行うことは推奨されません — 競合解決のエラーが予想以上に時間がかかり、リリースをブロックする可能性があります。
例外:ブランチを1人の開発者だけが使用している場合(個人のフィーチャーブランチ、未公開またはドラフトモードで公開)、プッシュ前のrebaseは標準的なプラクティスです。公開して共同作業を開始した後は — マージのみです。GitHubとGitLabはデフォルトでsquash mergeを妥協案として提供しています:コミットを1つにまとめますが、ターゲットブランチの履歴は書き換えません。
現代のチームは、GitHub Flowと組み合わせたrebase指向のワークフローを最も頻繁に使用します。プロセスは次のようになります:開発者はmainからフィーチャーブランチを作成し、そこで作業し、定期的にgit rebase mainで同期し、プルリクエストを作成する前に履歴を整理するためにインタラクティブrebaseを実行します。
PRを作成した後(mainから新しい変更を取り込む必要がある場合)、通常のgit pullの代わりにgit pull --rebase mainを使用します。これにより、不要なマージコミットを作成せずに変更を取り込めます。--rebaseフラグ付きのgit pullはgit fetch + git rebaseと同等です — Gitは最初に新しいコミットをダウンロードし、次にローカルの変更をその上にリベースします。
Gitはpullのデフォルト動作としてrebaseを設定できます:git config --global pull.rebase true。この設定後、git pullは常にmergeの代わりにrebaseを実行します。通常のpullが必要な場合 — git pull --no-rebaseを使用します。多くのチームはautostashも有効にしています:git config --global rebase.autoStash true — これにより、rebase前にコミットされていない変更が自動的に隠され、後に復元されます。
よくある質問
リベースするとは、git rebaseを実行することです:現在のブランチから別のブランチの先端にコミットを移動します。その結果、履歴は線形になり、各コミットは新しいハッシュを取得し、マージコミットは作成されません。このコマンドは、ログに不要なマージポイントを作成せずにブランチを同期するために使用されます。
Mergeは2つの親を持つマージコミットを作成し、並行履歴と元のハッシュを保持します。Rebaseは履歴を書き換えます — コミットは新しいハッシュを取得し、履歴は線形になります。Mergeは公開ブランチにとってより安全で、rebaseはよりクリーンなログを提供します。
git rebase -i HEAD~Nコマンドは、最後のN個のコミットを含むエディタを開きます。各コミットに対してアクションを選択できます:pick(保持)、reword(名前変更)、edit(変更)、squash(前のコミットと結合)、fixup(メッセージなしで結合)、drop(削除)。保存後、Gitは選択された変更を適用します。
Rebaseはコミットハッシュを書き換えるため、他の開発者のマシン上の同じコミットのコピーと履歴が互換性なくなります。同僚がgit pullで既にあなたのコミットを取得し、その後あなたがそれらをリベースした場合、そのgit pushは拒否され、git pullは重複したコミットと競合を生成します。
完了前 — git rebase --abortが完全にキャンセルします。完了後は、git reflogを介して以前の状態を復元できます — rebase前のコミットハッシュを見つけ、そこにgit reset --hardを実行します。Reflogはデフォルトで30日間HEADの移動履歴を保存します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。