この記事では『git rebaseコマンド』について、
git rebase
とはgit rebase
の使い方git rebase
して、作業ブランチを最新の状態に保つ手順
git rebase
のメリットgit rebase
の注意点- リベース(
rebase
)とマージ(merge
)との違い
などを図を用いて分かりやすく説明するように心掛けています。ご参考になれば幸いです。
git rebaseとは
git rebase
はあるブランチの基点(ベース)を新しい基点に再設定するGitコマンドです。
通常、Gitでブランチを作成すると、そのブランチには基点となるコミットがあります。例えば、上図の場合、feature
ブランチの基点はコミットAになります。feature
ブランチをmain
ブランチにリベースすると、feature
ブランチの基点がmain
ブランチの最新コミットEの後に移動されます。その結果、main
ブランチの最新の状態をfeature
ブランチに取り込むことができるようになります。
その他にもgit rebase
はコミットメッセージをまとめたり、コミットメッセージを修正したりする際にも使用することができます。
Gitにおけるリベース(rebase)は"Re Base"、すなわち「ベースを再設定する」という意味があります。
git rebaseの使い方
これからgit rebase
コマンドを用いてブランチの基点(ベース)を変更し、最新の状態に保つ方法を説明します。
例えば、新機能を追加するために、main
ブランチからfeature
ブランチを作成して、開発を進めたとします(下図ではコミットAからfeature
ブランチを作成しています)。この場合、feature
ブランチの基点はコミットAになります。そして、feature
ブランチでの作業でコミットを2回(B, C)したとします。すると、ブランチの状態は以下のようになります。
これをGitHubやCode Commit等にプッシュするには、以下のコマンドを実行します。
git push origin feature
上記のコマンド実行後にプルリクエストを出すことが多いと思います。しかし、チームで開発をしていると、他のメンバーの作業によって、以下のようにfeature
ブランチの作業中にmain
ブランチが更新されることが多いです。例えば、mainブランチで2回更新(コミットD,コミットE)された場合、ブランチの状態は以下のようになります。
この場合、main
ブランチの最新状態をfeature
ブランチに取り込んでからプッシュしないと、コンフリクトが起きる可能性があります(次にmain
ブランチの最新状態をfeature
ブランチに取り込む方法を説明します)。
git rebaseして、作業ブランチを最新の状態に保つ手順
main
ブランチの最新状態をfeature
ブランチに取り込む手順を以下に示します。main
ブランチが最新状態の場合、手順1と手順2は省略しても構いません。
手順
- 作業ブランチでの作業が終わったら、ブランチを
main
ブランチに戻す main
ブランチを最新の状態にする- ブランチを作業ブランチに戻す
git rebase
を実行する
作業ブランチでの作業が終わったら、ブランチをmainブランチに戻す
作業ブランチ(今回はfeature
ブランチ)での作業が終わったら、以下のコマンドを実行して、ブランチをmain
ブランチに戻します。
git checkout main
mainブランチを最新の状態にする
main
ブランチに切り替えたら、以下のコマンドを実行して、リモートリポジトリ上のmain
ブランチの最新状態を取り入れます。
git pull
ブランチを作業ブランチに戻す
main
ブランチを最新の状態にしたら、以下のコマンドを実行して、元の作業ブランチ(今回はfeature
ブランチ)に切り替えます。
git checkout feature
git rebaseを実行する
main
ブランチの最新状態をfeature
ブランチに取り込むため、以下のコマンドを実行します。
git rebase main
git rebase main
を実行すると、ブランチが以下のようになり、feature
ブランチの基点がmain
ブランチの最新コミットEの後に移動され、main
ブランチの最新状態をfeature
ブランチに取り込むことができるようになります。
その後、以下のコマンドを実行して、GitHubやCode Commit等にプッシュします。
git push origin feature
補足
今回はmain
ブランチの最新状態をfeature
ブランチに取り込みましたが、プロジェクトによっては別ブランチ(例えば、master
ブランチやdevelop
ブランチ)の最新状態をfeature
ブランチに取り込む場合があります。その際には、main
の箇所を別ブランチの名前(master
やdevelop
)に変えてください。
git rebaseのメリット
git rebase
を使用すると、どのようなメリットがあるのか、GUI上で実際に確認してみましょう。以下のmain
ブランチとfeature
ブランチを例にして説明します。
main
ブランチはfeature
ブランチより少し進んでいる状態です。この状況で、git rebase
のメリットについて説明します。
履歴が見やすくなる
feature
ブランチでgit merge main
を実行し、main
ブランチをマージ(merge)した場合、マージコミットが作成されてしまいます。例えば、feature
ブランチの作業中に10回main
ブランチを取り込もうとした場合には、マージコミットが10回も作成されてしまいます。また、上図から分かるように、GUI上で確認すると、feature
ブランチとmain
ブランチの線が重なり、コミット履歴が複雑になります。
一方、feature
ブランチでgit rebase main
を実行し、main
ブランチをリベース(rebase)した場合、マージコミットが作られず、履歴が一直線に並ぶため、変更履歴が見やすくなります。
最新のブランチを取り込んでコミットできる
main
ブランチをfeature
ブランチにマージ(merge)した場合、main
ブランチとfeature
ブランチのコミットが時系列順に並びます。そのため、feature
ブランチで機能追加後にマージを行うと、feature
ブランチの機能追加後にmain
ブランチの変更コミットが入ってきます。上図の例だと、feature
ブランチで[feature]B
と[feature]C
のコミットにより機能を追加したのに、マージをしたことで、main
ブランチでの変更コミット([main]D
と[main]E
)が入ってきてしまいます。
また、マージ後のfeature
ブランチにおいて、[feature]B
と[feature]C
のコミットにより追加した機能が正常に動作するかが不安になります(main
ブランチでの変更により、feature
ブランチの機能追加に影響がある可能性があるため)。
また、feature
ブランチの機能追加が終わると、feature
ブランチをmain
ブランチにマージすると思いますが、main
ブランチにマージ後も変更履歴が見にくいです。
一方、feature
ブランチでmain
ブランチをリベース(rebase)した場合、feature
ブランチの基点がmain
ブランチの最新コミットEになるため、feature
ブランチでは常にmain
ブランチの最新の変更を取り込んで機能を追加することができます。これにより、main
ブランチにfeature
ブランチでの変更を取り込む前に、feature
ブランチで行った変更による動作が、main
ブランチに加えられた変更(コミット)によって、おかしくなっていないかを確認することができます。
また、feature
ブランチをmain
ブランチにマージした後も変更履歴が見やすいです。
1つ1つのコンフリクトが小さい
マージ(merge)では、ブランチ同士の最終的な差分でコンフリクトがないかを確認します。上図の場合、feature
ブランチとmain
ブランチでコンフリクトがないかを確認しています。そのため、場合によっては大きなコンフリクトが発生することがあり、コンフリクトの解消が大変になります。
一方、リベース(rebase)では、1つ1つのコミットに対してコンフリクトを検出し、コンフリクトがあればその都度コンフリクトを解消します。結果として、コンフリクトが小さく済みます。上図の場合、まずfeature
ブランチのコミットBとmain
ブランチでコンフリクトがないかを確認します。コンフリクトがあれば、コンフリクトを解消します。次に、feature
ブランチのコミットCとコミットB'を含んだ状態のmain
ブランチでコンフリクトがないかを確認します。コンフリクトがあれば、コンフリクトを解消します。
このようにリベースでは、各々のコミットに対してコンフリクトを解消していくようになっています。
git rebaseの注意点
リベース(rebase)は、実際にはコミットを移動しているのではなく、既存のコミットを破棄して、新しいコミットを作成しています。新しく作成されたコミットは見た目は元のコミットと似ていますが、実際には別のコミットです。そのため、コミットのハッシュ値(コミットID)が変わります。
このようにリベース(rebase)はコミット履歴を書き換える操作であるため、公開リポジトリや共有プロジェクトで使用する際には注意が必要です。そのため、「git push
をした後やプルリクエストを出した後には git rebase
をしてはいけない」というのが、Gitのリベース(rebase)の説明によく出てきます。他のメンバーがリベース前のコミットを基点にして作業していると、git rebase
によりその基点となるコミットが破棄されてしまい、整合性が取れなくなることがあるからです。
リベース(rebase)とマージ(merge)との違い
今まで説明した内容と重複する点もありますが、リベース(rebase)とマージ(merge)の違いを以下にまとめます。
- コミット履歴の見やすさ
- リベース(rebase)
- コミット履歴が直線的になるため、コミット履歴が見やすい。
- マージ(merge)
- マージコミットが作成されるため、コミット履歴が複雑になることがある。
- リベース(rebase)
- コンフリクトの大きさ
- リベース(rebase)
- 1つ1つのコミットに対してコンフリクトを解消するため、コンフリクトが小さい。
- マージ(merge)
- ブランチ同士の最終的な差分でコンフリクトを解消するため、コンフリクトが大きくなる可能性がある。
- リベース(rebase)
- 既存のコミットを破棄するか否か
- リベース(rebase)
- 既存のコミットを破棄して新しいコミットを作成するため、コミットIDが変わる。
- そのため、公開リポジトリや共有プロジェクトで使用する際には注意が必要。
- マージ(merge)
- 既存のコミットをそのまま残すため、コミットIDは変わらない。
- そのため、公開リポジトリや共有プロジェクトで安全に使用できる。
- リベース(rebase)
本記事のまとめ
この記事では『git rebaseコマンド』について、以下の内容を説明しました。
git rebase
とはgit rebase
の使い方git rebase
して、作業ブランチを最新の状態に保つ手順
git rebase
のメリットgit rebase
の注意点- リベース(
rebase
)とマージ(merge
)との違い
お読み頂きありがとうございました。