Skip to main content

commitfmt logo

Utility for formatting and verifying commit messages.


Quality Assurance NPM Version PyPI Version

It's not a linter. At least not a complete replacement for commitlint, because commitfmt can't prevent you from writing a body or force you to write a description in uppercase (I don't know why you might want to do that), but it will help keep git history clean and readable.

By design, commitfmt runs on the prepare-commit-msg hook and formats the message according to git standards and conventional commits in particular.

Features

Formatting

commitfmt by default transforms a message like this:

feat ( scope     ,    scope  )  : add new feature.
body description

into well-formatted message:

feat(scope, scope): add new feature

body description

Linting

commitfmt can check that developers follow the rules set by the project.

For example, check that only allowed types and scopes are used. To do this, add the following to the configuration file:

[lint.header]
# Check allowed commit type
type-enum = ["chore", "ci", "feat", "fix", "refactor", "style", "test"]
# Check allowed commit scopes
scope-enum = ["cc", "config", "git", "linter"]

[lint.footer]
# Check required footers
exists = ["Issue-ID", "Authored-By"]

Performance

commitfmt is very fast because its code is written in Rust with memory consumption and performance in mind. It's about 18x faster than commitlint.

It natively supports following platforms:

OS Architecture
macOS x86_64, arm64
Windows x86_64, i686
Linux x86_64, i686, arm64

Installation

Script

You can use a simple script to install commitfmt. It will download the latest version of the binary and install it to the system.

# Install latest version
curl -sSfL https://raw.githubusercontent.com/mishamyrt/commitfmt/refs/heads/main/scripts/install.sh | bash

pnpm

pnpm add --save-dev commitfmt

npm

npm install --save-dev commitfmt

yarn

yarn add --dev commitfmt

pip

pip install commitfmt

Hook

After installing the package, you need to add a hook to the prepare-commit-msg event. You can use any hook manager.

Important: if you are using a pnpm, yarn or any other package manager, you need to run pnpm commitfmt, yarn commitfmt, etc. instead of commitfmt.

Script

You can use a simple script to add a hook.

echo "#!/bin/sh" > .git/hooks/prepare-commit-msg
echo "commitfmt" >> .git/hooks/prepare-commit-msg
chmod +x .git/hooks/prepare-commit-msg

Lefthook

Add to your lefthook.yml file:

prepare-commit-msg:
  - name: format commit message
    run: commitfmt

Husky

Add to your .husky folder prepare-commit-msg file with the following content:

#!/bin/sh
commitfmt

Configuration

In commitfmt, you cannot customize basic formatting rules such as extra spaces removal.

It is an opinionated formatter and the author has established best practices that should not harm anyone.

Linting

Most of the linting rules are disabled by default. Default config contains 2 rules as they can be safely auto-fixed:

[lint.header]
description-full-stop = true

[lint.footer]
breaking-exclamation = true

To enable more rules, create a commitfmt.toml or (.commitfmt.toml) file in the root of your project. Available lint rules can be found in the rules.md file.

If there is a problem with an enabled rule and it cannot be automatically fixed, the commit process will be aborted.

Unsafe fixes

Some rules may be fixed, but in certain contexts this fix may not be what is desired. For example, adding a full stop to the end of body will be useful in most cases, if there is a log at the end of the message, the period may distort it. You can see which rules have unsafe patches in the same rules.md file mentioned above.

To enable unsafe fixes, add the following to your config file:

[lint]
unsafe-fixes = true

Extending

You can extend the configuration of the parent project by adding the extends key to your config file:

extends = "node_modules/commitfmt-config-standard/commitfmt.toml"

Extension is only possible for the current configuration. If the current configuration extends another configuration, which in turn extends a third configuration, commitfmt will throw an error when trying to load such a configuration.

Parser Configuration

commitfmt can be configured to use custom footer separators and comment symbols for parsing commit messages.

Footer separators

By default, commitfmt uses git's trailer.separators configuration to determine which characters separate footer keys from values. You can override this in your config file:

footer-separators = ":#"

This allows footers like Issue-ID: 123 or Issue-ID #123 to be recognized.

Comment symbol

By default, commitfmt uses git's core.commentChar or core.commentString configuration to identify comment lines in commit messages. You can override this:

comment-symbol = "//"

Lines starting with the comment symbol will be ignored during parsing.

Additional footers

commitfmt can add additional footers to the commit message.

Static value

You can add a footer with a static value:

[[additional-footers]]
key = "Authored-By"
value = "John Doe"

Shell commands

You can use shell commands to dynamically generate footer values:

[[additional-footers]]
key = "Authored-By"
value = "{{ echo $USER }}"

Inside the template expression you can use any shell command available in the PATH.

Branch value pattern

You can also add the ticket number from the task tracker to the footer if it is in the branch name:

[[additional-footers]]
key = "Ticket-ID"
branch-pattern = "(?:.*)/(?<TICKET_ID>[A-Z0-9-]+)/?(?:.*)"
value = "${{ TICKET_ID }}"

For example, if your branch name is feature/CC-123/add-new-feature or feature/CC-123, the Ticket-ID footer will be added to the commit message with the value CC-123.

If the ticket number is not found in the branch name, footer will be skipped.

You can use rustexp to test your pattern.

Patterns

Examples of patterns for branch names in git flow format:

  • Jira/YouTrack: (?:.*)/(?<TICKET_ID>[A-Z0-9-]+)/?(?:.*)
    • feature/CFMT-123
    • feature/CFMT-123/add-new-feature
  • GitHub: (?:.*)/(?<ISSUE_ID>[0-9-]+)/?(?:.*)
    • feature/123
    • feature/123/add-new-feature

On conflict

If the footer already exists in the commit message, you can specify what to do with it. By default, the footer will be skipped.

[[additional-footers]]
key = "Ticket-ID"
branch-pattern = "(?:.*)/(?<TICKET_ID>[A-Z0-9-]+)/?(?:.*)"
value = "${{ TICKET_ID }}"
on-conflict = "error" # optional. default: skip. available: skip, append, error

Available options:

  • skip - skip the footer if it already exists
  • append - append the footer to the end of the footer list
  • error - abort the commit

Footer formatting

You can customize how footers are formatted using separator and alignment options:

[[additional-footers]]
key = "Ticket-ID"
value = "CFMT-123"
separator = "#"
alignment = "right"

Available alignment options:

  • left - align separator to the left (default)
  • right - align separator to the right

Recipe

To enforce conventional commits, you can use the following configuration:

[lint.header]
type-enum = ["chore", "ci", "feat", "fix", "refactor", "style", "test", "docs", "revert"]
description-case = "lower-first"
description-max-length = 72
description-full-stop = true
type-required = true
# scope-enum = ["cc", "config", "git", "linter"] # optional

[lint.body]
max-line-length = 72
case = "upper-first"

[lint.footer]
breaking-exclamation = true

Testing

To test the configuration and the work of commitfmt, run the following command:

echo "chore ( test ) : test commit" | commitfmt
# or
cat commit_text.txt | commitfmt

History testing

To test the history of commits, run the following command:

commitfmt --from HEAD~20
# or
commitfmt --from 1234567890 --to 1234567890

Ignoring commits

commitfmt ignores commit messages that start with Merge or Revert to avoid breaking standard git processes.

This happens both when formatting a single commit and when linting a history.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

commitfmt_linux-1.1.0.tar.gz (5.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

commitfmt_linux-1.1.0-py3-none-any.whl (5.0 kB view details)

Uploaded Python 3

File details

Details for the file commitfmt_linux-1.1.0.tar.gz.

File metadata

  • Download URL: commitfmt_linux-1.1.0.tar.gz
  • Upload date:
  • Size: 5.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for commitfmt_linux-1.1.0.tar.gz
Algorithm Hash digest
SHA256 b2beaeec6c72035341b2896a297e5d6fa9fb1d8f55aa1eb52453bc778295f6b2
MD5 58910a988e301c3b64395e40996b34cf
BLAKE2b-256 1f3ad5749c8be799430439da1efdb16cec3642e8e4cc78cfce1a122861575398

See more details on using hashes here.

File details

Details for the file commitfmt_linux-1.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for commitfmt_linux-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6f867c19a11fca1cc712951684d082c840f226f63ae897e74c883a1e1272d005
MD5 2b193cd230a8d3bd1bd0bb87d2b0a554
BLAKE2b-256 31038607ff468626483d333e7466588c2b4d064d432e14459a8eeeb6270ec8a9

See more details on using hashes here.

Release history Release notifications | RSS feed

1.2.0

2 files

This release

1.1.0 This release

2 files

1.0.10

2 files

1.0.9

2 files

1.0.4

2 files

1.0.3

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

0.4.1

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.5

2 files

0.1.1

2 files

0.1.0

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page