git-commit-best-practices
Git Commit Best Practices (limps)
Purpose
Guide the creation of clear, meaningful Git commits that follow conventional commit standards and repository-specific conventions. Ensures commits are atomic, well-documented, and integrate with automated tooling (release-please, changelog generation).
Scope
- If
$ARGUMENTSis "review-commits" or a commit range (e.g.,HEAD~5..HEAD,main..HEAD), review existing commits and suggest improvements. - If
$ARGUMENTSis a scope (paths or component), provide commit guidance for those changes. - If no arguments provided, guide commit message creation for staged changes.
Detecting Breaking Changes
When reviewing commits, detect breaking changes by:
- Parse commit messages:
git log --format="%H%n%s%n%b" <range>(includes full body) - Search for footer: Look for
BREAKING CHANGE:orBREAKING CHANGEin commit body (case-insensitive) - Extract description: Everything after
BREAKING CHANGE:until:- Next footer (e.g.,
Closes #123,Fixes #456) - End of commit message
- Empty line followed by non-footer text
- Next footer (e.g.,
- Example commands:
- Simple:
git log --format=%B main..HEAD | grep -A 10 -i "BREAKING CHANGE" - More robust:
git log --format="%H%n%s%n%b%n---" <range>then parse each commit separately
- Simple:
- Edge cases:
- Multi-line breaking changes: Extract until next footer or end
- Breaking change in subject: Look for
!after type/scope:feat!: breaking change - Merge commits: Check merge commit message for breaking changes
Conventional Commit Format
Structure
<type>(<scope>): <subject>
<body>
<footer>
Types
feat: New feature (triggers minor version bump)fix: Bug fix (triggers patch version bump)docs: Documentation changes onlystyle: Code style changes (formatting, whitespace, no logic change)refactor: Code refactoring (no feature change or bug fix)perf: Performance improvementstest: Adding or updating testschore: Maintenance tasks (deps, config, build)ci: CI/CD changesbuild: Build system changesrevert: Revert a previous commit
Scope (Optional but Recommended)
- Single scope (most common): Package name (
limps,limps-headless) or component (cli,server,tools,resources,rlm,indexer) - Multiple scopes: Use comma-separated for cross-package changes:
feat(limps,limps-headless): ... - When to use multiple: Only when change affects multiple packages/components in same commit
- Area scopes:
config,mcp,extensions,watcher(use when change is area-specific, not package-specific)
Subject Line Rules
- Imperative mood: "add feature" not "added feature" or "adds feature"
- Lowercase (except proper nouns, acronyms)
- No period at the end
- 50 characters or less (ideally)
- Clear and specific: Describe what the commit does, not why (why goes in body)
Body (Optional but Recommended for Complex Changes)
- Separated by blank line from subject
- 72 characters per line (wrap if needed)
- Explain what and why (not how - code shows how)
- Reference related issues, plans, or agents
- Note breaking changes if applicable
Footer (Optional)
- Breaking changes:
BREAKING CHANGE: <description> - Issue references:
Closes #123,Fixes #456,Related to #789 - Plan/Agent references:
Plan: NNNN-plan-name,Agent: 008
Examples
Simple Feature
feat(limps): add config migration utility
Adds utility to migrate config files between versions, handling
backward compatibility and preserving user settings.
Related to plan NNNN-plan-name
Bug Fix with Issue Reference
fix(server): handle missing config gracefully
Previously, missing config files would crash the server. Now
returns helpful error message and exits cleanly.
Fixes #42
Breaking Change
refactor(config): restructure config schema
BREAKING CHANGE: Config file format changed from JSON to YAML.
Existing configs must be migrated using `limps config migrate`.
Migration guide: docs/config-migration.md
Multi-Package Change
feat(limps,limps-headless): add extension system
Adds extension loader and context system to both packages.
Extensions can register custom tools and resources.
Plan: NNNN-plan-name
Agent: 007
Documentation Only
docs: update CLAUDE.md with extension system details
Adds documentation for extension development and integration.
Atomic Commits
Principles
- One logical change per commit: Each commit should represent a complete, working change
- Buildable and testable: Each commit should leave the repo in a valid state
- Reviewable: Changes should be grouped logically for code review
When to Split Commits
- Different types of changes (e.g., refactor + feature)
- Unrelated files or subsystems
- Formatting/style changes separate from logic changes
- Test changes separate from implementation
When to Combine Commits
- Related changes that depend on each other
- Small, related fixes in the same file
- Documentation updates that accompany code changes
Repository-Specific Guidelines
Monorepo Considerations
- Specify package scope when changes are package-specific:
feat(limps): ... - Use root-level scope for cross-package changes:
feat: ...orfeat(limps,limps-headless): ... - Workspace-aware: Consider impact on other packages
Plan/Agent Integration
- Reference plans/agents in commit body when applicable:
Plan: NNNN-plan-nameAgent: 008-complex-parsing
- Use agent titles in subject when committing agent work:
feat(limps-headless): implement complex parsing logic- Body:
Agent: 008-complex-parsing
Release-Please Integration
- Type matters:
feat→ minor bump,fix→ patch bump - Breaking changes: Use
BREAKING CHANGE:footer for major bumps - Scope helps: Package-scoped commits help release-please target correct package
Changelog Generation
- Commits with conventional format automatically appear in CHANGELOG.md
- Body content may be included in changelog entries
- Reference issues/PRs for better changelog links
Workflow
Before Committing
- Review staged changes:
git diff --cached - Check for unrelated changes: Split if needed
- Verify tests pass:
npm test(or workspace-specific:npm test --workspace <name>) - Check formatting:
npm run format:check(repo-specific command)- Note: These commands are limps-specific; adapt for other repos
Creating the Commit
- Determine type: What kind of change is this?
- Identify scope: Which package/component?
- Write subject: Clear, imperative, concise
- Add body (if needed): Explain context, why, related items
- Add footer (if needed): Issues, breaking changes, plans
After Committing
- Review commit:
git log -1to verify format - Amend if needed:
git commit --amend(before pushing)
Reviewing Commits
When reviewing commits (e.g., review-commits argument or commit range):
- Parse commits:
git log --format="%H%n%s%n%b%n---" <range>to get full commit messages - Check format: Does it follow conventional commits? (
<type>(<scope>): <subject>) - Evaluate atomicity: Should this be split or combined?
- Assess clarity: Is the message clear and informative?
- Verify completeness: Does it reference related issues/plans?
- Check breaking changes: Look for
BREAKING CHANGE:footer or!in type - Suggest improvements: Provide specific recommendations with examples
Review Output Format
When reviewing commits, use this structure:
## Commit Review: <commit-range>
### Summary
- Total commits: X
- Format compliance: Y compliant, Z need improvement
- Breaking changes: Found in commits [list]
### Findings by Commit
#### Commit <hash>: <subject>
- ✅ Format: Conventional commit format
- ⚠️ Issues: [if any]
- 🔴 Critical: [if any]
- Suggestions: [specific improvements]
### Overall Recommendations
- [Action items]
Common Mistakes to Avoid
❌ Too vague: fix: update code
✅ Specific: fix(server): handle undefined config paths
❌ Past tense: feat: added new feature
✅ Imperative: feat: add new feature
❌ Too long subject: feat(limps): implement comprehensive configuration management system with validation and migration support
✅ Concise: feat(limps): add config validation and migration
❌ Multiple unrelated changes: One commit with formatting + feature + test ✅ Separate commits: One for formatting, one for feature, one for test
❌ Missing context: fix: bug fix
✅ With context: fix(indexer): prevent SQL injection in search queries
Output Format
When providing commit guidance:
## Suggested Commit Message
<type>(<scope>): <subject>
<body>
## Rationale
- Why this type/scope
- What makes it atomic
- Related items (issues, plans, agents)
## Checklist
- [ ] Subject is imperative and clear
- [ ] Scope is appropriate
- [ ] Body explains context (if needed)
- [ ] Footer references issues/plans (if applicable)
- [ ] Commit is atomic
- [ ] Tests pass
Notes
- Prefer
git commitwith message over-mfor complex commits (opens editor) - Use
git commit --amendto fix commit messages before pushing - Use
git rebase -ito clean up commit history (before pushing) - Conventional commits enable automated tooling (release-please, changelog)
- Clear commits make code review and debugging easier
- Merge commits: Review merge commit messages; they should describe what's being merged
- Squash commits: When squashing, combine commit messages meaningfully
- Revert commits: Use
revert: <original-subject>format:revert: feat(limps): add feature