Conventional Commits に沿ったコミットメッセージを簡単に書く方法を模索する
ソフトウェア開発において、Conventional Commits に従ったコミットメッセージの記述は、履歴の可読性や自動化ツールとの連携を向上させるために非常に重要です。私は普段、手打ちでコミットメッセージを書くため、つい絵文字などの付加情報を忘れてしまうことがあります。そこで、今回はコミットメッセージを簡単に、そして漏れなく書くためのツール選定とその設定方法について検証した内容をまとめます。
背景
-
手打ちの限界:
普段は慣れた手打ちでコミットメッセージを書いているものの、絵文字などの関連情報を書き忘れてしまうことが度々ある。 -
自動化ツールへの期待:
チーム全体で統一したフォーマットを採用するためにも、手間を減らしつつ正しいフォーマットでコミットメッセージを生成できるツールがあったらいいな。
目標
最終的には以下のフォーマットに沿ったコミットメッセージを楽に作成できる環境を目指しました。
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
※ <description>
の冒頭には、 <type>
に応じた絵文字を付与する
検討したオプション
いくつかの選択肢を検討しました。
npm を利用する方法
- commitizen/cz-cli と leoforfree/cz-customizable の組み合わせ
- commitizen/cz-cli と withblocks/cz-customizable の組み合わせ
- commitizen/cz-cli と streamich/git-cz の組み合わせ
- commitizen/cz-cli と ngryman/cz-emoji の組み合わせ
- commitizen/cz-cli と Zhengqbbb/cz-git の組み合わせ
fish シェルの場合
- oh-my-fish/plugin-expand
- fish shell と peco の組み合わせ
Rust 製のツール
- k3ii/git-cz: シンプルな Commitizen
推奨する組み合わせ
検討の結果、以下の組み合わせが最も良さそうでした。
これらを使うことで、 git-cz で足りないと感じた「scope の選択式+任意記載」「typeに応じた絵文字の入力」を実現することができました。
cz-git の導入と設定
以下は、cz-git を利用した環境構築手順の一例です。
インストール
まずは npm 経由で必要なパッケージをグローバルにインストールします。
npm install -g cz-git commitizen
次に、プロジェクトルートまたはユーザーのホームディレクトリに .czrc
を作成し、以下の内容を記述します。
{
"path": "cz-git",
"$schema": "https://cdn.jsdelivr.net/gh/Zhengqbbb/cz-git@1.11.0/docs/public/schema/cz-git.json"
}
設定ファイル例
コミットメッセージの検証ツールとして commitlint を利用している場合、~/.commitlintrc.json
などで以下のように設定します。
基本的には Configure Template | cz-git で記載されている設定のママですが、 emoji の有効化や、コミットメッセージに入力される絵文字の部分をカスタムしています。
{
"rules": {
// 必要に応じてルールを追加
},
"prompt": {
"alias": { "fd": "docs: fix typos" },
"messages": {
"type": "Select the type of change that you're committing:",
"scope": "Denote the SCOPE of this change (optional):",
"customScope": "Denote the SCOPE of this change:",
"subject": "Write a SHORT, IMPERATIVE tense description of the change:\n",
"body": "Provide a LONGER description of the change (optional). Use \"|\" to break new line:\n",
"breaking": "List any BREAKING CHANGES (optional). Use \"|\" to break new line:\n",
"footerPrefixesSelect": "Select the ISSUES type of changeList by this change (optional):",
"customFooterPrefix": "Input ISSUES prefix:",
"footer": "List any ISSUES by this change. E.g.: #31, #34:\n",
"generatingByAI": "Generating your AI commit subject...",
"generatedSelectByAI": "Select suitable subject by AI generated:",
"confirmCommit": "Are you sure you want to proceed with the commit above?"
},
"types": [
{ "value": "feat", "name": "feat: ✨ A new feature", "emoji": "✨" },
{ "value": "fix", "name": "fix: 🐛 A bug fix", "emoji": "🐛" },
{ "value": "docs", "name": "docs: 📝 Documentation only changes", "emoji": "📝 " },
{ "value": "style", "name": "style: 💄 Changes that do not affect the meaning of the code", "emoji": "💄" },
{ "value": "refactor", "name": "refactor: ☘️ A code change that neither fixes a bug nor adds a feature", "emoji": "☘️" },
{ "value": "perf", "name": "perf: ⚡️ A code change that improves performance", "emoji": "⚡️" },
{ "value": "test", "name": "test: ✅ Adding missing tests or correcting existing tests", "emoji": "✅" },
{ "value": "build", "name": "build: 📦️ Changes that affect the build system or external dependencies", "emoji": "📦️" },
{ "value": "ci", "name": "ci: 🎡 Changes to our CI configuration files and scripts", "emoji": "🎡" },
{ "value": "chore", "name": "chore: 🔨 Other changes that don't modify src or test files", "emoji": "🔨" },
{ "value": "revert", "name": "revert: ⏪️ Reverts a previous commit", "emoji": "⏪️" }
],
"useEmoji": true,
"emojiAlign": "center",
"useAI": false,
"aiNumber": 1,
"themeColorCode": "",
"scopes": ["git","github","terraform","docker","script"],
"allowCustomScopes": true,
"allowEmptyScopes": true,
"customScopesAlign": "bottom",
"customScopesAlias": "custom",
"emptyScopesAlias": "empty",
"upperCaseSubject": false,
"markBreakingChangeMode": false,
"allowBreakingChanges": ["feat", "fix"],
"breaklineNumber": 100,
"breaklineChar": "|",
"skipQuestions": [],
"issuePrefixes": [{ "value": "closed", "name": "closed: ISSUES has been processed" }],
"customIssuePrefixAlign": "top",
"emptyIssuePrefixAlias": "skip",
"customIssuePrefixAlias": "custom",
"allowCustomIssuePrefix": true,
"allowEmptyIssuePrefix": true,
"confirmColorize": true,
"minSubjectLength": 0,
"defaultBody": "",
"defaultIssues": "",
"defaultScope": "",
"defaultSubject": ""
}
}
この設定により、対話形式でコミットメッセージが生成され、各ステップで適切な選択肢(type、scopeなど)を選ぶことができるようになります。
git cz
コマンドの実行結果
追記
作者の方からコメントいただいたので、 czg の方も試してみました。
次のように、インストールした cz-git
と commitizen
を削除して czg
をインストールします。
npm uninstall -g cz-git commitizen
npm install czg
# git repository 配下で実行
czg
# カスタム設定の適用
czg --config="./config/cz.json"
こちらのコマンドの方がサクサクと動作する気がします。
e.g. Config
// .config/cz-git/cz.js
const { definePrompt } = require('czg')
module.exports = definePrompt({
"rules": {
// 必要に応じてルールを追加
},
"prompt": {
"alias": { "fd": "docs: fix typos" },
"messages": {
"type": "Select the type of change that you're committing:",
"scope": "Denote the SCOPE of this change (optional):",
"customScope": "Denote the SCOPE of this change:",
"subject": "Write a SHORT, IMPERATIVE tense description of the change:\n",
"body": "Provide a LONGER description of the change (optional). Use \"|\" to break new line:\n",
"breaking": "List any BREAKING CHANGES (optional). Use \"|\" to break new line:\n",
"footerPrefixesSelect": "Select the ISSUES type of changeList by this change (optional):",
"customFooterPrefix": "Input ISSUES prefix:",
"footer": "List any ISSUES by this change. E.g.: #31, #34:\n",
"generatingByAI": "Generating your AI commit subject...",
"generatedSelectByAI": "Select suitable subject by AI generated:",
"confirmCommit": "Are you sure you want to proceed with the commit above?"
},
"types": [
{ "value": "feat", "name": "feat: ✨ A new feature", "emoji": "✨" },
{ "value": "fix", "name": "fix: 🐛 A bug fix", "emoji": "🐛" },
{ "value": "docs", "name": "docs: 📝 Documentation only changes", "emoji": "📝 " },
{ "value": "style", "name": "style: 💄 Changes that do not affect the meaning of the code", "emoji": "💄" },
{ "value": "refactor", "name": "refactor: ☘️ A code change that neither fixes a bug nor adds a feature", "emoji": "☘️" },
{ "value": "perf", "name": "perf: ⚡️ A code change that improves performance", "emoji": "⚡️" },
{ "value": "test", "name": "test: ✅ Adding missing tests or correcting existing tests", "emoji": "✅" },
{ "value": "build", "name": "build: 📦️ Changes that affect the build system or external dependencies", "emoji": "📦️" },
{ "value": "ci", "name": "ci: 🎡 Changes to our CI configuration files and scripts", "emoji": "🎡" },
{ "value": "chore", "name": "chore: 🔨 Other changes that don't modify src or test files", "emoji": "🔨" },
{ "value": "revert", "name": "revert: ⏪️ Reverts a previous commit", "emoji": "⏪️" }
],
"useEmoji": true,
"emojiAlign": "center",
"useAI": false,
"aiNumber": 1,
"themeColorCode": "",
"scopes": ["git", "github", "terraform", "docker", "script"],
"allowCustomScopes": true,
"allowEmptyScopes": true,
"customScopesAlign": "bottom",
"customScopesAlias": "custom",
"emptyScopesAlias": "empty",
"upperCaseSubject": false,
"markBreakingChangeMode": false,
"allowBreakingChanges": ["feat", "fix"],
"breaklineNumber": 100,
"breaklineChar": "|",
"skipQuestions": [],
"issuePrefixes": [{ "value": "closed", "name": "closed: ISSUES has been processed" }],
"customIssuePrefixAlign": "top",
"emptyIssuePrefixAlias": "skip",
"customIssuePrefixAlias": "custom",
"allowCustomIssuePrefix": true,
"allowEmptyIssuePrefix": true,
"confirmColorize": true,
"minSubjectLength": 0,
"defaultBody": "",
"defaultIssues": "",
"defaultScope": "",
"defaultSubject": ""
}
})
使用感と感想
検討を進める中で、以下の点が印象に残りました。
-
多くの類似ツール:
名前や機能が似たツールが多数存在し、どれを採用するか悩みました。 -
選択式の scope 入力:
特に git-cz などは scope の選択が固定されているため、自由入力できない点が改善の余地として感じられました。 -
AI 支援の可能性:
設定項目に AI を利用してコミットメッセージの生成候補を提示する機能があるものもあり、今後の発展に期待できると感じました。
最終的には、commitizen/cz-cli と Zhengqbbb/cz-git の組み合わせが最も使い勝手が良いと判断し、実際のプロジェクトでも採用しています。
まとめ
今回の記事では、Conventional Commits に従ったコミットメッセージを楽に書くためのツール検討と、実際に cz-git を中心とした環境構築手順を紹介しました。多くのツールが存在する中で、自分やチームの開発フローに最適な組み合わせを見つけることが大切です。必要に応じて、こういったツールの活用も検討してみてください。
【参考リンク】
以上、皆さんの開発環境に少しでも役立つ情報となれば幸いです。
Discussion