git pull(プル)とは何か?使い方を実例で解説|引数が無い場合の処理内容やFETCH_HEADとは何か?–rebaseオプションの使い方

github-prograshi(プロぐらし)-kv git/github
記事内に広告が含まれていることがあります。

Githubを使ったプロジェクトで頻繁に使用するコマンドの一つにgit pull(プル)があります。

Githubのリモートレポジトリのコミットをマージするんでしょ?という理解をされている方は多いと思います。その通りです。

ですが、実はgit pullはできることがたくさんあるとても便利なコマンドです。ただし、使い方には癖があり、理解が必要です。

ここではgit pullは具体的にどんな処理をしているのか?引数が無い場合の処理内容やFETCH_HEADとは何か?--rebaseオプションの使い方などについて実例を踏まえてまとめています。


git pullとは何か?

git pullとは、リモートレポジトリの更新内容を取得してきて、現在のブランチに統合(マージ)するコマンドです。

git fetchを使った場合、取得してきたコミットをマージするにはgit merge(あるいはgit rebase)を使います。この、git mergeのマージ作業もまとめて行うのがgit pullです。

なお、オプションに--rebaseをつけることで、git fetch + git rebaseの処理にすることもできます。

コミットのマージまで行うので、cloneやfetchと異なりコンフリクトが発生する可能性があります。

合わせて読みたい

git mergeやgit rebaseって何?コンフリクトが発生したらどう対処したらいいの?という疑問を持たれた方は下記をご参考ください。

【図解】git mergeとgit rebaseの違いを実例で解説(マージとリベースは何が違うのか?)


git pullの裏側の処理内容

git pullの処理はgit fetchとgit mergeを同時に実行しているのですが、具体的には以下のようになっています。

$ git pull <リモートレポジトリ名> <リモートのブランチ名>

 ↑↓ 同じ

$ git fetch <リモートレポジトリ名> <リモートのブランチ名>
$ git merge FETCH_HEAD

FETCH_HEADについは後述しています。

合わせて読みたい

git mergeで具体的にどのようなことが起こっているかや、コマンドの実例については下記をご参考ください。

【Git】git merge(マージ)とは何か?使い方を実例で解説


git pullの使い方

git pullの使い方は主に以下の3個です。

git pullの使い方
  1. リモートレポジトリ名とブランチ名を指定してマージする。
  2. 引数を省略してマージ(git pullのみ。上流ブランチの設定)
  3. --rebaseオプションでリベースする。


git pullの注意点

git pullを使う上で注意しておくべき点がいくつかあります。

どこのブランチで実行するかが重要

GitにはGithubのリモートレポジトリからコミットを取得してくるコマンドに、git pull以外にもgit cloneやgit fetchがあります。

git cloneやgit fetchはローカルレポジトリのどのブランチでコマンドを実行するかは関係ありません。

一方、git pullはgit fetchしてgit mergeまで行うのでどこのブランチで実行するかが大きく関係してきます

git pullを実行する前に、自分がどのブランチにいるかを確認し、マージしたいブランチにいるかを確認しておくことが重要です。


コンフリクトが発生する可能性がある

git cloneやgit fetchのようにただ情報をとってくるだけではなく、マージ(あるいはリベース)まで行うので、コンフリクト(conflict)が発生することがあります。

コンフリクトが発生した場合は下記をご参考ください。

【Git】git merge(マージ)でconflict(コンフリクト)が発生したファイルの修正方法をわかりやすく解説


リモートレポジトリ名とブランチ名を指定してマージする方法

リモートレポジトリ名とブランチ名を指定したマージのやり方

git pullで現在のブランチで、リモートレポジトリ名とブランチ名を指定してマージするときは以下のようにします。

git pull <リモートレポジトリ名> <リモートのブランチ名>


実例

リモートレポジトリ名「origin」のブランチ「aa」をコミット履歴を、ローカルレポジトリのブランチ「test」にマージする場合例を紹介します。

まずは、マージを実行したいブランチに移動します。

#現在のブランチはmain
$ git branch
  aa
* main
  test

#マージを実行したいブランチに移動
$ git checkout test
Switched to branch 'test'


#きちんと移動できてるか確認
$ git branch
  aa
  main
* test

マージを実行したいブランチ(ここでは「test」)にいることが確認できたら、マージしたいコミットを持つリモートレポジトリ名「origin」のブランチ「aa」を指定して、git pullを実行します。

$ git pull origin aa
From https://github.com/xxxxx/rails-test
 * branch            aa         -> FETCH_HEAD
Updating 61d3b4b..0701d9d
Fast-forward
 app/controllers/api/pj1/clients_controller.rb  |   8 +-
 app/javascript/components/Modal.vue            | 106 +++++++++++++++++++++++++
 app/javascript/components/clients/Clients.vue  |  42 +++++++++-
 config/initializers/content_security_policy.rb |  12 +--
 config/routes.rb                               |   2 +-
 docker-compose.yml                             |   2 +
 6 files changed, 162 insertions(+), 10 deletions(-)
 create mode 100644 app/javascript/components/Modal.vue

上記のように表示され、マージが実行されます。

「61d3b4b」から「0701d9d」のコミットを取り込んだことがわかります。

コミットログを確認すると、指定したリモートレポジトリのブランチと対応するリモート追跡ブランチ「origin/aa」と、git pullを実行したtestブランチが同じコミットを指していることがわかります。

$ git log --oneline --graph
* 0701d9d (HEAD -> test, origin/aa, aa) [U]docker-compose add webpack port 3035
* a90d4ef [U]content-security-policy(CSP) enable webpack-dev-server
* 6adca49 [A]destroyメソッド & Modal追加
* 61d3b4b [A]ClientEdit.vue
* 00093d1 [F]ClientNewからClientForm.vueを切り出し

なお上記の例では、コミットが分岐していないので、コミットのポインタを前に進めただけ(Fast-forwardしただけ)ですが、コミットが分岐しているブランチでgit pullを行った場合、コミット履歴は以下のようになります。

$ git log --oneline --graph
*   7f02744 (HEAD -> master, origin/master) Merge branch 'ft2'
|\
| * d6eb207 add h3 again
* | 07ea837 add h4
|/
* 788f5b1 remove all marks

分岐したコミット履歴が、マージされ統合されたことがわかります。


リモート追跡ブランチとは何か?(git pullの処理内容)

リモート追跡ブランチとは何か?

Gitではローカルレポジトリのブランチとリモートレポジトリの同じ名前のブランチが直接連携しているわけではありません

このため、例えば、ローカルレポジトリのブランチでgit pullしたときに、指定したリモートレポジトリのブランチを直接取り込んでいるわけではありません。

ローカルレポジトリには「リモート追跡ブランチ」というものがあり、これがリモートレポジトリの各ブランチと直接連動しているブランチです。

このため、まずリモートレポジトリの指定したブランチの内容をリモートレポジトリに同期し、それから、git pullしたブランチのコミット履歴に、リモート追跡ブランチのコミット履歴をマージするという処理が行われます。

リモート追跡ブランチは「remotes/リモートレポジトリ名/リモートブランチ名」という名前がついているブランチのことです。(例: remotes/origin/main)

リモート追跡ブランチは「git branch -a」で参照できます。-aはall(全てのブランチ)という意味です。


実例:リモート追跡ブランチの参照

$ git branch -a
* aa
  main
  vue-router
  remotes/origin/HEAD -> origin/main
  remotes/origin/aa
  remotes/origin/main

上記の例だと、リモートレポジトリには「main」と「aa」の2つのブランチがあり、それぞれのリモート追跡ブランチは「remotes/origin/main」「remotes/origin/aa」となっていることがわかります。

なお、「remotes/origin/HEAD -> origin/main」は取得してきた時点で最新のリモートレポジトリのデフォルトブランチを指しています。

「remotes/origin/HEAD」を使うことはほぼないので、あまり気にする必要はありません。

「remotes/origin/ブランチ名」はよく使うので覚えておく必要があります。


FETCH_HEADとは何か?

git pullすると以下のように「FETCH_HEAD」という表示がでます。

$ git pull origin master

From github.com:xxx/git-test
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> origin/master

これは、git mergeの前段階として、git fetchでコミット履歴を取得したブランチの最新のコミットがどこかを示す目印です

FETCH_HEADというポインタをセットしましたという意味になります。


引数を省略してマージ(git pullのみ。上流ブランチの設定)

引数を省略したマージのやり方

git pullでは現在のローカルレポジトリのブランチに「上流ブランチ」を設定すると、引数を省略してgit pullを実行することができます。

git pull

とてもシンプルなコマンドになります。


上流ブランチとは何か?

上流ブランチとは、ローカルレポジトリのブランチ毎に設定するもので、ローカルレポジトリのブランチをリモートレポジトリのブランチと紐づけるものです。

上流ブランチを設定すると、git pushなどのコマンドの引数を省略することができます。


上流ブランチの設定方法

上流ブランチを設定するには、通常のgit pull <リモートレポジトリ名> <リモートのブランチ名>のオプションとして「--set-upstream」を付けて実行します。

git pull --set-upstream <リモートレポジトリ名> <リモートのブランチ名>

なお、upstreamは上流という意味です。

注意点
  • 上流ブランチを設定するための初回のgit pullでは引数を省略することはできません。
  • git pushと違いショートオプション「-u」は存在しません。


実例:上流ブランチの設定

現在のローカルレポジトリの「main」ブランチにおいて、リモートレポジトリ「origin」の「aa」ブランチを上流ブランチに設定する場合は以下のようになります。

$ git pull --set-upstream origin aa
From https://github.com/xxxxx/rails-test
 * branch            aa         -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 app/controllers/api/pj1/clients_controller.rb    |  10 ++-
 app/javascript/app.vue                           |   8 +-
 app/javascript/components/Modal.vue              | 106 +++++++++++++++++++++++
 8 files changed, 215 insertions(+), 12 deletions(-)
 create mode 100644 app/javascript/components/Modal.vue

特に、上流ブランチを設定したという情報は表示されません。



上流ブランチの確認方法

上流ブランチが設定してあるかどうかはgit branch -vvコマンドを実行することで確認できます。

#上流ブランチがない場合
$ git branch -vv
* main dc53f35 first commit

#上流ブランチある場合
$ git branch -vv
* main dc53f35 [origin/main] first commit

上流ブランチがある場合は、[リモートレポジトリ名/リモートレポジトリのブランチ名] が表示されます。

よって、このローカルレポジトリのmainブランチでgit pushを実行すると、リモートレポジトリ名originのmainブランチにpushを行います。

なお、ブランチ名の横の 数値(例 dc54f35)は最新のコミット番号、末尾の「first commit」はコミットメッセージです。

リモートブランチ確認時の注意点

リモートブランチを確認するコマンド git branch -vv は「v」が2つ必要です。

「v」が一つだけだと、上流ブランチが設定されていても画面上に表示されません。

#「v」が2つの場合
$ git branch -vv
* main dc53f35 [origin/main] first commit
#「v」が1つの場合
$ git branch -v
* main dc53f35 first commit


実例:引数なしのgit pull

まずは上流ブランチが設定されていることを確認します。

$ git branch -vv
  aa         0701d9d [U]docker-compose add webpack port 3035
  main       21f31d2 [origin/main] [A]test.html.rb
* test       718eea7 [origin/aa: behind 6] [A]Client.vue

「main」ブランチと「test」ブランチの2つに上流ブランチが設定されていることがわかります。

testブランチでgit pullを実行します。

$ git pull
From https://github.com/xxxx/rails-test
 * [new tag]         v2.0       -> v2.0
 * [new tag]         v3.0       -> v3.0
Updating 718eea7..0701d9d
Fast-forward
 app/controllers/api/pj1/clients_controller.rb    |  46 +++++++++-
 app/javascript/app.vue                           |  16 +++-
 app/javascript/components/Modal.vue              | 106 +++++++++++++++++++++++
 app/javascript/components/clients/Client.vue     |  24 ++---
 12 files changed, 412 insertions(+), 29 deletions(-)
 create mode 100644 app/javascript/components/Modal.vue
 create mode 100644 app/javascript/components/clients/ClientEdit.vue

引数なしでgit pullが実行できました。


上流ブランチが設定されていない場合はエラーになる

上流ブランチが設定されていない状態で引数なしのgit pullを実行すると「There is no tracking information for the current branch.」という以下のようなエラーが発生します。

(参考)エラー:上流ブランチが設定されていない場合

$ git pull

There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=<remote>/<branch> master

表示されている内容は次の2つです。

git pull <remote> <branch>
通常通り、リモート名とブランチ名を指定する。または、

git branch --set-upstream-to=<remote>/<branch> masterで上流ブランチをセットしてくださいとの示唆。


--rebaseオプションでリベースする

--rebaseオプションの使い方

git pullのオプションで「--rebase」をつけると、git mergeの処理をgit rebaseに変えることができます。

git pull --rebase <リモートレポジトリ名> <リモートのブランチ名>

上流ブランチが設定してある場合は引数を省略できます。

git pull --rebase


git rebaseとは何か?

git rebaseは本質的にはマージではなく、コミット履歴を移動したり修正、削除したりするコマンドです。

マージ前にコミット履歴をきれいにする目的で使用するのが一般的です。(例えば、git rebaseをしてから、プルリクを出すなど)

ただし、他のブランチから分岐した以降のコミットをとってくることができるので、マージと似たような処理をすることになります。

git rebaseをすると、分岐している他のブランチのコミットを分岐した時点からとってきて、自分のコミットの前に付け足すことができます。

枝分かれの枝を根本からポッキっと追って、本流にくっつけるイメージです。

なお、rebaseとは土台を完全に移行するという意味です。このため元のブランチの内容を根っこから、指定したブランチのコミットログの先端にとりつける処理を指しています。

注意点

git rebaseをすると、分岐した時点からのコミット内容をとってきて、自分の変更後のコミットをその先端に移動します。

取得してきたコミット番号は変わりませんが、自分ブランチのコミットは変更になります。(過去のコミット履歴が変わるため)

合わせて読みたい

git rebaseで具体的にどのようなことが起こっているかや、コマンドの実例については下記をご参考ください。

【Git】git rebase(リベース)とは何か?使い方を実例で解説git rebase(リベース)とは何か?使い方を実例で解説


git pull –rebaseの裏側の処理内容

git pull --rebaseの処理はgit fetchとgit rebaseを同時に実行しているのですが、具体的には以下のようになっています。

$ git pull --rebase <リモートレポジトリ名> <リモートのブランチ名>

 ↑↓ 同じ

$ git fetch <リモートレポジトリ名> <リモートのブランチ名>
$ git rebase FETCH_HEAD


実例:git pull –rebase

現在のコミット履歴が以下のような状態とします。

例えば、現在のブランチが「test」ブランチで以下のようにリモートレポジトリ名「origin」ブランチ名「aa」という上流ブランチが設定されているとします。

$ git branch -vv
  aa         0701d9d [U]docker-compose add webpack port 3035
  main       21f31d2 [origin/main] [A]test.html.rb
* test       3aeb158 [origin/aa] [F]div-tag

testブランチのコミット履歴は以下のようになっているとします。一番最近のコミット「3aeb158」が上流ブランチ「aa」のコミットから分岐しているコミットです。

$ git log --oneline --graph
* 3aeb158 (HEAD -> test) [F]div-tag
* 00093d1 [F]ClientNewからClientForm.vueを切り出し
* a84cfc5 [A]ClientNew.vue
* 718eea7 [A]Client.vue

この状態でgit pull --rebaseを実行して、上流ブランチのコミット履歴をfetchしてrebaseします。

$ git pull --rebase
From https://github.com/shizen-shin/rails-aa
 * [new tag]         v2.1       -> v2.1
Successfully rebased and updated refs/heads/test.

「Successfully rebased and updated refs/heads/test.」と表示され、リベースが正しく行われたことがわかります。

コミット履歴を確認すると以下のようになっています。

$ git log --oneline
5095d55 (HEAD -> test) [F]div-tag
0701d9d (second/aa, origin/aa, aa) [U]docker-compose add webpack port 3035
a90d4ef [U]content-security-policy(CSP) enable webpack-dev-server
6adca49 [A]destroyメソッド & Modal追加
61d3b4b [A]ClientEdit.vue
00093d1 [F]ClientNewからClientForm.vueを切り出し
a84cfc5 (tag: v2.1) [A]ClientNew.vue
718eea7 [A]Client.vue

もとのコミット履歴に対して、「61d3b4b」~「0701d9d」が追加されています。

また、「a84cfc5」にタグ「v2.1」も追加されています。

過去の履歴が変わったので、これまでのtestブランチの最新のコミット番号が「3aeb158」から「5095d55」に変化していることも注目してください。

(※コミット番号は過去のコミット履歴と紐づいているため、履歴が変わればコミット番号のハッシュ値も変わります)

合わせて読みたい

上記で「v2.1」というタグが追加されています。タグは非常に便利なツールです。タグって何?という方は下記をご参考ください。

【Git】git tagコマンド完全理解|メリット・デメリットや注意点、使い方を実例で解説


タイトルとURLをコピーしました