A stupidly simple Conventional Commits message builder. You give it flags, it builds a properly formatted commit message and runs git commit for you. No more fat-fingering colons, parens, or forgetting the ! on a breaking change.
Find a file
2026-10-12 12:43:14 -05:00
.gitignore "test: updated testing to work, also added license + readme" 2026-06-18 09:59:58 -05:00
committy.py fix: spec-compliant breaking footer, real exit codes, python 3.8+ support 2026-10-12 12:43:03 -05:00
LICENSE "test: updated testing to work, also added license + readme" 2026-06-18 09:59:58 -05:00
README.md docs: document requirements, exit codes and tests, fix breaking-change examples 2026-10-12 12:43:14 -05:00
test_committy.py fix: spec-compliant breaking footer, real exit codes, python 3.8+ support 2026-10-12 12:43:03 -05:00

committy

A stupidly simple Conventional Commits message builder. You give it flags, it builds a properly formatted commit message and runs git commit for you. No more fat-fingering colons, parens, or forgetting the ! on a breaking change.

Why

Conventional Commits are great until you are typing them out by hand for the hundredth time and forget where the ! goes. committy builds the message from flags, so the format is never wrong, and breaking changes get the spec-compliant BREAKING CHANGE: footer that tools like commitlint and semantic-release look for.

Requirements

  • Python 3.8 or newer
  • git

There is nothing to pip install. It is a single file using only the standard library.

Install

git clone https://git.turngear.dev/josh/committy.git
cd committy
chmod +x committy.py
ln -s "$(pwd)/committy.py" ~/.local/bin/committy

Make sure ~/.local/bin is on your $PATH (echo $PATH to check; most modern Linux distros add it by default). Then use it from any repo like a normal command.

Usage

git add .
committy -t feat -s "new email system" -d "replace the old XYZ system" -b "not compatible with the previous email system"

That runs:

git commit -m 'feat(new email system)!: replace the old XYZ system' -m 'BREAKING CHANGE: not compatible with the previous email system'

which produces this commit message:

feat(new email system)!: replace the old XYZ system

BREAKING CHANGE: not compatible with the previous email system

Flags

Flag Long form Required Description
-t --type yes Commit type, one of the types listed below
-d --desc yes The commit description
-s --scope no Scope, rendered as type(scope):
-b --breaking no Adds ! to the type and a BREAKING CHANGE: footer
-p --preview no Dry run: prints the git command instead of running it

Commit types

ci, fix, docs, feat, perf, test, build, chore, style, revert, refactor

Preview before committing

Add -p to see the command without committing anything:

committy -t feat -d "testing this out" -p
git commit -m 'feat: testing this out'

Exit codes

committy is safe to use in scripts.

Code Meaning
0 Success (or a successful preview)
2 Invalid input, such as an unknown type or an empty description. The error goes to stderr
other Whatever git commit returned, for example 1 when nothing is staged

Format reference

<type>[(scope)][!]: <description>

[BREAKING CHANGE: <description>]
  • The ! and the BREAKING CHANGE: footer always appear together. Both are controlled by -b.
  • scope is optional and goes in parentheses right after the type.

Running the tests

python3 -m unittest

The suite covers message building, input validation, exit codes, and a real git commit inside a temporary repository.

License

MIT. See LICENSE.