A fast git commit message linter written in Rust. Validates commit messages against best practices and provides actionable suggestions.
pip install mixed-picklesOr with uv:
uv pip install mixed-picklescargo install mixed-picklesOr build from source:
git clone https://github.com/rommeld/mixed-pickles.git
cd mixed-pickles
cargo build --release| Validation | Default Severity | Description |
|---|---|---|
WipCommit |
Error | WIP markers, fixup!, squash! |
ShortCommit |
Warning | Messages below threshold (default: 30 chars) |
NonImperative |
Warning | Non-imperative mood ("Added" vs "Add") |
VagueLanguage |
Warning | Generic phrases ("fix bug", "update code") |
MissingReference |
Info | No issue reference (#123, PROJ-456) |
InvalidFormat |
Info | Not following conventional commits |
# Analyze all commits in current repo
mixed-pickles
# Analyze last 10 commits
mixed-pickles --limit 10
# Analyze specific repo
mixed-pickles --path /path/to/repo
# Strict mode (warnings become errors)
mixed-pickles --strict
# Customize severity
mixed-pickles --error short,vague --ignore ref
# Quiet mode (output only on issues)
mixed-pickles --quiet
# Run only on specific branches (supports glob patterns)
mixed-pickles --branch main --branch develop
mixed-pickles --branch "feature/*" --branch "release/**"import mixed_pickles
# Basic analysis - auto-loads pyproject.toml config
mixed_pickles.analyze_commits()
# Analyze with options
mixed_pickles.analyze_commits(
path=".", # Repository path
limit=10, # Number of commits
quiet=True, # Suppress output unless issues
strict=True # Treat warnings as errors
)
# Disable auto-loading of config file
mixed_pickles.analyze_commits(use_config=False)
# Load config from pyproject.toml or .mixed-pickles.toml
config = mixed_pickles.ValidationConfig.discover()
config = mixed_pickles.ValidationConfig.discover("/path/to/project")
# Load config from specific file
config = mixed_pickles.ValidationConfig.from_file("pyproject.toml")
config = mixed_pickles.ValidationConfig.from_file(".mixed-pickles.toml")
# Manual configuration
config = mixed_pickles.ValidationConfig(
threshold=50, # Minimum message length
require_issue_ref=False, # Disable issue reference check
require_conventional_format=False,
check_vague_language=True,
check_wip=True,
check_imperative=True,
branches=["main", "develop"] # Only validate on these branches
)
mixed_pickles.analyze_commits(config=config)
# Branch filtering with glob patterns
config = mixed_pickles.ValidationConfig(
branches=["main", "release/*", "hotfix/**"]
)
mixed_pickles.analyze_commits(config=config)
# Adjust severity levels
config = mixed_pickles.ValidationConfig()
config.set_severity(
mixed_pickles.Validation.MissingReference,
mixed_pickles.Severity.Error
)
config.set_severity(
mixed_pickles.Validation.ShortCommit,
mixed_pickles.Severity.Ignore
)
mixed_pickles.analyze_commits(config=config)
# Fetch commits for custom processing
commits = mixed_pickles.fetch_commits(limit=5)
for commit in commits:
print(f"{commit.short_hash}: {commit.message}")Add to your .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: mixed-pickles
name: Validate commit messages
entry: mixed-pickles
language: python
additional_dependencies: [mixed-pickles]
always_run: true
pass_filenames: false
stages: [pre-push]With uv, you can also run it directly:
repos:
- repo: local
hooks:
- id: mixed-pickles
name: Validate commit messages
entry: uv run mixed-pickles
language: system
always_run: true
pass_filenames: false
stages: [pre-push]Add to your workflow (.github/workflows/lint-commits.yml):
name: Lint Commits
on:
pull_request:
branches: [main, develop]
jobs:
lint-commits:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for commit analysis
- run: pip install mixed-pickles
- run: mixed-pickles --strict --quietAdd to your .gitlab-ci.yml:
lint-commits:
stage: lint
image: python:3.12
before_script:
- pip install mixed-pickles
script:
- mixed-pickles --strict --quiet
rules:
- if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"
- if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"| Option | Description |
|---|---|
--path <PATH> |
Repository path (default: current directory) |
--limit <N> |
Max commits to analyze |
--threshold <N> |
Minimum message length (default: 30) |
--branch <PATTERN> |
Only validate on matching branches (repeatable, supports globs) |
--quiet, -q |
Suppress output unless issues found |
--strict |
Treat warnings as errors |
--error <LIST> |
Validations to treat as errors |
--warn <LIST> |
Validations to treat as warnings |
--ignore <LIST> |
Validations to skip reporting |
--disable <LIST> |
Validations to disable entirely |
--config <PATH> |
Path to configuration file |
--no-config |
Ignore configuration file |
Validation aliases for CLI: short, ref, format, vague, wip, imperative
Configure mixed-pickles via pyproject.toml for project-specific settings:
[tool.mixed-pickles]
# Minimum commit message length (default: 30)
threshold = 50
# Only validate on specific branches (supports glob patterns)
# Empty = validate on all branches (default)
branch = ["main", "develop", "release/*"]
# Disable specific validations entirely
disable = ["reference", "format"]
# Override severity levels
[tool.mixed-pickles.severity]
wip = "error" # Block on WIP commits (default)
short = "warning" # Warn but allow (default)
vague = "ignore" # Don't report
reference = "info" # Informational only (default)Or use a dedicated .mixed-pickles.toml file (takes precedence over pyproject.toml):
threshold = 50
branch = ["main", "develop"]
disable = ["format"]
[severity]
short = "error"Settings are applied in this order (later overrides earlier):
- Defaults - Built-in default values
- Config file -
pyproject.tomlor.mixed-pickles.toml - CLI arguments - Command-line flags
| Name | Aliases | Default | Description |
|---|---|---|---|
short |
short-commit |
warning | Message below threshold |
wip |
wip-commit |
error | WIP/fixup/squash markers |
reference |
ref, missing-reference |
info | Missing issue reference |
format |
invalid-format |
info | Not conventional commits |
vague |
vague-language |
warning | Generic descriptions |
imperative |
non-imperative |
warning | Past/continuous tense |
- Error: Fails the check (exit code 1)
- Warning: Reported but passes (fails with
--strict) - Info: Informational only
- Ignore: Tracked but not reported
Run validations only on specific branches. Useful for CI/CD pipelines where you want strict rules on main/develop but flexibility on feature branches.
| Pattern | Matches | Does Not Match |
|---|---|---|
main |
main |
main-v2, feature/main |
feature/* |
feature/login, feature/auth |
feature/user/profile |
release/** |
release/v1, release/v1/hotfix |
releases/v1 |
*-stable |
v1-stable, prod-stable |
stable, v1-stable-2 |
release-? |
release-1, release-2 |
release-10 |
- Empty
branch: Validates on all branches (default) - Detached HEAD: Validation is skipped
- Non-matching branch: Validation is skipped (exits successfully)
See CONTRIBUTING.md for contribution guidelines.