$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

git gcの自動実行はいつ行われるのか

gitを使ってるとたまにgit gcが走る。これがどういうタイミングで実行されているか調べたので軽くメモしておく。

Gitでは時々auto gcが走る

Git - メインテナンスとデータリカバリ を見ると、以下のように書かれている。

Git は時々 "auto gc" と呼ばれるコマンドを自動的に実行します。大抵の場合、このコマンドは何もしません。もし沢山の緩いオブジェクト(パックファイルの中にないオブジェクト)があったり、あまりに多くのパックファイルがあると、Git は完全な(full-fledged)git gc コマンドを開始します。

さらに、auto gcは普段は何もせず、特定の条件を満たすと実際にgcするとも書かれている。

繰り返しますが、これは通常は何も行いません。約 7,000個もの緩いオブジェクトがあるか、または50以上のパックファイルがないと、Gitは実際に gc コマンドを開始しません。これらのリミットは設定ファイルの gc.auto と gc.autopacklimit によってそれぞれ変更することができます。

では緩いオブジェクトとパックファイルとはなんだろうか。

緩いオブジェクトとパックファイル

緩いオブジェクトとパックファイルについて知るには Git - パックファイル を見るのが良い。gitは保存した内容やcommit情報などをすべてファイルで管理している。これは.git/objects/以下に存在している。ここを見るとわかるが、2文字ディレクトリの下にsha1で名前付けられたファイルがたくさんある。また、packというディレクトリ以下にもファイルが存在する。この中で、2文字ディレクトリ以下にあるものが緩いオブジェクトで、packディレクトリ以下にあるものがパックファイルである。

このため、緩いオブジェクトとパックファイルはこの下のファイルを数えることで知ることができる。これはcount-objectsというコマンドでも調べることができる。ファイル数とcount-objectsで表示されたものを比べると確かに一致していることも分かる。

$ git count-objects -v
count: 457
size: 2336
in-pack: 327127
packs: 1
size-pack: 268511
prune-packable: 0
garbage: 0
size-garbage: 0

ここで出ているcountというのが緩いオブジェクトの数で、packsというのがパックファイルの数である。この数がしきい値を超えた時にgit gcが実際に走るようだ。

さらにgitの内部構造を知ろうと思ったら、以下のドキュメントが非常に参考になるのでおすすめ。

koseki.hatenablog.com

時々、とはいつか

上では「Git は時々 "auto gc" と呼ばれるコマンドを自動的に実行します」と書いた。では時々とはいつか。

調べてみるとgit help configのgc.autoの項目に少し情報が載っていた。https://www.kernel.org/pub/software/scm/git/docs/git-config.html

When there are approximately more than this many loose objects in the repository, git gc --auto will pack them. Some Porcelain commands use this command to perform a light-weight garbage collection from time to time. The default value is 6700. Setting this to 0 disables it.

つまりいくつかの「Porcelain commands」でgit gc --autoが実行されるようだ。


「Porcelain commands」というのが何か分からなかったので、さらに調べてみると http://schacon.github.io/git/git.html に情報が載っていた。これによるとgitではhigh levelコマンドのことをPorcelain commands、low levelコマンドのことをPlumbing commandsと呼んでいるらしい。gitは内部でやっているようなこともコマンドで提供してくれていたりするので、このように命名を分けているのかもしれない。代表的なPorcelain commandsはgit addやgit commit、代表的なPlumbing commandsにはgit ls-remoteやgit for-each-refなどがある。


以上からgitでよく使う上位コマンドのいくつかでgit gc --autoが実行されるということが分かった。

上位コマンドのいくつかとはどれか

どのコマンドで実行されているのか調べてみたか、情報を見つけること出来なかった。ここまで来るとコードを読まないと分からないのかもしれない。gitの内部コードを読んでみたらいまいち分からなかったが、twitterで教えてもらえた。


https://github.com/git/git/search?utf8=%E2%9C%93&q=argv_gc_auto
確かにこの検索方法で100%正しいかわからないが、おそらくfetchやmergeのタイミングで呼ばれているように見える。

まとめ

今回調べたことから、gitはPorcelain commandsの一種のfetchやmergeなどのタイミング(これは本当かどうか曖昧)で、git gc --autoを実行し、その時に約7,000個の緩いオブジェクトがあるか、または50以上のパックファイルがあると、実際にgit gcを走らせるということが分かった。

これ以上のことや、さらに正確な情報を調べようとするとコードを読むしかないだろう。読んでみようとしたけど、いまいち理解は出来なかった。たまにGitやMySQLなどの挙動を知りたくなるけどコード読もうとして失敗するということがあるので、どこかのタイミングでC言語C++辺りをきちんと勉強したい。