Pre-commit hooks with husky v6, commitlint and lint-staged

April 6, 2021 - 4 min read

Commit Conventions

While working on the larger projects the contributors may add any sorts of random commit messages that will make the git log messy. It's always good to enforce some kinds of conventions while making the commit message.It will make the commit history more readable.

We can write convention by ourself but there is already Conventional Commits and npm packages built for us to make this process a lot easier.

Example : Commit message with scope

feat(lang): add nepali language

You can check other conventions here.

commitlint

Credit : commitlint package docs

Pre-commit checks

Git hooks are the actions that git allows you to perform certain action when we trigger certain actions in our git workflow. The events might be:

  • pre-commit
  • pre-push
  • pre-rebase
  • post-update

Pre-commit hooks are actions that run after staging your changes and running git commit and before a commit is completed.

We can make pre-commit hooks to check conventional-commits on every commit. If the checks fail then the commit is not made and an error shown, while if all checks pass the commit is made as normal.

Husky 🐶

Husky makes these things easier by defining the hooks and run the certain sceipts when certain events are triggered in git workflow.

What's in Husky v6 ?

After the introduction from husky v4 to v6 there are sinificant changes in the husky tooling. The new Husky approach tends to keep the Husky away from the JS eco-system, instead making it hybrid.

There are two excellent articles by husky authors regarding this :

Local Setup

I've taken an React project in this example but you can setup on any projects.

Run following command in your terminal :

npx husky-init

Chack your package.json file. You may have seen prepare script and husky added as dev dependencies.

package.json

{
 
  "scripts": {
    ...
    "prepare": "husky install"
  },
  "devDependencies": {
    ...
    "husky": "^6.0.0"
  }
}

Install husky in your project :

npm install
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
 

Previously, all hooks lived within package.json under the "husky" object. Now it creates separate directory named .husky/ and creates two files commit-msg & pre-commit.

Checking comit-msg file you might find the following bash script :

.husky/commit-msg

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
 
npx --no-install commitlint --edit ""
 

Since, we are not doing any thing in pre-commit hooks clear everything what's inside the .husky/pre-commit and we will add additional scripts over here later.

Add commit-lint package to lint commit messages.

npm install @commitlint/config-conventional @commitlint/cli --dev

Create file named commitlint.config.js in your root directory and paste following code there : commitlint.config.js:

module.exports = { extends: ["@commitlint/config-conventional"] };

The setup now works for the commitlint !!

fail-commit

Adding lint-staged

But, the problem with our current setup is that the hooks runs of the whole file system in our project which is perfectly fine in small projects. Suppose we are working on large project where we have to lun prettier and lint before every commits pre-commit hooks will then run all the unstaged files too and makes the

But as the file size grows we want to only track those files which are only changed and staged.

For that we need npm package lint-staged.

npm install lint-staged --save-dev

Now go to package.json and write the following script pre-commit which runs the lint-staged in our project.

package.json

  "scripts": {
    ...
    "pre-commit": "lint-staged",
    "prepare": "husky install"
  },

Now create file named .lintstagedrc on our root directory and let us write configuration what we want the lint-staged to do before commits.

You can setup below file as per your needs here I've setup lint-staged to run the eslint and prettier on src/ directory.

.lintstagedrc:

{
  "src/**/*.+(js|json|ts|tsx)": ["eslint"],
  "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": ["prettier --write"]
}

Now inside .husky/pre-commit add the following script :

.husky/pre-commit:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
 
npm run pre-commit

That's it ! Now test everything that we've worked on.

commit-success

🧠 If you are already using husky in your project you can migrate easily yo v6 check this link!