Git FSMonitorとUntracked Cacheを有効化:巨大リポジトリでgit statusを劇的に高速化する方法

Git tutorial - IT technology blog
Git tutorial - IT technology blog

1. 課題:git status が開発フローのボトルネックになる時

モノレポや数十万単位のファイルを抱えるプロジェクトで作業していると、ターミナルの応答遅延が大きなストレスになります。git status を実行してから結果が表示されるまでに5〜10秒も待たされることがあり、これを1日に何十回も繰り返すことになります。このような度重なる待ち時間は開発の集中力を途切れさせ、生産性を著しく低下させます。

筆者自身も以前、32万ファイルを超えるリポジトリ(長年運用されたPHP/Node.jsのコードベースとサブモジュールの組み合わせ)でこの問題に直面しました。ブランチの確認やコミットのたびに、Gitがステータスをスキャンするだけで8秒以上かかっていました。しかしGit 2.37以降、標準搭載されたUntracked CacheとFSMonitor (File System Monitor)という2つの機能によって、この課題は根本的に解決されました。これらを有効にした結果、コマンドの実行時間は8.24秒からわずか0.14秒へと短縮されました。

2. なぜGitのデフォルトスキャンは遅いのか?

効果的な最適化を行うために、まずはGitがディスク上のファイル変更をどのように検知しているかを理解しましょう。

lstat() を用いたデフォルトのスキャンメカニズム

git status を実行するたびに、Gitはワーキングツリーとインデックスを比較する必要があります。システムは全ディレクトリを再帰的に走査し、ファイルごとにシステムコール lstat() を呼び出します。30万ファイル規模のプロジェクトでは、同等の回数だけディスクI/Oが発生するため、レスポンス速度はディスクの読み取り帯域幅に完全に左右されてしまいます。

Untracked Cache (core.untrackedCache)

この機能は、各ディレクトリの mtime(最終更新日時)を記録します。未追跡(untracked)ファイルをチェックする際、親ディレクトリの mtime に変更がなければ、Gitはその配下のサブツリー全体の走査を即座にスキップします。これにより、node_modules や vendor といった巨大な静的ディレクトリを深く読み込む無駄なリソース消費を防ぎます。

FSMonitor (core.fsmonitor)

FSMonitorはアプローチを根本から変えます。Git自身が隅々までスキャンする代わりに、バックグラウンドのデーモンプロセスがOSのファイルシステムイベント(macOSのFSEvents、WindowsのReadDirectoryChangesW、Linuxのinotify)を常時監視します。git status を実行すると、Gitはデーモンに対して「前回の確認以降、どのファイルが変更されたか?」と問い合わせるだけで済みます。デーモンは瞬時に該当する少数のファイル一覧を返し、Gitはリポジトリ全体を走査することなく、対象ファイルのみを読み取ります。

3. 設定手順とパフォーマンス計測

ステップ 1:Gitのバージョンと互換性の確認

まず、端末にインストールされているGitのバージョンを確認します。外部ツールのWatchmanを導入せずにビルトインのFSMonitorを利用するには、Git 2.37.0以降が必要です:

git --version

次に、使用しているファイルシステムがUntracked Cacheに必要な高精度の mtime をサポートしているか確認します:

git update-index --test-untracked-cache

出力の最終行に OK と表示されれば、準備完了です。

ステップ 2:Untracked Cache の有効化

プロジェクトのルートディレクトリで以下の2つのコマンドを実行します:

# 未追跡ファイルのキャッシュ設定を有効化
git config core.untrackedCache true

# インデックスに初期キャッシュデータを生成
git update-index --untracked-cache

ステップ 3:ビルトイン FSMonitor の有効化

組み込みのファイル監視プロセスを有効化します:

# 現在のリポジトリのみ有効化
git config core.fsmonitor true

# またはマシン上の全リポジトリにグローバル適用
git config --global core.fsmonitor true

次回Gitコマンドを実行した際に、バックグラウンドデーモン git-fsmonitor--daemon が自動起動し、セッション中のファイル監視を継続します。

ステップ 4:実際のパフォーマンス計測(ベンチマーク)

環境変数 GIT_TRACE2_PERF を使用して、詳細な実行時間を出力します:

GIT_TRACE2_PERF=1 git status

32万ファイル規模のリポジトリ(PCIe 4.0 NVMe SSD環境)での実測データ:

  • 最適化前: data: ... status: 8.241320 s(ディスク全体を順次スキャン)
  • Untracked Cache のみ有効: data: ... status: 3.110540 s(実行時間を62%以上削減)
  • 両方を同時に有効化: data: ... status: 0.142010 s(ほぼ瞬時に応答)

運用の注意点とTips

  • ネットワークドライブ(NFS/SMB): FSMonitorはネットワーク共有経由のファイルシステムイベントを受信できません。ローカル接続されたディスク(ローカルSSD/NVMe)でのみ使用してください。
  • Windows上のWSL2: ソースコードがWindows側のドライブ(/mnt/c/... 配下のパス)にある場合、9Pプロトコルの変換オーバーヘッドによりFSMonitorがボトルネックになります。最大限のパフォーマンスを得るには、コードをLinuxネイティブのファイルシステム(例:/home/username/code)に配置してください。
  • 無効化の手順: 万が一キャッシュの不整合など稀な不具合が発生した場合は、次のコマンドで即座に無効化できます:git config core.fsmonitor false。

4. まとめ

core.untrackedCache と core.fsmonitor の2つの設定を活用することで、追加ツールの導入なしにGitの応答速度をミリ秒単位まで高速化できます。数万〜数十万ファイル規模のプロジェクトを扱う場合は、開発初期からデフォルトで有効にしておくことを強く推奨します。

Share: