💭

git rebaseの具体的なメリット

2022/10/16に公開

はじめに

git使用歴1年以下の初心者です。現職場に転職してから使い始めました。
流石にcommitやpushは最低限できるようになったものの、git rebaseは恐怖心からずっと避けていました。
また何となくの役割は分かるものの、(初心者すぎて)具体的な開発でのメリットが分かってなかったので、ここで一度向き合いたいと思います。

git rebaseの基本

大きな役割の一つが指定ブランチの分岐点を変えることで、mergeのように、メインブランチの変更を開発ブランチに取り込みたい時に使えます。

例えば下記のように、masterブランチとfeatureブランチがあります。
featureはmasterのコミットBから生えています。masterは他のチームメンバーのコミットによりコミットDまで進んでいます。

ここでfeatureにチェックアウトした状態で、masterに対してgit rebaseを行います。

$ git checkout feature
$ git rebase master

するとfeatureのコミットがmainブランチの先頭にまるっとコピーされます。
下記だとコミットEがE'としてコピーされるイメージです。また移動ではなく、あくまでコピーなのでコミット番号は変わります。

結果元々コミットBから生えていたfeatureは、git rebaseによりmainのコミットDから生える形に変更されます。
これでmasterの変更を取り込むことができました。

git mergeとの違い

さらっとmergeでmasteの変更を取り込む場合も見ておきましょう。
mergeの場合、masterをfeatureに取り込む際にマージコミットが必ず作られます。
featureの分岐点は変わらず、既存コミットにも影響しません。

具体的なメリット

結局履歴が一直線になると何がいいのでしょうか。
今回はダミーで下記のようなブランチを用意しました。

mainとしてdevelopmentブランチ、開発用としてfeature/issue01と名づけています。今回もdevelopmentはissue01に対して少し進んでいる状態です。
developmentの変更をissue01に取り込みながら、rebeseの具体的なメリットを見ていきます。

1.ぱっと見で履歴が見やすい

まずmergeでdevelopmentを取り込んでGUI上での履歴を見てみます。下記のようにマージコミットが作られてマージされました。

次にrebaseで取り込んだ場合を見てみましょう。

前述の通りmergeでは必ずマージコミットが作られます。そのため実際の変更の内容を知りたいときはマージコミットの中身を見に行く必要があります。(メッセージを変更すればいいけど少し面倒)

またGUI上の見た目としても、マージの度にでブランチの線が重なっていきます。それがブランチの変更を取り込む = マージコミットを作るたびに繰り返されるので、とても見づらくなる可能性があります。

その点rebaseだとマージコミットが作られず、履歴が一直線に並ぶので変更履歴が見やすくなります。

2.常に最新のメインブランチを取り込んでコミットできる

mergeするとdevelopmentとissue01のコミットが単純に時系列順に並びます。
そのためissue01で機能を追加したコミットの後にmergeを行うと、もちろんissue01の機能追加後にdeveopmentの変更コミットが入ってきてしまいます。
正しくコンフリクト解消やテストができていれば問題ないですが、確認の手間も増えますし、履歴の見やすさ的にも少し微妙です。

▼issue01でのコミット([issue01]Third Commit)後にdevelopmentの変更(マージコミット)が入ってきている

rebeaseの場合だと、指定ブランチの最新コミットを分岐点とするため、常にメインブランチの最新の変更を取り込んだ上に機能を追加することができます。

3.1つ1つのコンフリクトが小さい

mergeの場合はブランチ同士の最終的な差分を付き合わせてコンフリクトを判断します。
そのため場合によってはコンフリクトが大きくなりすぎることがあります。

一方のrebaseは各コミットごとにコンフリクトを判断し、その度にコンフリクトを解消できます。結果コンフリクトの粒度が比較的小さく済みます。

※git rebaseでの具体的なコンフリクト解消手順はこちらに書かれています。

(注意)必ず自分だけが使うブランチのみで使用する

前述の通りrebaseではブランチの分岐を変えてしまいます。
そのため複数人が使用するブランチでrebase&pushすると、他の人から見えるブランチは元々の分岐点から生えたブランチのため整合性が合わなくなります。
git rebaseの話で必ず言われることですが、自分だけが使うブランチしか使わないようにしましょう。

ちなみに間違えてrebaseした場合は、下記コマンドで修正することができます。

$ git reflog
$ git reset --hard HEAD@{00} 
// ↑'00'には、reflogで表示された戻したいポイントのハッシュ番号が入ります

(おまけ)interactive(インタラクティブ)モード

rebaseにはinteractiveモードがあり、過去コミット内容の変更や、コミットの合体などが行えます。
詳しくはこちらの記事が分かりやすかったです。

まとめ

  1. git rebaseはブランチの分岐元を変えることで、メインブランチの変更を取り込める
  2. 履歴が一直線になるので見やすい
  3. コンフリクトでのミスの可能性も軽減できそう

git rebase = 歴史改変、初心者は使わない方がいい、というイメージだけで避けていたのですが、調べてみるとかなりメリットが多いコマンドでした。
メリット・デメリット理解して今後は積極的に使用していこうと思います。

参考

Discussion