git gc --auto を clone‑reset に組み込み、キャッシュのパック増大を抑制
Kamal のビルドキャッシュは kamal-clones ディレクトリを再利用することで高速化していますが、リポジトリのガーベジコレクションが行われず .git/objects/pack/ が無制限に肥大化していました。本 PR はその肥大化を防ぐため、クローンリセット工程の最後に git gc --auto --quiet を自動実行する変更です。
背景
Kamal はデプロイごとに同一サービスのビルドキャッシュを fetch + reset --hard + clean -fdx で再利用しています。このフローはビルド時間を大幅に短縮しますが、git gc が呼び出されない点が抜け落ちていました。その結果、git fetch が毎回新しいオブジェクトを .git/objects/pack/ に追加し、長期間使用されたキャッシュで数百メガバイト、場合によっては数ギガバイトまでサイズが増大します。実際に開発環境で SSD が 100% に達した事例が報告されており、クライアント側のディスク容量枯渇リスクが顕在化しています。
この問題は別 Issue #1794 のリモート BuildKit ボリューム肥大と同種の「キャッシュの寿命管理がない」ケースですが、今回はローカルキャッシュに焦点を当てた最小限の修正となります。
技術的な変更
clone_reset_steps 配列に git gc --auto --quiet を追加入しただけのシンプルな実装です。既存のステップは変更せず、サブモジュール更新の直後に新しいステップを追加する形を取っています。この追加により、Git が内部で設定された gc.auto(デフォルト 6700)や gc.autoPackLimit(デフォルト 50)を基準に自動でリパックを行い、パックファイルの無制限蓄積を防止します。
@@ -9,7 +9,8 @@ def clone_reset_steps
git(:fetch, :origin, path: escaped_build_directory),
git(:reset, "--hard", Kamal::Git.revision, path: escaped_build_directory),
git(:clean, "-fdx", path: escaped_build_directory),
- git(:submodule, :update, "--init", path: escaped_build_directory)
+ git(:submodule, :update, "--init", path: escaped_build_directory),
+ git(:gc, "--auto", "--quiet", path: escaped_build_directory)
]
end
さらに、テスト clone reset runs git gc --auto to bound pack growth が追加され、clone_reset_steps が期待通り gc --auto --quiet を含むことを自動的に検証しています。これにより、将来的なリグレッションが防がれ、変更の意図が永続的に保証されます。
設計判断
既存の配列に要素を追加するだけという非侵襲的なアプローチが選ばれました。git gc はデフォルトで何もしないケースが多く、--auto と --quiet の組み合わせは出力の副作用も最小化します。そのため、従来のデプロイフローの速度や挙動に影響を与えず、キャッシュサイズを自然に抑制できる設計となっています。また、新しい設定キーやオプションを導入しないことで、後方互換性が完全に保たれ、既存のデプロイパイプラインを改修する必要がありません。
この判断は、Kamal が提供する「設定なしで即戦力になる」理念に合致し、ユーザーが追加作業を行わずにディスク使用量の上限を確保できる点で価値があります。
まとめ
本 PR は git gc --auto --quiet をクローンリセット工程に組み込むだけの小さな変更で、キャッシュのパックファイル蓄積を自然に制御し、ディスク容量枯渇という実運用リスクを解消します。既存フローへの侵入は最小限に抑えられ、テストにより動作保証が追加されたため、今後のリリースでも安全に利用できるでしょう。