リベースとは
- 履歴を統合して整える
基本的なコマンド
git rebase <ブランチ名>
- ブランチの基点となるコミットを別のコミットに変更する
マージとの違い
例)mainブランチの内容でdevブランチをマージする場合
- devブランチにチェックアウトしてから、git merge origin/mainを実行してマージする
- mainブランチの変更点と、devブランチの変更点を比較して両方の変更を反映した内容がdevブランチ側にコミットされる(競合時は解消対応が必要)
例)mainブランチの内容でdevブランチをリベースする場合
- devブランチにチェックアウトしてから、git rebase mainを実行する
- mainブランチの最新のコミットが親コミットとして、devブランチの基点が変更される
- つまり、devブランチがmainブランチから枝分かれしたことをなかったことにして、現在のmainブランチの最新のコミット内容から、devブランチで変更を加えたことになるので、mainブランチの変更履歴が一直線になるのです
- リベースというのは、基点となるコミットをmainブランチの最新コミットから変更を加えたことにするのです
- devブランチで今までコミットしてきた内容は全てなかったことにするのではなく、mainブランチの最新の内容から、devブランチで行ったコミット内容の順番に変更していったことにしている
★コンフリクトの解消
マージ
- 各ブランチの最新のコミットを1つにマージするため、コンフリクトの解消は1回のみとなる
リベース
- 枝分かれしたコミットを順番に、リベース先ブランチの最新コミットにマージしていくため、1度コンフリクトが発生して解消しても、2つのコミットをマージするときに再びコンフリクトの解消が必要になることがある
- 最新のコミット同士を
★使い分ける判断基準
- プッシュしていないローカルの変更にはリベース
- プッシュ後は必ずマージ
- コンフリクトの可能性がある場合はマージ
マージ
- 【メリット】コンフリクトの解決が容易(マージコミット時の1回のみ)
- 【メリット】作業の履歴を細かく残せる
- 【デメリット】マージコミットが増えるので、履歴が複雑化しやすい
リベース
- 【メリット】履歴が単純化できる(きれいにできる)
- 【デメリット】コンフリクトの解決が面倒
一連の流れ
- mainブランチのコミット1がある
- mainブランチのコミット1を基点としてdevブランチを作成する
- mainブランチで変更を行いコミット2を作成する
- devブランチで変更を行いコミット3を作成する
- この時点でmainブランチからdevブランチは分岐している
【マージの場合】 - 本来ならば、コミット2(main)の変更をコミット3にマージして、コミット4(dev)がマージコミットとして作成する
- そして、コミット2(main)にコミット4(dev)をマージさせる(もしくはプルリクエスト)
【リベースの場合】 - rebaseコマンドを実行して、mainブランチのコミット2をdevブランチの親コミットに変更する
- つまり、devブランチの親コミットをコミット1からコミット2に変更している
- この状態でmainブランチにチェックアウトしてから、git merge origin/devを実行すると、fast-forwardコミットになるので、マージコミットは生まれません
★プルにはリベース型がある
- 通常のpullコマンドはマージ型である
- 以下のコマンドの場合はリベース型でプルできる
git pull --rebase <リモート名> <ブランチ名> git pull --rebase origin main
- リベース型の場合でも、フェッチの機能は同じである
- マージコミットが残らないので、ワークツリーにGitHubの内容をそのまま持ってきたいときは、リベース型を使う
- プルを常時--rebase(リベース型)に設定することもできる
してはいけないこと
①GitHubにプッシュしたコミットはリベースしてはいけない
- 【前提】リベースによって枝分かれ以降のコミットは最新コミットを除きすべて削除される
- 【前提】リベースはあくまでも自身のローカル内で履歴を統一しているだけで、GitHub側ではリベースしたことは把握していない
- 【制限】すでにGitHubにプッシュ済みのコミットがある場合、枝分かれは確定させることになるので、後からリベースをしてコミットを削除するようなことはできない
- 【理由】もしローカル側でリベースをしてしまった場合、GitHubとコミットの不整合が起こり、pushできなくなる
- 【補足】git push -fは絶対にやってはいけない。強制的にpushすることになるが、Gitの履歴が壊れてしまう
自分なりの理解
- 歴史改変系の小説でありがちだが、平行世界というのがあって、過去の分岐点に戻って違う選択を行うと、そこで世界が分岐する
- 分岐した別の世界で行った行動は本来は元の世界には影響がないが、不思議な力が働いて、わかれた平行世界が1つの世界に統合される
- その際に取りこんだ世界には別の世界の出来事が、あたかも順当にこの世界で発生したようになる。誰も気づかない
- 買い物でリンゴを買って帰ってから、バナナを買うのを買い忘れていた→過去に戻ってバナナも買う→バナナを買った世界の出来事が元の世界に統合されて、元の世界の事象や記憶が改変される
- つまり言うと、本来別世界に存在していた世界をなかったことにしてしまうということですね