その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

git でファイルごとのコミット数を取ってきて,プロジェクト中のホットなファイルを割り出すという試み

途中の段階でプロジェクトに入った時などに,「どれがそのプロジェクトの中心となっているファイルなんだろうか」というのを手っ取り早く知りたくなる時があります.僕はあります.


そこで「どのファイルが盛んに変更されているのか」という点を指標として注目すると,良い感じにそこら辺取れるのでは無いかと思って試してみました.
コミット数が多いファイルは多く変更を加えられているということから,そうしたファイルはホットであるということが言えそうな気がしたので,git でファイルごとのコミット数を取ってきて,それをソートして見てやれば良いよな,という意識でやっていきました.もちろんコミットの粒度などもあるでしょうから一概にはそうとは言い切れませんが,参考にはなる気はします.


使うスクリプトは至って簡単.以下の様な感じです.

git ls-files |
while read file ; do
  commits=`git log --oneline -- $file | wc -l`;
  echo "$commits - $file";
done | sort -n

git で管理されているディレクトリ内でこのシェルスクリプトを走らせるとそのような情報を取ってくることが出来ます.
railsリポジトリで試してみました所,以下の様な結果が得られました.

1 - actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb
1 - actionmailer/test/fixtures/anonymous/welcome.erb
1 - actionmailer/test/fixtures/another.path/base_mailer/welcome.erb
1 - actionmailer/test/fixtures/asset_host_mailer/email_with_asset.html.erb
1 - actionmailer/test/fixtures/asset_mailer/welcome.html.erb
<中略>
549 - activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
556 - actionpack/CHANGELOG.md
745 - activerecord/lib/active_record/associations.rb
1134 - activerecord/CHANGELOG.md
1145 - activerecord/lib/active_record/base.rb

なるほどという感じです.正しいのかどうかはよくわかりません.rails 識者の方どうでしょうか.
めっちゃコミット数あった (5万コミットくらい) ので実行に15分くらいかかって大変微妙な心境になります.


よくわからなかったので,なんとなくわかるであろう Plackリポジトリで試してみます.

1 - eg/dot-psgi/Dumper.psgi
1 - eg/dot-psgi/echo-stream-sync.psgi
1 - eg/dot-psgi/runnable.psgi
1 - eg/dot-psgi/static/index.html
1 - eg/dot-psgi/static/test.js
<中略>
113 - Makefile.PL
150 - lib/Plack/Response.pm
178 - Changes
197 - lib/Plack.pm
211 - lib/Plack/Request.pm

なるほど,それっぽい感じがしますね!! (こっちはすぐ実行し終わった)


という感じでまあまあ参考になる情報が取れるのではないでしょうか,という気持ちです.試しに色々なリポジトリに適用していってますが,それっぽい結果が得られてて面白いですね.
逆にコミット数が少ないファイルはメンテされてないから危険,みたいなのも分かるんでしょうか.要検討という感じです.
グラフ等で可視化してやるとまた面白さが出てくるかもしれませんね.

参考


[追記]
歴史が深いリポジトリでやるとめちゃめちゃ時間がかかって大変なので,トラックする log の数を制限するとかが必要になってくるかもわかりませんね.
あと「昔はホットだったけど最近はホットではない」みたいなのもあると思うので,常にすべてのコミット履歴を追う必要は無くて,ある一定のところでバチッと切ってしまうとか,そういうのも考えていく必要があるのかな~とか思った次第です.

こんな風に (この例では -1000 で制限をかけている).

git ls-files |
while read file ; do
  commits=`git log -1000 --oneline -- $file | wc -l`;
  echo "$commits - $file";
done | sort -n

[追記]
log の数に制限かけても処理時間そんな変わらないので,ファイル数の問題であることが伺えます.厳しい……
とは言え「昔はホットだったけど最近はホットではない」みたいなのには関係してきそうなので検討する価値はありそう.

間違っているので見なかったことにしましょう