Gitにおける巨大ファイルの未来はGitだ
原文は Tyler Cipriani により に公開されました。 このブログを購読する
Gitに天敵がいるとすれば、それは巨大なファイルだ。
巨大なファイルはGitのストレージを肥大化させ、git cloneを遅くし、Gitホスティングサービスに混乱をもたらす。
2015年、GitHubはGit LFSをリリースした。巨大ファイルの問題を力技で回避するGitの拡張機能だ。だがGit LFSは、新たな複雑さとストレージコストをもたらした。
一方で、Gitプロジェクトは水面下で巨大ファイルへの対応を進めてきた。そしてLFSはまだ現役ではあるものの、最新のGitのリリースは、LFSがついに不要になる未来への道筋を示している。
今すぐできること:Git LFSをGitのpartial cloneに置き換える
Git LFSは、巨大なファイルをリポジトリの外に保存することで機能する。
LFS経由でプロジェクトをクローンすると、リポジトリの履歴と小さなファイルは手に入るが、巨大なファイルはスキップされる。代わりにGit LFSは、作業コピーに必要な巨大なファイルだけをダウンロードする。
2017年、GitプロジェクトはGit LFSと同じ利点を提供するpartial cloneを導入した。
partial cloneにより、クローンやフェッチの際に[大きなバイナリアセット]を事前にダウンロードするのを避け、ダウンロード時間とディスク使用量を削減できる。
– Partial Clone Design Notes、git-scm.com
Gitのpartial cloneもLFSも、以下の点を実現する。
- 小さなチェックアウト – クローン時には、巨大なファイルのすべてのコピーではなく、最新のコピーだけを取得する。
- 高速なクローン – 巨大なファイルのダウンロードを避けるため、クローンは高速だ。
- 素早いセットアップ – shallow cloneとは異なり、プロジェクトの全履歴を取得できるため、すぐに作業を開始できる。
partial cloneとは?
Gitのpartial cloneとは、--filterを付けたクローンのことだ。
たとえば、100KBより大きなファイルのダウンロードを避けたい場合は、次のようにする。
git clone --filter='blobs:size=100k' <repo>その後、チェックアウトに必要な100KBを超えるファイルは、Gitが必要に応じて遅延ダウンロードする。
デフォルトでは、厄介な25MBのPNGファイルが何度も改訂されたリポジトリをgit cloneすると、クローンは遅く、チェックアウトは目障りなほど肥大化する。
$ time git clone https://github.com/thcipriani/noise-over-git
Cloning into '/tmp/noise-over-git'...
...
Receiving objects: 100% (153/153), 1.19 GiB
real 3m49.052sたった25MBのファイル1つをチェックアウトするのに、ほぼ4分もかかる!
$ du --max-depth=0 --human-readable noise-over-git/.
1.3G noise-over-git/.
$ ^ 🤬そして、そのたった1つの25MBファイルの50リビジョンで、1.3GBもの容量を食う。
だがpartial cloneなら、こうした問題を回避できる。
$ git config --global alias.pclone 'clone --filter=blob:limit=100k'
$ time git pclone https://github.com/thcipriani/noise-over-git
Cloning into '/tmp/noise-over-git'...
...
Receiving objects: 100% (1/1), 24.03 MiB
real 0m6.132s
$ du --max-depth=0 --human-readable noise-over-git/.
49M noise-over-git/
$ ^ 😻 (the same size as a git lfs checkout)フィルタのおかげでクローンは97%高速化し(3分49秒→6秒)、チェックアウトサイズは96%削減された(1.3GB→49M)!
ただし、いくつか注意点もある。
フィルタで除外したデータを必要とするコマンドを実行すると、Gitはそれを取得するためにサーバーに問い合わせる必要がある。そのため、git diffやgit blame、git checkoutといったコマンドは、実行時にGitホスティングサービスへのアクセスが必要になる。
だが、巨大なファイルに関しては、これはGit LFSと同じ挙動だ。
そもそも、PNGにgit blameをかけた記憶なんてないし🙃。
なぜわざわざ手間をかけるのか? Git LFSの何が問題なのか?
Git LFSは、Gitが抱える巨大ファイルの問題をユーザーに押し付けている。
そしてその問題は深刻だ。
- 🖕 強力なベンダーロックイン – GitHubがGit LFSを作った当時、他の巨大ファイル用システムであるGit FatやGit Annex、Git Mediaはサーバー側に依存しなかった。だがGitHubはユーザーを自社のプロプライエタリなサーバー実装に縛り付け、その利用に課金した。1
- 💸 高コスト – GitHubはリポジトリを無料でホストできることで勝利した。だがGit LFSは当初有料プロダクトとして始まった。現在は無料枠もあるが、価格設定はGitHubの気まぐれに左右される。今日、GitHubで50GBのリポジトリをホストするとストレージに年40ドルかかる。一方、Amazon S3の標準ストレージで50GBを保存するコストは年13ドルだ。
- 😰 元に戻すのが困難 – いったんGit LFSに移行すると、履歴を書き換えずに元に戻すことは不可能だ。
- 🌀 継続的なセットアップコスト – 共同作業者全員がGit LFSをインストールする必要がある。Git LFSがインストールされていないと、共同作業者は期待する巨大なファイルの代わりに、メタデータだらけの不可解なテキストファイルを手にすることになる。
未来:Gitのlarge object promisor
巨大なファイルは、Gitホスティングサービス側にも問題を引き起こす。
GitHubやGitLabは、大きなファイルほどホストコストがかさむため、ファイルサイズに制限を設けている2。Git LFSは、巨大なファイルをCDNにオフロードすることでサーバー側のコストを抑えている。
だがGitプロジェクトには新たな解決策がある。
今年の初め、Gitは新機能であるlarge object promisorをマージした。large object promisorは、ユーザー側の手間を省きつつ、LFSと同じサーバー側の利点を提供することを目指している。
この取り組みは特にサーバー側の改善を目的としており、とりわけすでにバイナリ形式で圧縮された大きなblobを対象としている。
この取り組みはGit LFSの代替を提供することを目的としている。
– Large Object Promisors、git-scm.com
large object promisorとは?
large object promisorとは、巨大なファイルだけを格納する特別なGitリモートのことだ。
明るく輝かしい未来では、large object promisorは次のように動作する。
- あなたは巨大なファイルをGitホスティングサービスにプッシュする。
- バックグラウンドで、Gitホスティングサービスはその巨大なファイルをlarge object promisorにオフロードする。
- クローンする際、GitホスティングサービスはGitクライアントにpromisorの存在を伝える。
- クライアントはGitホスティングサービスからクローンし、巨大なファイルは自動的にpromisorリモートから取得する。
だが、その明るく輝かしい未来には、まだ距離がある。
Gitのlarge object promisorはまだ開発途上だ。その一部は2025年3月にGitへマージされた。だが、やるべきことはまだ残っており、未解決の疑問もある。
だから今のところ、巨大なファイルにはGit LFSを使わざるを得ない。だがlarge object promisorが広く普及すれば、いつかGitHubでも100MBを超えるファイルをプッシュできるようになるかもしれない。
Gitにおける巨大ファイルの未来はGitだ。
Gitプロジェクトが巨大ファイルについて真剣に考えてくれている。だからあなたが悩む必要はない。
今日のところは、Git LFSから逃れられない。
だが近いうちに、Gitで巨大ファイルを扱う際の唯一の障害は、「MP3ライブラリをGitに突っ込むのはまずい」という、うっすらと記憶に残る不吉な予感だけになるだろう。
後になって、他のGitホスティングサービスが独自のLFSサーバーを作った。今日では複数のGitホスティングサービスにプッシュしたり、LFSトランスファーエージェントを使ったりすることもできるが、いずれもコントリビューターにとってセットアップは複雑になる。余計な手間をかけない限り、ほぼロックインされたままだ。↩︎
ファイルサイズ制限:100MB for GitHub、100MB for GitLab.com↩︎
記事をランダムに読む
コメント
ログインしてコメントする