チャプター ▾ 第2版

3.5 Gitのブランチ - リモートブランチ

リモートブランチ

リモート参照とは、リモートリポジトリ内の参照 (ポインタ) で、ブランチやタグなどを含みます。リモート参照の完全なリストは、git ls-remote <remote>で明示的に取得できます。また、リモートブランチに関する詳細な情報については、git remote show <remote>を使用します。しかし、より一般的な方法は、リモートトラッキングブランチを活用することです。

リモートトラッキングブランチは、リモートブランチの状態を参照するものです。これらは動かせないローカル参照であり、Gitはネットワーク通信を行うたびに自動的にこれを更新し、リモートリポジトリの正確な状態を反映するようにします。これらは、リモートリポジトリのブランチが最後に接続したときにどこにあったかを思い出させるブックマークのようなものだと考えてください。

リモートトラッキングブランチの名前は、<remote>/<branch>という形式を取ります。例えば、originリモートのmasterブランチが最後に通信したときにどうなっていたかを確認したい場合は、origin/masterブランチをチェックします。もしパートナーとある問題について作業しており、彼らがiss53ブランチをプッシュした場合、あなた自身のローカルなiss53ブランチを持っているかもしれませんが、サーバー上のブランチはリモートトラッキングブランチorigin/iss53によって表現されます。

これは少し混乱しやすいかもしれないので、例を見てみましょう。ネットワーク上にgit.ourcompany.comというGitサーバーがあるとします。ここからクローンすると、Gitのcloneコマンドは自動的にその名前をoriginとし、すべてのデータをプルし、そのmasterブランチがある場所へのポインタを作成し、ローカルでorigin/masterという名前を付けます。Gitはまた、作業の開始点として、originのmasterブランチと同じ場所から始まるあなた自身のローカルなmasterブランチを提供します。

「origin」は特別ではない

Gitにおいて、ブランチ名「master」が特別な意味を持たないのと同様に、「origin」も特別な意味を持ちません。「master」はgit initを実行したときに開始ブランチのデフォルト名として広く使われている唯一の理由ですが、「origin」はgit cloneを実行したときにリモートのデフォルト名です。もし代わりにgit clone -o booyahを実行した場合、デフォルトのリモートブランチはbooyah/masterになります。

Server and local repositories after cloning
図 30. クローン後のサーバーとローカルリポジトリ

もしあなたがローカルのmasterブランチで作業し、その間に誰かがgit.ourcompany.comにプッシュしてそのmasterブランチを更新した場合、あなたの履歴は異なって進んでいきます。また、originサーバーとの連絡を絶っている限り、origin/masterポインタは動きません。

Local and remote work can diverge
図 31. ローカルとリモートの作業が分岐する可能性

あなたの作業を与えられたリモートと同期させるには、git fetch <remote>コマンド(この場合、git fetch origin)を実行します。このコマンドは、「origin」がどのサーバーであるか(この場合、git.ourcompany.com)を調べ、まだ持っていないデータをそこから取得し、ローカルデータベースを更新し、origin/masterポインタを新しい、より最新の位置に移動させます。

`git fetch` updates your remote-tracking branches
図 32. git fetchがリモートトラッキングブランチを更新する

複数のリモートサーバーを持つことと、それらのリモートプロジェクトのリモートブランチがどのように見えるかを示すために、スプリントチームの1つだけが開発に使用する別の社内Gitサーバーがあると仮定しましょう。このサーバーはgit.team1.ourcompany.comにあります。これを、Gitの基本で説明したgit remote addコマンドを実行して、現在作業しているプロジェクトへの新しいリモート参照として追加できます。このリモートをteamoneと名付けます。これがそのURL全体の略称になります。

Adding another server as a remote
図 33. 別のサーバーをリモートとして追加する

これで、git fetch teamoneを実行して、まだ持っていないteamoneリモートサーバーが持っているすべてを取得できます。そのサーバーには、現在originサーバーが持っているデータの一部が含まれているため、Gitはデータをフェッチしませんが、teamone/masterというリモートトラッキングブランチを設定して、teamoneがそのmasterブランチとして持っているコミットを指すようにします。

Remote-tracking branch for `teamone/master`
図 34. teamone/masterのリモートトラッキングブランチ

プッシュ

ブランチを公開したいときは、書き込み権限のあるリモートにプッシュする必要があります。ローカルブランチは、書き込むリモートに自動的に同期されるわけではありません。共有したいブランチを明示的にプッシュする必要があります。そうすることで、共有したくない作業にはプライベートブランチを使用し、共同作業したいトピックブランチのみをプッシュできます。

他の人と一緒に作業したいserverfixというブランチがある場合、最初のブランチをプッシュしたのと同じ方法でプッシュできます。git push <remote> <branch>を実行します。

$ git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
 * [new branch]      serverfix -> serverfix

これは少し省略形です。Gitは自動的にserverfixというブランチ名をrefs/heads/serverfix:refs/heads/serverfixに展開します。これは、「ローカルのserverfixブランチを取得し、リモートのserverfixブランチを更新するようにプッシュする」という意味です。refs/heads/の部分についてはGitの内部で詳しく説明しますが、通常は省略できます。また、git push origin serverfix:serverfixとすることもできます。これは同じことを行います。「ローカルのserverfixをリモートのserverfixにする」と指示します。この形式を使用して、ローカルブランチを異なる名前のリモートブランチにプッシュできます。もしリモートでserverfixという名前にしたくない場合は、代わりにgit push origin serverfix:awesomebranchを実行して、ローカルのserverfixブランチをリモートプロジェクトのawesomebranchブランチにプッシュできます。

毎回パスワードを入力しない

HTTPS URLを使用してプッシュする場合、Gitサーバーは認証のためにユーザー名とパスワードを要求します。デフォルトでは、サーバーがプッシュを許可するかどうかを判断できるように、ターミナルでこの情報をプロンプト表示します。

プッシュするたびに毎回入力したくない場合は、「資格情報キャッシュ」を設定できます。最も簡単なのは、git config --global credential.helper cacheを実行して、数分間メモリに保持することです。

利用可能なさまざまな資格情報キャッシュオプションの詳細については、資格情報の保存を参照してください。

次に、共同作業者がサーバーからフェッチすると、リモートブランチorigin/serverfixの下にサーバーバージョンのserverfixへの参照が取得されます。

$ git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
 * [new branch]      serverfix    -> origin/serverfix

新しいリモートトラッキングブランチを取得するフェッチを実行しても、それらのローカルで編集可能なコピーが自動的に作成されるわけではないことに注意することが重要です。言い換えれば、この場合、新しいserverfixブランチは持っていません。変更できないorigin/serverfixポインタしか持っていません。

この作業を現在の作業ブランチにマージするには、git merge origin/serverfixを実行します。もし自分で作業できるserverfixブランチが欲しい場合は、リモートトラッキングブランチを基に作成できます。

$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

これにより、origin/serverfixの場所から始まる、作業可能なローカルブランチが作成されます。

トラッキングブランチ

リモートトラッキングブランチからローカルブランチをチェックアウトすると、自動的に「トラッキングブランチ」と呼ばれるものが作成されます(そしてそれが追跡するブランチは「アップストリームブランチ」と呼ばれます)。トラッキングブランチは、リモートブランチと直接的な関係を持つローカルブランチです。トラッキングブランチにいてgit pullと入力すると、Gitはどのサーバーからフェッチし、どのブランチをマージするかを自動的に認識します。

リポジトリをクローンすると、通常、origin/masterを追跡するmasterブランチが自動的に作成されます。ただし、必要に応じて他のトラッキングブランチを設定することもできます。これは、他のリモート上のブランチを追跡したり、masterブランチを追跡しないブランチを設定したりすることです。単純なケースは、先ほど見た例で、git checkout -b <branch> <remote>/<branch>を実行するものです。これは非常に一般的な操作なので、Gitは--trackという省略形を提供しています。

$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

実際、これは非常に一般的なので、そのショートカットのさらにショートカットがあります。チェックアウトしようとしているブランチ名が (a) 存在せず、(b) 1つのリモート上の名前に正確に一致する場合、Gitはあなたのためにトラッキングブランチを作成します。

$ git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

リモートブランチとは異なる名前でローカルブランチを設定したい場合は、最初のバージョンを異なるローカルブランチ名で簡単に使用できます。

$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'

これで、ローカルブランチsfは自動的にorigin/serverfixからプルするようになります。

すでにローカルブランチがあり、それをプルしたばかりのリモートブランチに設定したい場合、または追跡しているアップストリームブランチを変更したい場合は、いつでもgit branchコマンドの-uまたは--set-upstream-toオプションを使用して明示的に設定できます。

$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
アップストリームの省略形

トラッキングブランチを設定している場合、そのアップストリームブランチを@{upstream}または@{u}という省略形を使って参照できます。したがって、masterブランチにいて、それがorigin/masterを追跡している場合、必要に応じてgit merge origin/masterの代わりにgit merge @{u}のように言うことができます。

設定されているトラッキングブランチを確認したい場合は、git branchコマンドに-vvオプションを使用します。これにより、各ブランチが何を追跡しているか、ローカルブランチが先行しているか、遅れているか、またはその両方であるかを含む詳細情報とともに、ローカルブランチが一覧表示されます。

$ git branch -vv
  iss53     7e424c3 [origin/iss53: ahead 2] Add forgotten brackets
  master    1ae2a45 [origin/master] Deploy index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] This should do it
  testing   5ea463a Try something new

ここでは、iss53ブランチがorigin/iss53を追跡しており、2コミット「先行」していることがわかります。これは、ローカルに2つのコミットがあり、まだサーバーにプッシュされていないことを意味します。また、masterブランチはorigin/masterを追跡しており、最新であることもわかります。次に、serverfixブランチがteamoneサーバー上のserver-fix-goodブランチを追跡しており、3コミット先行し、1コミット遅れていることがわかります。これは、まだマージされていないサーバー上の1つのコミットと、まだプッシュされていないローカルの3つのコミットがあることを意味します。最後に、testingブランチはどのリモートブランチも追跡していないことがわかります。

これらの数値は、各サーバーから最後にフェッチしてからのものであることに注意することが重要です。このコマンドはサーバーにアクセスせず、これらのサーバーからローカルにキャッシュされた情報を示しています。完全に最新の先行/遅延数値が必要な場合は、これを実行する直前にすべてのリモートからフェッチする必要があります。これは次のように行えます。

$ git fetch --all; git branch -vv

プル

git fetchコマンドは、まだ持っていないサーバー上のすべての変更を取得しますが、作業ディレクトリを一切変更しません。単にデータを取得し、自分でマージできるようにします。しかし、git pullというコマンドがあり、これはほとんどの場合、git fetchの直後にgit mergeが続くものです。前のセクションで示したように、明示的に設定するか、cloneまたはcheckoutコマンドによって作成されたトラッキングブランチを設定している場合、git pullは現在のブランチが追跡しているサーバーとブランチを検索し、そのサーバーからフェッチし、そのリモートブランチをマージしようとします。

リモートブランチの削除

リモートブランチでの作業が終了したとします。たとえば、あなたと共同作業者が機能の作業を終え、それをリモートのmasterブランチ(または安定したコードラインがあるブランチ)にマージしました。git push--deleteオプションを使用してリモートブランチを削除できます。サーバーからserverfixブランチを削除したい場合は、次のコマンドを実行します。

$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
 - [deleted]         serverfix

基本的に、これはサーバーからポインタを削除するだけです。Gitサーバーは、ガベージコレクションが実行されるまでデータをしばらく保持するため、誤って削除された場合でも、多くの場合簡単に回復できます。

scroll-to-top