
2025/12/26 21:46
パッケージマネージャはいつもGitをデータベースとして使い続けるので、結局うまく動かない。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
パッケージマネージャは、Git の設計が小規模でローカルな履歴に最適化されているため、大規模レジストリではスケールしにくいという理由から、主要なストレージ層として生の Git リポジトリを使用することをやめつつあります。Cargo、Homebrew、CocoaPods、vcpkg、Go modules、Nixpkgs などのプロジェクトは、深い Git 履歴に依存すると顕著な遅延やインフラ警告が報告されています。高価な
操作を回避するため、これらのツールは現在、RFC 2789 のスパース HTTP ダウンロード、JSON エンドポイント、CDN ベースの配信、浅いフェッチ制限、および高速点検索をサポートするデータベースバックエンドなどの技術を使用しています。git clone
かつて Cargo はフル Git インデックスから RFC 2789 のスパースプロトコルへ切り替えました;Homebrew は 2023 年に浅いクローンを停止し、タップ更新には JSON を採用しました;CocoaPods は GitHub が大規模リポジトリに CPU 制限を課した後、CDN に移行しました;Nixpkgs は 83 GB のリポジトリが保守警告を引き起こしたため、Git ではなく S3/CDN 上に表現式を保存しています;vcpkg は再現性のために完全な履歴が必要であり、浅いクローンは依存解決を破綻させます。Go modules は Go 1.13 で GOPROXY(HTTP アーカイブ + sumdb)へ切り替え、の時間を約 18 分から約 12 秒に短縮し、暗号学的な完全性チェックも追加しました。go get
同様のスケーラビリティ問題は Git ベースのウィキ(Gollum)、CMS プラットフォーム(Decap)、GitOps ツール(ArgoCD)にも影響を与え、多くがストレージバックエンドとして git を放棄しています。根本原因はファイルシステム上の制約―過剰なファイル数、ケースセンシティブ性の衝突、パス長制限―とインデックスやロックなどのデータベース機能の欠如にあります。
トレンドとしては、メタデータの高速点検索を可能にする HTTP/CDN やデータベースバックエンドへ移行し、パッケージマネージャは残存する Git の制限を緩和するためにカスタムシャーディングやサーバー側チェックを追加しています。ユーザーにとってはインストールや更新が速くなります;企業は追加の CDN やデータベースインフラが必要になるかもしれませんが、スケーラビリティを得られます。最終的には、業界は Git の協働強みを保ちつつ、大規模配布により適したシステムを併用するハイブリッドモデルを採用できるでしょう。
本文
Gitをデータベースとして使うのは魅力的なアイディアです。
バージョン履歴が自動で取得でき、プルリクエストがレビュー作業フローを提供し、設計上分散型です。GitHub が無料でホスティングしてくれますし、誰もが使い方を知っています。
パッケージマネージャはこの誘惑に何度も引っかかり、うまくいきません
Cargo
crates.io のインデックスは最初 git リポジトリとして始まりました。Cargo クライアントはすべてこれをクローンしました。レジストリが小さかった頃は問題ありませんでしたが、インデックスは膨張し続けました。ユーザーは「デルタ解決中: 74.01 % (64415/95919)」といったプログレスバーが長時間ハングするのを目にします――これは Cargo の libgit2 ライブラリが何千もの過去コミットを含むリポジトリでデルタ解決を行っているためです。
CI では特に酷い。ステートレス環境は全インデックスをダウンロードし、ほんのごく一部だけを使い、ビルドごとに捨てます。
RFC 2789 によりスパース HTTP プロトコルが導入されました。これで Cargo はリポジトリ全体をクローンする代わりに HTTPS 経由でファイルを直接取得し、自分のプロジェクトが実際に使う依存関係のメタデータだけをダウンロードします。2025年4月時点で、crates.io へのリクエストの99 %はスパースがデフォルトとなっている Cargo バージョンから来ています。git インデックスはまだ存在し、日々数千コミットずつ増え続けますが、多くのユーザーは触れません。
Homebrew
GitHub は Homebrew に浅いクローン(shallow clone)の使用をやめるよう明示的に要求しました。ツリー構造と homebrew‑core、homebrew‑cask のトラフィックにより、更新は「非常に高価な操作」とされました。ユーザーは homebrew‑core を浅くするためだけに 331 MB をダウンロードし、
.git フォルダーが一部のマシンで 1 GB に達しました。brew のアップデートごとに git がデルタ解決を行うまで待たなければならず、時間がかかります。
2023年2月の Homebrew 4.0.0 は「git fetch と git clone が高価で遅い」ため、tap 更新を JSON ダウンロードへ切り替えました。これにより Auto‑updates は 5 分ごとではなく 24 時間ごとに走るようになり、git フェッチが不要になるので大幅に高速化しました。
CocoaPods
iOS・macOS 用のパッケージマネージャである CocoaPods は限界に直面しました。Specs リポジトリは数十万の podspec を深く入れ子になったディレクトリ構造で保持していました。クローンや更新が数分を要し、CI 時間が git 操作に吸い込まれました。
GitHub は CPU レート制限を課しました。原因は浅いクローンでした――これにより GitHub のサーバーはクライアントが既に持っているオブジェクトを計算しなければならなくなるからです。チームは
pod install で自動フェッチ停止、浅いクローンをフルクローンへ変換、リポジトリのシャーディングといったバンドエイドを試みました。
CocoaPods 1.8 はほとんどユーザーに git を完全に排除しました。CDN がデフォルトになり、podspec ファイルは HTTP で直接配信されます。この移行により、ユーザーは約 1 GB のディスクスペースを節約し、新規セットアップ時の
pod install はほぼ即座に完了します。
Nixpkgs
Nix はクライアント側問題をすでに解決していました。パッケージマネージャは S3 と CDN から tarball を取得し、git クローンではなくチャネル経由で表現式をフェッチします。ビルド済みパッケージは HTTP 経由でバイナリキャッシュから配信され、エンドユーザーは git リポジトリに触れません。
しかしリポジトリ自体が GitHub のインフラをテストしています。2025年11月、GitHub は NixOS チームへ「定期メンテナンスジョブの失敗とレプリカ間の合意取得障害」が発生していることを通知しました。解決しなければリポジトリは読み取り専用になる可能性がありました。
リポジトリ全体は 83 GB、50万のツリーオブジェクトと 20,000 のフォークがあります。ローカルクローンは 2.5 GB にすぎません。残りは GitHub のフォークネットワークが各プルリクエストブランチやマージコミットを保持しています。CI は毎日マージ可能性を問い合わせ、新しいマージコミットを生成します。
vcpkg
Microsoft の C++ パッケージマネージャである vcpkg は、ポートのバージョン管理に git ツリーハッシュを使用します。
github.com/Microsoft/vcpkg にある curated registry には 2,000 を超えるライブラリがあります。
問題は「builtin-baseline」を
vcpkg.json(再現可能ビルド用ロックファイル)で指定すると、vcpkg が過去コミットを検索して正確なポートバージョンを見つける必要があることです。これには完全なコミット履歴が不可欠です。
浅いクローンはすべてを壊します。GitHub Actions はデフォルトで浅いクローンを使用し、DevContainers もスペース節約のために vcpkg を浅くクローンします。CI システムは高速チェックアウトを最適化しています。結果として「vcpkg が浅いリポジトリとしてクローンされました…フルクローンで再試行してください」というエラーが発生します。
ワークアラウンドは醜く、
vcpkg.json からベースラインハッシュを抽出し、コミット日付を導き出して --shallow-since=<date> でフェッチするか、12 ヶ月分の履歴を含めてプロジェクトがベースラインを超える前にアップグレードされることを期待します。GitHub Actions ではチェックアウトステップに fetch-depth: 0 を指定し、依存関係解決のためにリポジトリ全履歴をダウンロードします。
vcpkg チームメンバーは「ポートバージョンはコミットハッシュを使用せず、ポートディレクトリの git ツリー ハッシュを使用する。特定のツリー ハッシュを追加したコミットを推測する方法はない」と説明しました。製品内修正は不可能で、git が深く組み込まれているため抜け道がありません。
Cargo、Homebrew、CocoaPods とは異なり、vcpkg は git レジストリから離れる計画を発表していません。カスタムレジストリはまだ git リポジトリである必要があります。ドキュメントではファイルシステムレジストリが代替として記載されていますが、これはローカルまたはマウントされたパスが必要で、HTTP アクセス・CDN・スパースプロトコルを利用できない状況です。
Go modules
Grab のエンジニアチームは
go get を 18 分から 12 秒に短縮しました。これは単なるタイポではありません。問題は go get が各依存関係のソースコードをフェッチして go.mod ファイルだけを読み取り、転送依存関係を解決する必要があったことです―1 ファイル取得のためにリポジトリ全体をクローンしなければならないのです。
Go はセキュリティ面でも懸念を抱えていました。元々は Bazaar や Fossil などで開発されたパッケージが「VCS ツールをインストールできない/使用したくないユーザーには利用不可」という分断を招くため、バージョン管理ツール自体を除外する設計でした。さらに VCS ツールの脆弱性が
go get のセキュリティに直結する恐れもありました。
Go 1.13 で
GOPROXY がデフォルトになりました。プロキシはソースアーカイブと go.mod ファイルを HTTP 経由で独立して提供します。また、チェックサムデータベース(sumdb)が導入され、モジュール内容の暗号学的ハッシュを記録し、強制プッシュによるタグ変更やリポジトリ削除時にもモジュールが利用可能な状態を保ちます。
パッケージマネージャ以外でも同様のパターン
Git をデータベースとして使うとき、開発者は以下のように同じ問題に直面します。
- Gollum(GitHub・GitLab が利用)などの Git ベース Wiki はスケールすると「やや遅すぎて使えない」ほどになり、ディレクトリ構造を閲覧するだけで数秒かかります。GitLab は完全に Gollum から離れる計画です。
- Decap のような Git ベース CMS は GitHub API のレート制限に直面します。大量のコレクション関係があると、10,000 エントリまでしかスケールできません。新規ユーザーはキャッシュが空で各エントリを取得するたびに 5,000 リクエスト制限をすぐに消費します。頻繁に更新されるサイトではデータベースの方が適しています。
- GitOps ツールも git の制約を回避しなければなりません。ArgoCD のリポジトリサーバはリポジトリクローンでディスクスペース不足になることがあります。単一コミットで全アプリケーションのキャッシュが無効化され、モノレポは特別なスケーリングを必要とします。
パターン
ホスティング上の問題は表面的な症状です。本質的には「git がファイルシステムの制限を継承し、ファイルシステムは悪いデータベースになる」という事実にあります。
| 問題 | 例 |
|---|---|
| ディレクトリ上限 | CocoaPods は フォルダー内で 16,000 個の pod ディレクトリを持ち、巨大なツリーオブジェクトと高コスト計算が必要でした。解決策はハッシュベースシャーディング:名前の先頭数文字でディレクトリを分割し、単一ディレクトリに過剰なエントリが入らないようにしました。Git 自体も フォルダーで 256 個のサブディレクトリへ分割しています。 |
| 大文字小文字感度 | Git はケースセンシティブですが、macOS や Windows のファイルシステムは通常そうではありません。 と を同時に持つリポジトリを Windows でチェックアウトすると二番目が一番目を上書きします。Azure DevOps はサーバー側でケース衝突のプッシュをブロックするようになりました。 |
| パス長制限 | Windows は 260 文字までしか許容しません(DOS 時代から)。Git は長いパスをサポートしますが、Git for Windows は OS 制限に従います。深くネストされた ディレクトリでは が「Filename too long」エラーになります。 |
| データベース機能の欠如 | データベースは CHECK / UNIQUE 制約を持ち、git にはありません。そのためパッケージマネージャは独自に検証層を構築します。ロック・コンテストも git にはなく、全てのアプリが同時に更新することが難しいです。「X に依存しているすべてのパッケージ」をクエリできるインデックスも git では自前で作らないといけません。スキーマ変更は「履歴を書き換えて全員に再クローンを強制する」形になります。 |
進化は予測可能です:フラットなファイルディレクトリ → ファイルシステム上限 → シャーディング実装 → クロスプラットフォーム問題への対処 → サーバー側検証構築 → カスタムインデックス作成 → ついに HTTP や本物のデータベースへ移行。結果として、git のフック・CI パイプライン・独自ツールで「既存のデータベース機能を再実装」する糸口が増えます。
結論
Git が悪いという意味ではありません。Git は設計通りに分散協働、ブランチ・マージ・オフライン作業を得意とします。問題は「全く別の用途」で使おうとしている点です。パッケージレジストリはメタデータへの高速ポイントクエリが必要で、git はキー‑バリュー検索よりも完全ドキュメント同期プロトコルを提供してしまいます。
もしパッケージマネージャを構築し、「git-as-index」が魅力的に見えるなら、Cargo、Homebrew、CocoaPods、vcpkg、Go などの事例を参考にしてください。彼らは成長とともにワークアラウンドを作り、ユーザーとメンテナーに痛みを与えてきました。プルリクエストフローやバージョン履歴は魅力的ですが、同じ壁に直面することになるでしょう。