7 ポイント 投稿者 GN⁺ 2025-12-27 | 2件のコメント | WhatsAppで共有
  • 多くの パッケージマネージャー は、バージョン管理やコラボレーションの利便性から Gitをデータベースのように利用してきたが、規模が大きくなるにつれて性能と保守の問題に突き当たった
  • CargoHomebrewCocoaPods などは、Gitインデックスの肥大化や更新速度の低下、CI環境での非効率により、最終的に HTTPベースのインデックスやCDN へ移行した
  • vcpkg は依然としてGitツリーハッシュを基盤に動作しており、浅いクローン(shallow clone)環境では ビルド失敗や複雑な回避策 が発生する
  • Goモジュールシステム は GOPROXY と チェックサムデータベース(sumdb) を導入し、Git依存を取り除いてセキュリティと速度を改善した
  • Gitはコードの共同作業には優れているが、パッケージメタデータの問い合わせや大規模レジストリ管理には不向き であることが繰り返し示されている

Gitをデータベースとして使う試みの反復的な失敗

  • Gitは バージョン履歴、分散構造、無料ホスティング などの利点により魅力的だが、データベースとして使うとスケーラビリティの限界に突き当たる
  • 複数のパッケージマネージャーがGitをインデックスとして採用したものの、時間の経過とともに 性能低下とインフラ負荷 が深刻化した

Cargo

  • crates.io インデックス はGitリポジトリとして始まり、すべてのクライアントが完全な複製(clone)を行っていた
    • リポジトリが大きくなるにつれ、delta resolution の段階で libgit2 の性能ボトルネック が発生した
    • CI環境では、ビルドのたびにインデックス全体をダウンロードするため無駄が大きかった
  • RFC 2789 により sparse HTTP プロトコル が導入され、必要なメタデータだけを HTTPS で取得する形に改善された
    • 2025年4月時点で、リクエストの99%が sparse モードを使用
    • Gitインデックスは今も存在するが、大半のユーザーはアクセスしていない

Homebrew

  • GitHub はHomebrewに対し 浅いクローンの利用停止 を要請し、更新が「非常に高コストな処理」だと指摘した
    • homebrew-core の .git フォルダは1GB近くに達し、更新時に delta resolution による遅延が発生した
  • 2023年2月の Homebrew 4.0.0 で tap 更新を JSON ダウンロード方式 に切り替えた
    • Git fetch をなくしたことで更新速度が向上し、自動更新周期も5分から24時間に変更された

CocoaPods

  • iOS/macOS向けパッケージマネージャー CocoaPods では、数十万件の podspec からなる Specs リポジトリ が過度に肥大化した
    • クローンや更新に数分かかり、CI時間の大半がGit操作に費やされていた
  • GitHub は CPU rate limit を適用し、浅いクローンがサーバー負荷の原因だと指摘した
  • チームは 自動 fetch の停止、完全クローンへの切り替え、リポジトリのシャーディング などの暫定対応を行った
  • 1.8 バージョン以降はCDNベースのHTTP配信 へ移行し、ユーザーのディスク使用量を約1GB削減、インストール速度も大幅に改善した

Nixpkgs

  • Nix はクライアント側ですでに tarball ベースのチャネル を使っており、Gitクローンを回避している
    • パッケージ式は S3 と CDN から HTTP で配信される
  • しかしGitHubのインフラは、83GB規模のリポジトリと20,000個のフォーク により負荷を受けている
    • 2025年11月、GitHub は レプリカ間の合意失敗と保守作業エラー を報告した
    • ローカルクローンは2.5GBだが、フォークネットワーク全体がGitHubのストレージ容量を圧迫している

vcpkg

  • Microsoft のC++パッケージマネージャー vcpkgGitツリーハッシュ によってバージョン管理している
    • builtin-baseline により特定コミット時点のポートを再現するには、履歴全体が必要になる
  • 浅いクローン環境(GitHub Actions、DevContainers) ではビルド失敗が発生する
    • 回避策として fetch-depth: 0 の設定が必要で、履歴全体のダウンロードが求められる
  • Gitツリーハッシュ構造では コミット追跡が不可能 であり、構造的な制約のため修正できない
  • 依然としてGitリポジトリベースのレジストリしかサポートしておらず、HTTP や CDN の代替手段はない

Goモジュールシステム

  • Grab のエンジニアリングチームは、モジュールプロキシ導入後に go get の時間が18分→12秒 に短縮された
  • 従来方式では、go.mod を読むために各依存関係のリポジトリ全体をクローンする必要があった
  • Goチームは VCSツールへの依存とセキュリティ脆弱性 を懸念していた
  • Go 1.13 以降、GOPROXY がデフォルトとなり、モジュールソースと go.mod を HTTP で提供する
    • sumdb(チェックサムデータベース) により、モジュールの完全性と永続性を保証する

Gitをデータベースとして使う際の一般的な問題

  • GitベースのWiki(Gollum) は、大規模リポジトリでディレクトリ探索やページ読み込みが遅くなる
    • GitLab はGollumの利用中止を計画している
  • GitベースのCMS(Decap) は、GitHub API のリクエスト上限(5,000回)に達する
    • 約10,000件以上で性能が低下し、キャッシュが空の新規ユーザーはリクエストが集中する
  • GitOpsツール(ArgoCD) は、リポジトリのクローン時にディスク容量超過の問題が発生する
    • 単一コミットでキャッシュ全体が無効化され、大規模モノレポでは別途スケーリングが必要になる

Gitがデータベースに不向きな構造的理由

  • ディレクトリの限界: ファイル数が増えるほど遅くなる
    • CocoaPods では16,000個のディレクトリにより巨大なツリーオブジェクトが生成され、ハッシュベースのシャーディングで対処した
  • 大文字・小文字の区別の問題: Gitは区別するが、macOS・Windows は区別しない
    • Azure DevOps は衝突防止のため、サーバー側のブロック機能を追加した
  • パス長制限: Windows の260文字制限により git status エラーが発生する
  • データベース機能の欠如:
    • CHECK/UNIQUE 制約、ロック、インデックス、マイグレーション機能がいずれも存在しない
    • 各パッケージマネージャーが独自の検証・索引システムを構築しなければならない

結論

  • Gitは ソースコードの共同作業 には優れているが、パッケージメタデータの問い合わせや大規模レジストリ管理 には不向きである
  • ほとんどのパッケージマネージャーは最終的に HTTPベースのインデックスやデータベース へ移行した
  • Gitの利点(バージョン履歴、PRワークフロー)は魅力的だが、データベースの代替としては失敗 している
  • 新しいパッケージマネージャーを設計する際、Gitインデックスが魅力的に見えても、Cargo・Homebrew・CocoaPods・vcpkg・Go の事例と同じ限界に到達する

2件のコメント

 
lamanus 2025-12-28

コントリビューターからの貢献を受けるためにシステムを別途作るより、git のほうが手軽だから使っているのでしょう。限界だと言いますが、あまり共感できませんし、現実的な問題に対する代案もまったく見えてきません。

 
GN⁺ 2025-12-27
Hacker Newsの意見
  • これは一種の共有地の悲劇のように見える。GitHubは無料で優れた機能が多いので、みんな使いたがる。しかしこうした意思決定は、外部性があると常に起きる。
    私が最も重要だと考える外部性はユーザーの時間だ。ほとんどのソフトウェア企業はエンジニアリング時間のコストしか気にせず、ユーザーの時間を無視する。機能開発には熱心だが、ユーザーとのインタラクション時間は最適化しない。たとえば、私がアプリを1秒速くするのに1時間使えば、100万人のユーザーが毎年277時間を節約できる。しかしユーザー時間は外部性なので、この種の最適化はほとんど行われない。
    結局、ユーザーは無駄に多くのデータをダウンロードして待たされることになり、開発者はその浪費に責任を負わない

    • 「ソフトウェアハウス」という表現が正確に何を意味するのかは分からないが、私が働いたほとんどのコンシューマー向けソフトウェア製品では、起動速度やレイテンシのような指標を重要項目として追跡していた。こういうことは数十年前から常識だった。たとえば、Amazonがページ読み込みの数ミリ秒の差で数百万ドルを失うという話もよく聞いた
    • これは「速度も**機能(feature)**の一つだ」という話と同じ文脈だ。ただしユーザー時間は単なる性能だけでなく、UI設計にも大きく左右される
    • これは「共有地の悲劇」ではないと思う。GitHubはMicrosoftの所有なので、彼らが負担可能だと判断したということだ。本当の共有地は、誰にも所有されず、全員が利益を得る構造であるべきだ
    • この問題を深く考えると、Alan Kayの言葉を思い出す ― 「本当にソフトウェアを重要視するなら、ハードウェアも自分で作るべきだ」。ネットワーク越しの読み込みは本質的に悪いユーザー体験だ。本当にユーザーを尊重するなら、**ローカルファースト(native-first)**のアプリケーションを作るべきだ。しかし、そこまでユーザー体験を尊重する会社はきわめて少ない
    • Andy Hertzfeldの文章 "Saving Lives" も興味深い ― 「Macintoshの起動が遅すぎる。もっと速くしなければならない!」という逸話がある
  • 私はC向けのCargo/UVを作っている。良い記事で、強く共感した。
    始めたばかりの段階では、レジストリ運用は本当に難しい。コードを書くことやツール品質の確保、コミュニティの拡大だけでなく、全世界のトラフィックに耐えるインフラまで考えなければならない。そういう状況ではgitベースのソリューションは魅力的だ。
    しかし問題はsparse checkoutだ。gitでパッケージマニフェストをバージョン管理したいが、任意のコミットを追跡しなければならず非効率だ。結局、2回コミットをpushしなければならない構造なので、現実的には不可能だ。
    Conanのアプローチが最も実用的だと思う。完全な再現性の代わりに、条件付きロジックをマニフェストに入れる方式だ。バージョン範囲ごとのマニフェストマッピングも可能だ。完璧ではないが、実用的で有用な折衷案だ。
    もちろん本当の解決策はデータベースを使うことだが、誰かがサーバー代や維持費を肩代わりしてくれるわけでもないので、現実的には難しい

    • 見方を変えれば、成功したパッケージマネージャの大半は最初はGitベースで始まり、必要になった時点でより効率的な構造に移行している
    • Arch Linux AUR方式も検討に値する。各パッケージが独立したgitリポジトリを持ち、マニフェストだけを含む。こうすればmonorepo問題や参照の悪夢を避けられる
    • S3のような単純なHTTPバックエンドでリポジトリを運用するのも魅力的だ。初期は単一サーバーで始めて、人気が出たらスポンサーを探してクラウドへ移行すればよい。
      資金と独立性が問題なら、P2P方式も可能だ。ただしCIキャッシュが効かないとトラフィックが急増する可能性がある
    • まだユーザーが多くないなら、全世界向けインフラを先に用意するのは時期尚早
    • わざわざすべての履歴データをユーザーに見せる必要はない。post-commit hookでHEAD状態だけを静的ファイルとしてレンダリングし、GitHub Pagesのように提供すればよい。
      Debian、Fedora、openSUSEのようなLinuxディストリビューションのミラー構成も参考になる
  • この記事は二つの問題を混同している。一つはgitをパッケージインデックスのデータベースとして使うこと、もう一つは各パッケージのコードをgitで取得することだ。両者は別問題だ。
    インデックスはgit、パッケージはzip/tarという構成もできるし、その逆も可能だ。Goの場合はそもそもインデックス自体がない構造だ

    • 筆者は少し混乱しているように見える。「すべてのユーザーにデータベースを複製させるべきではない」という主張には同意するが、だからといってgitグラフをデータエンコーディングに使えない理由にはならない。
      GitHubのバックエンド実装や2万個のフォークの話は本質と無関係だ。gitワーキングツリーがなくても効率的なkey-value参照は可能だ。
      「gitの履歴書き換えはDBマイグレーションと同じだ」という主張も妙だ。むしろPostgresを1台動かした方がよくないか?
    • 記事の要点はコードそのものではなく、go.modファイルを取得する過程にある。だから解決策としてgo.modを別途ホスティングしたのだ
    • gitでも必要な単一ファイルだけを取得することは可能だが、それでも構造的に不自然だ
  • 「動いているうちは簡単な方法を使い、ダメになったら直そう」というアプローチは現実的だ。
    Juliaも同じ方式を使っていて、Rustよりパッケージ数が1/7程度なので、まだ問題はない。
    最上位の Registry.toml ファイルだけを受け取り、必要なパッケージだけをダウンロードするよう改善できる。大きな問題ではない

    • Juliaはgitレジストリを**公式台帳(ledger)**としてのみ使い、実際のクライアントは Pkg Protocol を使う
    • このアプローチは「FAFO(とりあえずやってみて痛い目を見る)」精神と呼べるかもしれない。実用的ではあるが、個人的には好みではない
    • こうした態度は非倫理的だと思う。「まず簡単に作って後で直そう」という発想は、結局技術的負債を増やす。
      「Move fast and break things」文化が生んだ結果が、今の遅くてバグの多いソフトウェアだ
    • 問題を後で直すと、コストは指数関数的に増加する。結局は「少し壊れたまま使おう」という結論になる。記事中のvcpkgの事例がまさにそれだ
    • 誰かがUUIDを意図的に操作したように見える例があるが、それが可能なのは少し不安だ
  • 「Gitはパッケージマネージャの出発点として優れたデータベースだ」という結論に同意する

    • ただしクライアントはリポジトリ全体を受け取るのではなく、キャッシュやDB層を置くのがよい。CI/CD環境では特に効率が重要だ
    • NixpkgsもGitのおかげで成功した。スケールの問題は後になってからの贅沢な悩みだ
    • ただしGitを称賛する前に、データベース研究を少しでも読んでみた方がよい
    • Gitはサプライチェーンの悪夢を引き起こすこともある。Leftpad騒動が毎週繰り返されるかもしれない
    • Gitはパッケージマネージャ向けDBとしてはひどい。ただGitHubが無料でホスティングしてくれるので、みんな使っているだけだ
  • 「結果的にはうまくいったじゃないか」という立場だ。初期運用には十分役立ち、スケール問題は後から解決できた

    • しかし一部のプロジェクトはアーキテクチャ上の限界のせいでgitから抜け出せずにいる
    • gitのようなファイルシステムベースのストアから始めると、後でプロトコルを切り替えるのはほぼ不可能だ。最初からAPI中心設計で行くべきだ
    • むしろgitをもっと効率的に活用できる余地がある。代案を示さずにgitを捨てようというのは中途半端な結論
    • 「0から1兆ユーザーまでスケールしないからゴミだなんて」という皮肉めいた冗談もある
  • ここには生存者バイアス(survivorship bias)がある。Cargoが成功したからこそgitインデックスが肥大化して問題になったのだ。
    ほとんどの小さなプロジェクトは、gitをデータ配布プロトコルとしてうまく使っている。
    スケールが不確かな初期段階では、gitとGitHubを活用して
    核心的な問題に集中
    するのは合理的だ

    • 早すぎる最適化には注意すべきだ。CargoやHomebrewも簡単な道を選んで成長し、スケール問題は後からの「良い問題」だった
  • HNのトップページで「今あなたがやっていることは間違っている」という記事を見ると、いつも謙虚な気持ちになる。
    私も何度かそういう経験がある。今回はPG Notify関連の記事がそうだった。
    しかし今は一人で開発していて、プロジェクトが成功するかどうかすら分からないので、gitでプラグイン配布するのがいちばん現実的だ。
    それでも後でスケール問題が出たら、この記事を参考にするつもりだ

    • 今のうちでもいくつかの落とし穴は避けられる。GitHub依存のようなベンダーロックインの方が大きな問題かもしれない
  • 私は個人的にForgejoでコードをホスティングしている。外部公開せず、mTLSで保護している。
    しかしGoモジュールは証明書を要求するため、私のForgejoインスタンスを認識してくれない。
    SSHを使ってもHTTPSアクセスが必要だと言われ、結局replace directiveでローカル複製を使っている。かなり面倒だ

    • モジュールパスの末尾に .git を付けて $GOPRIVATE を設定すれば、HTTPSリクエストなしでgitコマンド認証を使える。公式ドキュメント参照
    • インスタンスの**TLS証明書(CA)**を信頼ストアに追加すれば、HTTPSダウンロードも可能だ
    • 「HTTPアクセスが必要だ」というのは事実ではない。ローカルプロキシで解決できる
    • Tailscale DNSと証明書を使えば、外部公開なしでLet’s Encrypt証明書を取得できる
  • パッケージマネージャに限らず、多くの小規模プロジェクトがデータをgitリポジトリにクラウドソーシングしている。
    ほとんどは規模が小さいため、技術的限界にはぶつからない。
    ただしこうした構造は、非開発者の参加障壁を高める。パッケージマネージャは例外だが、一般的なプロジェクトでは問題になる
    私はこうした問題を支援するために、Datatigというオープンソースライブラリを作った。
    関連発表資料は こちら にある。今後はこの記事を参考にして、スケーリング関連の内容も追加する予定だ