
Husky and Commitlint are not about making commit messages look pretty. They automate one basic collaboration rule: every commit should state what changed and where. That makes code review, changelog generation, release notes, and rollback investigation more reliable.
The highest-value first step is usually a commit-msg hook, not a heavy pre-commit pipeline.
What problem this solves
Commit message rules are worth adding when a team repeatedly sees:
- Commits named
update,fix bug, orchanges. - One commit mixing unrelated work.
- Release notes that require manual archaeology.
- Changelog or semantic-release tooling with unreliable input.
- Reviewers unable to understand history from Git alone.
The goal is not to replace review discipline. It is to remove the lowest-quality commit messages before they enter shared history.
Commitlint's job
Commitlint checks whether a commit message matches configured rules. It does not write the message for you.
Common Conventional Commit shape:
<type>(scope): <subject>
Examples:
git commit -m "feat(auth): add Google login"
git commit -m "fix(search): handle empty keyword"
git commit -m "docs(readme): update setup steps"
For most projects, extending @commitlint/config-conventional is the practical starting point.
Husky's job
Husky connects scripts to Git hooks. For this workflow, it runs Commitlint when Git is about to create a commit.
Install the tools:
npm install --save-dev husky @commitlint/cli @commitlint/config-conventional
npx husky init
Modern Husky setup commonly uses husky init, which creates the .husky/ directory and updates the package prepare script. Older tutorials that use husky install and husky add may be version-specific.
Minimal Commitlint config
Create commitlint.config.js:
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
["feat", "fix", "docs", "style", "refactor", "test", "chore"],
],
"subject-case": [0],
},
}
Then update .husky/commit-msg:
npx --no -- commitlint --edit "$1"
Now an invalid message fails before the commit is created.
Why start with commit-msg
Many teams put too much into pre-commit too early:
- lint
- tests
- typecheck
- format
- build
That can make local commits slow and brittle. Developers then start bypassing hooks, which defeats the purpose.
A commit-msg check is cheap, fast, and easy to understand. Add heavier checks gradually through lint-staged, local scripts, and CI after the team trusts the workflow.
Branch strategy should stay simple
Commit rules do not require a complex Git Flow setup. Small teams often do well with:
main: releasable codefeature/*: new workfix/*: bug fixes
Clear commits and small PRs matter more than an elaborate branch naming system. For the basic flow, see A Practical Git Workflow: Add, Commit, Fetch, Pull, and Push.
What to add later
After commit messages are consistent, you can extend the workflow:
- Generate changelogs.
- Use semantic-release.
- Re-check commit messages in CI.
- Add PR templates.
- Use
lint-stagedfor staged-file checks.
The order should be: standardize messages, enforce them locally, then connect them to release automation.
Common misunderstandings
Husky is not Commitlint. Husky runs hooks. Commitlint validates messages.
Valid format is not the same as a good commit. feat: update many files may pass the rule and still be too broad.
Old Husky tutorials may not match your installed version. Check current tool docs before copying setup commands.
Related FreeMac guides
- For the base Git workflow, read A Practical Git Workflow: Add, Commit, Fetch, Pull, and Push.
- For formatting and config files, read EditorConfig and Prettier: Keep Code Style Consistent.
- For project environment setup, read Front-End Config: Env, Node, Git, ESLint, and TypeScript.
Continue reading
Git worktree: The Git Command That Made Me Use stash Much Less
Learn how Git worktree keeps multiple branches open at once, when it is better than stash or clone, and the commands needed for a practical workflow.
10 min readA Practical Git Workflow: Add, Commit, Fetch, Pull, and Push
Understand Git's working tree, staging area, local repository, and remote—then use add, commit, fetch, pull, push, branches, and restore deliberately.
14 min readFront-End Config: Env, Node, Git, ESLint, and TypeScript
Set up .env files, Node versions, Git ignores, ESLint flat config, Prettier, and TypeScript with clear responsibilities, safe secret handling, and a repeatable workflow.
Subscribe to FreeMac
Weekly picks: free Mac software reviews, trusted source updates, alternatives, and low-friction guides.