Gitガベージコレクションを極めて最高のパフォーマンスを実現

git gcを実行すべきタイミング、クリーンアップされる内容、アクティブなリポジトリでの危険なアグレッシブクリーンアップを避ける方法を学びます。

Gitガベージコレクションを極めて最高のパフォーマンスを実現

Gitのガベージコレクションは、リポジトリがルーズオブジェクト、古い到達不能なコミット、非効率なパックファイルを永遠に蓄積するのを防ぎます。リポジトリの動作が遅い、ディスク容量を多く消費している、または多くのリベースやブランチのクリーンアップを行った場合、git gcは最初に理解すべきメンテナンスツールの一つです。

通常、毎日実行する必要はありません。Gitは通常のコマンド実行中に、特定のしきい値に達すると自動メンテナンスを実行します。それでも、その動作を理解することで、2つの一般的な間違いを避けることができます:数ヶ月間肥大化したリポジトリを無視すること、または影響を理解せずに共有リポジトリでアグレッシブなクリーンアップを実行することです。

Gitガベージコレクションの機能

Gitはデータをオブジェクトとして保存します:コミット、ツリー、ブロブ、タグです。新しいオブジェクトは最初は.git/objects/の下にルーズファイルとして存在する場合があります。時間が経つにつれて、Gitは多くのオブジェクトをコンパクトなパックファイルにまとめることができます。パックされたオブジェクトはディスクをより効率的に使用し、通常Gitがスキャンする際に高速です。

git gcは以下のメンテナンスタスクを実行します:

  • ルーズオブジェクトをパックファイルにパックする。
  • 必要に応じて既存のパックファイルを統合する。
  • 古くなった到達不能なオブジェクトを削除する。
  • 中断された操作によって残された一時ファイルをクリーンアップする。
  • 設定されている場合、最新のGitセットアップでコミットグラフファイルなどの補助データを更新する。

到達不能とは、すぐに削除しても安全という意味ではありません。コミットはリベース、修正、リセット、またはブランチの削除後に到達不能になることがあります。Gitは通常、最近到達不能になったオブジェクトを猶予期間保持し、git reflogで復旧できるようにします。

クリーンアップ前にリポジトリサイズを確認する

推測する代わりに、リポジトリを測定することから始めましょう:

git count-objects -vH

有用なフィールドには、countsizein-packpackssize-packがあります。ルーズオブジェクトの数が多いと、日常のGit操作が遅くなる可能性があります。size-packが大きい場合は、単にリポジトリに多くの履歴、大きなバイナリファイル、またはベンダーアセットがあることを意味する場合があります。

ディスク使用量を直接確認するには、次を実行します:

du -sh .git

誰かがビルドアーティファクトや大きなアーカイブをコミットしたために.gitが巨大な場合、ガベージコレクションだけでは根本的な問題は解決できません。将来のコミットから大きなファイルを削除したり、Git LFSに移動したり、チームと調整した後にgit filter-repoなどのツールで履歴を書き換える必要があるかもしれません。

通常のガベージコレクションを実行する

定期的なクリーンアップには、次を使用します:

git gc

これは安全なデフォルトです。Gitにどのメンテナンス作業を行う価値があるかを判断させ、通常のプルーニングルールに従います。

しきい値が必要と判断した場合のみ自動メンテナンスを実行するようGitに依頼することもできます:

git gc --auto

ほとんどのユーザーは手動で--autoを呼び出す必要はありません。Gitは既にバックグラウンドでこれを行っているからです。それでも、毎回完全なリパックを強制せずに低コストのクリーンアップパスを実行したいスクリプトでは便利です。

標準の猶予期間を使用して古い到達不能なオブジェクトを削除したい場合は、次を実行します:

git gc --prune=now

--prune=nowは注意して使用してください。git reflogで見つけられるかもしれない復旧ポイントを削除する可能性があります。複雑なリベース、ブランチ削除、またはリセットの直後には、古いオブジェクトが不要であると確信できない限り避けてください。

--aggressiveに注意する

git gc --aggressiveは、Gitにオブジェクトパッキングの最適化により多くのCPU時間を費やすよう指示します:

git gc --aggressive

これは魔法のスピードボタンではありません。多くのリポジトリでは、通常のgit gcと比較して追加の作業による利点はほとんどなく、大規模な履歴では長時間かかる可能性があります。実際のリポジトリサイズやパフォーマンスの問題を測定し、メンテナンスウィンドウを確保できる場合にのみ使用してください。

日常の作業では、プレーンなgit gcを優先してください。リポジトリが定期的にアグレッシブなクリーンアップを必要とする場合、より深い問題は、大きなファイル、生成されたアーティファクト、または多くの到達不能な履歴を作成するワークフローであることが多いです。

継続的なケアのために最新のGitメンテナンスを使用する

最近のGitバージョンにはgit maintenanceが含まれており、プラットフォームと設定に応じて、プリフェッチ、コミットグラフの更新、インクリメンタルリパックなどのバックグラウンドタスクをスケジュールできます。

メンテナンスを一度実行するには:

git maintenance run

ユーザーアカウントでスケジュールされたメンテナンスを有効にするには:

git maintenance start

自動化でスケジュールされたメンテナンスに依存する前に、Gitのバージョンとローカルのドキュメントを確認してください。正確なスケジューラの統合は、オペレーティングシステムとGitビルドによって異なります。

実用的なクリーンアップワークフロー

ローカルリポジトリの安全なクリーンアップフローは次のようになります:

git status
git count-objects -vH
git gc
git count-objects -vH

メンテナンスの前に作業ツリーがクリーンであることを確認してください。Gitはローカルの変更が存在する状態でもガベージコレクションを実行できますが、クリーンなツリーは後でトラブルシューティングが必要な場合の不確実性を排除します。

サーバー上の共有ベアリポジトリの場合、静かな時間帯にメンテナンスをスケジュールしてください。CIアクティビティのピーク時に重いリパックを避けてください。クローン、フェッチ、プッシュ操作がディスクとCPUを競合する可能性があるからです。

ガベージコレクションが役に立たない場合

ガベージコレクションはすべての遅いGitリポジトリを修正できるわけではありません。履歴内でまだ到達可能なファイルは削除しません。アクティブな履歴に何年分もの大きなアセットが含まれている場合、モノレポを小さくすることはできません。それ自体で破損したリポジトリを修復することはできません。

通常のクリーンアップ後もパフォーマンスが悪い場合は、以下の原因を調査してください:

  • Gitに直接コミットされた大きなバイナリファイル。
  • リポジトリで追跡されている生成されたファイルが多すぎる。
  • アンチウイルスまたはファイルシステムインデックスがすべての操作で.gitをスキャンしている。
  • 作業ツリーをホストする遅いネットワークストレージ。
  • スパースチェックアウトが役立つ可能性がある非常に大きな作業ツリー。

git gcをメンテナンスとして使用し、リポジトリの衛生状態の代わりとして使用しないでください。オブジェクト数が増加したときに通常のクリーンアップを実行し、必要性を測定しない限りアグレッシブなクリーンアップを避け、大きな追跡アーティファクトをソースで修正するワークフローの問題として扱ってください。