CLIでもコミットメッセージはAIに書いてもらえる (cz-git,czg)
はじめに
モテるGit管理 (gh, ghq, git-cz, lazygit)のコメントにて cz-git を紹介していただいたので試しに使ってみました。
cz-git とは?
cz-gitは、簡単にフォーマットに沿ったコミットメッセージを生成することができるツールです。
英語であればコミットメッセージをAIに生成してもらえるので英語学習にもピッタリですね😎
AIでコミットメッセージを作成している様子
コミットメッセージのフォーマットは、Conventional Commits の元である Angular のコミットメッセージ標準 に沿っています。
似たツールとして git-cz や Commitizen がありますが、cz-git は複雑な依存関係を解決し、さらに軽量化しています。
148 MB node_modules/git-cz
1.9 MB node_modules/cz-git
cz-gitの推しポイント
以前はgit-czを使っていたのですが、cz-gitの場合は以下のようなメリットがあったため移行しました。
- 絵文字あり/なし を簡単に切り替え
- AIによるコミットメッセージ生成
czg とは?
公式のページを見にいくと、どうやらcz-gitの他にczgというものがあるようです。
czgとは、cz-gitをCLIツールとして利用できるようにしたものです。
プロジェクトごとに導入する場合は cz-git、CLIツールとして手軽に使用したい場合は czg を利用すると良いでしょう。
cz-gitの場合は cz
または git cz
で実行するのに対し、czg の場合は czg
または git czg
で実行できます。
この記事ではCLIツールとして使用するため czg の導入方法を紹介します。
cz-git の導入
git-cz のアンインストール
自分の環境には git-cz が入っているため、アンインストールします。
npm uninstall -g git-cz
インストール
czgは単品では使用できないため、cz-gitもインストールする必要があります。
# npmの場合
npm install -g czg cz-git
# voltaの場合
volta install czg cz-git
参照: czg | Interactive Commitizen CLI that generate standardized git commit message
cz-git のフォーマット設定
設定ファイルはホームディレクトリか、プロジェクトルートに配置します。
優先順位は プロジェクトルートにある設定ファイル > ホームディレクトリにある設定ファイル
です。
const { defineConfig } = require('cz-git')
module.exports = defineConfig({
rules: {
// @see: https://commitlint.js.org/#/reference-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: ':sparkles:' },
{ value: 'fix', name: 'fix: 🐛 A bug fix', emoji: ':bug:' },
{ value: 'docs', name: 'docs: 📝 Documentation only changes', emoji: ':memo:' },
{ value: 'style', name: 'style: 💄 Changes that do not affect the meaning of the code', emoji: ':lipstick:' },
{ value: 'refactor', name: 'refactor: ♻️ A code change that neither fixes a bug nor adds a feature', emoji: ':recycle:' },
{ value: 'perf', name: 'perf: ⚡️ A code change that improves performance', emoji: ':zap:' },
{ value: 'test', name: 'test: ✅ Adding missing tests or correcting existing tests', emoji: ':white_check_mark:' },
{ value: 'build', name: 'build: 📦️ Changes that affect the build system or external dependencies', emoji: ':package:' },
{ value: 'ci', name: 'ci: 🎡 Changes to our CI configuration files and scripts', emoji: ':ferris_wheel:' },
{ value: 'chore', name: 'chore: 🔨 Other changes that don\'t modify src or test files', emoji: ':hammer:' },
{ value: 'revert', name: 'revert: ⏪️ Reverts a previous commit', emoji: ':rewind:' },
],
useEmoji: true,
emojiAlign: 'center',
useAI: false,
aiNumber: 1,
themeColorCode: '',
scopes: [],
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,
scopeOverrides: undefined,
defaultBody: '',
defaultIssues: '',
defaultScope: '',
defaultSubject: '',
},
})
しかし、初期設定のままだと絵文字ではなく文字として表示されてしまいます。
(✨が :sparkles:
になっている)
以下のようにemoji
の部分を変更すると、コミットメッセージにも絵文字が反映されます。
const { defineConfig } = require("cz-git");
module.exports = defineConfig({
rules: {
// @see: https://commitlint.js.org/#/reference-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: [],
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,
scopeOverrides: undefined,
defaultBody: "",
defaultIssues: "",
defaultScope: "",
defaultSubject: "",
},
});
AIにコミットメッセージを書いてもらう
AIにコミットメッセージを書いてもらいたい場合は、別途設定が必要です。
対応しているモデル: https://cz-git.qbb.sh/recipes/openai
GitHub Modelsを使用する場合は以下のコマンドで設定できます。
czg --api-key="ghp_xxxxxx" --api-endpoint="https://models.inference.ai.azure.com" --api-model="gpt-4o-mini"
api-keyは以下のページから作成できます。
https://github.com/settings/tokens
コマンドを実行すると、~/.config/.czrc
というファイルが作成されます。
{
"openAIToken": "ghp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"apiEndpoint": "https://models.inference.ai.azure.com",
"apiModel": "gpt-4o-mini"
}
このファイルはトークン情報を含んでいるため、dotfiles を育てている方は必ず.gitignore
に追加しましょう。
+ .config/.czrc
AIに書いてもらったメッセージを変更したい
AIによって生成されたメッセージには scope がつきません。
こんな時はどうすればいいのでしょうか?
画面を確認してみると、何やら不思議な文字 (Ynemh)
がありますね
試しにここでm
を入力してみると...
なんということでしょう!scopeを追加できる画面になったではありませんか!
試しにscopeをnvim
と入力してみましょう。
feat(nvim):
に変更できました!やったね!
Lazygitから実行できるように設定する
Lazygit からも実行できるようにしておくと幸せになれます。
Lazygitからコマンドを実行したい場合はcustomCommands
で設定できます。
# https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md
customCommands:
- command: czg
context: files
subprocess: true
key: c
- command: czg ai
context: files
subprocess: true
key: C
設定するとこんな感じでNeovimから出ることなくコミットできるので楽ちんですね🙌
絵文字を使用しない
絵文字を使用しない場合は、useEmoji: false
にすると変更できます。
設定ファイルを指定して実行
プロジェクトルート以外に設定ファイルをおきたい場合は、czg --config
で指定することができます。
# 例: ./config/cz.json の設定を使用してコミットする
czg --config="./config/cz.json"
おわりに
cz-gitはいいぞ
Discussion