コードの履歴を管理するGitには、Githubにあるリモートレポジトリからデータを取得する主なコマンド、git clone(クローン), git fetch(フェッチ),git pull(プル)の3つがあります。
どれもGithub上のリモートレポジトリからデータを取得してくるだけなのに何が違うの?という方も少なくないでしょう。
ここでは、git clone(クローン), git fetch(フェッチ),git pull(プル)のそれぞれのコマンドによる処理の違いを実例で解説しています。
clone(クローン), fetch(フェッチ), pull(プル)の違い
clone(クローン), fetch(フェッチ), pull(プル)で大きく異なるのは、リモートレポジトリからとってきたデータをどのように保存するかです。
簡単にまとめると次のようになります。
コマンド | 内容 |
---|---|
clone(クローン) | リモートレポジトリの内容を丸ごとコピーして、新しいディレクトリを作成する。 |
fetch(フェッチ) | リモートレポジトリのコミット履歴をすべて取得してくる。ただしマージはしない。 |
pull(プル) | fetch(フェッチ)とmerge(マージ)を組み合わせたコマンド。リモートレポジトリのコミット履歴を取得して、マージする。 |
使いどころは、git clone(クローン)がプロジェクトを作成する一番初め。
git fetch(フェッチ)は各リモートレポジトリの各ブランチで更新があるかを確認したい場合など(結構頻繁に使う)。マージは自分のタイミングでしたい場合。
git pull(プル)は、自分のローカルレポジトリのブランチにリモートリポジトリの内容を取り込みたい(マージ)したいときに使います。
以下で、各コマンドについて実例で解説しています。
git clone
git cloneとは何か?
git clone(クローン)はGithub上の指定したリモートレポジトリをローカルに丸ごとコピーするコマンドです。クローンという名前の通りのコマンドです。
git cloneの使い方
git cloneは使い方が大きく4つあります。
第1引数でリモートレポジトリのURLを指定し、必要に応じて第2引数でコピー先のディレクトリを指定します。
(4)はあまり知られていませんが自分のローカル環境にあるレポジトリを他のディレクトリに丸ごとコピーすることもできます。(単に使う場面がないだけですが、、)
現在のディレクトリにリモートレポジトリを丸ごと展開する場合
git cloneでは引数にリモートレポジトリのURLを指定します。
git clone <リモートレポジトリのURL>
実例
例えば、現在のディレクトリが「~/documents/projects/vue」で、ディレクトリの中身が以下のようになっているとします。
$ ls
local-pj/ vuecli/
ここに、リモートレポジトリ名 rails-testをクローンします。(URL: https://github.com/xxxxx/rails-test.git)
$ git clone https://github.com/xxxxx/rails-test.git
Cloning into 'rails-test'...
remote: Enumerating objects: 539, done.
remote: Counting objects: 100% (539/539), done.
remote: Compressing objects: 100% (291/291), done.
remote: Total 539 (delta 235), reused 503 (delta 199), pack-reused 0Receiving objects: 87% (469/539), 4.50 MiB | 8.98 MiB/s
Receiving objects: 100% (539/539), 7.27 MiB | 9.68 MiB/s, done.
Resolving deltas: 100% (235/235), done.
これでクローンが完了です。
ディレクトリの状態を確認すると、クローンしたレポジトリ名のディレクトリができていることが確認できます。
$ ls
local-pj/ rails-test/ vuecli/
クローンしたディレクトリの中身を確認すると、リモートレポジトリのファイル一式がインストールされていることがわかります。
$ ls -a rails-test
./ .gitignore config/ entrypoint.sh* package.json storage/
../ .ruby-version config.ru Gemfile postcss.config.js test/
.browserslistrc app/ db/ Gemfile.lock public/ tmp/
.git/ babel.config.js docker-compose.yml lib/ Rakefile vendor/
.gitattributes bin/ Dockerfile log/ README.md yarn.lock
.gitなどの隠しディレクトリやファイルもきちんとコピーされています。
これで、該当のディレクトリでコミット履歴も参照することができます。
現在のディレクトリにディレクトリ名を指定して、リモートレポジトリを丸ごと展開する
git clone <リモートレポジトリのURL>
ではリモートレポジトリ名と同じ名前のディレクトリが自動生成されます。
ディレクトリ名を変えたいな~という場合もあるでしょう。その場合は第2引数でディレクトリ名を指定します。
git clone <リモートレポジトリのURL> <ディレクトリ名>
実例
例えば、現在のディレクトリが「~/documents/projects/vue」で、ディレクトリの中身が以下のようになっているとします。
$ ls
local-pj/ vuecli/
ここに、リモートレポジトリ名 rails-testの中身一式を「clone-test」というディレクトリ名の中にクローンします。(URL: https://github.com/xxxxx/rails-test.git)
第2引数を「clone-test」としてgit cloneを実行します。
$ git clone https://github.com/xxxxx/rails-test.git clone-test
Cloning into 'clone-test'...
remote: Enumerating objects: 539, done.
remote: Counting objects: 100% (539/539), done.
remote: Compressing objects: 100% (291/291), done.
remote: Total 539 (delta 235), reused 503 (delta 199), pack-reused 0Receiving objects: 87% (469/539), 6.38 MiB | 12.77 MiB/s
Receiving objects: 100% (539/539), 7.27 MiB | 12.10 MiB/s, done.
Resolving deltas: 100% (235/235), done.
これでクローンが完了です。
ディレクトリの状態を確認すると、クローンしたレポジトリ名のディレクトリができていることが確認できます。
$ ls
clone-test/ local-pj/ vuecli/
クローンしたディレクトリの中身を確認すると、リモートレポジトリのファイル一式がインストールされていることがわかります。
$ ls -a clone-test
./ .gitignore config/ entrypoint.sh* package.json storage/
../ .ruby-version config.ru Gemfile postcss.config.js test/
.browserslistrc app/ db/ Gemfile.lock public/ tmp/
.git/ babel.config.js docker-compose.yml lib/ Rakefile vendor/
.gitattributes bin/ Dockerfile log/ README.md yarn.lock
.gitなどの隠しディレクトリやファイルもきちんとコピーされています。
これで、該当のディレクトリでコミット履歴も参照することができます。
ディレクトリと名前を指定してリモートレポジトリを丸ごと展開する場合
git cloneでは第2引数でディレクトリパスを指定することで、指定したディレクトリにリモートレポジトリを丸ごと展開することができます。
現在のディレクトリじゃなくて、一階層上や一階層下などに新しくディレクトリを作成したい場合に使えます。
git clone <リモートレポジトリのURL> <ディレクトリのパス>
実例
例えば、現在のディレクトリが「~/documents/projects/vue」で、ディレクトリの中身が以下のようになっているとします。
$ ls
local-pj/ vuecli/
一つ上の階層に新たに「new_dir」というディレクトリを作成して、その中に、リモートレポジトリ名 rails-testをクローンします。(URL: https://github.com/xxxxx/rails-test.git)
第2引数で「../new_dir」を指定します。
$ git clone https://github.com/xxxxx/rails-test.git ../new_dir
Cloning into '../new_dir'...
remote: Enumerating objects: 539, done.
remote: Counting objects: 100% (539/539), done.
remote: Compressing objects: 100% (291/291), done.
remote: Total 539 (delta 235), reused 503 (delta 199), pack-reused 0
Receiving objects: 100% (539/539), 7.27 MiB | 11.19 MiB/s, done.
Resolving deltas: 100% (235/235), done.
これでクローンが完了です。
ディレクトリの状態を確認すると、クローンしたレポジトリ名のディレクトリができていることが確認できます。
#一つ上の階層に移動
$ cd ..
$ ls
vue/ new_dir/
クローンしたディレクトリの中身を確認すると、リモートレポジトリのファイル一式がインストールされていることがわかります。
$ ls -a new_dir
./ .gitignore config/ entrypoint.sh* package.json storage/
../ .ruby-version config.ru Gemfile postcss.config.js test/
.browserslistrc app/ db/ Gemfile.lock public/ tmp/
.git/ babel.config.js docker-compose.yml lib/ Rakefile vendor/
.gitattributes bin/ Dockerfile log/ README.md yarn.lock
.gitなどの隠しディレクトリやファイルもきちんとコピーされています。
これで、該当のディレクトリでコミット履歴も参照することができます。
ローカルレポジトリの内容をコピーする
あまり知られていませんが、ローカルレポジトリの内容をクローンすることもできます。
その際は第1引数でローカルレポジトリのパスを指定します。
git clone <ローカルレポジトリのパス> <コピー先ディレクトリのパス>
実例
例えば、現在のディレクトリが「~/documents/projects/vue」で、ディレクトリの中身が以下のようになっているとします。
$ ls
local-pj/ vuecli/
一つ上の階層に新たに「new_dir」というディレクトリを作成して、その中に、ローカルレポジトリ「local-pj」というディレクトリを作成し、ファイル一式をコピーします。
第2引数で「../new_dir/local-pj」を指定します。
$ git clone local-pj ../new_dir/local-pj
Cloning into '../new_dir/local-pj'...
done.
これでクローンが完了です。
現在のディレクトリを確認すると対象のローカルレポジトリはそのまま存在しているのがわかります。
$ ls
local-pj/ vuecli/
一つ上の階層のディレクトリの状態を確認すると、クローンしたレポジトリ名のディレクトリができていることが確認できます。
#一つ上の階層に移動
$ cd ..
$ ls
vue/ new_dir/
#new_dirの中身を確認
$ ls new_dir
local-pj/
new_dirのディレクトリの中に、local-pjというディレクトリが生成されています。
クローンしたディレクトリの中身を確認すると、リモートレポジトリのファイル一式がインストールされていることがわかります。
$ ls -a new_dir/local-pj
./ ../ .git/ .gitignore babel.config.js package.json package-lock.json public/ README.md src/
.gitなどの隠しディレクトリやファイルもきちんとコピーされています。
これで、該当のディレクトリでコミット履歴も参照することができます。
補足
なお、ローカルレポジトリのクローンは単純にディレクトリをコピーしただけなので以下の処理と同じです。
cp -r <コピー元のディレクトリパス> <コピー先のディレクトリパス>
-rオプションは--recursive
のショートオプションで、ディレクトリの深い階層も含めて再帰的にコピーするという意味です。
指定したディレクトリが存在場合はエラーになる
なお、クローン先に指定したディレクトリに既に同じ名前のディレクトリ名がある場合は、「fatal: destination path ‘生成するディレクトリ名’ already exists and is not an empty directory.」というエラーが表示されます。
実例
$ git clone git@github.com:xxx/git-test.git
fatal: destination path 'git-test' already exists and is not an empty directory.
対処法
既に同じ名前のディレクトリ名がありますというエラー「fatal: destination path ‘生成するディレクトリ名’ already exists and is not an empty directory.」が表示された場合は以下で対応します。
ローカルに登録されるリモートレポジトリ名
git cloneすると、指定したリモートレポジトリが「origin」というエイリアス(別名)でリモートレポジトリに登録されます。
登録されているリモートレポジトリ名とURLを確認するには git remote -v
を実行します。
$ git remote -v
origin https://github.com/xxxxx/レポジトリ名.git (fetch)
origin https://github.com/xxxxx/レポジトリ名.git (push)
なお、ローカルレポジトリをクローンした場合は、URLではなくディレクトリパスが登録されています。
$ git remote -v
origin C:/Users/hlaup/Documents/projects/xxxxx/レポジトリ名 (fetch)
origin C:/Users/hlaup/Documents/projects/xxxxx/レポジトリ名 (push)
git fetch
git fetchとは何か?
git fetch(フェッチ)はリモートレポジトリのコミット履歴をとってきて、ローカルレポジトリにコピーするコマンドです。
ローカルレポジトリのリモート追跡ブランチのコミット履歴をアップデートするだけで、マージは行いません。
なお、「fetch」は取ってくると言う意味です。
リモート追跡ブランチとは何か?
Gitではローカルレポジトリのブランチとリモートレポジトリの同じ名前のブランチが直接連携しているわけではありません。
このため、例えば、ローカルレポジトリのmainブランチで作業しているときに、git fetchを行うと、コミット履歴が更新されるのはローカルレポジトリのmainブランチではありません。
リモートレポジトリの各ブランチと直接連動しているブランチは他にあり、そのブランチのことを「リモート追跡ブランチ」と呼びます。
リモート追跡ブランチは「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/ブランチ名」はよく使うので覚えておく必要があります。
git fetchの使いどころやメリット
他のプロジェクトメンバーが作業進めたかな?メインのブランチ(mainやmasterなど)でアップデートがあったかな?といったことを調べたいときに使います。
git fetchした後は、ローカルレポジトリのコミット履歴がアップデートされるので、必要に応じてgit mergeやgit rebaseを実行してコミットを取り込むことができます。
強制的にマージまで実行してしまうgit pullと違って、自分でマージのタイミングを選べるのもgit fetchのポイントです。
リモートレポジトリのブランチの状態をそのまま再現できる。
git fetchの使い方
git fetchは主に次の5つの使い方があります。
それぞれのコマンドは以下のようになります。
コマンド | コマンド例 | 内容 |
---|---|---|
git fetch(引数無し) | git fetch | 取得対象のリモートレポジトリの優先度: 「上流ブランチ」 > 「origin」 |
git fetch <リモートレポジトリ名> | git fetch second | 指定したリモートレポジトリの最新のコミット履歴をまるごと取得 |
git fetch <リモートレポジトリ名> <ブランチ名> | git fetch origin main | 指定したリモートレポジトリの指定したブランチのみの最新のコミット履歴を取得 |
git fetch <リモートレポジトリ名> <ブランチ名>:<生成するブランチ名> | git fetch origin main:test | 指定したリモートレポジトリの指定したブランチのみの最新のコミット履歴を取得して、新たなローカルブランチを作成 |
git fetch --all | git fetch --all | 全てのリモートレポジトリの全てのブランチの最新のコミット履歴をとってくる |
引数なしのgit fetch
git fetchを引数なしで実行した場合は、実行したブランチに上流ブランチが設定してある場合は、上流ブランチの最新のコミット履歴を取得してきます。
上流ブランチが設定されておらず、リモートレポジトリ名に「origin」が登録されている場合は、「origin」というリモートレポジトリのすべてのブランチの最新のコミットをまるごととってきます。
git fetch
上流ブランチとは、ローカルレポジトリのブランチ毎に設定するもので、ローカルブランチをリモートレポジトリのブランチと紐づけるものです。
上流ブランチを設定すると、git pushなどのコマンドの引数を省略することができます。
実例
まずはローカルレポジトリに登録してあるリモートレポジトリ名確認します。上流ブランチの有無も含めて確認する場合は git remote -vv
を実行します。
$ git remote -vv
origin https://github.com/xxxx/rails-test.git (fetch)
origin https://github.com/xxxx/rails-test.git (push)
上流ブランチはなしでリモートレポジトリ「origin」があります。このためgit fetchを実行すると「origin」の全てのブランチの最新のコミット履歴をとってくる処理になります。
git fetch
remote: Enumerating objects: 89, done.
remote: Counting objects: 100% (89/89), done.
remote: Compressing objects: 100% (40/40), done.
remote: Total 89 (delta 46), reused 80 (delta 38), pack-reused 0
Unpacking objects: 100% (89/89), done.
From github.com:xxx/git-test
8fccfd033..2a06b79c8 hotfix -> origin/hotfix
6115dc29d..1f60a6761 develop -> origin/develop
* [new branch] ft1 -> origin/ft1
* [new branch] test -> origin/test
大きく2つの記述があることがわかります。
既存のリモート追跡ブランチのコミット履歴を更新
1つ目はコミット番号とブランチ名が表示されているものです。
8fccfd033..2a06b79c8 hotfix -> origin/hotfix
これは以下のような記述になります。
<更新していない最初のコミット番号>..<最新のコミット番号> <リモートレポジトリのブランチ名> -> <リモート追跡ブランチ名>
つまり、既にリモート追跡ブランチとして存在している「hotfix」ブランチにコミット番号「8fccfd033」から「2a06b79c8」までが追加されたという内容です。
新たなリモート追跡ブランチを作成
2つ目は[new branch]と記載があるものです。
* [new branch] ft1 -> origin/ft1
これは以下のような記述になります。
* [new branch] <リモートレポジトリのブランチ名> -> <リモート追跡ブランチ名>
つまり、リモートレポジトリに新たに「ft1」というブランチが追加されているので、「origin/ft1」というリモート追跡ブランチを新たに生成しましたという意味です。
git fetchで上流ブランチを設定する方法
git fetchで上流ブランチを設定するには、通常のgit fetch <リモートレポジトリ名> <リモートのブランチ名>
に「--set-upstream
」オプションを付けて実行します。
git fetch --set-upstream <リモートレポジトリ名> <リモートのブランチ名>
なお、upstreamは上流という意味です。
初回の実行で上流ブランチをセットすれば、後は引数無しのgit fetchコマンドが使えます。
リモートレポジトリ名を指定したgit fetch
リモートレポジトリが複数登録してある場合など、対象のリモートレポジトリを指定してgit fetchすることもできます。
その場合は第2引数でリモートレポジトリ名を指定します。
git fetch <リモートレポジトリ名>
実例
まずはローカルレポジトリに登録してあるリモートレポジトリ名確認します。
$ git remote -v
origin https://github.com/xxxx/rails-test.git (fetch)
origin https://github.com/xxxx/rails-test.git (push)
second https://github.com/yyyy/git-test.git (fetch)
second https://github.com/yyyy/git-test.git (push)
「origin」と「second」という名前のリモートレポジトリが2つ登録されていることがわかります。
git fetchで「second」のリモートレポジトリの全てのブランチの最新のコミット履歴をとってきます。
git fetch second
remote: Enumerating objects: 89, done.
remote: Counting objects: 100% (89/89), done.
remote: Compressing objects: 100% (40/40), done.
remote: Total 89 (delta 46), reused 80 (delta 38), pack-reused 0
Unpacking objects: 100% (89/89), done.
From github.com:yyyy/git-test
* [new branch] aa -> second/aa
* [new branch] main -> second/main
上記の場合は、git fetchの結果、新しいリモート追跡ブランチ「second/aa」と「second/main」が追加されたことがわかります。
実際にブランチを確認すると以下のようにリモート追跡ブランチが生成されているのがわかります。
$ git branch -a
* aa
main
vue-router
remotes/origin/HEAD -> origin/main
remotes/origin/aa
remotes/origin/main
remotes/second/aa
remotes/second/main
リモートレポジトリが存在しない場合
指定したリモートレポジトリが存在しない場合は「fatal: ‘リモートレポジトリ名’ does not appear to be a git repository」「fatal: Could not read from remote repository.」というエラーが表示されます。
$ git fetch no
fatal: 'no' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
リモートレポジトリ名とブランチ名を指定してgit fetchする
「全てのブランチの情報ではなく、特定のブランチの更新履歴だけが欲しい」という場合は、リモートレポジトリのブランチ名を指定することもできます。
git fetch <リモートレポジトリ名> <リモートレポジトリのブランチ名>
実例
まずはローカルレポジトリに登録してあるリモート追跡ブランチを確認します。
$ git branch -a
* aa
main
vue-router
remotes/origin/HEAD -> origin/main
remotes/origin/aa
remotes/origin/main
remotes/second/aa
remotes/second/main
この中で、リモート追跡ブランチ「remotes/origin/main」すなわちリモートレポジトリ名「origin」ブランチ名「main」のみを更新したい場合は、git fetchの第1引数に「origin」、第2引数に「main」を指定します。
$ git fetch origin main
From https://github.com/xxxxx/rails-test
* branch main -> FETCH_HEAD
上記のように表示され、指定したリモート追跡ブランチの情報のみが更新されていることがわかります。
ブランチが存在しない場合
指定したブランチが存在しない場合は「fatal: couldn’t find remote ref ブランチ名」というエラーが表示されます。
$ git fetch second no
fatal: couldn't find remote ref no
リモートレポジトリ名とブランチ名と、生成するブランチ名を指定してgit fetchする
リモートレポジトリ名とブランチ名と、生成するブランチ名を指定してgit fetchすると、指定したリモートレポジトリのブランチの内容で、新たなブランチをローカルに生成することができます。
git fetch <リモートレポジトリ名> <リモートのブランチ名>:<ローカルに生成するブランチ名>
なお、ローカルに指定したリモートの追跡ブランチが存在する場合は、指定したローカルブランチのみを生成します。
どちらもない場合は、(1)追跡ブランチと(2)指定したローカルブランチの2つを作成します。
実例
リモートレポジトリ名「origin」のブランチ「master」を、ローカルレポジトリに「test」というブランチ名として生成する場合は以下のようになります。
$ git fetch origin master:test
remote: Enumerating objects: 70, done.
remote: Counting objects: 100% (70/70), done.
remote: Compressing objects: 100% (31/31), done.
remote: Total 70 (delta 41), reused 62 (delta 34), pack-reused 0
Unpacking objects: 100% (70/70), done.
From github.com:xxxx/rails-test
* [new branch] master -> test
* [new branch] master -> origin/master
新たにローカルブランチ「test」と、リモートブランチ「origin/master」が生成されたことがわかります。
ブランチの状態を確認すると、それぞれのブランチが生成されていることがわかります。
$ git branch -a
test
remotes/origin/master
全てのリモートレポジトリの全てのブランチの情報をとってくるオプション(--all)
引数無しのgit fetchを実行した場合、上流ブランチがある場合や、リモートレポジトリ名「origin」がある場合といった制約がつきます。
細かいことは抜きにして登録してある全てのリモートレポジトリの全てのブランチの最新のコミットを取ってきたい場合は「--all
」オプションを使用します。
git fetch --all
実例
ローカルレポジトリに登録してあるリモートレポジトリ名が以下のような状態だとします。
$ git remote -v
origin https://github.com/xxxx/rails-test.git (fetch)
origin https://github.com/xxxx/rails-test.git (push)
second https://github.com/yyyy/git-test.git (fetch)
second https://github.com/yyyy/git-test.git (push)
登録してあるリモートレポジトリは「origin」と「second」の2つです。この状態で--all
オプションをつけたgit fetchを実行すると次のようになります。
$ git fetch --all
Fetching origin
Fetching second
このように、「origin」と「second」の両方とものリモートレポジトリをfetchしていることがわかります。
サブモジュールがある場合のgit fetch
リモートレポジトリにサブモジュールが存在するときに「git fetch」を実行すると、メインのリモートレポジトリの内容だけでなく、サブモジュールの内容も取得することができます。
実例
$ git fetch
remote: Enumerating objects: 193, done.
remote: Counting objects: 100% (193/193), done.
remote: Compressing objects: 100% (79/79), done.
remote: Total 193 (delta 135), reused 156 (delta 114), pack-reused 0
Receiving objects: 100% (193/193), 82.78 KiB | 657.00 KiB/s, done.
Resolving deltas: 100% (135/135), completed with 48 local objects.
From github.com:xxxx/rails-pj
8fccfd033..2a06b79c8 test -> origin/test
* [new branch] apc -> origin/apc
888570c19..0ce7f2188 master -> origin/master
+ 98ab8117f...c3d2ff203 test_ga -> origin/test_ga (forced update)
Fetching submodule rails-user
From github.com:xxxx/rails-user
f5bd9fa..e0af519 master -> origin/master
6439adb..e63c502 test -> origin/test
Fetching submodule rails-api
From github.com:xxxx/rails-api
d2ab8a8..865f236 master -> origin/master
+ 302d6ae...8aa0c0e ft -> origin/ft (forced update)
* [new branch] pr -> origin/pr
上記の場合、実行したのはgit fetch
のみですが、メインのリモートレポジトリ「rails-pj」以外に、サブモジュール「rails-user」と「rails-api」の全てのブランチの最新のコミットも取得していることがわかります。
git pull
git pullとは何か?
git pullとは、リモートレポジトリの更新内容を取得してきて、現在のブランチに統合(マージ)するコマンドです。
git fetchを使った場合、取得してきたコミットをマージするにはgit merge(あるいはgit rebase)を使います。この、git mergeのマージ作業もまとめて行うのがgit pullです。
なお、オプションに--rebase
をつけることで、git fetch + git rebaseの処理にすることもできます。
コミットのマージまで行うので、cloneやfetchと異なりコンフリクトが発生する可能性があります。
git pullの裏側の処理内容
git pullの処理はgit fetchとgit mergeを同時に実行しているのですが、具体的には以下のようになっています。
$ git pull <リモートレポジトリ名> <リモートのブランチ名>
↑↓ 同じ
$ git fetch <リモートレポジトリ名> <リモートのブランチ名>
$ git merge FETCH_HEAD
FETCH_HEADについは後述しています。
git pullの使い方
git pullの使い方は主に以下の3個です。
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は上流という意味です。
実例:上流ブランチの設定
現在のローカルレポジトリの「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 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オプションでリベースする
git pullのオプションで「--rebase
」をつけると、git mergeの処理をgit rebaseに変えることができます。
git pull --rebase <リモートレポジトリ名> <リモートのブランチ名>
上流ブランチが設定してある場合は引数を省略できます。
git pull --rebase
git rebaseとは何か?
git rebaseは本質的にはマージではなく、コミット履歴を移動したり修正、削除したりするコマンドです。
マージ前にコミット履歴をきれいにする目的で使用するのが一般的です。(例えば、git rebaseをしてから、プルリクを出すなど)
ただし、他のブランチから分岐した以降のコミットをとってくることができるので、マージと似たような処理をすることになります。
git rebaseをすると、分岐している他のブランチのコミットを分岐した時点からとってきて、自分のコミットの前に付け足すことができます。
枝分かれの枝を根本からポッキっと追って、本流にくっつけるイメージです。
なお、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」に変化していることも注目してください。
(※コミット番号は過去のコミット履歴と紐づいているため、履歴が変わればコミット番号のハッシュ値も変わります)
上流ブランチの設定方法
上流ブランチは、git pull, git fetch, git push, git branchなどのコマンドでも設定可能です。
コマンドのオプション以外にも、コマンドでconfigファイルに追記したり、configファイル自体を書き換えする方法もあります。
オプションで指定する方法
--set-upstream
オプション
pull, fetch, pushのいずれでも使用可能です。
・git pull --set-upstream <リモートレポジトリ名> <リモートのブランチ名>
・git fetch --set-upstream <リモートレポジトリ名> <リモートのブランチ名>
・git push --set-upstream <リモートレポジトリ名> <リモートのブランチ名>
-uオプション(git pushのみ)
git pushのみショートオプションの「-u」が使えます。
git push -u <リモートレポジトリ名> <リモートのブランチ名>
--set-upstream-to
オプション(git pushのみ)
git branchコマンドにも上流ブランチを設定するコマンドがあります。
設定ファイルを編集する方法(コマンドで.git/configファイルに追記)
configファイルに追記する場合は、対象のリモートブランチの(1)remote、(2)mergeの2つの値を設定する必要があります。
(1) $ git config branch.<ローカルブランチ名>.remote <リモートブランチ名>
(2)$ git config branch.<ローカルブランチ名>.merge refs/heads/<リモートブランチ名>
実例
$ git config branch.topic.remote origin
$ git config branch.topic.merge refs/heads/master
configファイルの確認
#configファイルの中身を見る
cat .git/config
エディタでファイルの中身を見ると以下のようにtopicブランチに対して、上流となる、リモートレポジトリ名とブランチ名が登録されていることがわかります。
[branch "topic"]
remote = origin
merge = refs/heads/master
設定ファイルを直接編集する方法(.git/configファイルに追記)
configファイルの中身を直接編集することもできます。
#エディタで開く
vim .git/config
vimエディタが起動するので、以下のように追加すれば完了です。
[branch "ローカルのブランチ名"]
remote = リモートレポジトリ名
merge = refs/heads/リモートのブランチ名
上流ブランチを活用するコマンド
現在のローカルブランチに上流ブランチの設定ができれば、git pull, fetch, push時に引数を省略して実行することができます。
使うときは、どのブランチでコマンドを実行しているかに注意してください。