巨大リポジトリを「爆速」に変える:Gitの深淵、パックファイルと参照最適化の極意
「`git status` に3秒かかる」「`git fetch` が終わらない」。そんな悲鳴が聞こえてきたら、君のチームのリポジトリは既に悲鳴を上げている。数千のブランチ、数万のコミットが重なれば、Gitは単なるバージョン管理ツールから「重たい足かせ」へと変貌する。
今日は、Gitの内部構造をハックし、物理的なパフォーマンスを限界まで引き出すための「禁断のチューニング」を伝授しよう。
—
1. なぜリポジトリは「重く」なるのか?
Gitの正体は単なるファイルシステムではない。「オブジェクトデータベース」だ。
- ルーズオブジェクトの氾濫: 毎回コミットするたびに、`.git/objects` 配下に小さなファイルが大量生成される。ディスクI/Oが死ぬ原因だ。
- 参照(Refs)の肥大化: `refs/heads/` に数千のファイルが散らばると、ファイルシステムのスキャンがボトルネックになる。
- デルタ圧縮の劣化: 類似ファイルの差分を保持する「パックファイル(`.pack`)」の効率が悪化すると、計算コストが爆発的に増える。
これらを解決するのは、単なる `git gc` ではない。もっと深い部分を叩く必要がある。
—
2. 参照のパック化:`git pack-refs` の真実
数千のブランチを抱える現場では、`refs` ディレクトリ内のファイル数がパフォーマンスを直撃する。これを解決するのが `git pack-refs` だ。
参照を1つのファイル(packed-refs)にまとめ、ルーズな参照を削除する
git pack-refs –all –prune
なぜこれが効くのか?
通常、Gitはブランチ情報を個別のファイルとして読む。これを単一のテキストファイルに統合することで、ファイルシステムのオープン回数を激減させる。特にCI環境で数千のタグやブランチを扱う場合、これだけで `git fetch` の速度が体感レベルで変わる。
—
3. デルタ圧縮の限界突破:`git repack` の最適化
デフォルトの `git gc` は万人向けだ。プロは、リポジトリの特性に合わせて `repack` を微調整する。
デルタ圧縮のウィンドウサイズと深さを極限まで高める
git repack -a -d –depth=50 –window=250 –window-memory=1g
- `–depth`: デルタチェーンの長さを指定。CPU性能が余っているなら大きくする。
- `–window`: 圧縮時に比較するオブジェクトの数。メモリを食うが、パックファイルのサイズを劇的に縮小できる。
注意: これは低速なマシンで行うと終わらない。深夜のCIパイプラインや、強力なビルドサーバーで行うのがセオリーだ。
—
4. チーム開発を加速させる「神設定」の共有
個人の設定だけ速くても意味がない。`.gitconfig` をモジュール化して共有しよう。
`.gitconfig` のベストプラクティス
リポジトリ直下に `.gitconfig.shared` を置き、`git config –local include.path .gitconfig.shared` で読み込ませるのが鉄則だ。
.gitconfig.shared
[core]
# 巨大リポジトリではfsmonitorを有効化(変更監視をバックグラウンド化)
fsmonitor = true
# 圧縮レベルを最大に(CPUと引き換えにI/Oを削減)
compression = 9
# 並列処理の最適化
packedGitWindowSize = 1024m
packedGitLimit = 4096m
[gc]
# 自動GCを抑制し、メンテナンス時間を制御する
auto = 0
# プリパック後のルーズオブジェクト保持期間を短縮
pruneExpire = now
—
5. 伝説のエンジニアが選ぶ「導入すべきプラグイン」
1. [git-delta](https://github.com/dandavison/delta):
`git diff` の出力にシンタックスハイライトと行の差分表示を適用する。コードレビューの速度が「読む」から「スキャンする」に変わる。
2. [git-filter-repo](https://github.com/newren/git-filter-repo):
`git filter-branch` は忘れていい。巨大なバイナリを履歴から完全に消去し、リポジトリを「物理的に」軽量化するならこれ一択だ。
—
6. 実戦:爆速メンテナンスの自動化スクリプト
週に一度、cronやCIのメンテナンスジョブでこれを叩くことで、リポジトリの健康状態を維持する。
!/bin/bash
git-optimize.sh
リポジトリの健康を保つための最終手段
echo “Starting deep optimization…”
1. 参照のパック化
git pack-refs –all –prune
2. デルタ圧縮の再構成(ウィンドウサイズを最大化)
git repack -a -d -f –depth=50 –window=250
3. 未使用オブジェクトの完全削除
git prune –expire now
4. 書き込みインデックスの更新
git update-index –refresh
echo “Optimization complete. Repository is now lean.”
—
テックリードからの提言
Gitは「ツール」であると同時に「インフラ」だ。
「最近リポジトリが重いな」と愚痴をこぼす時間が、年間で何時間あるか計算してみろ。その時間は、本来コードを書き、設計を練り、未来を創るために使うべきものだ。
最適化は一度で終わらない。 リポジトリの成長に合わせて、パックファイルの構成戦略を常にアップデートせよ。それが、技術でチームの生産性を底上げするということだ。
さあ、今すぐ `git pack-refs` を実行して、その速さを体感してくれ。