灰いじり

This blog's posts are licensed under CC-BY 4.0.

GitのUntracked cacheという機能

執筆時点のGitのバージョン

Git 2.8.2

Untracked cache

GitのUntracked cacheとは、おおざっぱに言うと、ワーキングツリーのファイル構成が変化したかどうかを識別する方法を簡略化させて、Gitの動作を高速化させる機能。これをオンにすると例えばgit statusが速くなるらしい。

具体的には「ディレクトリの」mtime(最終更新日時)だけを見てファイル構成の変化を察知することで高速化を図る(ということは普段は違うのか)。ドキュメントの「Untracked cache」の節を読むと「この機能は、ワーキングツリーのディレクトリのmtimeを記録しておき、mtimeに変化がないディレクトリは読み飛ばして、その中のファイルに対するstat callを省略する」と書かれている。

ディレクトリのmtimeの変化

一応整理しておくと、*nixやOS Xファイルシステムでは、ディレクトリのmtimeは以下の時に変化する。

  • そのディレクトリの中にファイルが追加される。
  • そのディレクトリの中のファイルが削除される。
  • そのディレクトリの中のファイルがリネームされる。

けれど、

  • そのディレクトリの中のファイルの中身が変更される。

の場合は、ディレクトリのmtimeは書き変わらない。だからこの機能は恐らくファイル内容の変化を識別することについては関係がない(ハズ)。あくまでファイルの追加/削除を調べるのが高速化される。

Untracked cacheを有効化できるか

速くなるならとりあえず有効化してみるか、と思いきや実は罠があり、OSやファイルシステムによってはディレクトリのmtimeがGitが想定した動作をしない場合がある。そういう場合はUntracked cacheを有効化するとマズイ(例えばファイル構成の変化を誤判断する)ので、有効化しても大丈夫なのか事前にテストしなければならない。テストにはgit update-index --test-untracked-cacheを使う。

自分の所(OS X 10.11.4 El Capitan、HFS+)で実行してみると、

$ git update-index --test-untracked-cache
Testing mtime in '/path/to/repo' ...... OK

となり有効化できるようだ。

どういう環境でこのテストが失敗するのかがよくわからないけれど、HackerNewsの記事のコメントではParallelsでのホスト・ゲスト間の共有フォルダなんかでは失敗するとか。

Untracked cacheを有効化する

ではテストも成功したので、有効化してみよう。以下のようにする。

$ git update-index --untracked-cache

オフにするには以下を使う。

$ git update-index --no-untracked-cache

単発のコマンドで機能のオンオフを切り替えるのってなんかわかりづらいですね。新しい機能だからとりあえずこうしましたって感じなのだろうか。

git configで設定する方法(2.8.0から)

と思ったら、Git 2.8.0からはgit configでオンオフできるようになっていたようだ。

$ git config --global core.untrackedCache true

さきほど「有効化できない環境もあるかもしれない」と述べたが、それが割と重要で、例えばUntracked cacheを有効化したリポジトリが後からUntracked cacheのテストが失敗するようなファイルシステム上にcloneされるという状況も考えられる。となるとこのconfigは個々のリポジトリに対して設定するのはあまりよくないかも。危険性は十分に理解して使ってください。

Gitのindexという領域について

いままで、Gitのindexのことを「リポジトリとワーキングディレクトリの間にあり、コミットの準備に使うステージング領域」という風にしか捉えていなかったのだが、git update-indexのドキュメントなんかを読むともっと他にも意味が持たせられているような気がする。Gitがリポジトリ側からワーキングディレクトリを見る際のフィルタというかそんな感じ?