1. HOME
  2. ブログ
  3. IT技術
  4. 【Git】rebaseについて解説

【Git】rebaseについて解説

目次

rebaseとは

Gitに用意されているコマンドの一つになります。指定ブランチに連なっているコミットを別ブランチの最新コミットに続く形でつけかえる(rebase)ことができます。指定ブランチの内容を取り込むという意味ではgit mergeコマンドに似ていますが、rebaseにはmergeにないメリットがあるため使い分けられています。ただmergeと比べるとややこしい部分があるため、細かく解説していこうと思います。

解説

まずrebaseを実行した際にどういった変更がブランチに加わるのか図で見ていきます。
以下構成のブランチがあるとします。

developブランチ(以下develop)のBコミットから派生したfeatureブランチ(以下feature)のEコミットがあり、それにF、Gというコミットが連なっている状態です。

カレントブランチをfeatureとした状態で以下を実行します。

もしカレントブランチがdevelopになっている場合は以下のコマンドでも上記コマンドと同様の結果にすることができます。(featureにチェックアウトした後rebaseを実行してくれる)

するとブランチ構成は以下のように変更されます。

派生の起点がBコミットからDコミット(developの最新コミット)に移動したことがわかります。
また、featureブランチのコミットにシングルクォーテーションがついたことに注目してください。
これはコミット番号が変わったことを表現しており、rebase前のブランチとは履歴上別コミットとして扱われます。

mergeとの違い

先程と同じrebase前のブランチ構成でmergeコマンドを実行してみましょう。

すると以下のようになります。

rebaseとの違いがはっきりわかりますね。mergeの場合、developのコミットを含めた新たなコミットHがfeatureに作成されます。また、B→Eの分岐点は変わっておらずE, F, Gのコミット番号はそのままになります。

コンフリクトの解消方法

コンフリクトの解消方法においてもrebaseとmergeで少し動きが異なります。コンフリクト箇所を修正するという点は共通ですが、rebaseの場合各コミットごとに適用していくことになります。具体的には、以下のブランチ構成だったとしてE, Fコミットはdevelopでの修正箇所と被っているとします。

この状況でgit rebase developを実行するとまずEコミットがdevelopと競合がないか検証されます。今回Eコミットはdevelopと修正箇所が被っているというシチュエーションのためコンフリクトが発生します。

コンフリクトを解消するための修正を加えた後、対象のファイルを git add することでステージングします。これで一区切りになっており、次のFコミットをdevelopに適用するには以下のコマンドを実行します。

developに適用されていない残りのコミットがコンフリクトしなければここでrebaseが完了となりますが、今回Fコミットはdevelopと競合すると言う条件なので再びコンフリクトします。

Eコミットのときと同じように対応し、コンフリクトを解消しステージングします。そして再度git rebase --continueを実行することでrebaseが完了となります。(Gコミットはdevelopと競合していないため対応不要)

これでコミット履歴が整理されましたが、rebaseにはコミットをまとめる機能が存在します。
これを利用し履歴を更に整理していきます。履歴がきれいになるイメージをしやすくするために上記記載のrebase後のブランチを再現してみました。

rebase したことにより、developの最新コミットであるCommitDの後に続く形でCommitE, F, Gが存在します。きれいな一直線になっていますね。ここからさらにCommitE, F, Gを1つにまとめることで、より一層履歴を見やすいものにすることができます。

そのためには以下のコマンドを実行します。

HEADの部分はgit log --onelineコマンドを実行した際のHEADとなっているコミットから3つ分のコミットを示しています。ここで指定したコミット(E, F, G)をこれから1つにまとめていきます。

rebaseコマンドの-iオプションを実行したことによりvimが開きます。

1行目から3行目を見てみると先程指定した3つのコミットが記載されており、先頭には「pick」というワードがあります。この「pick」を指定したコミットが、rebase先に適用する際に使用されます。今回はコミットをまとめたいのでコミットE以外は「pick」ではなく「fixup」を指定します。「fixup」は指定したコミットを直前のコミットに統合します。つまりCommitEにFとGが統合されひとまとめになります。

同じようなコマンドとして「squash」があります。これもコミットを統合するコマンドですが、「fixup」との違いは統合する際のコミットメッセージの扱いです。「fixup」を指定した場合はコミットF, Gのメッセージは無視され、コミットEのメッセージが採用されます。「squash」は特に自分でいじらなければ元々のコミットメッセージが統合されます。

fixupした場合とsquashした場合のコミットログを抜粋したものが以下になります。squashの方は統合前のコミットメッセージが残っていますね。

コミットを統合しているという意味はfixupsquashも同じなので、プロジェクトの方針やお好みに合わせて使い分ければいいと思います。

これでコミットを整理することができました。ログを確認するとdevelopの最新コミットであるコミットDの後に、先程統合したコミットEが並んでる形になっています。

まとめ

今回はrebaseの使い方について紹介しました。今までmergeしか使ってこなかったので、最初は手こずりましたが慣れるとコミットログが整理されて見やすいため便利に感じました。ただ後々ログを見返すことがない場合やプロジェクトの方針で特に使用する必要がない場合はmergeの方が楽なのでどちらを使うかはケースバイケースかなと思います。

書いた人はこんな人

かじー(エンジニア)
かじー(エンジニア)
フルスタックエンジニアとして活躍することを目指す新米エンジニア。
現在はバックエンドを担当しており、日々奮闘中。
プログラムを組んで課題を解決することが好きなため
休日も開発に勤しむことも、、、

関連記事

採用情報

\ あの有名サービスに参画!? /

バックエンドエンジニア

\ クリエイティブの最前線 /

フロントエンドエンジニア

\ 世界を変える…! /

Androidエンジニア

\ みんなが使うアプリを創る /

iOSエンジニア