Skip to content

rommeld/mixed-pickles

Repository files navigation

Mixed Pickles

A fast git commit message linter written in Rust. Validates commit messages against best practices and provides actionable suggestions.

Installation

Python (Recommended)

pip install mixed-pickles

Or with uv:

uv pip install mixed-pickles

Rust

cargo install mixed-pickles

Or build from source:

git clone https://github.com/rommeld/mixed-pickles.git
cd mixed-pickles
cargo build --release

What It Checks

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

Usage

CLI

# 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/**"

Python API

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}")

Pre-commit Hook

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]

CI/CD Integration

GitHub Actions

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 --quiet

GitLab CI

Add 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"

CLI Options

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

Configuration

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"

Configuration Precedence

Settings are applied in this order (later overrides earlier):

  1. Defaults - Built-in default values
  2. Config file - pyproject.toml or .mixed-pickles.toml
  3. CLI arguments - Command-line flags

Available Validations

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

Severity Levels

  • Error: Fails the check (exit code 1)
  • Warning: Reported but passes (fails with --strict)
  • Info: Informational only
  • Ignore: Tracked but not reported

Branch Filtering

Run validations only on specific branches. Useful for CI/CD pipelines where you want strict rules on main/develop but flexibility on feature branches.

Glob Patterns

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

Behavior

  • Empty branch: Validates on all branches (default)
  • Detached HEAD: Validation is skipped
  • Non-matching branch: Validation is skipped (exits successfully)

Contributing

See CONTRIBUTING.md for contribution guidelines.

About

Simple git linter written in Rust.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors