git pull と git pull –rebase の違いって?図を交えて説明します! このエントリをはてなブックマークに登録

2015年07月22日

asachunasachun /

はじめに

こんにちは、クレイの亀井です。ここ最近一気に気温が上がりましたね。顔に重点的に汗をかくタイプの私には憂鬱な季節がやってまいりました😩💦

さて、今月正式リリースしました(!) DocBase プロジェクトではクレイ外部のデザイナーの方と一緒に開発しています。SourceTree で Git を使っている方で、軽いデザイン修正などは弊社の Rails プロジェクトに直接手を加えてプルリクエストを送ってくれます。

こちらのデザイナーさんに「プルリクエストを送る際は、作業ブランチで git pull --rebase origin master してから送ってもらえますか?」とお願いすると「pull はわかるんですけど、この --rebase ってなんですか?これつけると何が変わるんですか?」と質問がきたのです。

作業ブランチで git pull --rebase origin master してほしい理由はなるべく最新の master に近い状態でプルリクエストを送ってほしいからなのですが、デザイナーさんは作業ブランチに最新の master を取り込むのに git pull origin master を使っていました。

なぜ git pull --rebase する必要があるのか、改めて説明しようとするととても難しく、口頭では説明しきれなくて自分自身の力不足を感じました。。

もっと段階を踏んで理解する必要がある

業務の中で Git のことが理解できるようになってからわかったことですが、git pull --rebase を理解するには、なんとfetchmergerebase の3つの Git コマンドをちゃんと理解する必要があります。ヒャー!
この記事では図を交えながら、感覚的に理解できることを目指して説明していきたいと思います。
長くなりますが、ファイトです!

Gitに慣れていない方はこちらをどうぞ。

さっそく説明といきたいところですが!今後の説明に使うので、まずはローカルリポジトリとリモートリポジトリについてさらっとおさらいします。

ローカルリポジトリとリモートリポジトリ

Git にはローカルリポジトリとリモートリポジトリという2種類のリポジトリがあります。ローカルリポジトリは作業者のPCにあるリポジトリ、リモートリポジトリは共用のサーバに設置されているリポジトリです。

ローカルリポジトリで作業して、適宜リモートリポジトリにプッシュするというのがGitを使った開発の大まかな流れになります。

Git のローカルリポジトリには
* ワーキングツリー
* インデックス
* ローカルブランチ
* リモート追跡ブランチ

があります。
Gitの構造

ローカルリポジトリの中に「リモート追跡ブランチ」というのがいますが、これはリモートリポジトリのコピーです。これだけ言われてもなんのこっちゃと思う方もいらっしゃるかもしれませんが、これからの説明の肝になるので注意しておいてください!

ではではざっくり Git の構造を図にしたところで、fetchmergerebasepull & pull --rebase の説明をしていきたいと思います。

git fetch とは

git fetch とは「リモートのコピーをローカルにダウンロードする」コマンドです。ローカルのリモート追跡ブランチ(リモートのコピー置き場)にコピーしてくるだけなのでワーキングツリーには何も影響を及ぼしません。


git fetch

上記のコマンドを実行した場合の動きを、図に表してみます。
git fetch の動きその1

git fetch の動きその2

  1. リモートのコピーちょうだいって言う
  2. ローカルとの差分を見つつ、リモートリポジトリが変更や新規ブランチをリモート追跡ブランチに渡す
  3. リモート追跡ブランチが更新される

ちなみにこの「リモート追跡ブランチ」とはあくまでリモートの状態を示すもので、ユーザー自身がこのブランチの内容を変更することはできません。(内容を見たりとかはできます)また、リモートの状態は自動的に反映されるわけではなく、git fetchコマンドで明示的に行う必要があります。※SourceTreeには自動フェッチ機能があるそうです。(使ったことないのであまりよくは知らないです、すみません)

このリモート追跡ブランチの内容を見たり、ローカルブランチにマージしたりするときは


git merge origin/master

というふうに、origin/ブランチ名 の形でアクセスできます。

git merge とは

git merge とは、今いるブランチに別のブランチの内容を結合させるコマンドです。リモートリポジトリにあるブランチや、ローカルの別のブランチをマージしたいときに使います。

ローカルブランチがこんなかんじであるとしまして(masterhige はブランチ名です)

git merge その1

hige ブランチに master ブランチの内容をマージしたいときは、以下のコマンドを使います。


git checkout hige  // 現在higeブランチにいるなら不要
git merge master

git merge その2

これで hige ブランチの中に master ブランチの内容が取り込まれます。また、マージした場合は「マージコミット」というコミットが積まれます。

また、マージには Fast-ForwordNon-Fast-Forword という2種類のマージがありますが、ここでは割愛します。わかりやすく解説してくださっている方がいるので、そちらを参照してください。

【git】分かりやすく!mergeは「合流」、rebaseは「付け替え」!

リモートリポジトリのブランチをマージする場合

ちなみに、上記のコマンドはローカルリポジトリの master ブランチをマージするものなので、リモートの master ブランチをマージするには以下のコマンドを実行します。


git fetch // 先にリモートの状態をリモート追跡ブランチにコピー
git merge origin/master // リモートのコピーからマージ

まず git fetch でリモートにリモート追跡ブランチを合わせたあと、
git merge その3

git merge origin/mastermasterorigin/master の差分が取り込まれます。
git merge その4

origin/ブランチ名 はリモート追跡ブランチのことでしたね。(fetch のセクション参照)git merge コマンドでリモートのブランチをマージしたい場合は、いったんリモートのコピーをとってきて、そのコピーをマージするという手順になります。

git rebase とは

git rebase とは、merge と同じく今いるブランチに別のブランチの内容を取り込むコマンドですが、merge とは動きが違います。

前提は、git merge の時と同じこちらの状態です。

git merge その1

この状態で、hige ブランチを master にリベースしたい場合、以下のようになります。


git checkout hige // higeブランチにいるなら不要
git rebase master

まず、hige ブランチにあるふたつのコミットを一時的に保存、hige ブランチをリベース先のブランチに git reset --hard します。

git rebase その1

リセット後の hige ブランチの上に一時保存していたコミットを乗せます。

git rebase その2

hige ブランチの猫には口がなかったのに、リベース後は口がついてますね。差分がコンフリクトしていなければ Git がうまいことくっつけてくれます。(コンフリクトしたときはエディタを開いて手動で直しましょう。。。)

ただ、マージと違ってリベースの場合はコミットを新しく作りなおすので、リベース前とはコミット自身の id と親の id が変わります。master の変更を取り込んで別物になったので当然ですね。

git rebase その3

親のidが変わると、すでにリモートリポジトリにブランチをプッシュしていた場合、リモートにあるブランチの親の id が一致せずプッシュできなくなり(rejectされ)ます。(git push -f で強制的にプッシュできますが、よくわかっていないうちは使わないほうがいいでしょう。)

マージは現在のブランチの上に他のブランチの内容を取り込むというかんじですが、リベースは取り込みたいブランチの上に今のブランチの内容を乗せるといったかんじですね。

git pull とは

git pull とは、さきほど説明したgit fetchgit merge をいっぺんに実行するコマンドのことです。

git merge のセクションで言っていた以下のコマンド。


git fetch // 先にリモートの状態をリモート追跡ブランチにコピー
git merge origin/master // リモートのコピーからマージ

こちらのコマンドは、


git pull origin master

とイコールです。フェッチしてからマージするのMENDOIと思うようになったら使いどきです。

git pull --rebase とは

ついにお待ちかねの git pull --rebase です。

--rebasegit pull コマンドのオプションです。git pullfetch + merge ですが、--rebase オプションをつけると fetch + rebaseとして実行します。


git pull --rebase origin master

git pull と git pull --rebase の違い

冒頭で以下の様なやりとりをデザイナーさんとしていますが、

「ブランチを git pull --rebase origin master してからプルリクエストを送ってもらえますか?」

なぜこのようなお願いをしたかといいますと、--rebase オプションをつけてプルしたほうがマージコミットが作られない&履歴が綺麗になるからです。

git pull --rebase だと履歴がきれいになる

このときに --rebase オプションをつけなくても「作業ブランチに最新の master を取り込む」という目的は達成できるのですが、上記の理由があるため作業ブランチに master を取り込むときは git pull --rebase でお願いしていました。

ただこちらはいろいろ議論がありまして、(「ログが綺麗になるとしても履歴を書き換えるべきではない」など)いきなりリベースをするとチームの規約に反する場合もありますので、そのあたりは事前にチームの人に確認してください。

また、マージするのに比べてリベースするほうが差分がコンフリクトしたときに修正するのが面倒なときがあったりするので、あまり Git に慣れていないうちは git merge でリモートリポジトリの差分を取り込むほうがいいかもしれません。

最後に

git pullgit pull --rebase の違いを説明するだけなのに、なんだかとても長くなってしまいました。そして、書くのに時間がかかりすぎて冒頭で質問してくれたデザイナーさんはすでに DocBase チームから離れていました。。。Kさん、見ていらっしゃいますでしょうか…?

Git はコミットさえしていれば間違えてコミットやブランチを消してしまっても元に戻せる方法があるので、テスト用のブランチを切って試してみるのもいいかもしれません💪元に戻しやすいのは Git のいいところのひとつですね!

ここまで読んでくださった方、ありがとうございました!この記事を読んで Git の理解が少しでも進めば幸いです。

宣伝

DocBase
安全性に優れ、柔軟な権限設定が可能な情報共有サービス DocBase を本リリースしました。
DocBase

DocBaseとは

DocBaseとは、成長する組織のための情報共有サービスです。
成長とともにメンバーが増加する中でも円滑に情報共有を行うことを可能にします。エンジニア以外のメンバーでも使いやすい仕組み、柔軟な権限設定によって従来の情報共有ツールで起こりがちだった心理的ハードルを下げ、積極的な情報共有と業務の効率化を実現します。

詳しくはこちらから。
http://kray.jp/news/docbase/

クレイについてもっと知りたい方は…

  1. クレイの3つの強みを見てみる。
  2. WEBシステムのことなら何でもご相談ください。

「いいね!」で応援よろしくお願いします!

このエントリーに対するコメント

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


トラックバック
  1. Git トピックブランチに統合ブランチをマージする & rebaseについて - くまおの森2016/02/19, 3:20 PM

    […] こちらのサイトの方が、図があってとってもわかりやすいです。 http://kray.jp/blog/git-pull-rebase/ pull […]

we use!!Ruby on RailsAmazon Web Services

このページの先頭へ