「そんなの知ってるよ!pre-commithook使えばできるんでしょ。楽勝でしょ。」なんて思っている時期が私にもありました。

要件


  • コミット時に自動でフォーマットをかけたい
  • 対象は変更したファイルと新規作成したファイル
  • フォーマットしたファイルはそのまま同時にコミットしたい

方法


結論から書くとpre-commithookを使えばいいのですが、ちょっと一手間かかりました。以下、すべてのコードはpre-commithookに記述するものとします。Gitのhookについてはこちらを見てください

コード


まず、初めに書いたコードが下記のものです。

1
2
3
for FILE in `git diff --name-only | grep .php`; do
# ここで言語に応じたなんらかのフォーマット処理
done

git diffで変更したファイルのうちgrepで拡張子がphpのものに絞り込んでそのファイルに対してフォーマットを行います。これでうまくいきますね。めでたしめでたし…。ではないんですね。

このコードだと変更したファイルのうち、拡張子がphpのものに対して フォーマットを行うところまで は上手くいきます。ところが、フォーマットしたファイルはステージに入っていないので、一緒にそのままコミットされないんですね。というわけで、下記のように改良します。

1
2
3
4
for FILE in `git diff --name-only | grep .php`; do
# ここで言語に応じたなんらかのフォーマット処理
git add $FILE
done

フォーマットをかけた後にgit addでフォーマット後のファイルをステージに追加します。これでフォーマットされたファイルがコミットされます。これで解決し…ないんですね。

このコードだと 新規作成したファイルがフォーマットされない んですね。なぜか。ただのgit diffだとすでにgitのリポジトリにあるファイルで変更されているものしか表示されないからです。というわけで、下記のように改良します。

1
2
3
4
for FILE in `git diff --staged --name-only | grep .php`; do
# ここで言語に応じたなんらかのフォーマット処理
git add $FILE
done

stagedオプションを付けます。新規ファイルだろうが、コミット前には一度ステージに入っているわけで、ステージに入ったファイルを対象とすることで当初の要件をすべて満たせます。