Conventional Commits
Commit git changes using the Conventional Commits v1.0.0 specification.
Commit Message Format
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Commit Types
| Type | Description | SemVer |
|------|-------------|--------|
| feat | New feature | MINOR |
| fix | Bug fix | PATCH |
| docs | Documentation only | - |
| style | Formatting, whitespace (no code change) | - |
| refactor | Code restructuring (no feature/fix) | - |
| perf | Performance improvement | - |
| test | Adding/updating tests | - |
| build | Build system or dependencies | - |
| ci | CI configuration | - |
| chore | Maintenance tasks | - |
| revert | Reverting commits | - |
Breaking changes: Add ! after type/scope (e.g., feat!: or feat(api)!:) or include BREAKING CHANGE: footer.
Workflow
-
Analyze workspace state
git status git diff --stat git diff --staged --stat -
Review actual changes for each modified file to understand the nature of changes:
git diff <file> # unstaged git diff --staged <file> # staged -
Group changes logically
- Separate commits (default): Each distinct change gets its own commit
- Combined commits: Only when changes are tightly coupled and make no sense apart
Examples of separate commits:
- Adding a feature + updating docs → 2 commits
- Fixing bug A + fixing bug B → 2 commits
- Refactoring module X + adding tests → 2 commits
Examples of combined commits:
- Feature code + its unit tests (if tests only make sense with the feature)
- Migration file + model changes (if they're atomic)
-
Determine commit order
- Infrastructure/build changes first
- Core functionality before dependent features
- Tests can go with or after the code they test
- Documentation typically last
When order is ambiguous: Ask the user before proceeding.
-
Stage and commit each group
git add <files> git commit -m "<type>[scope]: <description>"
Writing Good Commit Messages
Description (first line):
- Use imperative mood: "add feature" not "added feature"
- No period at end
- Under 72 characters
- Be specific: "fix null pointer in user auth" not "fix bug"
Scope (optional):
- Module, component, or area affected
- Examples:
feat(auth):,fix(parser):,docs(readme):
Body (when needed):
- Explain what and why, not how
- Wrap at 72 characters
- Separate from description with blank line
Footer (when needed):
BREAKING CHANGE: <description>for breaking changesRefs: #123for issue referencesReviewed-by: Namefor attribution
Examples
# Simple feature
git add src/auth/oauth.py
git commit -m "feat(auth): add OAuth2 support for Google login"
# Bug fix with scope
git add lib/parser.js
git commit -m "fix(parser): handle empty arrays in JSON input"
# Docs only
git add README.md
git commit -m "docs: add installation instructions for Windows"
# Breaking change
git add api/v2/
git commit -m "feat(api)!: redesign user endpoints for v2
BREAKING CHANGE: /users endpoint now requires authentication.
Old endpoint /users/list is removed, use /users instead."
# Refactor with body
git add src/utils/
git commit -m "refactor(utils): extract date formatting to separate module
Moved date formatting logic from multiple components into
a centralized utils/dates.py module to reduce duplication
and ensure consistent formatting across the application."
Handling Ambiguity
Ask the user when:
- Multiple unrelated changes exist and commit order matters for history
- Changes span features that could be atomic or separate
- It's unclear whether changes are one logical unit or multiple
Example prompt:
I see changes to the auth module and the API routes. Should I:
- Commit them separately (auth first, then routes)?
- Commit them together as a single feature?
- Different order?