みなさんこんにちは!フリーランスプログラマーのsatoです。
今回はgitのrebaseコマンドについて見ていきます。実はこのコマンド。なかなかに取り扱いが難しいコマンドです。使いこなせれば、ログを綺麗に保つことができるようになり、非常に良い効果をもたらすでしょう。
しかしその反面、その本質を理解せず使用すると、一部のログが表示から突然消えるなどチームに混乱をもたらします。そのため、個人的にもしっかりと、理解しその上で扱ってほしいコマンドだと考えています。
- [基本]rebaseとは
- [基本]2つの主要な使い方!
- [応用]mergeとの使い分け方
今回はまず「rebaseコマンド」の本質を、図を見てで学んでいきましょう。そのあとで、この手の話で、必ず話題に上がるmergeコマンドとの違いについて見てきましょう。それではよろしくお願いいたします。
rebaseとは
まずrebaseコマンドを一言で言い表せば「指定したコミットを、ブランチを変えて作り直したり、ひとまとめにしたりして、ログを綺麗にするコマンド」です。
もっとシンプルにいえば「指定コミットを作り直して、ログを掃除するためのコマンド」とも言えるでしょう。と言葉で言っても理解しづらいと思います。その実践的な使い方を、図とともに見ていきましょう。
rebaseの2つの主要な使い方!
では早速説明に入りたいところですが…。実はrebaseには主に2種類の使い方が存在します。
片方は「別々のブランチで伸ばしていた開発コミットを繋げ直す」といった使い方。もう片方は「複数のコミットを1コミットにまとめる」という使い方です。それぞれ見ていきましょう。
開発コミットを繋げ直す
まずは「別々のブランチで伸ばしていた開発コミットを繋げ直すといった使い方から見ていきます。
まずは図で見てみよう
まずは何ができるのか図で見ていきましょう。
例えば以下のような開発状況があったとします。丸部分はコミットです。「ブランチA」「ブランチB」でそれぞれ開発が進んでいました。
そんな時、「ブランチA」を「ブランチB」へ取り込む必要が出てきたとします。
単純にマージするなら以下のようになるでしょう。
しかしrebaseコマンドを利用すると以下のようになります。
ブランチAの先から、ブランチBの更新内容を新規コミットとして、生成し繋げ直すことができるわけです。
マージと、の違いを図で見てみましょう。
rebaseの方が、更新ログが一直線で見やすいですね!これなら過去の更新履歴を追う時も見やすいです。
このようにブランチごとに進んでいる開発を、繋げ直し掃除を行うことが、「rebaseコマンド」の機能の一つです。
コマンドの詳細を見てみよう
では早速繋ぎ直した時に使用するコマンドを見てみましょう。
今回は、自分はブランチBを使用していることにします。その状態で以下のコマンドを打ちましょう。
例:
git rebase [つなぐ元にするブランチ名]
rebaseコマンドの後ろに、つなぐ元にするブランチ名をつけるだけです。
※コミットIDを指定することもできます。
使い方は非常に簡単ですね!もう少し実例で見てみましょう。例えば、さきほどの画像の状況を実現させるのなら…
ブランチBをチェックアウトしたのち、以下のコマンドを打ちましょう。
実例:
git rebase ブランチA
ここまででrebaseの有用性と、使い方を理解していただけたと思います。
複数コミットを1コミットにまとめる
次にもう一つのrebaseの使い方を見ていきましょう。
まずは図で見てみよう
今回はブランチAを使用していることにします。そして以下のような開発の進捗があったとしましょうか。
そしてこの4つのコミットABCDが、非常に細かい修正で「ひとまとめにしたいな…」なんて考えが頭をよぎった時は…
rebaseコマンドの出番です。rebaseコマンドの「-i」オプションを利用すれば、複数コミットを1コミットへまとめることができます。
こんな風に「新規コミットE」として、指定した複数のコミットを作り直すことができるわけです!どうでしょう。これもなかなか有用そうではありませんか。
コマンドの詳細を見てみよう
複数コミットを1コミットにまとめるには、「-iオプション」を使用した以下のコマンドを打つ必要があります。
git rebase -i [ひとまとめにする地点の一つ前のコミットID]
[ひとまとめにする地点の一つ前のコミットID]がわかりづらいですね…
画像を元に何を指定すれば良いのか見ていきましょう。
上記画像を実現するのなら「開始地点コミットのコミットID」を指定する必要があります。それを指定することで「開始地点コミット 〜 現在位置」までの、「コミットABCD」をひとまとめにすることができるわけです。
また該当コマンドを打った直後、どのコミットをひとまとめにするかの指定画面が表示されます。ちょうど以下のような画面です。
pick d9a1f0e コミットA pick 400f340 コミットB pick f35185d コミットC pick 8dfc486 コミットD
この画面でどのコミットをひとまとめにするか指定しましょう。
統合するコミットの「pick(何もしない)」部分を「squash(統合する)」に変更し、保存して終了すれば、統合が実行されます。ただしこの際、先頭のコミットは統合元となるため、pickのままにしなければなりません。その点に注意しましょう。
pick d9a1f0e コミットA squash 400f340 コミットB squash f35185d コミットC squash 8dfc486 コミットB
全部統合するならこんな感じですね!
mergeとの使い分け方
ここまででrebaseの基本は学べたと思います。そこで最後に、よく比較して説明にあがるmergeコマンドとの使い分け方について見ていきましょう。
「mergeコマンド」について、わからない人は詳細は以下のリンクをお読みください。
mergeとrebaseの違い
具体的な使い分け方ですが、まずは二つのコマンドの一番の違いについて着目しましょう。二つのコマンドの一番の違いは「既存のコミットへ影響を与えるか・与えないか」です。
最初に説明した通り「rebaseコマンド」は、処理を作り直してしまいます。対して「mergeコマンド」は既存コミットに影響を与えずにマージコミットを作成してくれます。この点がこの二つの一番の違いです。
そしてこの点が「共同開発」を行っているときに重要な点になってきます。
共同開発の側面から見たとき
ある日、自分の上げたはずのコミットがなくなってしまっていた!そんなことになったら、非常にこまりますよね!
そう、共同開発をしている以上「rebaseコマンド」を安易に使用すると、誰かのコミットを勝手に作り直すことになり、チームに混乱を招くわけです。
つまり…
誰にも影響を与えない「まだpushしていない、ローカルの開発内容」だったら、rebaseを使用しても大丈夫です。
逆に一度でもpushして誰かの目に一度でも触れた処理や、他の人の手の入っている箇所では、rebaseは絶対に使わないようにしましょう。その場合はmergeを使用しましょう。
まとめ
今回はrebaseについて一通り見てきました。ログを綺麗に保つことができる、強力なコマンドです。
しかしその分、ある意味で破壊的なコマンドでもあります。特に共同開発を行っている場合は、ルールを守った上で上手に利用していきましょう。