git用のpre-commit gemが便利すぎる

まずは

$ gem install pre-commit
# In your git repo
$ pre-commit install

これだけで、うっかり残念なコミットをする事故が防げます。

Git フック使ってますか?

http://git-scm.com/book/ja/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF

コミットする前にバリデーションかけて、通らなかったらコミット中止する。コミットメッセージにブランチ名を自動挿入する。など、ルーティンワークをフックに仕込んでおけば、誰も読まないガイドラインページを書く手間が省けますし、強制する事ができて幸せです。

じゃあ、何をフックに設定するかと言うと

コードレビューしていると、気になるけどいちいち指摘するのも面倒くさい事が良いんじゃないかと。

  • 行末の空白文字くらい消せよ!
  • タブインデント止めて!
  • binding.pry消し忘れてんぞ! などなど

そこで、pre-commit gemですよ

https://github.com/jish/pre-commit

デフォルトで便利なバリデーションをたくさん持っているので、いちいち自分で作成する必要が無いところがありがたい。 現在のチェック項目を確認したい場合は、pre-commit listで確認できます。

$ pre-commit list
Available providers: default(0) git(10) git_old(11) yaml(20) env(30)
Available checks   : before_all ci closure coffeelint common console_log csslint debugger gemfile_path go jshint jslint json local merge_conflict migration nb_space php pry rails rspec_focus rubocop ruby ruby_symbol_hashrockets scss_lint tabs whitespace yaml
Default   checks   : common rails
Enabled   checks   : common rails
Evaluated checks   : tabs nb_space whitespace merge_conflict debugger pry local jshint console_log migration
Default   warnings : 
Enabled   warnings : 
Evaluated warnings : 

common と rails がデフォルトで有効になっているcheck項目で、実際には"Evaluated checks"のが実行されます。

  • tabs: インデントにタブが使われていないか
  • nb_space: ノーブレークスペースが使われていないか
  • whitespace: git diff --check --cachedを実行する(Git自体に便利コマンドがある!)
  • merge_conflict: コンフリクトが解消されていないファイルを上げようをしていないか
  • debugger: debuggerを消し忘れていないか
  • pry: binding.pryを消し忘れていないか
  • local: ユーザが定義したバリデーションが通るか
  • jshint: JSファイルがjshintを通るか
  • console_log: console.logを消し忘れていないか
  • migration: Railsのdb, schemaファイルの整合性は取れているか(片方だけコミットしようとしていないか)

これだけでも、十分有用です

check追加したい

git configに追加する方法と、YAMLファイルで管理する方法があります。YAML形式で書き出しておいて、このファイルもプロジェクトに含めてしまえば、他のチームメンバーはpre-commit installをするだけで済むので、YAMLがいいんじゃないかと。

checks, warningsの違いはチェックに引っかかった時に、コミットを許容するか否かです。 cheksだと、そのままコミットさせない。warningsだと、警告を出すだけにとどめる。

$ pre-commit <enable|disable> <git|yaml> <checks|warnings> check1 [check2...]
# rubocopのチェックを追加するが、警告を出すだけ
$ pre-commit enable yaml warnings rubocop

独自バリデーションも適応したい

config/pre-commit.rb というファイルを置いておけば、引数としてコミット対象のファイル名を渡してくれます。exitで0よりも大きな数字を返せば、バリデーションに通らなかったことを通知できます。

# config/pre-commit.rb
valid = ARGV.all? do |file|
  # validate
end

exit valid ? 0 : 1

Guidelines as a Code

人力チェックリストを作るくらいなら、機械にテストさせた方がよっぽど正確だよね。って話でした。