チャプター ▾ 第2版

7.12 Git ツール - バンドル

バンドル

Git データをネットワーク経由で転送する一般的な方法(HTTP、SSH など)については説明しましたが、実はもうひとつ、あまり使われていませんが非常に便利な方法があります。

Git には、そのデータを単一のファイルに「バンドル」する機能があります。これは様々なシナリオで役立ちます。例えば、ネットワークがダウンしていて、同僚にUに変更を送信したい場合。あるいは、オフサイトで作業していて、セキュリティ上の理由からローカルネットワークにアクセスできない場合。ワイヤレス/イーサネットカードが故障した場合。一時的に共有サーバーにアクセスできない場合、誰かに更新をメールで送りたいが、40コミットをformat-patchで転送したくない場合。

ここでgit bundleコマンドが役立ちます。bundleコマンドは、通常git pushコマンドでネットワーク経由でプッシュされるすべてのデータをバイナリファイルにまとめます。このファイルを誰かにメールで送信したり、USBフラッシュドライブに入れたりして、別のリポジトリでアンバンドルできます。

簡単な例を見てみましょう。2つのコミットを持つリポジトリがあるとします。

$ git log
commit 9a466c572fe88b195efd356c3f2bbeccdb504102
Author: Scott Chacon <schacon@gmail.com>
Date:   Wed Mar 10 07:34:10 2010 -0800

    Second commit

commit b1ec3248f39900d2a406049d762aa68e9641be25
Author: Scott Chacon <schacon@gmail.com>
Date:   Wed Mar 10 07:34:01 2010 -0800

    First commit

そのリポジトリを誰かに送りたいが、プッシュするリポジトリにアクセスできない、または単に設定したくない場合は、git bundle createでバンドルできます。

$ git bundle create repo.bundle HEAD master
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 441 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)

これで、リポジトリのmasterブランチを再作成するために必要なすべてのデータを含むrepo.bundleというファイルができました。bundleコマンドでは、含めたいすべての参照または特定のコミット範囲をリストアップする必要があります。これを別の場所でクローンするつもりなら、ここで示したようにHEADも参照として追加すべきです。

このrepo.bundleファイルを誰かにメールで送ったり、USBドライブに入れて手渡したりできます。

一方、このrepo.bundleファイルを受け取って、プロジェクトに取り組みたいとします。URLからクローンするのと同じように、このバイナリファイルからディレクトリにクローンできます。

$ git clone repo.bundle repo
Cloning into 'repo'...
...
$ cd repo
$ git log --oneline
9a466c5 Second commit
b1ec324 First commit

参照にHEADを含めなかった場合、-b masterまたは含まれているブランチを指定する必要があります。そうしないと、どのブランチをチェックアウトすればよいかわかりません。

さて、3つのコミットを行い、USBスティックまたはメールで新しいコミットをバンドルで送り返したいとします。

$ git log --oneline
71b84da Last commit - second repo
c99cf5b Fourth commit - second repo
7011d3d Third commit - second repo
9a466c5 Second commit
b1ec324 First commit

まず、バンドルに含めたいコミットの範囲を決定する必要があります。ネットワークプロトコルがネットワーク経由で転送する最小限のデータセットを自動的に判断してくれるのとは異なり、私たちはこれを手動で判断する必要があります。もちろん、同じようにリポジトリ全体をバンドルすることもできますが、それはうまくいきます。しかし、作成したばかりの3つのコミットだけをバンドルする方が良いです。

それを行うには、差分を計算する必要があります。 「コミット範囲」で説明したように、コミットの範囲はいくつかの方法で指定できます。元々クローンしたブランチにはなかった、私たちのmasterブランチにある3つのコミットを取得するには、origin/master..masterまたはmaster ^origin/masterのようなものを使用できます。これはlogコマンドでテストできます。

$ git log --oneline master ^origin/master
71b84da Last commit - second repo
c99cf5b Fourth commit - second repo
7011d3d Third commit - second repo

バンドルに含めるコミットのリストができたので、それらをバンドルしましょう。git bundle createコマンドを使用して、バンドルのファイル名と含めたいコミットの範囲を指定します。

$ git bundle create commits.bundle master ^9a466c5
Counting objects: 11, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (9/9), 775 bytes, done.
Total 9 (delta 0), reused 0 (delta 0)

これで、ディレクトリにcommits.bundleファイルが作成されました。これをパートナーに送ると、その間にさらに作業が進んでいたとしても、彼女はそれを元のリポジトリにインポートできます。

バンドルを受け取ったとき、彼女はそれをリポジトリにインポートする前に、何が含まれているかを確認できます。最初のコマンドはbundle verifyコマンドで、ファイルが実際に有効なGitバンドルであり、適切に再構成するために必要なすべての祖先を持っていることを確認します。

$ git bundle verify ../commits.bundle
The bundle contains 1 ref
71b84daaf49abed142a373b6e5c59a22dc6560dc refs/heads/master
The bundle requires these 1 ref
9a466c572fe88b195efd356c3f2bbeccdb504102 second commit
../commits.bundle is okay

もしバンドラーが、3つのコミットすべてではなく、彼らが実行した最後の2つのコミットだけをバンドルしていた場合、元のリポジトリは必要な履歴が欠落しているため、それをインポートできませんでした。その場合、verifyコマンドは次のように表示されたでしょう。

$ git bundle verify ../commits-bad.bundle
error: Repository lacks these prerequisite commits:
error: 7011d3d8fc200abe0ad561c011c3852a4b7bbe95 Third commit - second repo

しかし、最初のバンドルは有効なので、そこからコミットをフェッチできます。バンドルにインポートできるブランチが何であるかを確認したい場合、ヘッドをリストするコマンドもあります。

$ git bundle list-heads ../commits.bundle
71b84daaf49abed142a373b6e5c59a22dc6560dc refs/heads/master

verifyサブコマンドもヘッドを教えてくれます。要点は何がプルできるかを見ることなので、fetchまたはpullコマンドを使ってこのバンドルからコミットをインポートできます。ここでは、バンドルのmasterブランチを、私たちのリポジトリのother-masterという名前のブランチにフェッチします。

$ git fetch ../commits.bundle master:other-master
From ../commits.bundle
 * [new branch]      master     -> other-master

これで、インポートされたコミットがother-masterブランチに、そしてその間に私たちのmasterブランチで行われたコミットも確認できます。

$ git log --oneline --decorate --graph --all
* 8255d41 (HEAD, master) Third commit - first repo
| * 71b84da (other-master) Last commit - second repo
| * c99cf5b Fourth commit - second repo
| * 7011d3d Third commit - second repo
|/
* 9a466c5 Second commit
* b1ec324 First commit

つまり、git bundleは、適切なネットワークや共有リポジトリがない場合に、共有やネットワークタイプの操作を行うのに非常に役立ちます。

scroll-to-top