overcommitとは?
git hooksの管理と、その拡張を簡単にできるRuby製ツールです。同様のツールにpre-commit by YelpやRailsに特化したpre-commitがあります。overcommitはこれらのツールと違い、pre-commit以外のフックにも対応しています。
リポジトリはこちら
overcommitの導入でできること
- コミットのタイミングでrubocopやeslintなどlintツールをかけられる
- コードの読みやすさが向上することを期待できます
- checkoutやpullのタイミングで
bundle installやnpm installを実行できる- 他の開発者が
Gemfileやpackage.jsonに追加したらしくなんか動かない問題を回避できる
- 他の開発者が
- pushする前に変更したファイルのみ対象に
rspecを実行できる- CIする前に自分が行った変更の結果を再確認できるので、少なくとも自分が書いたコードに問題がないか確認できる
- コミットコメントのフォーマットをチェックできる
- 1行80文字以下に収めることで
git log実行時の一覧性をあげたり、不当に大きなコミットにならないように示せる
- 1行80文字以下に収めることで
- 既存のgit hookを使い回せる
- CustomScriptというHookがあり、これを使うと既存のhookに処理を委譲できます
制限事項
- 残念ながらgit-worktreeには未対応とのこと
インストール
overcommitはRuby製のツールなので、Rubyのインストールを忘れずに。その後、rubygemsで配布されているので下記のコマンドでOKです。rvmやrbenvを使っている方は適宜コマンドを補完してください。
$ gem install overcommit
その後、overcommitを利用したいリポジトリで下記のコマンドを実行します。もし既存のgit hookを利用している場合は、そのファイルをバックアップしておきましょう。上述した通り、CustomScriptとして再利用できます。バックアップをお忘れなく
$ cd git-repo
$ overcommit --install
これでovercommitのベースとなるhookが対象のgitリポジトリにインストールされました。試しに適当なファイルをコミットしてみましょう。
こんな感じで最初はRun overcommit --sign if you trust the hooks in this repository.と出ます。overcommit --signはovercommit経由で実行するスクリプトのハッシュを記録しておき、fetchした時に不正にスクリプトが書き換わって意図しない動作を防ぐための機構です。overcommitに何も登録していない状態ではコミットメッセージのチェックだけなので、signしてしまいましょう。
$ overcommit --sign
を実行後、再度git commitをすると下記のようにコミットメッセージがチェックされるはずです。
リポジトリからのアンインストールも下記のコマンドでおkっす
$ overcommit --uninstall
設定方法
設定ファイルたる.overcommit.ymlを書き換えたらovercommit --signを実行するのを忘れずに
pre-commit
Rubocopの設定
overcommitの設定は、.overcommit.ymlファイルに記述します。例えばコミット前のタイミング(言い換えればpre-commit)でrubocopを実行したいのであれば、下記のように.overcommit.ymlを設定します。
PreCommit:
RuboCop:
enabled: true
command: ['bundle', 'exec', 'rubocop'] # bundlerの中でrubocopを実行する場合
これで、.rbやGemfileの変更がcommitされる前にrubocopのチェックが走ります。1行目のPreCommitはpre-commitグループにフックを追加する、という意味で、フックポイントごとにグループを宣言します。
commandは実際に実行するコマンドを記述します。実行ファイルが渡される前に部分と考えていいでしょう。
ESLintの設定
同様にESLintのチェックを行いたい場合は下記のように.overcommit.ymlを記述します。(overcommit側のメッセージ解析の都合上、package.jsonも調整が必要です)
ESLint:
enabled: true
required_executable: 'npm'
command: ['npm', 'run', 'lint']
{
"scripts": {
"lint": "eslint -f compact"
},
"devDependencies": {
"eslint": "^2.0.0"
}
{
ESLintの場合、jsファイル等がステージングにある時に実行されます。詳しくはhookのソースをみるとよいです。
required_executableは必要な実行ファイルを指定する設定です。相対パスの場合はリポジトリ内のパス、そうでない場合はPATH上に存在するかどうかをチェックします。npmはPATHに存在しなければ実行できないので、指定する必要があります。これがないと、npm run lintが動作しません。
カスタムスクリプト
すでにスクリプトを利用している場合は下記の設定
CustomScript:
enabled: true
required_executable: '.pre-commit.sh' # スクリプトのパスを指定する
post-checkout
bundle install
他のブランチをcheckoutしたタイミングでgem fileの更新をしたい場合は下記のように.overcommit.ymlを設定しましょう
PostCheckout:
BundleInstall:
enabled: true
npm install
npm installの場合もこんな感じです。
NpmInstall:
enabled: true
ここまでの設定を全て有効にする場合、.overcommit.ymlはこんな感じになっているでしょう。
PreCommit:
RuboCop:
enabled: true
command: ['bundle', 'exec', 'rubocop'] # bundlerの中でrubocopを実行する場合
ESLint:
enabled: true
required_executable: 'npm'
command: ['npm', 'run', 'lint']
CustomScript:
enabled: true
required_executable: '.pre-commit.sh' # スクリプトのパスを指定する
PostCheckout:
BundleInstall:
enabled: true
NpmInstall:
enabled: true
これらのHookの詳細はリポジトリの説明からたどることができます。
こんな感じでプロジェクトに必要なhookを組み合わせて設定できます。
FAQ
コミット時に特定のHookをスキップしたい
$ SKIP=RuboCop git commit
コミット時に全てのHookをスキップしたい
OVERCOMMIT_DISABLE=1 git commit

