Help us understand the problem. What is going on with this article?

【Git】リモートからの取得とリモートへの反映で行っていること(fetch,pull,push)

More than 1 year has passed since last update.

fetchはリモートの「情報」を取ってくるだけ、
pullは情報を取ってきて、さらに実データをローカルに反映する。
という理解でした。

でも、fetchで何やら情報を取得している様子なのに、その後行ったpullでは何も情報が取得されない。
ということが有ったので、fetchって一体何をしているの?ということで調べてみた。

まずはブランチについて

ブランチの種類

image

ローカルブランチ

ローカルで開発するときにcheckoutで開いてコミットしていくお馴染みのもの。

master
develop
feature/topic

ローカルで作成したブランチは、pushすることでリモート追跡ブランチにも反映される。

リモート追跡ブランチ

ローカルに保持している、クローン元リポジトリのブランチを取り込んだもの。
反映はfetchやpullコマンドを実行したタイミングであり自動取得はしないので、
いつの間にかリモートリポジトリ側と不一致になっていたということも有る。

git branch -a

とすると、

remotes/origin/master
remotes/origin/develop
remotes/origin/feature/topic

と表示されるもので、
コマンドのパラメータには、

origin/master
origin/develop
origin/feature/topic

と書く。

ローカルブランチとしてcheckoutするには、
origin/を外して、

git checkout feature/topic

とする。この時、ローカルブランチとリモート追跡ブランチのorigin/feature/topicが紐づけられる。

なお、リモート追跡ブランチは、あくまでも「リモートを"追跡する"ブランチ」なので、これをローカルでcheckoutしてコミットすることは出来ない。

git checkout origin/feature/topic

は不可。

リモートのブランチ

クローン元リポジトリにおけるローカルブランチ。
間接的にリモート追跡ブランチを通じてしか知り得ない。

リモートから取得する

手順としては、
1. リモートの情報を取得する
2. ローカルブランチにマージする
を行います。

この時、fetch, pull, merge, rebaseなどのコマンドを使います。

  • fetchコマンドでリモートの情報を取得する

fetchコマンドは、前回取得して以降に更新された、全ブランチの全コミットデータを取ってきます。

この時、

「リモート追跡ブランチ」のみに反映します。ローカルブランチは変更しません。
コミットは、ローカルとリモート両方を共存する形で保持します。ローカルのコミットは変更しません。

なので、fetchではローカルのブランチとコミットには影響しない、ということになります。

  • pullコマンド

fetch + mergeの動作を行います。
fetchで全ブランチの全コミットデータを取得してから、checkout中のカレントブランチに、対応するリモート追跡ブランチをマージします。

パターン別のリモートからの取得方法

具体的にどういう動きをしているかパターン別に見てみましょう。

必要に応じて、
[Git] 脱初級!誤コミットはもう怖くない
の「ブランチは枝では無い」辺りも参考にして下さい。

ローカルに無いリモートブランチ

リモートで作成されたブランチを初めて取得してくる時の動きです。

fetchで情報を取得する

  • リモートブランチ

image
リモートにdevelopブランチが新規に作成され、コミットA,B,Cが存在する状態。

git fetch
  • fetch後のローカル環境

image

のようにコミットA,B,Cとブランチ「origin/develop」がローカルに作成されます。

ただし、作成されるのは「リモート追跡ブランチ」(origin/develop)のみで、ローカルブランチは作成されません。

  • ローカルブランチの作成

ブランチ名から origin/ を外した、

git checkout develop

でローカルブランチが作成されます。

image.png

参考) リモート追跡ブランチに無いブランチをローカルで作成する場合は、branchコマンドを使う必要が有ります。

 

ローカルでコミット無し、リモートでコミットされていた場合

fetchでリモートの情報を取得する

  • リモートブランチ

developブランチに新しくCがコミットされている状態。
image

  • fetch前のローカルブランチ

リモート追跡ブランチ origin/develop は、前回fetchで取得した時の状態。
image
ここで、fetchを実行すると。

git fetch
  • fetch後のローカルブランチ

image

のように、ローカルブランチにリモートのコミットCが継ぎ足されて、
リモート追跡ブランチorigin/developが更新されます。
ローカルブランチdevelopは変更されません。

注意点として、この状態からローカルブランチdevelopにコミットしてしまうと、
image
のように枝分かれしてしまいます。

対処法としては、fetchしたら速やかにマージするというところでしょうか。
そういう意味では、fetchとmergeがセットになっているpullを使うのがいいのかもしれません。

ローカルブランチにマージする

fetchにより以下図の状態になっています。

image

リモートのコミットをそのまま受け入れるだけでいいので、いわゆるFast-Forwardマージのケースです。
動作としては、developブランチがorigin/developのところに移動するだけです。

  • merge コマンド
git checkout develop
git merge origin/develop
  • pull コマンド

fetch + mergeと同じ動作です。

git checkout develop
git pull

pullの引数無しの場合、カレントブランチのみが対象となります。

  • rebase コマンド
git checkout develop
git rebase origin/develop

これらのコマンドはどれでも、以下状態になります。
image

(オプション指定によっては変わってきますが。とりあえず標準動作として)

ローカルでコミット有り、リモートでコミット無しの場合

image

リモートに更新情報が無いのでfetchやpullを行っても何も変化は有りません。
むしろ、Dコミットをリモートに反映させる必要が有ります。

ローカルとリモート両方でコミット有りの場合

fetchでリモートの情報を取得する

  • リモートブランチ

developブランチに新しくCがコミットされている状態
image

  • fetch前のローカルブランチ

前回fetchをしたコミットBから新しくDがコミットされている状態
image

git fetch

以下図のように、リモートのコミットCを別の枝として取り込むので、
ローカルブランチには影響が出ません。

  • fetch後のローカルブランチ

image

ローカルブランチにマージする

developにorigin/developを取り込みます。
ある程度はGitが自動マージしてくれるのですが、同じファイルの同じ場所を編集していた場合は、
手で編集する必要が有ります。

  • merge コマンド
git checkout develop
git merge origin/develop

image

ローカルにマージコミットEが新しく作られdevelopブランチが更新されます。
リモートより先に進むので、リモートに反映させる(pushコマンド)必要が有ります。

  • pull コマンド
git checkout develop
git pull

fetch + mergeコマンドと動作、結果は同じです。

  • rebase コマンド

origin/developが指すコミットCの後ろにdevelopブランチのコミットDを移動します。

git checkout develop
git rebase origin/develop

image

リモートへの反映

originよりローカルブランチの方がコミットが進んでいるケースです。

  • ローカルブランチ

前回fetchしたコミットBから、ローカルに新しくCがコミットされた状態
image

pushでカレントブランチのコミットをリモートに反映します。

git checkout develop
git push

pushは、checkoutで開いたブランチのみをリモートに反映します。
(注意:gitのversion 1.x系は、リモートと紐づいている全てのブランチをリモートに反映するのがデフォルト動作なのでご注意下さい。必要に応じて、ブランチ名を指定するかオプションでデフォルト動作を変える必要が有ります)

これにより、リモートリポジトリ及び自リポジトリ内のリモート追跡ブランチorigin/developに、
ローカルブランチdevelopが反映されます。

image

あと、ローカルでブランチを新規作成してコミットしたものをリモートに反映する場合も同じです。

まとめ

  • fetchは全ブランチの全コミットの情報を取ってきている
  • fetchはローカルコミットとローカルブランチを変更しない
  • pullはfetch+カレントブランチのみマージする動作
  • pushもカレントブランチのみ対象
forest1
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away