Imagine navigating a large codebase and encountering a commit history filled with vague messages like "fix stuff" or "update code." Needless to say, this can lead to confusion, miscommunication, and a lot of wasted time trying to figure out what changed and why.
In my experience, commit messages are often an afterthought, sort of a "write something quick so I can move on" task. I feel this is a missed opportunity to improve collaboration and maintainability.
While there might be many ways to write good commit messages, I've found that adopting a standardized approach like Conventional Commits can make a world of difference. Not only does it bring clarity and consistency, but it also enables automation and better collaboration within teams.
What is Conventional Commits?
The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history.
The format is straightforward:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Type
Types of commits include:
- build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- ci: Changes to your CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
- docs: Documentation only changes
- feat: A new feature
- fix: A bug fix
- perf: A code change that improves performance
- refactor: A code change that neither fixes a bug nor adds a feature
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.)
- test: Adding missing tests or correcting existing tests
- revert: reverts a change
Example:
feat: add OAuth2 login support
Types can be found in configurations like
@commitlint/config-conventional
based on the (Angular convention).
Scope (optional)
A scope may be provided to a commit’s type, to provide additional contextual information and is contained within parenthesis.
Example:
feat(auth): add OAuth2 login support
Body (optional)
A commit body is free-form and MAY consist of any number of newline separated paragraphs.
Example:
feat(auth): add OAuth2 login support
Implemented OAuth2 login functionality for Google and GitHub, including new
routes for OAuth2 callback handling and token exchange.
Footer (optional)
One or more footers MAY be provided one blank line after the body. Each footer
MUST consist of a word token, followed by either a :<space>
or <space>#
separator, followed by a string value (this is inspired by the
git trailer convention).
Footers can include:
- BREAKING CHANGE: Description of a change that breaks backward compatibility.
- References: Links or issue numbers related to the commit.
Example:
feat(auth): add OAuth2 login support
Implemented OAuth2 login functionality for Google and GitHub, including new
routes for OAuth2 callback handling and token exchange.
BREAKING CHANGE: The login API has changed to support OAuth2
Closes #456
More examples here.
Reverts
Conventional Commits does not make an explicit effort to define revert behavior.
One recommendation is to use the revert
type, and a footer that references the
commit SHAs that are being reverted:
revert: undo the great pizza disaster of '23
Refs: 8b5c8f0, 9a2f8d7
Benefits
Clarity and Consistency
- Before:
"fix bug"
- After:
fix(auth): resolve logout issue by resetting session data
The latter provides clear information on what was fixed and where, making it easier for anyone reviewing the commit history to understand the changes.
Automated Tools
- Tools can automatically generate changelogs based on commit messages.
- Helps in versioning your software with Semantic Versioning.
Example: From the above commits, an automated tool can generate a changelog entry like:
- New Features:
- Add user login functionality
- Bug Fixes:
- Resolve logout issue by resetting session data
- Breaking Changes:
- The login API has changed to support OAuth2.
Better Collaboration
This practice allows your team to quickly grasp the context of each change. New team members can also get up to speed faster, as the commit history provides a clear and concise record of changes.
Improved Code Quality
Conventional Commits encourage thoughtful, meaningful commits, promoting a more disciplined approach to version control. Basically, it encourages you to think about what you are committing and why, leading to better code quality over time.
How to Adopt Conventional Commits
- Start Simple: Begin by following the format manually.
- Use Tools: Tools like commitlint can help enforce the specification and make it easier to write proper commit messages.
- Educate Your Team: Share the benefits and encourage your team to adopt the practice.
For more details and a a full list of examples, visit the Conventional Commits website.