Commit Like a Pro: A Beginner’s Guide to Conventional Commits
Imagine this: you’re part of a team working on an exciting project. Changes are happening quickly—new features, bug fixes, and updates to documentation. However, if you look at the commit history, it is chaotic. Messages like “stuff fixed” or “update” leave you wondering what happened and why. Sound familiar?
Conventional Commits is a straightforward way to write commit messages. It helps bring clarity and consistency to your development process, and it can even support automation.
In this guide, you’ll learn the basics, explore practical examples, and see how Conventional Commits can make your workflow a breeze.
What Are Conventional Commits?
Conventional Commits is a lightweight specification for writing commit messages that follow a simple format:
<type>[optional scope]: <description>
At the heart of this system are four basic types of commits:
- feat: Adds a new feature.
Example:feat: add user authentication via OAuth
- fix: Fixes a bug.
Example:fix: resolve crashing issue on login page
- docs: Updates documentation without altering any code.
Example:docs: add API usage examples in README
- chore: Handles maintenance tasks, such as updating dependencies or configuration.
Example:chore: update Node.js version in CI pipeline
Label your commits clearly. This helps your team and future self understand what is happening in the codebase.
A Basic Guide for Commit Messages
A good commit message consists of two main parts: the header and the body (optional but recommended). Here’s how to craft them:
1. The Header
The header is mandatory and follows this structure:
<type>[optional scope]: <description>
- Type: Describes the kind of change. Stick to the basic types (
feat
,fix
,docs
,chore
) for simplicity. - Scope (optional): Specifies the part of the codebase affected. Example:
fix(ui):
orfeat(auth):
. - Description: A short, imperative sentence summarizing the change.
Examples:- ✅
feat: add login functionality
- ✅
fix: resolve error on form submission
- ❌
added login functionality
(Avoid past tense—write in the imperative mood.)
- ✅
2. The Body
The body provides additional context for your change. Use it to explain the why and how behind your commitment. Example:
fix(auth): correct token validation logic
The token validation was failing due to a mismatch in timezones.
This fix ensures that UTC is used for all comparisons, resolving the issue.
3. The Footer
The footer is optional but highly useful for noting breaking changes or referencing issues:
- Breaking changes:
BREAKING CHANGE: The `authToken` parameter is now required in all API requests.
- Issue references:
Refs: #123
Versioning Made Simple: How It Fits with Semantic Versioning
Conventional Commits shine when paired with Semantic Versioning (SemVer). Here’s how:
- feat bumps the minor version:
If your current version is1.2.0
, adding a feature makes it1.3.0
. - fix bumps in the patch version:
If your version is1.2.0
, fixing a bug updates it to1.2.1
. - docs and chore don’t affect the version number:
These changes are for clarity or maintenance, not functionality.
This mapping helps you keep a consistent release schedule. It ensures that developers, users, and stakeholders all understand what each release means and its effects.
Bonus Tips: Mastering Commit Message References
- Linking Issues: Adding
#issue-number
in your commit message links the commit to that issue for easy reference.
Example:fix(auth): resolve token mismatch issue #456
- Automatically Closing Issues: Using keywords like
Fixes #issue-number
in your commit message not only references the issue but also automatically closes it when the commit is merged.
Example:fix(auth): resolve token mismatch issue Fixes #456
If you want to learn how to write effective GitHub issues, check out our post on 7 Secrets to Writing GitHub Issues That Get Bugs Fixed Fast.
Why Should You Care About Conventional Commits?
- Clarity and Communication:
Everyone on the team instantly knows the purpose of each commit. No more deciphering vague messages. - Streamlined Workflows:
Tools like semantic-release use Conventional Commits to automate changelogs and versioning. - Better Debugging:
Pinpointing the source of an issue becomes much easier with clear commit messages. - Encourages Good Practices:
Thinking in terms of features, fixes, and maintenance encourages more thoughtful and organized commits.
Practical Examples
Here are some examples you can use right away:
- Adding a feature:
feat(api): add support for GraphQL endpoints
- Fixing a bug:
fix(ui): resolve button alignment issue in Safari
- Updating documentation:
docs: update FAQ section with new troubleshooting tips
- Maintenance tasks:
chore(deps): update dependencies to latest versions
The Bigger Picture
Adopting Conventional Commits is more than a format tweak; it’s a culture shift. Here’s why it matters:
- Automate the Boring Stuff: Stop manually managing changelogs and versions—let tools do it for you.
- Foster Collaboration: Clear commit messages to reduce friction in team communication.
- Future-Proof Your Codebase: A well-documented commit history makes onboarding new team members and revisiting old projects a breeze.
Your Next Steps
Now that you’ve unlocked the power of Conventional Commits, it’s time to put it into action:
- Start using
feat
,fix
,docs
, andchore
in your commit messages. - Follow the structure of
<type>[optional scope]: <description>
for headers. - Include meaningful bodies and footers when needed.
- Add issue references with
#issue-number
or close issues automatically withFixes #issue-number
. - Explore tools like
commitlint
to enforce commit message formatting. - Share this guide with your team to build a consistent workflow.
With Conventional Commits, your version control history will tell a clear, consistent story—one that’s easy for everyone to follow. So go ahead, commit to committing better!
Further Reading: 7 Secrets to Writing GitHub Issues That Get Bugs Fixed Fast