😇

Prettierで整形だけしてコミットしたら「[FAILED] Prevented an empty git commit!」と言われた。

2023/12/25に公開

Reactのリポジトリにてコーディング作業中に、ファイルを編集しかけてやっぱりこのファイルじゃないなと思い、特に修正はしていないですがいつものくせで、VSCode(Prettier拡張インストール済み)のショートカットでコード整形をして保存をしたら、差分があったのでコミットをしたところ表題のメッセージが出たときの話です。

環境とか前提条件とか

以下のような環境で起こった事象になります。

  • リポジトリ自体にPrettierは導入済み
  • husky+pre-commitでコミット時にPrettierを実行して整形するようになっている
  • コーディングはPrettierの拡張機能がインストール済みのVSCodeで行っている

そもそも

huskypre-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では「jsxBracketSameLinebracketSameLineに置き換えるよ〜」と言われていました。

そして今回のリポジトリで使用しているPrettierは2.4.0以上でしたのでjsxBracketSameLineは非推奨になっています。

つまり

この非推奨となっているルールであるjsxBracketSameLineが使用されていた場合の扱いが、CLIとVSCode拡張で異なる。というのが今回の現象の根本原因だと思われます。

取るべき対応

jsxBracketSameLineの使用はやめて、後継のbracketSameLineを使うようにしましょう。
(ちなみに後継といってもjsxBracketSameLineからbracketSameLineに置き換えるとフォーマットのされ方はわりと異なるようで、結構差分が出ました。)

所感

  • VSCodeのjsxBracketSameLineでのフォーマットのされかたはbracketSameLineとほぼ同じように見えたので、もしかしたらjsxBracketSameLineが設定されていた場合、VSCodeのPrettierではよしなに判断してbracketSameLineを適用しているのかな?とも思えました。
  • 歴史あるリポジトリでは今回のように、現在では非推奨となったルールを使用している可能性があるため、作業時に異変を感じたら.prettierrcファイルを確認してみるのが良さそう。

以上🐈

Discussion