10 人が閲覧(直近 30 日) GitHub

Conventional Commitsとは?形式・type一覧とcommitlint・semantic-releaseの設定【v1.0.0】

Conventional Commitsとは?形式・type一覧とcommitlint・semantic-releaseの設定【v1.0.0】

Conventional Commits(コンベンショナル・コミット)は、Gitのコミットメッセージを type(scope): description の形式で書くための規約です。先頭の feat や fix を機械が読めるので、次のバージョン番号とCHANGELOGを履歴から自動で決められます。この記事では、仕様v1.0.0の形式とtype一覧を整理したうえで、commitlint 21・husky 9でコミット時に検査する手順と、semantic-releaseの既定設定では feat!: が破壊的変更として扱われない落とし穴を、手元で動かした結果とともに説明します。

まとめ:Conventional Commitsの形式と導入の要点

  • 形式は type(scope): description。必須はtypeとコロン+半角スペースと説明文だけで、scope・本文・フッターは任意。
  • 仕様が意味を決めているtypeは feat(MINOR)と fix(PATCH)の2つだけ。docs・chore・refactorなどは@commitlint/config-conventionalが採用している慣習で、破壊的変更を示さない限り、仕様上のバージョン更新には対応しない。
  • 破壊的変更は feat!: の ! か、フッターの BREAKING CHANGE: で示す。どちらもMAJORに対応し、フッターでは BREAKING-CHANGE も同じ意味。
  • 検査はcommitlint+huskyのcommit-msgフック。commitlint 21はNode.js 22.12.0以上が必要で、設定ファイルは commitlint.config.mjs にすると読み込みエラーを避けられる。
  • semantic-releaseは既定のままだと ! を読まない。commit-analyzerの既定presetがangularのためで、preset: "conventionalcommits" を指定する。
  • リリース自動化を使わない個人開発では、形式を守る手間に見合う効果は小さい。

Conventional Commitsとは:仕様v1.0.0の位置づけと読み方

Conventional Commitsは、コミットメッセージに機械可読な構造を持たせるための軽量な規約です。仕様はconventionalcommits.org の v1.0.0で公開されており、ライセンスはCC BY 3.0です。読み方は「コンベンショナル・コミッツ」または「コンベンショナル・コミット」で、Conventionalは「慣例に従った」という意味です。「カンバセーショナル」と読むのは誤りです。

仕様が目的として挙げているのは、CHANGELOGの自動生成、コミットのtypeに基づくバージョン番号の自動決定、変更内容を利用者に伝えること、ビルドや公開処理の起動などです。つまり人間が読みやすいことより、履歴を後段のツールの入力にできることに価値があります。コミットそのものの仕組みや1コミットの粒度の決め方はコミットとは?Gitが変更履歴を記録する仕組みと粒度・メッセージ設計で扱っています。

コミットメッセージの形式:ヘッダー・本文・フッター

メッセージは1行目のヘッダー(必須)、空行を挟んだ本文(任意)、さらに空行を挟んだフッター(任意)で構成します。

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

ヘッダー:type・scope・descriptionの書き方

typeの直後に、任意のscopeを丸括弧で付け、コロンと半角スペースを挟んで説明文を書きます。仕様はscopeを「コードベースの区画を表す名詞」と定めています。

feat(parser): add ability to parse arrays
fix: array parsing issue when multiple spaces were contained in string
docs: correct spelling of CHANGELOG

コロンの後のスペースは必須で、feat:add のように詰めると規約外になります。説明文の長さや言語は仕様では決まっていません。後述するcommitlintの既定ルールでは、ヘッダー全体の上限が100文字で、説明文の末尾のピリオドと先頭の大文字はエラーになります。

本文とフッター:トークンの規則とIssue参照

本文には変更の理由を自由に書けます。フッターは本文の後に空行を1行挟み、トークン: 値 または トークン #値 の形で並べます。トークン内の空白は、例外の BREAKING CHANGE を除き、Reviewed-by のようにハイフンに置き換えます。これはGitのtrailerの書き方にならったもので、複数段落の本文とフッターを機械が区別するための規則です。

fix: prevent racing of requests

Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Reviewed-by: Z
Refs: #123

Refs: #123 はIssueとの関連付けに使う慣習です。GitHubでは、コミットメッセージに Closes #123 を含むコミットをデフォルトブランチへマージするとIssueが閉じますが、これはGitHub側の機能で、Conventional Commitsの仕様とは別物です。

破壊的変更の書き方:!とBREAKING CHANGE

後方互換性を壊す変更は、typeまたはscopeの直後に ! を付けるか、フッターに BREAKING CHANGE: を書いて示します。! を付けた場合はフッターを省略でき、その場合は説明文で何が壊れるかを伝えます。

feat(api)!: send an email to the customer when a product is shipped

feat: allow provided config object to extend other configs

BREAKING CHANGE: `extends` key in config file is now used for extending other config files

仕様の細則で見落とされやすいのは次の2点です。

  • 大文字小文字:実装はtypeなどの要素の大文字小文字を区別してはならない(MUST NOT)。例外は BREAKING CHANGE で、フッターでは大文字で書く。
  • ハイフン版:フッターのトークンとしては BREAKING-CHANGE も BREAKING CHANGE と同じ意味に解釈しなければならない(MUST)。

ただし、主要なツールはこの2点を仕様どおりには扱いません。具体的な挙動は後半の「semantic-releaseのpreset」の章で示します。

type一覧:仕様が決めるのはfeatとfixだけ

仕様(v1.0.0)が意味を定めているtypeは feat と fix だけです。その他のtypeは仕様で禁止されておらず、@commitlint/config-conventional がAngularの規約をもとに11種類を許可リスト(type-enum)にしています。なおAngular本家のガイドラインが挙げるtypeはbuild・ci・docs・feat・fix・perf・refactor・testの8種類で、chore・style・revertは含みません。この記事では、@commitlint/config-conventionalの既定設定で許可される11種類を紹介します。

type 対象の変更 semantic-release既定のリリース
feat 新機能の追加 minor
fix バグ修正 patch
perf 性能の改善 patch
revert 過去のコミットの取り消し revertとして解析された場合はpatch
refactor 機能もバグも変えない内部の書き換え なし
docs ドキュメントだけの変更 なし
style 空白・整形など意味を変えない変更 なし
test テストの追加・修正 なし
build ビルドの仕組み・依存関係 なし
ci CIの設定・スクリプト なし
chore 上記に当てはまらない雑務 なし

右列は@semantic-release/commit-analyzerの既定ルールによる扱いです。仕様はperfやrevertのバージョンへの影響を定めていません。既定ルールではperfと、パーサーがrevertとして認識したコミットがpatchの対象です。どのtypeでも、パーサーが破壊的変更として認識すればmajorになります。

迷いやすいtypeの切り分け

判断がぶれるのは、利用者から見た動作が変わるかどうかの境界です。次の基準で分けると、チーム内の表記ゆれが減ります。

  • fixとrefactor:誤った動作を正したならfix。動作が同じで書き方だけ変えたならrefactor。
  • styleとrefactor:フォーマッタを当てただけならstyle。変数名の変更や関数の分割はrefactor。
  • buildとchore:依存パッケージの更新やバンドラ設定はbuild。.gitignore の修正などどれにも当たらないものはchore。
  • ciとbuild:GitHub Actionsのワークフローファイルの変更はci。
fix(cart): prevent negative quantity on update
refactor(cart): extract price calculation into a helper
build(deps): update eslint and prettier
ci: cache npm dependencies in test workflow

1つの変更が2つのtypeにまたがる場合、仕様のFAQは「可能な限りコミットを分割する」ことを勧めています。

scopeの決め方とrevertの書き方

scopeは任意です。モジュール名やパッケージ名を入れておくと、CHANGELOGや git log --grep で範囲を絞り込めます。scopeの候補はチームで一覧にし、commitlintの scope-enum ルールで固定すると表記ゆれを防げます。モノレポではパッケージ名をscopeにするのが一般的です。

revertの扱いを仕様は定めていません。仕様のFAQは、revert typeを使い、取り消すコミットのSHAをフッターの Refs: で示す方法を勧めています。

revert: let us never again speak of the noodle incident

Refs: 676104e, a215868

この推奨形は、semantic-releaseではrevertとして扱われません。commit-analyzer 13.0.1で解析すると、angularとconventionalcommitsのどちらのpresetでも「リリースなし」でした。patchになったのは、本文に git revert が既定で書く This reverts commit <SHA>. の行を残したコミットです。取り消しをリリースに反映させたいなら、この行を消さずにコミットします。

SemVerとの対応:featはMINOR、fixはPATCH

Conventional CommitsはSemVer(MAJOR.MINOR.PATCH)と組み合わせる前提で設計されています。前回のリリース以降のコミットを走査し、最も大きい変更で次の版を決めます。

前回リリース以降のコミット 上がる桁 例
fixだけ PATCH 1.2.3 → 1.2.4
featを1件以上含む MINOR 1.2.3 → 1.3.0
破壊的変更を1件以上含む MAJOR 1.2.3 → 2.0.0

開発初期のコミットについて、仕様のFAQは「すでに製品をリリースしているかのように扱う」ことを勧めています。SemVerそのものの規則や、APIのバージョン設計との違いはバージョニングとは?セマンティック/APIバージョニングの意味と運用設計で詳しく説明しています。

1.0.0未満の期間の扱いはツールによって違います。release-please 17.11.2の標準設定では0.x系でもfeatはminorを上げ、bump-patch-for-minor-pre-major を true にするとpatchに抑えられます(manifest-releaserのドキュメント)。

commitlintとhuskyによるコミットメッセージの検査

口頭で共有した規約だけでは、形式違反を自動で検出できません。commitlintでメッセージを検査し、huskyでGitのcommit-msgフックに組み込むと、規約外のメッセージはコミットの時点で止まります。以下は2026年10月29日時点の正式版(@commitlint/cli 21.2.4、husky 9.1.7)で確認した手順です。コマンドはGit管理下のnpmプロジェクトで、macOSまたはLinuxのシェルから実行します。

commitlintのインストールと.mjs設定ファイルの作成

npmレジストリ上の@commitlint/cli 21.2.4は engines に node >=22.12.0 を指定しています。Node.js 20のCIはこの条件を満たさないので、先にNode.jsの版を確認します。

npm install --save-dev @commitlint/cli @commitlint/config-conventional husky
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.mjs

commitlintの公式手順は同じ内容を commitlint.config.js に書くよう案内しています。しかし npm init -y で作ったpackage.json(npm 11.17.0では "type": "commonjs" が入る)のままだと、コミット時に SyntaxError: Unexpected token 'export' で検査そのものが失敗しました。拡張子を .mjs にするか、package.jsonに "type": "module" を指定すれば読み込めます。

commit-msgフックの追加と動作確認

husky 9は husky init で .husky/ と prepare スクリプトを作ります。続けてcommit-msgフックにcommitlintの呼び出しを書きます。

npx husky init
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg

husky init は npm test を実行するpre-commitフックも作ります。npm init -y が作る既定のtestスクリプトは exit 1 で終わるため、テストを用意していないリポジトリではコミットが毎回失敗します。不要なら .husky/pre-commit を削除するか中身を書き換えます。設定後に規約外のメッセージでコミットすると、次のように止まります。

$ git commit -m "update stuff"
⧗   --- input ---
update stuff
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

✖   found 2 problems, 0 warnings
ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

husky - commit-msg script failed (code 1)

config-conventionalの既定ルールで落ちるメッセージ

@commitlint/config-conventionalは、type-enumのほかに header-max-length(100文字)、subject-case、subject-full-stop などをエラーに設定しています。手元で9通りのメッセージを検査した結果は次のとおりです。

メッセージ 結果 違反したルール
feat: add login 通過 –
feat: Add login エラー subject-case
feat(auth): ログイン機能を追加 通過 –
feat: ログイン機能を追加。 通過 –
feat!: drop v1 通過 –
Feat: add エラー type-case・type-enum
feature: add エラー type-enum
wip: tmp エラー type-enum
feat:add エラー type-empty・subject-empty

英語で書くチームが最初につまずくのは subject-case です。説明文を大文字で始めると落ちるので、add のように小文字の動詞で始めます。日本語の説明文は大文字小文字の判定を受けず、句点「。」も subject-full-stop(対象はピリオド)に引っかかりません。句点を付けるかどうかはチームで決めておきます。

CIによるPull Request内のコミット検査

フックは git commit --no-verify で飛ばせます。そのため、CIでも同じ検査を回します。commitlintのCI設定ガイドにあるGitHub Actionsの例は、Pull Requestの差分にあるコミットをまとめて検査します。

以下は、pull_request を起動条件にしたGitHub Actionsワークフローの、ジョブ内の steps に置く抜粋です。

- uses: actions/checkout@v4
  with:
    fetch-depth: 0
- uses: actions/setup-node@v4
  with:
    node-version: lts/*
- run: npm ci
- name: Validate PR commits with commitlint
  if: github.event_name == 'pull_request'
  run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose

fetch-depth: 0 を省くと、比較元のコミットが取得されず範囲を検査できません。ワークフローの書き方そのものはGitHub Actionsとは?できること・使い方と最初のワークフローを参照してください。

semantic-releaseのpreset:angularによるfeat!の解析制限

commitlintが通したメッセージでも、リリースツールが同じように読むとは限りません。semantic-releaseでコミットを解析する@semantic-release/commit-analyzerは、preset を指定しないと angular を使います。angularのパーサーはヘッダーを ^(\w*)(?:\((.*)\))?: (.*)$ で読むため、! を含むヘッダーはtypeとして解釈されません。

@semantic-release/commit-analyzer 13.0.1で、angular 9.4.0とconventionalcommits 10.4.1のpresetを切り替えた結果が次の表です。表中の「+」は空行を挟んだフッターの追加を表します。

コミット angular(既定) conventionalcommits
feat!: drop node 18 リリースなし major
feat(api)!: drop v1 リリースなし major
feat: x + BREAKING CHANGE: y major major
feat: x + BREAKING-CHANGE: y minor major
perf: speed patch patch
Feat: Upper リリースなし リリースなし

既定のままでは、feat!: で書いた破壊的変更がリリースされず、ハイフン版のフッターはminorで出てしまいます。先頭だけ大文字の Feat: はどちらのpresetでも無視されました。既定ルールには全大文字の FEAT(minor)と FIX(patch)だけが登録されているためで、仕様の「大文字小文字を区別してはならない」とは合っていません。! を使うなら、設定で conventionalcommits を明示します(presetのパッケージ conventional-changelog-conventionalcommits も devDependencies に入れます)。

以下をリポジトリ直下の .releaserc.json に保存します。

{
  "branches": ["main"],
  "plugins": [
    ["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }],
    ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }],
    "@semantic-release/npm",
    "@semantic-release/github"
  ]
}

大文字小文字の扱いはツールのルールに依存するため、この記事の運用ではcommitlintの type-case で小文字に統一します。commit-analyzerとrelease-notes-generatorのpresetをそろえないと、版は上がったのにリリースノートに破壊的変更が載らない、という食い違いが起きます。

リリース自動化ツールの選び方:semantic-release・release-please・commit-and-tag-version

Conventional Commitsの履歴から版とCHANGELOGを作るツールは、公開までを全自動にするか、人が確認してから出すかで選びます。

ツール 最新版(2026-10-29) 動き方 向く場面
semantic-release 25.0.9 CIで版決定・タグ・公開まで実行 npmライブラリの全自動公開
release-please 17.11.2(Action v5) リリース用PRを作り、マージ後にGitHub Releaseを作成 公開前に人が確認したい
commit-and-tag-version 13.3.0 手元のコマンドで版・タグ・CHANGELOG GitHub Actionsを使えない環境

semantic-release 25.0.9は node ^22.14.0 || >=24.10.0 を要求します。release-pleaseは feat!: や fix!: をmajorとして扱うとREADMEに明記しており、squashマージの利用を強く勧めています。以前よく使われたstandard-versionは、リポジトリのREADMEで非推奨と告知され、GitHub利用者にはrelease-please、それ以外にはフォークのcommit-and-tag-versionが案内されています。作ったタグとリリースノートをGitHub上でどう公開するかはGitHub Releasesの使い方にまとめています。

間違ったtypeを直す方法とsquashマージでの運用

仕様のFAQは、マージやリリースの前なら git rebase -i で履歴を書き換えて直すことを勧めています。直前のコミットだけなら git commit --amend で十分です。リリース後に見つけた場合の直し方は、使っているツール次第です。

仕様は、全員がこの規約でコミットする必要はないとも書いています。squashマージを使えば、マージする人が最後に1つのメッセージを整えればよいからです。GitHubでは、squashマージ時の既定のコミットメッセージを「Pull Requestのタイトル」にする設定があります(リポジトリ設定のPull Requests欄)。この設定にした場合、検査すべきなのは個々のコミットではなくPull Requestのタイトルです。タイトルの検査にはamannn/action-semantic-pull-request(v6.1.1)などのActionを使います。squashマージの仕組みはgit squashとは?、Pull Requestのマージ方式の選び方はGitHubのPull Requestの作り方で説明しています。

形式を覚えきれないメンバーがいる場合は、commitizen(4.3.2)を使うと、typeやscopeを選択肢から選んでメッセージを組み立てられます。公式READMEの手順は、CLIを入れたあとリポジトリでアダプターを設定し、git cz でコミットする流れです。

npm install -g commitizen
commitizen init cz-conventional-changelog --save-dev --save-exact
git cz

導入を見送るべき場面と失敗パターン

この記事では、リリース自動化やCHANGELOG生成を導入判断の軸にします。履歴を人が読みやすくする用途もありますが、その目的だけなら、まず短く具体的な説明文を優先する方針です。

  • リリース自動化もCHANGELOG生成もしない個人開発:導入しない。git log を人が読むだけなら、短く具体的な説明文で足りる。
  • commitlintを入れず口頭のルールで始める:規約外のコミットはツールに無視され、CHANGELOGから黙って漏れる。導入するならフックとCIの検査を同じ日に入れる。
  • semantic-releaseのpresetを既定のまま ! を使う:破壊的変更がリリースされない。前章のとおり conventionalcommits を明示する。
  • typeを自由に増やす:update や wip を足すと境界が曖昧になる。追加はtype-enumに登録し、リリースへの影響を決めてからにする。

複数人でライブラリを保守し、定期的にリリースするプロジェクトでは、版の判断とリリースノート作成の手作業がなくなるので導入する価値があります。ブランチ戦略や命名規則まで含めたチームのGit運用はGit運用のベストプラクティス、CI/CDの構築まで任せたい場合はDevOps・CI/CD導入支援も参考にしてください。

よくある質問

Conventional Commitsの形式とは何ですか?

1行目を type(scope): description で書く形式です。必須はtypeとコロン+半角スペースと説明文で、scope、空行の後の本文、フッターは任意です。

typeはfeatとfix以外に何がありますか?

@commitlint/config-conventionalが許可するbuild・chore・ci・docs・perf・refactor・revert・style・testが広く使われています。仕様が用途を定めているtypeはfeatとfixだけです。そのほかのtypeも、破壊的変更を示す場合はMAJORに対応します。

コミットメッセージは日本語で書いてもよいですか?

説明文と本文は日本語で書けます。typeは feat などの英単語のまま残します。commitlintの既定ルールでも日本語の説明文は通ります。

typeは大文字で書いてもよいですか?

仕様上は大文字小文字を区別しない決まりですが、commitlintの既定ルールはエラーにします。semantic-releaseの既定ルールも Feat: のような先頭だけ大文字のtypeは解析しません。小文字で統一してください。

破壊的変更はどう書けばよいですか?

feat!: のようにtypeの直後に ! を付けるか、フッターに BREAKING CHANGE: 内容 を書きます。semantic-releaseで ! を使う場合は、presetを conventionalcommits にしておく必要があります。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.11.06 テックブログ ドコモ不正アクセス:最大29.5万件の流出項目と見舞金、My docomo停止の経過と偽連絡の見分け方
  2. 2026.11.03 テックブログ ネットマイル不正アクセスで最大549万人:対象確認と退会会員データを消す実装
  3. 2026.11.06 テックブログ あいおいニッセイ同和の不正アクセス:44.4万件の漏えい項目と窓口、止まった手続きの代わり
  4. 2026.11.07 コラム サイバーセキュリティ緊急対策パッケージとは?4本柱の施策と期限、企業と委託先が今やること
  5. 2026.07.09 テックブログ Muse Imageとは?Metaの画像生成AIの使い方・API料金(1枚0.01ドル)と日本での提供状況【2026年10月】

RELATED POSTS 関連記事

目次