今回は、Gitのrebaseについて解説しています。
Gitを使っていると、次のような場面はありませんか?
- コミット履歴がごちゃごちゃして見づらい
- ブランチを統合したら履歴が複雑になった
mergeとrebaseの違いが分からない- GitHubのプルリクエスト前に履歴を整理したい
このような場合に便利なのがgit rebaseです。
rebaseを使うと、コミット履歴を一直線に整理できるため、プロジェクト全体の履歴が見やすくなります。
この記事では、Git rebaseの基本的な使い方から、mergeとの違い、安全に利用するための注意点まで解説していきます。
Git rebaseとは
Git rebaseとは、あるブランチの変更履歴を別のブランチの先頭へ付け替える機能です。
例えば、次のような履歴があるとします。
main
A --- B --- C
feature
\
D --- E
mainブランチのBコミットの地点からfeatureブランチを作って、D・Eとコミットを重ねた状態です。
mainブランチの方はBコミットの後に、Cコミットを重ねています。
この状態でfeatureブランチに対してrebaseを実行すると、下記のようになります。
main
A --- B --- C
feature
\
D' --- E'
mainコミットの最新からfeatureブランチのコミットが足されたような形になります。
一見同じように見えますが、DとEは新しいコミットとして作り直されています。
そのため、履歴が一直線になり、あとから変更履歴を追いやすくなります。
Git rebaseとmergeの違い
rebase機能とよく比較されるのがmergeです。
mergeの場合
マージの場合は、下記のようにマージ先のブランチ(main)に変えて
マージ元のブランチ(feature)を取り込みます。
git switch main
git merge feature
そうすると、履歴は次のようになります。
A --- B --- C -------- M
\ /
D --- E ----
mainブランチのBコミットから、featureブランチのD・Eコミットをmainブランチにマージしました。
このときにマージコミット(M)が作成されます。
このようにgit mergeでは、マージされた履歴が残りますが、履歴がわかれることになります。
rebaseの場合
リベースの場合になりますが、下記のように操作することで
git switch feature
git rebase main
履歴は次のようになります。
A --- B --- C (main) --- D' --- E' (feature)
このように履歴が一直線になり、わかりやすくなります。
どちらを使うべき?
一般的には次のように使い分けます。
| 操作 | おすすめ |
|---|---|
| 履歴をきれいにしたい | rebase |
| 履歴をそのまま残したい | merge |
| プルリク前の整理 | rebase |
| 本番ブランチへの統合 | merge |
Git rebaseの基本的な使い方
例えばmainの最新変更をfeatureへ取り込みたい場合です。
まずはfeatureブランチへ移動します。
git switch feature
続いてrebaseを実行します。
git rebase main
これだけです。
実行後の履歴は次のようになります。
main
A --- B --- C
feature
\
D' --- E'
mainブランチの最新コミット、Cに続いて、featureブランチのD'・E'が作られます。
rebase中にコンフリクトが発生した場合
rebase中に同じ箇所を編集していると、コンフリクトが発生することがあります。
例えば次のようなエラーが表示されます。
CONFLICT (content): Merge conflict in sample.php
その場合は対象ファイルを修正します。
git status
修正後に追加します。
git add .
そしてrebaseを再開します。
git rebase --continue
もし作業を中止したい場合は、下記コマンドを実行します。
git rebase --abort
これでrebase前の状態へ戻せます。
コミットをまとめる(git rebase -i)
rebaseの便利な機能として、コミットをまとめることもできます。
例えば次のような履歴があるとします。
A 修正
B 修正
C 修正
細かくコミットしすぎてしまった場合、下記のようにrebaseコマンドに
-iオプションをつけて実行します。(HEAD~3で3つ前のコミットです)
git rebase -i HEAD~3
すると、下記のような画面が表示されます。
pick aaa A修正
pick bbb B修正
pick ccc C修正
これを次のように変更します。
pick aaa A修正
squash bbb B修正
squash ccc C修正
そして保存すると、3つのコミットがA修正の1つにまとめられます。
プルリクエスト前の履歴整理でよく利用される方法です。
Git rebase後にpushできない場合
rebaseを実行するとコミットIDが変わります。
そのため、すでにリモートへpush済みの場合は通常のpushが失敗します。
git push
! [rejected]
この場合は強制的に履歴を更新します。
git push --force-with-lease
--forceよりも安全なため、基本的にはこちらを利用しましょう。
Git rebaseの注意点
git rebaseを使う時の注意点です。
共有ブランチには使わない
他のメンバーも利用しているブランチでrebaseすると、コミット履歴が書き換わります。
すると他の開発者の履歴とずれてしまい、トラブルの原因になります。
基本的には次のルールがおすすめです。
- 自分専用ブランチ → rebase OK
- 共有ブランチ → rebase非推奨
mainブランチでは慎重に扱う
本番運用中のブランチでrebaseすると履歴が変更されます。
チーム開発では特に注意しましょう。
Git rebaseとmergeはどちらがよい?
結論としては、開発中はrebase、統合時はmergeという使い分けが分かりやすいです。
例えば次の流れです。
- featureブランチで開発
- rebaseで最新mainを取り込む
- Pull Requestを作成
- mergeでmainへ統合
この方法なら履歴も見やすく、安全に運用できます。
rebaseは開発ブランチへの取り込みや、コミットをまとめるなど、開発中のブランチで使うと良いかと思います。
まとめ
git rebaseを使うと、コミット履歴をきれいに整理できました。
主なコマンドはこちらです。
git rebase main
コンフリクト解決後の再開
git rebase --continue
中止する場合
git rebase --abort
コミットをまとめる場合
git rebase -i HEAD~3
ただし、rebaseは履歴を書き換える操作です。
共有ブランチでは慎重に利用し、基本的には自分の作業ブランチで使うようにしていきましょう。
コメント