コミットメッセージの体裁を強制してみたお話
自己紹介
こんにちは。若手の web エンジニアの柿です!
フロントエンド領域を生業としています :)
個人でなにかやるときには React/Next を使いますが、仕事では Vue/Nuxt を使用しています。
今回のお話
今回は、コミットメッセージの体裁を強制してみることを頑張ったときのお話です。
なぜ頑張ったのかというと、
「コミットメッセージ、lint できるようにしてみてよ!」
という大先輩からの一言があったからです。
チームの課題として、一時期「コミットメッセージの体裁が乱れていたこと」を提起させて頂いた過去があったので、
これできるようになったらおもろいな、と思った次第です。
少なくともコミットメッセージに prefix(feat:, fix:など)がついているだけで、どんな類のコミットなのか分かりやすくなりますし、なにより見た目がいいですよね!笑
今回のゴールとしては、
「✨ feat: 対応内容」
というコミットメッセージの形式でコミットできるようにすることです。
私は Gitmoji が好きなので、それも取り入れた形にします。
今回導入するもの
今回導入するツールは大きく分けて
- husky
- commitlint
- commitizen
の3つです。
次のパートから早速やってみます。
husky の導入
今回は Git hooks を利用するので、それを簡単にするツール husky を導入して使用します。
pnpm add -D husky
今回の husky のバージョンは、9.0.11
を使っていきます。
{
"devDependencies": {
"husky": "^9.0.11"
}
}
パッケージが追加できたら初期設定を行っていきます。
pnpm exec husky init
上記コマンドを打つと、.husky
ディレクトリが作成され、その中にpre-commit
ファイルが作成されると思います。
そして、scripts にprepare
が追加されると思います。
{
"scripts": {
"prepare": "husky"
}
}
今回はpre-commit
ファイルは使用しないので、削除していただいても構いません。
もし活用したい場合は、lint-staged
も合わせて導入すると、コミット対象のファイルのみに eslint
や prettier
をかけることができ、エラーが残っている場合はコミットできなくなるので、品質担保におすすめです。
機会があれば、別記事で導入記事を書こうと思います。
commitlint の導入
次に、コミットメッセージの体裁を強制するために commitlint を導入します。
lint という名前がついている通り、コミットメッセージのリントツールになります。
有名なコミットメッセージの規約として、
Conventional Commits
があります。
この規約のコミットメッセージの形式は、
<type>[optional scope]: <description(subject)>
[optional body]
[optional footer(s)]
となっています。
私は<type>
の部分に Gitmoji を使っているため、このまま使うとコミットが失敗します。
そのため、他のルールセットを使うことにしました。
今回導入したのは、commitlint-config-gitmojiというものです。
このルールセットを使うと、Gitmoji を使ったコミットメッセージの形式を強制することができます。
:gitmoji: <type>: <description(subject)>
[optional body]
[optional footer(s)]
という形式になります。
それでは、関連パッケージをインストールしておきましょう。
pnpm add -D @commitlint/cli commitlint-config-gitmoji
使用しているパッケージのバージョンは以下の通りです。
{
"devDependencies": {
"@commitlint/cli": "^19.3.0",
"commitlint-config-gitmoji": "^2.3.1"
}
}
パッケージを追加できたら、commitlint
の設定ファイルを作成します。
touch commitlint.config.cts
今回は ts ファイルを作成しましたが、他にも
.commitlintrc
.commitlintrc.json
.commitlintrc.yaml
.commitlintrc.yml
.commitlintrc.js
.commitlintrc.cjs
.commitlintrc.mjs
.commitlintrc.ts
.commitlintrc.cts
commitlint.config.js
commitlint.config.cjs
commitlint.config.mjs
commitlint.config.ts
commitlint.config.cts
といったファイルの作成が可能です。
公式ドキュメントではmodule.exports={}
を使用しているので、.cjs
もしくは.cts
の拡張子を使うといいかもれません。
(私はexport default
できるか試してみたかったので、.ts
を使っています)
次に作成したファイルに以下の内容を記述します。
const config = {
extends: ['gitmoji'],
};
module.exports = config;
これでcommitlint-config-gitmoji
の設定を適用することができます。
(commonJS ではない場合はmodule.exports = config;
を export default config;
に変更してください)
次に<type>
の部分にどんな type が来るのかを設定します。
feat
,fix
といった prefix たちですね。
const config = {
extends: ['gitmoji'],
rules: {
'header-max-length': [2, 'always', 100],
'type-case': [0, 'always', 'lower-case'],
'type-enum': [
2,
'always',
[
'feat',
'improve',
'update',
'fix',
'hotfix',
'refactor',
'delete',
'style',
'docs',
'move',
'test',
'chore',
'package',
'WIP',
],
],
},
};
module.exports = config;
header-max-length は、コミットメッセージの長さを指定するルールです。
type-enum は、許可する type を指定するルールです。今回はこれらの prefix を許可するようにしました。
次にコミットしたときに、commitlint
が動作するように設定します。
.husky
ディレクトリ配下にcommit-msg
ファイルを作成します。
touch .husky/commit-msg
そして、以下の内容を記述します。
npx --no -- commitlint --edit "$1"
これでコミットしたときに、commitlint
が動作するようになりました。
設定した prefix 以外のコミットメッセージや、prefix がないコミットメッセージを行った場合は、コミットが失敗するはずです。
commitizen の導入
commitlint だけでも十分効果を発揮しますが、いちいちどれが問題ない prefix なのかを覚えるのは大変なことです。
そのため、コミットメッセージの prefix 及び gitmoji を対話形式で選べるようにしたいと思います。
そのためには commitizen を導入します。
pnpm add -D commitizen cz-customizable
commitizen は、対話形式でコミットメッセージを作成するためのもので、
cz-customizable は、commitizen の設定をカスタマイズするためのものです。
使用しているパッケージのバージョンは以下の通りです。
{
"devDependencies": {
"commitizen": "^4.3.0",
"cz-customizable": "^7.0.0"
}
}
次に、commitizen
の設定ファイルを作成します。
touch .cz-config.cts
このファイルはどうやら commonJS で書かないといけないようだったので、.cts
を使っています。(.cjs
でも可)
これは、cz-customizable
の設定ファイルで、対話形式でコミットメッセージを作成する際の設定を記述します。
const config = {
types: [
{
name: 'feat: ✨ 新機能の追加',
value: ':sparkles: feat',
},
{
name: 'improve: 🎨 コードの構造/ロジックの改善',
value: ':art: improve',
},
{
name: 'update: 🩹 軽微な修正',
value: ':adhesive_bandage: update',
},
{
name: 'fix: 🐛 バグ修正',
value: ':bug: fix',
},
{
name: 'hotfix: 🚑 緊急バグ修正',
value: ':ambulance: hotfix',
},
{
name: 'refactor: ♻️ リファクタリング',
value: ':recycle: refactor',
},
{
name: 'delete: 🔥 ファイルやコードの削除',
value: ':fire: delete',
},
{
name: 'style: 💄 UIやスタイルファイルの追加/更新',
value: ':lipstick: style',
},
{
name: 'docs: 📝 ドキュメンテーションの追加/更新',
value: ':memo: docs',
},
{
name: 'move: 🚚 ファイルやディレクトリの移動',
value: ':truck: move',
},
{
name: 'test: ✅ テストの追加/更新/合格',
value: ':white_check_mark: test',
},
{
name: 'chore: 🔧 設定ファイルの追加/更新',
value: ':wrench: chore',
},
{
name: 'package: 📦 パッケージの追加/更新',
value: ':package: package',
},
{
name: 'WIP: 🚧 作業途中',
value: ':construction: WIP',
},
],
messages: {
type: 'コミットの種類(型)を選択してください:\n',
subject: 'コミットメッセージを入力してください:\n',
body: '変更内容の詳細があれば書いてください:(enterでスキップ)\n',
confirmCommit: '上記のコミットを続行してもよろしいですか?(Y/n)\n',
},
skipQuestions: ['scope', 'breaking', 'footer'],
subjectLimit: 100,
upperCaseSubject: true,
};
module.exports = config;
types の配列には先程 commitlint の設定ファイルで設定した prefix を記述します。
name:
には対話形式で表示される内容、value:
には実際のコミットメッセージに追加される内容を記述します。
messages には対話形式で表示される質問の内容を記述します。
対話の種類としては
type: <type>の部分、prefix を選択する質問
scope: <type>(scope)の部分、スコープを選択する質問(ui, api, etc...)
subject: <description(subject)>の部分、コミットメッセージを入力する質問
body: [optional body]の部分、変更内容の詳細を書く質問(3行目にあたる部分)
breaking: <type!>の部分、破壊的変更がある場合に書く質問(! がつく)
footer: [optional footer(s)]の部分、issue 番号などを書く質問
があります。
私としては、scope
、breaking
、footer
は使わないので、skipQuestions
に記述して対話をスキップします。
コミットメッセージの文字数制限はsubjectLimit
で設定します。
今回は 100 文字にしておきました。
そんなに書くのであれば、body
に書いてほしいですが笑
git commit したときに対話できるようにする
最後に、git commit
したときに対話形式でコミットメッセージを作成できるようにします。
まずは、.husky
ディレクトリ配下にprepare-commit-msg
ファイルを作成します。
touch .husky/prepare-commit-msg
そして、以下の内容を記述します。
exec < /dev/tty && node_modules/.bin/cz --hook || true
次にpackage.json
に以下の内容を追記します。
{
"config": {
"commitizen": {
"path": "./node_modules/cz-customizable"
},
"cz-customizable": {
"config": ".cz-config.cts"
}
}
}
これで.cz-config.cst
の設定が適用され、git commit
したときに対話形式でコミットメッセージを作成できるようになります。
まとめ
さて、これで一連の導入が終わりました。
一度コミットまでの流れを確認してみましょう!
まずgit commit
すると、対話形式になり、まずは prefix を選択します。
次にコミットメッセージを入力します。
次になにか詳細があれば書きます。ときになければ enter でスキップ可能です。
最後にできあがったコミットメッセージの確認があります。
問題がなければY
か enter を押してください。
なにか問題があればn
を押してやり直してください
これでチーム全体でコミットメッセージの体裁を揃えることができます。
ぜひ皆様のチームでも導入を検討してみてください!
Discussion