Chapter 10-9 — Conventional Commits Standard | DevInHyderabad☕ ☕ 15 min read

Conventional Commits Standard

Professional teams conventional commits use karti hain. Changelog auto-generate hota hai.

01The Problem: Meaningless Commit Messages

"fix", "update", "changes", "wip", "asdfgh" — these commit messages are useless. They tell you nothing about what changed or why.

Without context, you cannot understand what a commit does without reading the entire diff. Code review becomes harder. Bisecting bugs becomes harder. Generating changelogs is impossible.

"What did I change last week?" — impossible to answer with bad commit messages.

Git log becomes a wall of noise instead of a useful project history. Good commit messages are DOCUMENTATION. They tell the story of your project.

# BAD commit messages
git log --oneline
# abc1234 fix
# def5678 update
# ghi9012 changes
# jkl3456 stuff
# mno7890 wip
# pqr1234 final
# stu5678 final_v2
# vwx9012 final_final_really

# GOOD commit messages (conventional commits)
git log --oneline
# abc1234 feat(auth): add JWT authentication
# def5678 fix(api): handle null response from payment gateway
# ghi9012 chore(deps): update express to v4.18
# jkl3456 docs: update API endpoint documentation
# mno7890 refactor(db): extract connection pool to shared module
# pqr1234 test(auth): add integration tests for login flow
# stu5678 ci: add PostgreSQL service to test workflow

# The good messages tell you:
# - WHAT type of change (feat, fix, chore)
# - WHERE the change happened (scope: auth, api, db)
# - WHY the change was needed (the description)
Bad commit messages are technical debt. Every time someone writes "fix" or "update", the entire team loses context. Code review takes longer because reviewers must read the full diff. Bug bisection fails because git bisect shows useless messages. Changelogs cannot be generated. The cost compounds over time — a project with 1000 commits of "fix" and "update" has no useful history.
02The Conventional Commits Specification

Conventional Commits is a specification for commit message formatting. It provides a simple set of rules for creating an explicit commit history.

Format: type(scope): description

Types:

  • feat: — new feature (triggers MINOR version in semver)
  • fix: — bug fix (triggers PATCH version in semver)
  • docs: — documentation only
  • style: — formatting, semicolons, whitespace (no code change)
  • refactor: — code restructuring (no feature or fix)
  • perf: — performance improvement
  • test: — adding or updating tests
  • chore: — maintenance, dependencies, build config
  • ci: — CI/CD configuration changes

Breaking changes: feat!: or feat(scope)!: description (triggers MAJOR version)

Footer: BREAKING CHANGE: description or Closes #123

# Conventional Commit format
# type(scope): description
#   |     |         |
#   |     |         └─ imperative mood, lowercase, no period
#   |     └─ optional: module/area of change
#   └─ required: type of change

# Examples:
feat(auth): add login with OAuth2
fix(api): resolve timeout on slow network
docs(readme): add installation instructions
style(lint): fix semicolon warnings
refactor(cart): extract pricing logic to service
perf(queries): add index to orders table
test(auth): add unit tests for token validation
chore(deps): update dependencies
ci: add coverage report to workflow

# Breaking change (MAJOR version)
feat(api)!: change response format from XML to JSON
# OR with footer:
feat(api): change response format
BREAKING CHANGE: API responses now use JSON instead of XML

# With issue reference
fix(payments): handle declined cards
Closes #42

# Multi-paragraph commit
feat(dashboard): add real-time analytics

Implement WebSocket connection for live data updates.

This replaces the previous polling approach.

Closes #100
03Automated Enforcement with commitlint + Husky

Commit messages should be validated automatically, not by human review. Humans forget. Humans take shortcuts. Automation does not.

commitlint checks commit messages against the conventional commits format. @commitlint/config-conventional provides the standard rules.

Combine with Husky to run commitlint on every commit message. Invalid messages are rejected — the commit is not created.

This ensures 100% compliance across the entire team. No exceptions, no gradual degradation.

# Install commitlint + Husky
npm install --save-dev @commitlint/cli @commitlint/config-conventional husky

# Configure commitlint
echo "module.exports = {extends: ['@commitlint/config-conventional']};" > commitlint.config.js

# Setup Husky hook
npx husky init
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg

# Now try bad commit messages:
git commit -m "update stuff"
# ⧗   input: update stuff
# ✖   type may not be empty [type-empty]
# ✖   subject may not be empty [subject-empty]
# ✖   type must be one of [feat, fix, docs, style, refactor, perf, test, chore, ci] [type-enum]
#
# ✖   3 problems (3 errors, 0 warnings)

# Good commit passes:
git commit -m "feat(auth): add login page"
# ✔ passes!

# Even better: use commitizen for interactive prompts
npm install -g commitizen cz-conventional-changelog
echo '{"path": "cz-conventional-changelog"}' > ~/.czrc
git cz
# Interactive prompts guide you to write proper messages
commitlint + Husky = enforced discipline. Without automation, conventional commits degrade over time. New team members forget, people in a hurry write "fix: stuff", and within months 40% of commits no longer follow the format. With commitlint, every single commit is validated before it is created. The commit is simply rejected if the message does not conform. Zero manual review needed.
04Auto-Generating Changelogs from Commits

Conventional commits enable automatic changelog generation. This is where the real payoff happens.

conventional-changelog reads your commit history and produces a categorized changelog. standard-version goes further — it bumps the version, generates the changelog, and creates a git tag, all automatically.

semantic-release goes even further: analyzes commits, determines version, generates notes, publishes to npm, creates GitHub release.

Without conventional commits, someone must manually write changelogs — error-prone and tedious. With conventional commits, changelogs are a byproduct of your commit discipline.

# Generate changelog from conventional commits
npm install -g conventional-changelog-cli

# First release
conventional-changelog -p angular -i CHANGELOG.md -s -r 0
# Creates CHANGELOG.md with all commits categorized:
# ## 1.0.0 (2024-01-15)
# ### Features
# * **auth:** add login page (abc1234)
# * **dashboard:** add real-time analytics (def5678)
# ### Bug Fixes
# * **api:** handle null response (ghi9012)
# * **payments:** handle declined cards (jkl3456)

# Subsequent releases
conventional-changelog -p angular -i CHANGELOG.md -s

# Using standard-version (bump + changelog + tag)
npm install --save-dev standard-version
npx standard-version
# 1. Analyzes commits since last tag
# 2. Bumps version (feat→minor, fix→patch, !→major)
# 3. Updates CHANGELOG.md
# 4. Creates git tag (v1.1.0)
# 5. Commits version bump + changelog

# Release command
npm run release  # → npx standard-version
git push --follow-tags origin main
05The Full Automated Release Pipeline

The ultimate goal: commit with conventional format, and EVERYTHING else is automated.

Pipeline: commit → commitlint validates → CI runs tests → semantic-release publishes.

semantic-release automates: version bump, changelog, git tag, GitHub release, npm publish. No manual version bumps. No manual changelogs. No manual releases.

The commit message IS the release instruction. feat: = minor release. fix: = patch. ! = major.

This is how professional open-source projects and mature teams operate.

# The complete automated release setup

# 1. Enforce commit format
npm install --save-dev @commitlint/cli @commitlint/config-conventional husky

# 2. Generate changelogs
npm install --save-dev standard-version

# 3. Full automation (optional, advanced)
npm install --save-dev semantic-release

# package.json scripts
cat > package.json << 'EOF'
{
  "scripts": {
    "commitlint": "commitlint --edit",
    "release": "standard-version",
    "release:first": "standard-version --first-release"
  },
  "devDependencies": {
    "@commitlint/cli": "^18.0.0",
    "@commitlint/config-conventional": "^18.0.0",
    "husky": "^9.0.0",
    "standard-version": "^9.5.0"
  }
}
EOF

# Workflow:
# 1. Developer writes: git commit -m "feat(auth): add OAuth2"
# 2. Husky + commitlint validates the message
# 3. CI runs tests
# 4. On main merge, run: npm run release
# 5. standard-version:
#    - Reads commits since last tag
#    - Bumps version (2.1.3 → 2.2.0 because feat)
#    - Updates CHANGELOG.md
#    - Commits + tags v2.2.0
# 6. git push --follow-tags origin main
# 7. GitHub release created automatically
💡 Pro Tip: Start with commitlint + Husky (enforce the format), then add standard-version (generate changelogs), then upgrade to semantic-release (full automation). You do not need the full pipeline on day one. Incremental adoption works best.
Conventional Commits are the foundation of automated releases. When every commit follows a standard format, tools can automatically: 1) Validate messages (commitlint), 2) Generate changelogs, 3) Determine version bumps, 4) Create releases. The commit message becomes a machine-readable instruction for your release pipeline. This is why professional teams never write "fix" or "update" as commit messages.

Lo kar liya — Key Points:

  • ✅ Conventional Commits standardize commit messages with format type(scope): description
  • ✅ Types include feat, fix, docs, style, refactor, perf, test, chore, ci — each has semantic meaning
  • ✅ feat: triggers MINOR version bump, fix: triggers PATCH, ! triggers MAJOR (breaking change)
  • ✅ commitlint + Husky automatically validates commit messages, rejecting non-conventional formats
  • ✅ Conventional commits enable auto-generated changelogs using conventional-changelog or standard-version
  • ✅ semantic-release fully automates: version bump, changelog, git tag, GitHub release, npm publish
  • ✅ The commit message becomes a machine-readable instruction for your release pipeline
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase