クライアントhookの機能でcommit前に介入することができます。
commit前に.git/hooks/pre-commit
があれば、実行されて、結果が0以外の場合は、commitがキャンセルされます。
(引数は渡されません)
.git/hooks/pre-commit.sample
というサンプルスクリプトがあるのでまずはこれを試してみます。
pre-commit.sampleを使ってみる
百聞は一見に如かず。とりあえずやってみます。
以下のコマンドでpre-commit.sample
をpre-commit
にコピーします。
$ cp .git/hooks/pre-commit{.sample,}
2バイト文字のファイルを作成し、commitしてみます。
$ touch "ぺとあすか.txt"
$ git add .
$ git commit -m "ファイル追加"
Error: Attempt to add a non-ascii file name.
This can cause problems if you want to work
with people on other platforms.
To be portable it is advisable to rename the file ...
If you know what you are doing you can disable this
check using:
git config hooks.allownonascii true
$ git rm --cached "ぺとあすか.txt"
$ rm !$
何やら怒られてしまいました。(理由は後述)
次は、以下の作業をコミットしてみます。
$ touch suzaki-nishi.txt
$ git add suzaki-nishi.txt
$ git commit -m "first"
$ echo -e "洲崎西\n\t" >> suzaki-nishi.txt
$ git commit -m "second"
suzaki-nishi.txt:2: trailing whitespace.
+
suzaki-nishi.txt:2: new blank line at EOF.
こちらもコミットがキャンセルされてしまうことが確認できました。
どんな仕組みなのかは以下で説明します。
pre-commit.sampleの説明
サンプルスクリプトには2つの機能があります。
1.ascii文字以外のファイル名のコミットを禁止
2.空白行が含まれるファイルのコミットを禁止
4b825dc642cb6eb9a060e54bf8d69288fbee4904
は空のツリーを示す値です。
なので通常はHEAD(現在の最新のコミット)が$aginstにセットされます。
おまじないだとでも考えましょう。
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
.git/configの値を取得しています。
空白行を許可していればチェックされません。
allownonascii=$(git config hooks.allownonascii)
ここがファイル名をチェックしているところです。
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
git-add
された範囲の内容に対して、空白行のみが無いかチェック(--check)しています。
無ければ0が返ります。
exec git diff-index --check --cached $against --
syntaxチェック
ここからが本題です。
サンプルでexit 0
以外を返せばよいことがわかったので、
.git/hooks/pre-commit
に書いてみます。
Perlのsyntaxチェックは-c
で、-Mstrict
はuse strict
したことになります。
#!/bin/sh
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Redirect output to stderr.
exec 1>&2
for file in `git diff-index --cached --name-only HEAD`; do
case "${file##*.}" in
pl | cgi | pm | t)
perl -Mstrict -Mwarnings -c $file || exit 1
;;
php)
php -l $file || exit 1;
;;
*)
;;
esac
done
# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --
こんな感じでcommit時に自動でチェックできます。
$ git ci -m third
Global symbol "$undefind_value" requires explicit package name at a.pl line 1.
a.pl had compilation errors.
参考
git diffをカラー表示 - rochefort's blog
http://rochefort.hatenablog.com/entry/20110811/p1
bash 例解: 第 2 回 bash による初歩のプログラミングの続編
http://www.ibm.com/developerworks/jp/linux/library/l-bash2.html
case 文の使用方法 - UNIX & Linux コマンド・シェルスクリプト リファレンス
http://shellscript.sunone.me/case.html
エラーのあるファイルはコミットしない(git編) - 肉とビールとパンケーキ by @sotarok
http://sotarok.hatenablog.com/entry/20090223/1235363846
Gitのpre-commit.sampleにある4b825dc642cb6eb9a060e54bf8d69288fbee4904とは? - Qiita
http://qiita.com/fieldville/items/5518ed98ce38eb9df351