Good commit messages turn Git history into documentation. In this lesson you will learn the anatomy of a great commit message, the Conventional Commits standard used by many teams, and how to enforce it automatically.
๐ What You’ll Learn: why commit messages matter, the subject, body and footer rules, bad vs good examples, Conventional Commits types and scopes, breaking changes, benefits like automated changelogs, enforcing the format with commitlint and Husky, and examples for test projects.
โ๏ธ Why Commit Messages Matter
Six months from now, someone (probably you) will run git log or git blame to understand why a line of code exists. A message like “fix” or “update” tells them nothing. A good message saves hours of investigation, makes code review easier and can even generate release notes automatically.
๐ The Anatomy of a Good Commit Message
Fix flaky checkout test by waiting for the order API
The test clicked "Finish" before the cart total was recalculated,
so it failed about 1 in 20 runs in CI. Wait for the /api/order
response instead of using a fixed 2-second timeout.
Closes #87
| Part | Rules |
|---|---|
| Subject line | About 50 characters (hard limit around 72); imperative mood (“Fix”, not “Fixed” or “Fixes”); capitalised; no full stop |
| Blank line | Separates subject and body (tools rely on it) |
| Body (optional) | Wrap at about 72 characters; explain what and why, not how (the diff shows how) |
| Footer (optional) | Issue references (Closes #87), BREAKING CHANGE:, co-authors |
๐ก Tip: A simple test for the subject line: it should complete the sentence “If applied, this commit will ___”. “If applied, this commit will fix flaky checkout test by waiting for the order API.”
Write multi-line messages by running git commit without -m; Git opens your configured editor.
โ Bad vs โ Good Examples
| โ Bad | โ Good |
|---|---|
fix | Fix tax rounding on the checkout summary page |
update tests | Add negative login tests for locked-out users |
changes as per review | Use getByRole for the login button |
WIP | Squash WIP commits before merging (interactive rebase) |
Fixed the bug where the thing didn't work on Safari when the user... | Fix date picker on Safari (details in the body) |
๐งฉ Conventional Commits
Conventional Commits is a widely used specification that adds a type (and optional scope) to the subject:
<type>(<optional scope>): <description>
[optional body]
[optional footer(s)]
| Type | Use for | Example |
|---|---|---|
feat | A new feature | feat(cart): add discount code field |
fix | A bug fix | fix(checkout): round tax to two decimals |
test | Adding or fixing tests | test(login): add locked-out user scenario |
docs | Documentation only | docs: add setup steps to README |
refactor | Code change that neither fixes a bug nor adds a feature | refactor(pages): extract BasePage |
style | Formatting, whitespace (no code meaning change) | style: apply Prettier formatting |
perf | Performance improvement | perf(api): cache product list |
build | Build system or dependencies | build: upgrade @playwright/test |
ci | CI configuration | ci: shard Playwright tests across 4 jobs |
chore | Maintenance that does not fit elsewhere | chore: update .gitignore |
revert | Reverting a commit | revert: undo feat(cart) discount field |
Breaking changes
Mark changes that break compatibility with ! or a footer:
feat(api)!: rename /users endpoint to /accounts
BREAKING CHANGE: clients must call /accounts instead of /users.
Why teams adopt Conventional Commits
- History is easy to scan and filter (
git log --oneline --grep="^fix"). - Tools can generate changelogs and choose the next version automatically (
fixโ patch,featโ minor, breaking โ major; see semantic versioning). - PR titles in the same format become clean commit messages when using Squash and merge (pull requests).
๐ค Enforce the Format Automatically
Teams usually enforce the format with commitlint running in a Git hook managed by Husky:
npm install -D @commitlint/cli @commitlint/config-conventional husky
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.mjs
npx husky init
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg
Now a commit message like update stuff is rejected before the commit is created. Hooks are covered in Git Hooks and Husky.
๐งช Commit Messages for Test Automation Projects
test(checkout): add data-driven tests for invalid postcodes
fix(tests): replace waitForTimeout with web-first assertion in search spec
refactor(pages): move cart locators into CartPage
ci: upload Playwright traces on failure
build: bump @playwright/test to the latest version
๐ Assignment
- Rewrite these messages properly: “fix”, “tests”, “updated readme”, “final changes”.
- Make three commits in
git-practiceusing Conventional Commits with different types and scopes. - Write one commit with a subject, a body explaining why, and a
Closes #<n>footer, using your editor instead of-m. - Run
git log --oneline --grep="^test"to list only test commits. - Bonus: set up commitlint with Husky and try to commit a bad message.
โ FAQ
๐ค How do I write a good Git commit message?
Use a short imperative subject (about 50 characters), a blank line, and an optional body explaining what changed and why, with issue references in the footer.
๐ค What are Conventional Commits?
A specification for commit messages in the form type(scope): description, such as fix(login): handle locked users, that enables readable history and automated changelogs and versioning.
๐ค Should commit messages be in past or present tense?
The common convention is the imperative mood: “Add test”, “Fix bug”, as if giving a command.
๐ค What does feat! mean in a commit message?
The ! marks a breaking change, which usually triggers a major version increase.
๐ค How do I write a multi-line commit message?
Run git commit without -m to open your editor, or use -m twice: git commit -m "Subject" -m "Body".
๐ฏ Next Steps
- ๐งโ๐ป Git and GitHub in VS Code
- โ Git Workflow Best Practices for Teams
- ๐ Git and GitHub Tutorial: full course
๐ฌ Learn Git and GitHub step by step: watch the series on YouTube!
Subscribe to SqaToolsByDY • Practice on sqatools.in
2 thoughts on “How to Write Good Git Commit Messages (and Use Conventional Commits)”