Git Commit Messages
This document outlines the required standards and conventions for writing Git commit messages within our project. It serves as a primary reference for all contributors to ensure our version control history remains clear and consistent.
Why Commit Messages Matter
Good commit messages are essential for maintaining a healthy codebase. They serve as a historical record of what changed, why it changed, and how it impacts the project. Well-written commits help teammates understand your work, make code reviews more efficient, enable easier debugging when issues arise, and create a clear audit trail for future developers.
Think of commit messages as documentation that lives alongside your code-they're often the first place someone will look when trying to understand why a particular change was made.
Our Commit Message Format
We follow the Conventional Commits specification, which provides a standardized structure:
<type>(<optional scope>): <description>
[optional body]
[optional footer]
Commit Types Reference
The Conventional Commits specification define the following commit prefixes:
- feat: A new feature for users or a new capability in the code. This signals that you've added something new to the code base. These changes typically result in a minor version bump in semantic versioning.
- Example:
feat(auth): add login functionality - fix: A bug fix that corrects unwanted behavior. Use this when you've resolved an issue or error. These changes typically result in a patch version bump.
- Example:
fix(parser): handle edge case - docs: Documentation changes only, such as updating README files, adding comments, or revising API documentation. No code functionality changes.
- Example:
docs(readme): update installation instructions - style: Code formatting changes that don't affect functionality-fixing indentation, adding missing semicolons, removing whitespace, or applying linting rules.
- Example:
style: fix indentation of user model - refactor: Code restructuring that neither adds features nor fixes bugs. This might include renaming variables for clarity, reorganizing functions, or improving code structure without changing behavior.
- Example:
refactor: extract validation logic into service - test: Adding new tests or updating existing test cases. Use this when working exclusively on test files.
- Example:
test: add unit tests for new API endpoint - chore: Routine maintenance tasks like updating dependencies, modifying build configurations, or other housekeeping that doesn't modify source or test files.
- Example:
chore: update dependencies to latest stable - build: Changes to the build system or external dependencies-updating package.json, modifying webpack config, or adjusting build scripts.
- Example:
build: update webpack configuration - ci: Changes to continuous integration configuration files or scripts, such as GitHub Actions, Jenkins, or deployment pipelines.
- Example:
ci: add E2E test job - perf: Performance improvements that make code run faster or use fewer resources without changing functionality.
- Example:
perf: optimize image loading speed - revert: Reverting a previous commit. Include information about which commit is being reverted and why.
- Example:
revert: "feat: experimental feature"
Adding Scope and Breaking Changes
Scope (optional) provides additional context about which part of the codebase changed: feat(api): add user endpoint or fix(parser): handle edge case.
Breaking Changes are indicated with an exclamation mark before the colon: feat!: redesign authentication system. You can also include a BREAKING CHANGE: footer in your commit message to explain the impact.
Quick Tips
- Keep the description line under 50-72 characters when possible
- Use the imperative mood: "add feature" not "added feature"
- The description should complete the sentence: "This commit will..."
- Use the optional body to explain why you made the change, not just what changed
- Reference issue numbers in footers when relevant:
Refs: #123
Following these conventions makes our project history scannable, enables automated changelog generation, and helps everyone on the team understand changes at a glance.
Examples
Simple style
style: remove unused imports flagged by linter
Test with scope
test(auth): add unit tests for login validation
Refactor with body
refactor: rename getUserData to fetchUserProfile
New name better reflects that this function makes an async network request rather than just returning cached data
Fix with breaking change
fix(database)!: change user ID from integer to UUID
Switched from auto-incrementing integers to UUIDs for better distributed system support and security.
BREAKING CHANGE: user IDs are now strings instead of numbers
Migration: scripts/migrate_user_ids.sql
Refs: #321