リベース
前回紹介した「マージ」 では、各ブランチで行われた変更内容を結合して、ブランチの変更内容を別のブランチに結合しました。もうひとつ、ブランチの変更内容を別のブランチに結合する方法があります。
「リベース」です。
「リベース」には、ブランチとブランチを結合する方法と、特定の「コミットオブジェクト」で行われた変更内容をコピーして、新規に「コミットオブジェクト」を作成し、リベース先に結合する方法があります。
リベースとは
簡潔に言えば、既存の変更内容を別の「コミットオブジェクト」に新規に適用することです。既存の「コミットオブジェクト」から変更内容を抽出し、その変更内容を別の「コミットオブジェクト」に連結します。
ただし、リベース時に「コミットオブジェクト」は新規に作成されるため、既存の「コミットオブジェクト」と、連結した「コミットオブジェクト」は、変更内容は同じでも別の「コミットオブジェクト」として扱われます。
この変更内容には、ファイルに対して行った変更内容の他に、コミットメッセージやコミットした日付やコミットしたユーザーの情報など、「コミットオブジェクト」のメタデータも含まれています。
単純な「コミットオブジェクト」の移動ではない点に留意してください。
ブランチとブランチのリベース
ブランチとブランチをリベースして変更内容を結合する方法です。「リベース」でよく利用される方法です。
例えば、リポジトリーにブランチが1つ存在するとします。
そのブランチをブランチすると、リポジトリーにあるブランチが2つになります。
それぞれのブランチは、以下のように、お互い干渉せずに並行して変更内容をコミットしていくことができます。
この時「リベース」による変更内容の結合を行うと、リベース元の変更内容をリベース先に連結します。
上図は、「fix」ブランチを「master」ブランチにリベースした結果です。
「Commit8」は「Commit6」の変更内容を含んでいます。
「Commit9」は「Commit7」の変更内容を含んでいます。
それぞれのブランチで並行してコミットしていた変更内容が、1つのブランチ上で変更内容をコミットしていたかのような結合になります。
簡潔に言えば、ブランチの連結とブランチの統合です。
あるブランチで行っていたコミットを、別のブランチでコミットし直します。
ブランチの分岐直後から「ブランチヘッド」までの変更内容が、別のブランチに統合されます。
この統合される点が「マージ」と大きく異なる点です。
ただし「リベース」で結合しても、ブランチ自身は削除されません。
リベースされたコミットオブジェクト
上図の「Commit8」と「Commit9」は、「リベース」によって生成された「コミットオブジェクト」です。このような「リベース」によって生成された「コミットオブジェクト」のことを、「リベースされたコミットオブジェクト」といいます。
コミットオブジェクトは新規に作成される
リベースを実行すると、リベース先には新規に「コミットオブジェクト」が生成されます。上記のブランチのリベースでは、「Commit6」から変更内容を抽出し、その変更内容を元に新規にコミットを行い、「Commit8」を生成しています。
同様に、「Commit7」から変更内容を抽出し、その変更内容を元に新規にコミットを行い、「Commit9」を生成しています。
リベースはリベース元で行ったコミットを、リベース先で再実行します。
変更内容など、リベース元でコミットした内容は引き継ぎますが、「コミットオブジェクト」は別のものになります。
リベース対象になったコミットオブジェクトは破棄される
リベース実行時、リベース元のブランチに存在する「コミットオブジェクト」は、破棄されます。上記のブランチのリベースの例では、「Commit6」と「Commit7」が履歴から削除されます。
また変更内容は同じでも、「Commit6」と「Commit8」及び、「Commit7」と「Commit9」は異なる「コミットオブジェクト」なので、コミットオブジェクトの識別子は異なります。
破棄されたコミットオブジェクトは参照できなくなる
後述しますが、リベースにより破棄された「コミットオブジェクト」は、参照できなくなります。もし他に、その破棄された「コミットオブジェクト」を参照しているユーザーがいた場合、そのユーザーは作業を中断せざるを得なくなります。
他のユーザーと共有しているリポジトリーで「リベース」を実行する時は、この点に注意してください。
リベース対象になったコミットオブジェクトが破棄されない場合もある
リベースの方法によっては、リベース対象になった「コミットオブジェクト」が破棄されない場合もあります。リベース元のブランチの「ブランチヘッド」が、リベース後に変更されなかった場合、リベース対象になった「コミットオブジェクト」は破棄されません。
すでにリベース先に取り込まれている変更内容はスキップされる
「リベース」実行時、すでにリベース先に取り込まれている変更内容は、適用がスキップされるため、「コミットオブジェクト」は生成されません。従って、スキップされた「コミットオブジェクト」に含まれるコミットメッセージなどのメタデータも反映されません。
言い換えれば、すでに適用済みとして処理されるということです。
例えば、以下の構成のリポジトリーがあるとします。
「Commit2A」と「Commit2B」の変更内容は同じです。
「fix」ブランチを「master」ブランチにリベースすると、「Commit2B」は「Commit2A」と変更内容が同一であるため、処理がスキップされます。
「Commit4」の変更内容を元に「Commit4’」を生成してリベースが完了します。
スナップショットはマージもリベースも同じになる
同一のブランチ構成かつ、同じ内容でコンフリクトの解決を行った場合、マージ完了後の「スナップショット」とリベース完了後の「スナップショット」は、どちらも同じ結果になります。どちらの「スナップショット」からプロジェクトのファイル群を取得しても、同じ内容のファイル群が取得できます。
最新の「スナップショット」のファイル群に違いはありません。
履歴が変わる
ブランチとブランチを「リベース」すると、履歴が変わります。「マージ」では、ユーザーが作成した「コミットオブジェクト」は、そのまま残ります。
一方「リベース」では、「リベース」対象の「コミットオブジェクト」は全て破棄され、新規に「コミットオブジェクト」が生成されます。
このように、履歴自体が変わります。