git fetch コマンドは、リモートリポジトリからコミット、ファイル、参照をローカルリポジトリにダウンロードします。フェッチはほかのユーザー全員の作業内容を確認するときに実行します。中心的な履歴の進捗状況を確認する点では svn update に似ていますが、変更をリポジトリにマージするよう強制されることはありません。Git ではフェッチしたコンテンツを既存のローカルコンテンツから分離するため、ローカルの開発作業には一切影響が出ません。フェッチしたコンテンツは、git checkout コマンドを使用して明示的にチェックアウトする必要があります。このためフェッチすると、コミットをローカルリポジトリに統合する前に安全にレビューできます。

リモートリポジトリからコンテンツをダウンロードするときは、git pull コマンド、git fetch コマンドを使用してタスクを実行できます。git fetch はこれら 2 つのコマンドの「安全」な方と考えて構いません。リモートコンテンツがダウンロードされますが、ローカルリポジトリの作業状態は更新されず、現在の作業がそのまま残ります。これに対し git pull は、より積極的な選択肢です。リモートコンテンツがアクティブなローカルブランチにダウンロードされ、すぐに git merge が実行されて、新しいリモートコンテンツのマージコミットを作成します。現在の作業に保留中の変更がある場合は、これにより競合が起こるため、マージ競合を解決するフローが開始されます。

リモートブランチでの git fetch の具体的な動作

git fetch の具体的な動作について理解を深めるため、Git がコミットを整理して保存する仕組みについて話しましょう。内部を見ると、Git ではリポジトリの ./.git/objects ディレクトリにリモートとローカルのコミットがすべて保存されます。Git ではブランチの参照を使用することで、リモートとローカルのブランチのコミットがはっきりと区別されます。ローカルブランチの参照は ./.git/refs/heads/ に保存されます。git branch コマンドを実行すると、ローカルブランチの参照のリストが出力されます。以下はデモ用のブランチ名を含む git branch 出力の例です。

git branch
master
feature1
debug2

/.git/refs/heads/ ディレクトリの中を調べると、同様の出力を確認できます。

ls ./.git/refs/heads/
master
feature1
debug2

リモートブランチはローカルブランチとよく似ていますが、リモートブランチでは所有者の異なるリポジトリからのコミットにマッピングされる点で異なります。リモートブランチとローカルブランチを混同しないように、リモートブランチには所属するリモートのプレフィックスが付いています。ローカルブランチと同じように、Git ではリモートブランチの参照も使用します。リモートブランチの参照は ./.git/refs/remotes/ ディレクトリにあります。次のコードスニペットには、わかりやすく "remote-repo" と名付けられたリモートリポジトリをフェッチした後に表示されるブランチの例を示しています。

git branch -r
# origin/master
# origin/feature1
# origin/debug2
# remote-repo/master
# remote-repo/other-feature

この出力には、先ほど見たローカルブランチが表示されていますが、今度は origin/ というプレフィックスが付いています。また今度はリモートブランチに remote-repo というプレフィックスが付いているのがわかります。リモートブランチはローカルブランチと同じ要領でチェックアウトできますが、その結果、detached HEAD 状態になります (古いコミットのチェックアウトと同様)。これらは読み取り専用ブランチと考えることができます。リモートブランチを表示するには、-r フラグを git branch コマンドに渡します。

通常の git checkout コマンドや git log コマンドを使用してリモートブランチの内容を確認できます。リモートブランチに含まれる変更を承認する場合、通常の git merge コマンドを使用してそれをローカルリポジトリにマージできます。したがって、SVN とは異なり、ローカルリポジトリをリモートリポジトリと同期する操作は、実際にはフェッチとマージの二段階の操作です。git pull コマンドはこの二段階の操作を簡便化します。

Get fetch コマンドとオプション

git fetch <remote>

リポジトリからすべてのブランチをフェッチするコマンドです。このコマンドを実行すると、付随するすべてのコミットおよびファイルもそのリポジトリからダウンロードされます。

git fetch <remote> <branch>

上のコマンドと同様の機能を有するコマンドですが、ただしフェッチする対象は指定したブランチのみです。

git fetch --all

上は、登録されたリモートとブランチをすべてフェッチする強力な操作です。

git fetch --dry-run

この --dry-run オプションを指定すると、このコマンドの実行デモが実行されます。フェッチ中に起こるアクションの例を出力しますが、実際には適用しません。

git fetch の例

リモートブランチの git fetch

次の例では、リモートブランチをフェッチしてローカルの作業状態をリモートコンテンツで更新する方法を示します。この例では、原典とする中央リポジトリである「origin」があり、git clone コマンドを使用してそこからローカルリポジトリのクローンが作成されているものとします。また feature_branch を含む "coworkers_repo" という別のリモートリポジトリがあると仮定し、その設定とフェッチを行います。これらの前提に基づき、引き続きこの例を見ていきましょう。

まず git remote コマンドを使用してリモートリポジトリを設定する必要があります。

git remote add coworkers_repo git@bitbucket.org:coworker/coworkers_repo.git

ここではリポジトリの URL を使用して coworkers のリポジトリへの参照を作成しました。今度はこのリモートの名前を git fetch に渡してコンテンツをダウンロードします。

git fetch coworkers feature_branch
fetching coworkers/feature_branch

ローカルに coworkers/feature_branch のコンテンツを用意したところで、今度はこれをローカルの作業コピーに統合する必要があります。このプロセスを始めるに当たり、git checkout コマンドを使用して、新しくダウンロードしたリモートブランチをチェックアウトしましょう。

git checkout coworkers/feature_branch
Note: checking out coworkers/feature_branch'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b <new-branch-name>

このチェックアウト操作の出力を見ると、detached HEAD 状態になっています。これは想定どおりであり、HEAD 参照がローカルの履歴と適合しない参照をポイントしていることがわかります。coworkers/feature_branch の参照で HEAD がポイントされているため、この参照から新しいローカルブランチを作成できます。上の 'detached HEAD' の出力を見ると、git checkout コマンドを使用してこの操作を行う具体的な方法がわかります。

git checkout -b local_feature_branch

ここでは「local_feature_branch」という新しいローカルブランチを作成しました。これで、最新のリモートコンテンツをポイントするよう HEAD が更新されるため、このポイントから開発を続行できます。

git fetch と origin の同期

次の例では、ローカルリポジトリを中央リポジトリの master ブランチと同期する際の典型的なワークフローを説明します。

git fetch origin

このコマンドを実行すると、ダウンロードされたブランチが表示されます:

a1e8fb5..45e66a4 master -> origin/master
a1e8fb5..9e8ab1c develop -> origin/develop
* [new branch] some-feature -> origin/some-feature

下図では、これらの新しいリモートブランチに含まれるコミットは円ではなく四角形で表示されています。これでわかるとおり、git fetch コマンドを実行すると、別のリポジトリのブランチ全体にアクセスできます。

上流の master に加えられたコミットを調べる場合は、次のように origin/master をフィルターとして使用し、git log コマンドを実行します。

git log --oneline master..origin/master

以下のコマンドで、変更を承認してローカルの master ブランチにマージします。

git checkout master
git log origin/master

次に git merge origin/master を使用します。

git merge origin/master

origin/master および master ブランチは同じコミットをポイントし、上流の開発と同期します。

git fetch の概要

ここまでを振り返りましょう。git fetch はリモートリポジトリからコンテンツをダウンロードするために使用する主要コマンドです。ローカルリポジトリをリモートの状態に更新するときは、git fetchgit remotegit branchgit checkoutgit reset と組み合わせて使用します。git fetch コマンドは、コラボレーションによって進行する Git のワークフローに欠かせない重要な要素です。git fetchgit pull と動作が似ていますが、git fetch の方が安全で、操作に支障をきたしません。