LoginSignup
61
54

More than 5 years have passed since last update.

チームで共有しておきたい!オススメ githooks まとめ

Posted at

はじめに

githooksをうまく使うことで、lintによる規約チェックやコミットメッセージのフォーマット確認など、チームメンバー全員のコード品質を担保したり、作業の漏れを防ぐことが出来ます。

というわけで、今回はチームメンバー全体で共有しておきたい、オススメのgithooksをまとめてみたいと思います。

注意点

基本的にbash前提で書いているので、 #!/bin/bash をgithooksの各ファイルの1行目に書いておいてください。

また、githooksは実行権限がないと動きません。
なので、ファイルを作った後は必ず権限を付与してあげてください。

vi .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

vi .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg

それと、hookしたい処理はメソッド化しておき、メソッド呼び出しを下にまとめておいたほうがあとあと楽です。
(hookしたい処理のON/OFFやチェック順の変更が簡単にできるので)

メッセージフォーマット

コミットメッセージに [add] とか [fix] とか付けよう、というルールがあったとします。
githooksを使えば、そのルールをコミット時にチェックすることが出来ます。

.git/hooks/commit-msg
MSG=$(cat "$1")

check_message_format() {
  local REGEX='^\[add|fix|update|remove\].+'

  if [[ ! $MSG =~ $REGEX ]]; then
    printf "\e[31m[Error]: コミットメッセージのフォーマットが正しくありません\e[0m\n"
    exit 1
  fi
}

check_message_format

ルールを変更したい場合は REGEX の正規表現を変えてあげるだけでOKです。

コーディング規約

コミットのタイミングでコーディング規約に違反していないかどうかチェックすることも出来ます。
今回はサンプルとしてRubyの規約チェックツール rubocop を使ってみます。

.git/hooks/pre-commit
check_rubocop() {
  rubocop -v >/dev/null 2>&1 || { printf >&2 "\e[31m[Error]: rubocopが見つかりません\e[0m\n"; exit 1; }

  local FILES="$(git diff --cached --name-only --diff-filter=AMCR | grep "\.rb$" | tr '\n' ' ')"
  if [ -n "$FILES" ]; then
    rubocop ${FILES}
    if [ $? -ne 0 ]; then
      printf "\e[31m[Error]: Rubyのコーディング規約に準拠していません\e[0m\n"
      exit 1
    fi
  fi
}

check_rubocop

Pythonだったら pep8 を、JavaScriptだったら ESLint を使えば同等のことができると思います。

コミット時刻

テストでローカルPCの時刻を変更していて、うっかりコミットしてしまうとおかしな時刻になってしまいます。
これは、それを防ぐhookスクリプト例です。

.git/hooks/pre-commit
check_ntpd() {
  if ntpdate -q ntp.nict.jp | grep step ; then
    printf "\e[31m[Error]: 時刻がずれています\e[0m\n"
    exit 1
  fi
}

check_ntpd

コンフリクトの対応漏れ

コンフリクトが残った状態でコミットしてしまうことも良くあります。
下記スクリプトを仕込んでおくことで、コンフリクトが残っていた場合、該当箇所の前後3行を出してくれます。

.git/hooks/pre-commit
check_conflict() {
  local FILES="$(git diff --cached --name-only --diff-filter=AMCR | tr '\n' ' ')"
  local FILE
  for FILE in $FILES; do
    conflict=`grep -3 -E '(<<<<<<<|>>>>>>>)' $FILE | grep -v '^$'`
    if [ -n "${conflict}" ]; then
      printf "\e[31m[Error]: ${FILE} コンフリクトの対応が残っています\e[0m\n"
      printf "${conflict}\n"
      exit 1
    fi
  done
}

check_conflict

本番ビルド

つい本番用のビルドを忘れてしまうことがあります。
jenkinsなどのリリース手順に含めてしまうのが一番いいのですが、設定が面倒だったりするのであれば、代替としてhookスクリプトを使用するのでもいけます。

下記はRailsのcompile例です。webpackなら webpack -p とかでしょうか。

.git/hooks/pre-commit
compile_production() {
  local FILES="$(git diff --cached --name-only --diff-filter=AMCR | grep "^app/assets")"
  if [ -n "$FILES" ]; then
    printf "Precompiling assets...\n"
    bundle exec rake assets:precompile:all RAILS_ENV=production
    git add public/assets/*
  fi
}

compile_production

ちなみに、これまでのhookスクリプトでステージング上の差分ファイルを何回も取得してしまっているので、下記のようにグローバルで取得して使いまわすと良いかもしれませんね。

FILES="$(git diff --cached --name-only --diff-filter=AMCR)"

AWSアクセスキー

これはちょっと番外編になります。
AWSのアクセスキーを誤ってコミットしてしまわないようにする方法なのですが、githooksに書くやり方ではありません。
というのも、公式が出しているgit-secretsというのがあるので、それを使ったほうが良いからです。

最高に分かりやすくまとめてくれている方がいるので、こちらをご参考ください。

hookさせない

--no-verify オプションを付けると、pre-commit/commit-msgのhookスクリプトをスキップすることができます。
緊急時でどうしてもという場合のみ許可しましょう。

git commit --no-verify

まとめ

Git 2.9.0から core.hooksPath を使ってgithooksのパスを指定できるようになったということもあり、チーム間でもgithooksが共有していく流れがになるのではないかと感じています。(使い方として合ってますかね…?)
上記以外でもチームのルールとして強制できるものがあれば、どんどんhookスクリプト化しましょう。

61
54
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
61
54