おおいしつかさ


旅行とバイクとドライブと料理と宇宙が好き。
Ubie Discoveryのプログラマ。
Share:  このエントリーをはてなブックマークに追加

Gitのリモートブランチと追跡ブランチは違うよ

いまさら感がひしひしと伝わってくる今日この頃ですが、ようやくまともにGitを触りはじめています。
Gitについては Learn Git Branching という素晴らしいサイトがあって基本的なところはだいたい理解できました。
ところでGitの本を読んでいると大きくわけて三つのブランチが出て来ます。

* ローカルブランチ
* 追跡ブランチ
* リモートブランチ

最初の頃、追跡ブランチとはローカルブランチが追従しているリモートブランチのことで、つまりはリモートブランチと追跡ブランチは同じものを指していると思っていました。両方ともリモートリポジトリ上にあるものだと勘違いしていて、ここでちょっと混乱していました。
実のところ、追跡ブランチ自体はローカルリポジトリ上にあります。これに気づくといろいろとGitの理解が深まりました。ちゃんとこのことを書いている本ってあまりないですよね。

以下のような状態を考えてみます。

$ git branch  
 * master  

ローカルブランチにはmasterだけがあります。

git branch コマンドに -a オプションを渡すと、ものの本にはリモートブランチの一覧も表示されるとよく書いてあります。

$ git branch -a  
* master  
  remotes/origin/HEAD -> origin/master  
  remotes/origin/master  

remotes/origin/masterがリモートブランチのすべてであるように見えます。
このとき、サンフランシスコの同僚がリモートリポジトリに新しいブランチをpushしていたとします。このことをいつ知ることができるのでしょうか。
git branch -a コマンドを何回叩いても、現れるのは上記の通りorigin/masterのみです。

つまり、git branch -a コマンドはリモートブランチの一覧を表示しているわけではないのです。
では何を表示しているのかというと、リモートブランチの情報を持っているローカルリポジトリの中の特殊なブランチの一覧を表示しているのです。この特殊なブランチ、つまり追跡ブランチですが、これ自体はローカルに存在しているのでローカルブランチの一種であるといえます。そのため、最新のリモートリポジトリの状態なんて知らないのです。

最新のリモートリポジトリの情報を取得して追跡ブランチに反映するためには git fetch コマンドを使います

$ git fetch  
From github.com:tsukasaoishi/sample  
 * [new branch]      redwood_city -> origin/redwood_city  

new branch redwood_city -> origin/redwood_city という表記は、リモートリポジトリにある redwood_city というブランチから、ローカルリポジトリにorigin/redwood_cityという追跡ブランチを作ったよ、ということを表しています。

$ git branch -a  
* master  
  remotes/origin/HEAD -> origin/master  
  remotes/origin/master  
  remotes/origin/redwood_city  

さっきまでなかった、remotes/origin/redwood_cityが表示されました。これがサンフランシスコの同僚が作ったブランチです。このブランチで作業をしたいときは、この追跡ブランチからローカルブランチを作る必要があります。
ブランチを作るコマンドはgit branchですね。

$ git branch redwood_city origin/redwood_city  
Branch redwood_city set up to track remote branch redwood_city from origin.  

$ git branch -a  
* master  
  redwood_city  
  remotes/origin/HEAD -> origin/master  
  remotes/origin/master  
  remotes/origin/redwood_city  

git branch redwood_city origin/redwood_city というコマンドは、ローカルブランチredwood_city を、追跡ブランチである origin/redwood_city から作ってね、という意味になります。

git fetchはリモートブランチの最新状態をローカルの追跡ブランチに反映するコマンドです。なので、リモートブランチmasterの最新状態も、ローカルのorigin/masterに反映されています。ここで

$ git checkout master  
$ git merge origin/master  

というようにしてあげると、最新状態に更新された追跡ブランチorigin/masterを現在作業中のブランチ(上記だとローカルのmasterブランチ)にマージします。結果的に、ローカルのmasterブランチにリモートリポジトリのmasterブランチの最新状態をマージしたことになります。
これってつまり、git pull コマンドが中でやっていることです。