A good commit message is the mark of a professional developer who cares about their team. Imagine you need to track when a bug was introduced into the code, or understand the reason behind a change made two months ago. A poorly written commit history — full of messages like "update", "fix", or "asdfjkl" — makes that tracking nearly impossible. This article covers how to write commit messages that are informative, consistent, and useful.
Why Do Commit Messages Matter?
A commit message isn't just a note for yourself. It's communication with:
- Teammates who have to understand your changes during code review.
- Your future self when debugging a problem that appears months later.
- Automation tools like changelog generators or CI/CD pipelines that read commit messages.
The Basic Format of a Good Commit Message
A good commit message has this structure:
<type>(<scope>): <short description>
[optional body — a more detailed explanation]
[optional footer — issue/ticket reference]
A complete example:
feat(auth): add JWT token validation to the middleware
The token's expiry was previously not validated, so an
expired token could still be used to access endpoints.
Closes #142
Conventional Commits — The Industry Standard
Conventional Commits is a commit message specification widely adopted by the industry. Its main format is type(scope): description. Here are the commonly used types:
feat— Add a new feature.fix— Fix a bug.docs— Documentation changes only.style— Code format/style changes (whitespace, semicolons) without changing logic.refactor— Refactor code without adding a feature or fixing a bug.test— Add or fix tests.chore— Routine tasks like updating dependencies, build configuration.perf— A performance improvement.ci— CI/CD configuration changes.
Examples of Correct Commit Messages
feat(user): add a profile photo upload feature
fix(cart): fix the total price calculation when a discount applies
docs(readme): update the installation guide for Windows
refactor(api): move validation logic into a service class
chore: update laravel from version 10 to 11
test(auth): add a unit test for the failed login process
Basic Rules for Writing Commit Messages
- Use the imperative mood for the short description: "add", "fix", "remove" — not "added" or "fixed".
- The first line should be at most 72 characters so it's easy to read in the log.
- Separate the subject and body with a blank line if more explanation is needed.
- Explain "why", not just "what". What was changed is visible from the diff — what isn't visible is the reason.
- One commit, one logical change. Don't combine a bug fix and a feature addition in a single commit.
Bad vs. Good Commit Messages
A comparison of commit messages to avoid vs. better ones:
BAD:
update
fix bug
asd
change button color and fix login and add profile page
GOOD:
style(button): change the CTA button color to primary blue
fix(auth): fix the redirect after a failed login
feat(profile): add a user profile edit page
Adding an Issue or Ticket Reference
If your team uses an issue tracker like GitHub Issues or Jira, include the reference in the commit footer:
fix(payment): fix the error when the gateway times out
The payment gateway returned status 503 but the application
did not handle it and immediately showed a 500 error.
Fixes #234
Refs: PROJ-891
On GitHub, keywords like Fixes, Closes, or Resolves will automatically close the referenced issue when that commit is merged into the main branch.
Using git commit Without the -m Flag for Long Messages
For longer messages with a body, run commit without the -m flag so a text editor opens:
git commit
Git will open the default editor (usually Vim or nano). To change the default editor to VS Code:
git config --global core.editor "code --wait"
Conclusion
Writing good commit messages is a small habit that has a big impact on the quality of team collaboration and long-term code maintainability. Adopt Conventional Commits as your standard, write the reason behind the change, and keep each commit focused on one thing. A clean and informative commit history is one of the marks of a developer who truly cares about their team and the quality of their code.