An interactive CLI for creating conventional commits, built on cocogitto and inspired by cz-cli.
GitHub Actions Workflow Status Codecov Crate Version Current Release Dependency Status License
- Create conventional commits with ease
- Use alongside cocogitto for automatic versioning, changelog generation, and more
- Use emoji 👋 (or, shortcodes)
- Autocomplete for commit scope
- Run as a git hook
- Custom commit types
Community-maintained
brew install koji
Community-maintained
yay -S git-koji-bin
Community-maintained
nix-shell -p koji
curl -sS https://webinstall.dev/koji | bashcargo install --locked koji
Be sure to have git installed first.
The basic way to use koji is as a replacement for git commit,
enforcing the conventional commit
standard by writing your commit through an interactive prompt.
# Do some work cd dev/koji git add README.md # Commit your work koji
See koji --help for more options.
Use koji completions <SHELL> to generate completion scripts for your shell.
An alternative way to use koji is as a git hook,
running it any time you run git commit.
Update .git/hooks/prepare-commit-msg with the following code:
#!/bin/bash exec < /dev/tty && koji --hook || true
npx husky add .husky/prepare-commit-msg "exec < /dev/tty && koji --hook || trueAdd the prepare-commit-msg hook type and the koji hook to .pre-commit-config.yaml:
default_install_hook_types: [prepare-commit-msg, ...] repos: - repo: local hooks: - id: prepare-msg name: prepare commit message entry: bash -c "exec < /dev/tty && koji --hook || true" language: system stages: [prepare-commit-msg]
Similar should work for any hook runner, just make sure you're using
it with the prepare-commit-msg hook.
When using it as a hook, any message passed to git commit -m will be used
for the commit summary. Writing your commit as a conventional commit,
e.g. git commit -m "feat(space): delete some stars", will bypass
koji altogether.
Config values are prioritized in the following order:
- Passed in as arguments (see:
koji --help) - Read from file passed in via
--config .koji.tomlin the working directory- Unix/Redox:
$XDG_CONFIG_HOME/koji/config.toml~/.config/koji/config.toml
- Windows:
%USERPROFILE%\AppData\Roaming\koji\config.toml
- The default config
- Type:
bool - Optional:
true - Description: Enables auto-complete for scope prompt via scanning commit history.
autocomplete = true
- Type:
bool - Optional:
true - Description: Enables breaking change prompt.
breaking_changes = true
- Type:
Vec<CommitType> - Optional:
true - Description: A list of commit types to use instead of the default.
[[commit_types]] name = "feat" emoji = "✨" description = "A new feature"
- Type:
bool - Optional:
true - Description: Prepend the commit summary with relevant emoji based on commit type.
emoji = true
- Type:
bool - Optional:
true - Description: Enables issue prompt, which will append a reference to an issue in the commit body.
issues = true
- Type:
bool - Optional:
true - Description: When
true, the scope prompt becomes a selection list restricted to the configuredcommit_scopes. If a single scope is auto-detected from staged changes it is pre-selected automatically.
force_config_scopes = true
- Type:
bool - Optional:
true - Description: When
false, a scope is required and cannot be left blank. Pressing<esc>without a detected scope will abort the commit. Defaults totrue.
allow_empty_scope = false
- Type:
Vec<CommitScope> - Optional:
true - Description: A list of named commit scopes. Each scope can carry a human-readable
description(For CLI use), pathpatternsfor automatic detection, and anast_greprule for content-based detection.
For automatically assigning scopes based on the context of the change
[[commit_scopes]] name = "core" description = "Changes to the core library" patterns = "/crates/core/**/*.rs" [[commit_scopes]] name = "build" patterns = ["^/build\\.rs$", "/justfile"] [[commit_scopes]] name = "test" description = "Test-only changes" patterns = "/tests/**" # In reference the above scope \/ (TOML is weird) [commit_scopes.ast_grep] language = "Rust" files = ["**/*.rs"] rule = { kind = "function_item", has = { stopBy = "end", pattern = "#[test]" } }
patterns -- one or more regex strings matched against staged file paths (prefixed with /).
ast_grep -- an ast-grep rule. When any staged file matches both the files filter and the structural rule, this scope is pre-assigned. Requires the ast-grep feature (included by default). As a warning: the rule is read from the staged blob only, so renamed and deleted paths are matched against their pre-change content.