pre-commitを使ってRubocopで検査すると遅い
もともとの.git/hooks/pre-commit
はこうなっていた。
#!/bin/sh
bundle exec rubocop -P
if [ "$?" -ne 0 ]; then
exit 1
fi
これによって、コミット前にRubocopを強制実行してルールに外れている場合はコミットさせないようにしているのだけれど、如何せん遅い😡
遅い原因
かれこれ6年も運営しているRailsプロジェクトで行うと数分間応答がなくなってしまう。検査対象が全てのファイルになっているからだ👎
課題
gitで変更があったファイルだけに対してRubocopを実行すればよい👍
対策
変更があったファイルだけを取り出す
gitで変更のあったファイルだけを抽出するには、git diff
を使う。
git diff --cached --name-only --diff-filter=AMRC
オプションの説明
--cached
は、addされたファイルだけを対象にする。
--name-only
は、変更のあったファイル名だけを取り出す。
--diff-filter=AMRC
は、Added, Modified, Renamed, Copiedなファイルを対象とする。
Rubyのファイルだけを取り出す
現時点だとRuby以外の変更ファイルも抽出されるので、さらにgrepで絞り込む
git diff --cached --name-only --diff-filter=AMRC | grep '\.rb\>$'
拡張子が.rb
で終わっているファイルだけに絞り込んだ。
Rubocopを実行する
絞り込まれた結果に対してRubocopを行う。渡す方法にはxargs
を使う。
git diff --cached --name-only --diff-filter=AMRC | grep '\.rb\>$' | xargs bundle exec rubocop -P
これで、変更のあったRubyファイルだけを対象にRubocopを実行することに成功した🎉
ということで、.git/hooks/pre-commit
を修正した。
#!/bin/sh
git diff --cached --name-only --diff-filter=AMRC | grep '\.rb\>$' | xargs bundle exec rubocop -P
if [ "$?" -ne 0 ]; then
exit 1
fi
オマケ
Auto Collectもこれを使うとめっちゃ速い😎
git diff --cached --name-only --diff-filter=AMRC | grep '\.rb\>$' | xargs bundle exec rubocop -a
しかしpre-commitには含めたくないし、いい感じのコマンドにしたいけれど、いいコマンド名を思いつかない…🤔