Prettierで整形だけしてコミットしたら「[FAILED] Prevented an empty git commit!」と言われた。
Reactのリポジトリにてコーディング作業中に、ファイルを編集しかけてやっぱりこのファイルじゃないなと思い、特に修正はしていないですがいつものくせで、VSCode(Prettier拡張インストール済み)のショートカットでコード整形をして保存をしたら、差分があったのでコミットをしたところ表題のメッセージが出たときの話です。
環境とか前提条件とか
以下のような環境で起こった事象になります。
- リポジトリ自体にPrettierは導入済み
- husky+pre-commitでコミット時にPrettierを実行して整形するようになっている
- コーディングはPrettierの拡張機能がインストール済みのVSCodeで行っている
そもそも
husky
とpre-commit
でコミット前にPrettierで自動整形するようにしているので、何も編集してないファイルにコード整形して差分が発生するのは変。
なぜ「[FAILED] Prevented an empty git commit!」と言われるのか?
このメッセージは「変更がないからコミットすることがないよ」というものです。
pre-commitの設定に--allow-empty
を追加して
"pre-commit": "lint-staged --allow-empty”
とすれば無理やりコミット自体はできるのですが、空コミットになってしまい、なんの解決にもなりません。
(差分が出てると思いコミットすると何も変更なしでコミットされ、しかもコミット後は対象ファイルはフォーマット前に戻っていました)
直接的な原因
いろいろ試してみたら以下のことが原因だとわかりました。
- VSCodeのPrettier(ショートカット)での整形の仕方と、CLIのPrettierの整形の仕方がなぜか異なる
つまり、pre-commit
による整形はCLIでかつコミットの直前に行われるため、VSCodeで整形したら差分がでたからといってコミットしようとするとその瞬間にCLIで再整形され、差分が無くなり「空コミットできないよ!」と言われているというカラクリでした。
根本的な原因を調べる
ではなぜこのようなことが起きるのか?
調べてみました。
まず、Prettierの設定ファイルがちゃんとあるのかを確認したところ、ちゃんと.prettierrc.js
は存在していました。
これがあれば(プロジェクトにインストールされている)CLIで実行されるPrettierも、VSCodeにインストールされている拡張機能のPrettierも同じルールで整形してくれるはずです。
.prettierrc.js
に書かれたルールを確認してみる
とりあえず.prettierrc.js
のルール書き換えてCLIとショートカット(VSCode拡張)で整形して同じようにルールの変更が適用されているか確認しました。
すると一見良さそうでしたが、1つだけルールの適用なされかたが異なるルールがありました。
それがこちらです。
jsxBracketSameLine: true
ちなみにjsxBracketSameLine
というルールはtrueにすると
<button
className="prettier-class"
id="prettier-id"
onClick={this.handleClick}
>
Click Here
</button>
みたいなbuttonタグの>
だけでの改行することはしなくなりますよーというルールです。
このjsxBracketSameLine
について公式ドキュメントを確認してみると。
This option has been deprecated in v2.4.0, use --bracket-same-line instead
とあり非推奨と言われており、こちらのBlogでは「jsxBracketSameLine
はbracketSameLine
に置き換えるよ〜」と言われていました。
そして今回のリポジトリで使用しているPrettierは2.4.0以上でしたのでjsxBracketSameLine
は非推奨になっています。
つまり
この非推奨となっているルールであるjsxBracketSameLine
が使用されていた場合の扱いが、CLIとVSCode拡張で異なる。というのが今回の現象の根本原因だと思われます。
取るべき対応
jsxBracketSameLine
の使用はやめて、後継のbracketSameLine
を使うようにしましょう。
(ちなみに後継といってもjsxBracketSameLine
からbracketSameLine
に置き換えるとフォーマットのされ方はわりと異なるようで、結構差分が出ました。)
所感
- VSCodeの
jsxBracketSameLine
でのフォーマットのされかたはbracketSameLine
とほぼ同じように見えたので、もしかしたらjsxBracketSameLine
が設定されていた場合、VSCodeのPrettierではよしなに判断してbracketSameLine
を適用しているのかな?とも思えました。 - 歴史あるリポジトリでは今回のように、現在では非推奨となったルールを使用している可能性があるため、作業時に異変を感じたら
.prettierrc
ファイルを確認してみるのが良さそう。
以上🐈
Discussion