git fetch と pull の違い。「取ってくる」だけか、「取り込む」までか

左で雲のリモートから荷物を受け取って玄関に置く(fetch)。右でその荷物を部屋の中まで運び入れる絵(pull)
目次
  1. 取りに行くまで、Git は更新を知らない
  2. 玄関の荷物は、開ける前に中身を見られる
  3. 玄関の荷物を、部屋に入れる
  4. pull は、この2つを、1つにしたもの
  5. pull が、止まる日
  6. 結局、どっちから使えばいい?
  7. まとめ

友だちから、メッセージが届きます。「共有フォルダに、新しい資料を入れたよ」。でも、自分のパソコンにある資料は、まだ古いまま。自分から取りに行かなければ、新しい資料は手元に来ません。

Git でも同じことが起きます。だれかがリモートに更新を push しても、Git はそれを勝手には教えてくれません。取りに行くためのコマンドが、git fetch と git pull の2つです。

「どっちを使えばいいの?」「違いは何?」と、手が止まったことはありませんか。

取りに行くまで、Git は更新を知らない

先に、こんな場面を見てください。相手が先に push したあとで、自分の git status を見ます。

$ git status
On branch main
Your branch is up to date with 'origin/main'.

「リモートと同じ」と言っています。でも、リモートには、すでに新しい更新が入っています。origin/main は、リモートの main を最後に取りに行った時点の姿で、手元に記録したものだからです。取りに行くまで、この記録は古いまま。だから git status は「同じ」と答えてしまいます。

取りに行くコマンドが、fetch です。

$ git fetch
From (リモートの URL)
   2199620..a795d69  main       -> origin/main

Pro Git(Git の公式の解説書)は、fetch を、リモートのプロジェクトから、まだ持っていないデータをすべて取ってくるコマンドと説明しています。

そのあとの git status は、こう変わります。

$ git status
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)

「1つ遅れています」。fetch して、はじめて遅れていることが分かりました。

左に、雲の形のリモートから荷物が届く絵と「fetch = 取ってくる」。荷物は、玄関に置かれたまま。右に、荷物を部屋の中に運び入れる絵と「pull = 取り込む」

荷物でいえば、宅配便を受け取って、玄関に置いた状態です。家(手元)には届いています。でも、部屋(自分のブランチ)には、まだ入っていません。

玄関の荷物は、開ける前に中身を見られる

荷物が玄関にあるうちは、部屋は何も変わっていません。だから、取り込む前に中身を確認できます。何が届いたかは、こう見られます。

$ git log main..origin/main --oneline
a795d69 Add a line to README

「手元の main にはなくて、origin/main にはある commit」の一覧です。1つ届いています。変更の中身を見たいときは、git diff です。

$ git diff main...origin/main
 hi
+bob line

README に1行追加されています。

玄関の荷物を、部屋に入れる

中身を見て「取り込んで大丈夫」と思ったら、部屋に運び入れます。git merge です。

$ git merge origin/main
Updating 2199620..a795d69
Fast-forward
 README | 1 +
 1 file changed, 1 insertion(+)

取り込んだあとの git status は、こうなります。

$ git status
On branch main
Your branch is up to date with 'origin/main'.

手元の main が、origin/main に追いつきました。

pull は、この2つを、1つにしたもの

Pro Git によると、pull は、現在のブランチがリモートのブランチを追跡しているとき、自動で fetch して、さらにマージまでやるコマンドです。ふつうの設定では、こうなります。

git pull = git fetch + git merge

先ほどとは別の場面で、fetch せずにいきなり pull したときの出力です。

$ git pull
From (リモートの URL)
   a795d69..709ba75  main       -> origin/main
Updating a795d69..709ba75
Fast-forward
 README | 1 +
 1 file changed, 1 insertion(+)

上の2行(From と矢印)が fetch の部分、下の3行が merge の部分です。fetch から取り込みまでを、1回でやってくれました。荷物でいえば、受け取って、そのまま部屋まで運び入れてくれた形です。

pull が、止まる日

pull は、いつもすんなり進むとは限りません。自分の手元にも、まだ push していない commit があるのに、リモートにも新しい commit が入っていたら、どうなるでしょう。

荷物でいえば、部屋の中にも自分の荷物があって、そこへ新しい荷物が届く状態です。Git は「どう合わせるか」を決めなければなりません。設定を何もしていない状態で pull すると、こう止まります。

$ git pull
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
...
fatal: Need to specify how to reconcile divergent branches.

「どうやって合わせるか、指定してください」と言っています。merge で合わせるのか、rebase で合わせるのか。初心者がいちばんつまずきやすい所です。

結局、どっちから使えばいい?

いちばん安全な基本の形は、まず fetch して、中身を見て、取り込むことです。fetch は自分のブランチを変えないので、何が届いたかを見てから決められます。

pull はその近道です。便利ですが、取り込む前に中身を見る機会がありません。さっきの「止まる日」のように、思わぬ形で止まることもあります。慣れるまでは、git fetch → git log main..origin/main → git merge origin/main の順で、1つずつ進めると、手元で何が起きているかがよく分かります。

push が rejected されたときも同じです。git commit と push の違いで書いたように、まず fetch して、中身を見て、取り込んでから、もう一度 push します。

まとめ

  • Git は、リモートの更新を取りに行くまで知らない(fetch するまで、git status は「同じ」と答える)
  • fetch は、リモートの更新を手元に取ってくるだけ。自分のブランチは変わらない
  • pull は、ふつうの設定では fetch + merge。取り込みまでやる
  • 基本は、fetch → 中身を見る → 取り込む。pull はその近道
  • 手元にも commit があるときの pull は、止まることがある

git status が「behind」と言ったら、荷物は玄関に届いています。

コメント 0件 · 新着順

fetch と pull、あなたは、どちらを使うことが多いですか?

投稿するにはログインしてください。読むだけならそのままでOKです。ログイン

まだコメントはありません。最初のコメントを書いてみませんか?