The Hook (The "Byte-Sized" Intro)
"fixed stuff", "wip", "asdfgh". Three months later, you need to find the commit that broke payments. Good luck. Conventional Commits solve this: structured messages (feat:, fix:, chore:) that enable automated changelogs, semantic versioning, and searchable history. One format. Every commit. Forever useful.
📖 What are Commit Message Standards?
A team-wide convention for structuring commit messages to make history readable, searchable, and automatable.
Conceptual Clarity
Conventional Commits format:
<type>(<scope>): <description>
[optional body]
[optional footer]
Types:
| Type | Purpose | Bumps |
|---|---|---|
feat | New feature | Minor version |
fix | Bug fix | Patch version |
docs | Documentation only | None |
style | Formatting, whitespace | None |
refactor | Code change, no new feature | None |
test | Add/update tests | None |
chore | Build, deps, config | None |
ci | CI/CD changes | None |
perf | Performance improvement | None |
Breaking changes:
feat(auth)!: change login API response format
BREAKING CHANGE: The login endpoint now returns { token }
instead of { access_token }.
The ! or BREAKING CHANGE footer bumps the major version.
Real-Life Analogy
Commit messages are like entries in a ship's log. "Sailed somewhere" is useless. "Departed New York at 0800, heading 045° for London, crew of 12" — that's actionable.
Visual Architecture
Why It Matters
- Searchability:
git log --grep="^fix"finds all bug fixes. - Automation: Tools generate changelogs and version bumps from commit types.
- Code review: Reviewers understand the intent before reading the code.
- History: Six months later, structured messages tell the story.
Code
# ─── Good commit messages ───
git commit -m "feat(auth): add JWT token refresh endpoint"
git commit -m "fix(cart): resolve race condition on quantity update"
git commit -m "docs(readme): add deployment instructions"
git commit -m "chore(deps): upgrade React to v19"
# ─── With body and footer ───
git commit -m "fix(payments): handle expired card gracefully
Previously, expired cards caused a 500 error. Now we return
a 400 with a clear message asking the user to update their card.
Fixes #234"
# ─── Enforce with commitlint + Husky ───
npm install --save-dev @commitlint/cli @commitlint/config-conventional
echo "module.exports = { extends: ['@commitlint/config-conventional'] }" > commitlint.config.js
echo 'npx commitlint --edit "$1"' > .husky/commit-msg
# ─── Search by type ───
git log --grep="^feat" --oneline # All features
git log --grep="^fix" --oneline # All fixesKey Takeaways
- Use Conventional Commits:
type(scope): description. - Types drive automation: changelogs, version bumps, search.
- Enforce with commitlint + a
commit-msghook. BREAKING CHANGEor!signals a major version bump.
Interview Prep
-
Q: What are Conventional Commits? A: A specification for structuring commit messages as
type(scope): description. Types likefeat,fix,chorecategorize changes, enabling automated changelogs, semantic versioning, and searchable history. -
Q: How do Conventional Commits enable automated versioning? A: Tools like
semantic-releaseread commit types:fix→ patch bump,feat→ minor bump,BREAKING CHANGE→ major bump. This eliminates manual version decisions. -
Q: How do you enforce commit message standards? A: Using
commitlintwith acommit-msghook (via Husky). The hook validates every commit message against the Conventional Commits spec and rejects non-conforming messages.