git-conventional-commits: version, changelog and commit validation from one CLI
Git Conventional Commits Util to generate Semantic Version and Markdown Change Log and Validate Commit Messag
At a glance
- What is it?
- git-conventional-commits is a JavaScript command line tool that reads a repository's commit history, derives the next semantic version, writes a Markdown changelog and rejects commit messages that do not follow the convention, all driven by one YAML config file. It suits teams that already write conventional commits and want the release chores automated rather than taught.
- Who is it for?
- git-conventional-commits is a good fit for a team that has already adopted conventional commits and now spends release time assembling changelogs and bumping versions by hand, since the config file makes the rules explicit and the commit-msg hook makes them self-enforcing.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 14 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the tool does: four commands and no daemon
git-conventional-commits is a command line utility for the Conventional Commits convention, and the whole interface is one command with four subcommands:
init [options] create a config file template `git-conventional-commits.yaml`
version [options] determine version from conventional commits
changelog [options] generate changelog from conventional commits
commit-msg-hook [options] <commit-msg-file> check for conventional commit message formatEach of those does one job, and the mapping onto release work is direct. init writes a configuration file, version reads the commit history and tells you the next semantic version, changelog turns that history into Markdown, and commit-msg-hook is the piece that runs inside a git hook to reject a malformed message before the commit is created.
The README notes that the help flag -h can be added to any command to list all possible options, which is a small sign of a tool that expects to be run from a script as often as by hand.
What the tool does not do is teach the convention. It does not rewrite messages, it does not squash or rebase history, and it does not publish anything. The README's companion document for that job is the Git Conventional Commits Cheat Sheet, a separate gist linked from the top of the readme. The division is sensible: the convention is a human practice, and the tool mechanises the parts a machine can check.
The package is plain Node. The manifest names git-conventional-commits at version 2.9.0, with the entry point cli.js and a bin mapping so that npx finds it, and its only two runtime dependencies are yaml for the config file and yargs for the argument parsing. Tests run with jest, and the published files are the CLI, the lib directory, a default configuration file and a commit-msg.sh script.
First run: init writes the configuration you then edit
The README's first use section is two steps. Run npx git-conventional-commits init, then adjust the config file git-conventional-commits.yaml to your needs.
That generated file is the specification of the tool, and the repository ships two of them, git-conventional-commits.yaml and git-conventional-commits.default.yaml, so you can see the defaults the tool ships with next to the file in your own repository.
The configuration has two top-level sections, convention and changelog, and the convention section is where you describe what a valid commit message looks like:
---
convention:
# commitMessageRegexPattern: ^(?<type>\w+)(?:\((?<scope>[^()]+)\))?(?<breaking>!)?:\s*(?<description>.+)
commitTypes:
- feat # Commits that add, adjust or remove a feature to/of/from the API or UI
- fix # Commits that fix a bug of a preceded `feat` commit
- refactor # Commits that rewrite/restructure your code, however do not change any behaviour
- perf # Commits that are special `refactor` commits or that improve performance
- style # Commits that do not affect the meaning (white-space, formatting, missing semicolons, etc.)
- test # Commits that add missing tests or correcting existing tests
- build # Commits that affect build components like build tool, ci pipeline, dependencies, project version, etc.
- ops # Commits that affect operational components like infrastructure, deployment, backup, recovery, etc.
- docs # Commits that affect documentation only
- chore # Miscellaneous commits e.g. modifying `.gitignore`
- merge
commitScopes: []
releaseTagGlobPattern: v[0-9]*.[0-9]*.[0-9]*The comments are the documentation. Each commit type carries a sentence explaining when to use it, and the wording encodes the relationship between them, such as fix being described as a bug fix of a preceding feat commit and perf as a special case of refactor. That is the kind of detail teams argue about, and putting it in the config file means the argument has one answer that everyone sees at commit time.
Two defaults matter more than the rest. featureCommitTypes defaults to feat, and that list is what decides which commits count as features for versioning purposes. releaseTagGlobPattern defaults to v[0-9]*.[0-9]*.[0-9]*, the glob that filters release tags, with the requirement that release tags must contain a semantic version.
The convention block: what is validated and what is only a warning
The validation rules are documented one option at a time, and the distinction between a hard failure and a warning is the thing to read carefully.
commitTypes is an array of expected commit types, and it shows warnings for unexpected types. If it is not set or is empty, commit type validation is disabled. The same shape applies to commitScopes: an array of expected scopes, warnings for unexpected ones, and validation disabled when the list is empty. So the tool will not block a commit with an unknown type unless you have listed the expected types, and it warns rather than fails by default.
commitMessageRegexPattern is the escape hatch for teams that do not write the canonical format. The default pattern for the Conventional Commit format is given in full, and the README explains how to use it: you need to prepend or append your custom parts to this pattern if you still want to keep following the Conventional Commit format. That is a useful framing, because it tells you the custom pattern replaces the default rather than extends it.
The default pattern itself is worth reading as a description of the format:
^(?<type>\w+)(?:\((?<scope>[^()]+)\))?(?<breaking>!)?:\s*(?<description>.+)The named groups are type, an optional scope in parentheses, an optional breaking marker, a colon, whitespace and the description. Everything the tool does downstream, version bumps, changelog sections, breaking change detection, depends on this pattern extracting those groups, so a change here is a change to how everything else behaves.
The repository's own directory listing shows the supporting pieces: a pre-commit hooks definition in .pre-commit-hooks.yaml, a commit-msg.sh script, and a test directory, which is where the behaviour of these rules is pinned down.
The changelog block: filtering, headlines and link templates
The changelog section is a filter and a renderer, and its options are more numerous than the convention ones because it has to answer two separate questions: which commits belong in the changelog, and what should the output look like.
commitTypes filters commits by type and is documented as a subset of convention.commitTypes plus merge commits, and if it is not set or empty the filter is disabled. commitScopes filters by scope in the same way. includeInvalidCommits includes commits without a valid type and defaults to true, and setting it to false removes all commits with undefined commit types from the changelog. commitIgnoreRegexPattern filters by commit subject and defaults to ^WIP , which is what keeps work-in-progress commits out of a release note.
headlines is the map from identifier to heading, and it is a subset of changelog.commitTypes plus a breakingChange section. The default mapping is feat to Features, fix to Bug Fixes, merge to Merges and breakingChange to BREAKING CHANGES, and a changelog.commitTypes entry with no matching headline simply gets no section of its own.
Links are template strings. commitUrl is a URL template for Markdown links to repository commits with a %commit% placeholder, and commitRangeUrl does the same for a comparison range with %from% and %to%. issueRegexPattern is the pattern used to find issue identifiers, with the example being a Jira pattern, and issueUrl is the template with an %issue% placeholder. If commitUrl or issueUrl is not set or empty, link generation is disabled, which is what you want if the repository is not publicly reachable.
The combined effect is a changelog that is a function of the config file rather than of code, which is the point of the whole design: the release notes change when the YAML changes.
Enforcing the convention with a commit-msg hook
Validation only works if it happens at the moment of the commit, and the README gives two ways to arrange that.
The first is the pre-commit framework, with a .pre-commit-config.yaml in the repository root:
repos:
- repo: https://github.com/qoomon/git-conventional-commits
rev: <RELEASE_TAG>
hooks:
- id: conventional-commitsYou then install the framework with pip install pre-commit and install the hook with pre-commit install -t commit-msg. Pinning rev to a release tag is what keeps the check consistent across a team, since the hook runs on every developer's machine.
The second is the manual route. You navigate to the repository directory, create a hook directory with mkdir .git-hooks, point git at it with git config core.hooksPath .git-hooks, and create the hook script and make it executable with touch .git-hooks/commit-msg and chmod +x .git-hooks/commit-msg. The script content is short:
#!/bin/sh
# fix for windows systems
PATH="/c/Program Files/nodejs:$HOME/AppData/Roaming/npm/:$PATH"
npx git-conventional-commits commit-msg-hook "$1"The PATH line exists because the hook runs in a shell that does not inherit a normal interactive environment, which is the classic cause of a hook that works on one machine and fails on another. The README then says to add and commit the .git-hooks/commit-msg file to the repository, which is the important detail of the manual route: the hook travels with the repository instead of living in each developer's home directory.
Note that the commit-msg hook receives the path to the message file as its argument, which is what the commit-msg-hook command expects, and that the hook runs after the editor closes, so it validates what the developer actually wrote.
Maintenance, licence and where this tool is the wrong choice
The project is by qoomon, licensed under GPL-3.0, with the package manifest declaring the licence as GPLv3 and the repository shipping a LICENSE file. The default branch is master, the last push to the repository was on 2026-10-09, and the repository is not archived. The published releases are 2.9.0 from 2026-04-14, 2.7.2 from 2025-02-10 and 2.6.7 from 2024-01-02, so the project ships on its own schedule with the semver-like numbering of the tool itself.
The first wrong case is a repository whose history does not already follow the convention. The version and changelog commands work from the commit log, so if the history predates the convention the output will be thin or wrong, and the tool has no rewriting or fixing mode. A team that wants to start using the convention has to adopt the practice first and let the history accumulate.
The second wrong case is a team that wants more than the four commands. There is no publishing, no tag creation, no release notes beyond the Markdown changelog, and no integration with a package registry.
The third wrong case is a monorepo with per-package versioning, since the configuration describes one convention and one changelog per repository.
The realistic alternative is the tooling that already surrounds most Conventional Commits teams, such as a release script built on standard-version or a CI job that runs a changelog generator. The difference in approach is that this tool is configuration-driven rather than code-driven: the commit types, the scope list, the headings, the ignore patterns and the link templates live in a YAML file that the same tool reads for validation, versioning and changelog generation, so the three stay consistent by construction rather than by convention.
Editorial conclusion
git-conventional-commits is a good fit for a team that has already adopted conventional commits and now spends release time assembling changelogs and bumping versions by hand, since the config file makes the rules explicit and the commit-msg hook makes them self-enforcing. It is not a teaching tool for the convention, and it is not a fit for a repository whose history is already written in a different style, because the version and changelog commands work from what is in the log. Verify first that your existing commit messages parse against the default message regex, that your release tags match the configured releaseTagGlobPattern, and that the hooks path you set in the repository is one your team actually clones, since the manual setup stores the hook script in the repository rather than in each developer's home directory.
Frequently asked questions
How do I run git-conventional-commits?
Through npx with the package name, for example npx git-conventional-commits init. The tool has four commands: init to create a git-conventional-commits.yaml template, version to determine the version from the conventional commits, changelog to generate the changelog, and commit-msg-hook to check a commit message file. The -h flag lists the options of any command.
How do I enforce the commit message convention automatically?
Install the commit-msg hook. With the pre-commit framework you add a .pre-commit-config.yaml entry pointing at the repository with a pinned rev and the conventional-commits hook id, then run pre-commit install -t commit-msg. Manually, you create a .git-hooks directory, set git config core.hooksPath .git-hooks, and put a script that runs npx git-conventional-commits commit-msg-hook "$1" into .git-hooks/commit-msg, then commit that script to the repository.
Can I use a different commit message format?
Yes, through the commitMessageRegexPattern option. The README gives the default Conventional Commit pattern and explains that you prepend or append your custom parts to it if you want to keep following the Conventional Commit format.
How do I keep work-in-progress commits out of the changelog?
The changelog option commitIgnoreRegexPattern filters commits by their subject, and its default is the pattern ^WIP , which is what excludes work-in-progress commits by default.
What happens when a commit uses a type that is not configured?
The tool shows a warning for unexpected types, and commit type validation is disabled entirely if commitTypes is not set or is empty. On the changelog side, includeInvalidCommits defaults to true, and setting it to false removes all commits with undefined commit types from the changelog.
Under which licence is git-conventional-commits released?
GPL-3.0. The package manifest records the licence as GPLv3 and the repository ships a LICENSE file. The latest published version is 2.9.0, released on 2026-04-14.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/qoomon-git-conventional-commits)Was this useful?