Four unrelated changes, four clean commits.
Run pilot commit instead of git commit -m. It reads your staged diff, writes a Conventional Commits message, and when the diff mixes unrelated work, offers to split it into separate commits.
Split mode commits exactly what you staged.
Stage everything at once and CommitPilot plans one commit per piece of work, checks the plan, and makes the commits from your staged patch.
Plans are checked
Every staged file must appear in exactly one commit. A bad plan goes back to the model once with the errors; if it's still wrong, files are grouped by folder instead.
Patches, not `git add`
Each commit gets its files' slice of the staged patch through git apply --cached, so unstaged edits stay out, and renames, deletions and binaries survive.
Safe on failure
The staged patch is saved under .git/ first. If a commit fails (a hook, say), the commits not yet made are staged again.
What it looks like
A real run against Groq (openai/gpt-oss-120b) on a test repo with four unrelated changes staged together.
$ pilot commit --split
📋 Analyzing 5 staged files (+32 -3)...
🧭 Grouping the changes...
✂ Split into 4 commits:
1. ci: add GitHub Actions workflow for running tests
.github/workflows/test.yml
2. docs(readme): clarify rate limit description
README.md
3. feat(api): add limit parameter to items endpoint
api/app.py
4. feat(export): add CSV export helper
api/export.py, tests/test_export.py
[y] Commit all [e] Edit messages [n] Cancel > y
[main ed135ce] ci: add GitHub Actions workflow for running tests
[main 7fa6207] docs(readme): clarify rate limit description
[main 11b1c03] feat(api): add limit parameter to items endpoint
[main f4908e0] feat(export): add CSV export helperKey concepts & stack
Checked messages
A reply with a bad type, a header over 72 characters, a trailing period or a capitalised subject is sent back once with the problems listed.
Condensed diff
Lockfiles and binaries become one line, each file is capped at 2,500 characters, and past 20,000 only stats are sent.
Accept, edit, regenerate
y accepts, e opens your git editor, r asks again, s splits, n cancels. Nothing is committed until you say so.
Your repo's style
Recent commit subjects go into the prompt, and --style emoji writes ✨ api: add x instead of feat(api): add x.
Script-friendly
pilot message only prints a suggestion; --yes commits without asking and --dry-run only shows the plan.
Tested on real repos
Tests create temporary git repositories and use a fake chat model, so splitting is checked against real git behaviour.
Install and run
Needs Python 3.11+, git, and an API key. Groq has a free tier; OpenAI or a local Ollama work too.
Install
- 1Clone and install it as a command:
git clone https://github.com/akshatgcodes/CommitPilot cd CommitPilot && uv tool install . - 2Give it a key:
export GROQ_API_KEY=gsk_...
Use
- 1Stage your work and ask for a message:
git add -A pilot commit - 2Or go straight to the split plan:
pilot commit --split