8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Git】mergeとrebase

Last updated at Posted at 2021-08-10

Gitでは、2つのブランチの履歴を統合する方法として mergerebase の2つが用意されています。私自身、rebase についてよくわかっておらず、「どんな時でも merge!」派だった過去があるのですが、 rebase を理解できてからは mergerebase を使い分けられるようになりました。
今日は、mergerebaseの違いについてまとめていきます。

#確認環境

  • Mac
  • git version 2.30.0

#前提

  • 各コマンドの使い方やオプションについての説明はここでは省略させていただきます
  • featureブランチにdevelopブランチを統合する、という操作をそれぞれのコマンドで実行していきます
  • git log コマンドに使用しているオプションについてはこちら git-log からご確認ください

#merge
以下のような履歴を持つリポジトリを使います。

% git log --graph --pretty=format:"%h %s" develop-merge feature-merge
* 49ea0ef develop-merge first commit
| * deefe27 feature-merge first commit
|/  
* 09c96b7 first commit

develop-mergeブランチ、feature-mergeブランチ、それぞれに変更が入っています。featureブランチにdevelopブランチをmergeしてみます。すると、以下のようになります。

% git switch feature-merge
Already on 'feature-merge'
% git merge develop-merge
# コンフリクトが発生しました。解消は割愛させていただきます。
[feature-merge 8b3ec25] Merge branch 'develop-merge' into feature-merge

% git log --graph --pretty=format:"%h %s" develop-merge feature-merge
*   8b3ec25 Merge branch 'develop-merge' into feature-merge
|\  
| * 49ea0ef develop-merge first commit
* | deefe27 feature-merge first commit
|/  
* 09c96b7 first commit

8b3ec25 という新しいマージコミットが生まれています。また、マージコミットの親となるコミットが2つ(49ea0ef と deefe27)になり、枝分かれしています。このようにmergeコマンドを使用すると、今までの履歴に影響を与えずに新しいコミットを生み出し2つのブランチの履歴を統合します。

※FastForward状態になるとマージコミットが生まれません。ここでは説明を割愛します。

#rebase
mergeの例と同様、以下のような履歴を持つリポジトリを使います。

% git log --graph --pretty=format:"%h %s" develop-rebase feature-rebase
* 49ea0ef develop-merge first commit
| * deefe27 feature-merge first commit
|/  
* 09c96b7 first commit

develop-rebaseブランチ、feature-rebaseブランチ、それぞれに変更が入っています。featureブランチにdevelopブランチをrebaseしてみます。すると、以下のようになります。

% git switch feature-rebase
Switched to branch 'feature-rebase'
% git rebase develop-rebase
# コンフリクトが発生しました。解消は割愛させていただきます。
[detached HEAD 9159f39] feature-merge first commit
 1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/feature-rebase.

% git log --graph --pretty=format:"%h %s" develop-rebase feature-rebase
* 9159f39 feature-merge first commit
* 49ea0ef develop-merge first commit
* 09c96b7 first commit

先ほどのmergeの例とは違って、履歴が一直線になりました。また、新たなコミットも生まれていません。
ですが、よくみてみると、 feature-merge first commit というメッセージのコミットのcommitIDが変わっています。

  • rebase前
  • deefe27 feature-merge first commit
  • rebase後 
  • 9159f39 feature-merge first commit

rebaseコマンドを実行すると、rebase先のブランチの先頭コミット(今回はdevelop-rebaseの49ea0ef)に対して、現在チェックアウトしているブランチの新しい変更(今回はfeature-rebaseのdeefe27)を適応する、といったことが行われます。このような挙動によって、mergeの時とは違って履歴が一直線になります。またdeefe27コミットはIDが変わります。

#merge と rebase
しばしば、「rebaseを使うとコミットの履歴が綺麗になる」と言われますが、上記のように、一直線の履歴になる、マージコミットがない、といったことがそのように言われる理由にだと思います。
しかし、rebaseはmergeと違ってコミット自体を書き換えてしまいます。そのため、メンバーと共有しているリポジトリ内でrebaseを使うと他のメンバーがpullできない、pushできない、といった事態も起こりかねません。このあたりはチームによって運用が異なると思います。

###使い分けの一案
私が実際に行っている使い分けです。あくまで一案になります。

  1. 開発の最新となるdevelopブランチからfeatureブランチをきる
  2. featureブランチで作業を行い、コミットする
  3. featureブランチにdevelopブランチをrebaseする
  4. developブランチに対してfeatureブランチをプルリクする
  5. developブランチにfeatureブランチをmergeする(実際はプルリクエストのマージ)

上記のように作業を行うことで、featureブランチの履歴は一直線になり、マージコミットなども入らずに、レビューがしやすいです。一方、開発の中心となるdevelopブランチにはmergeを行います。こうすることで、developブランチの履歴にはmergeコミットが残り、どのタイミングでどのプルリクエストがマージされたのかが分かりやすくなります。

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?