Clean Git Log with Husky and Commitlint

May 29, 2020/3 min read
Achieve a clean and readable git log with husky and commitlint
git
Clean Git Log with Husky and Commitlint thumbnail

Find the source code of the article in this github repo

Introduction

In our programming life most of us came across git logs which looked like this

4a3e5ba fix
c8a54df style change
0677dc5 fix
84ebabf fix
dbf7300 fix bug
6942670 pr changes
32d06bc pr changes

It's impossible to understand from these commits what is going on in our repository and makes it harder to navigate between commits.

There is a simple solution you can apply in 5 minutes using husky and commitlint to avoid this problem, and the sooner the better!


Husky

Git provides us with something called Git Hooks, simply lets us hook into specific git workflow (commiting, pushing, etc) and run commands.

Although you can write your git hooks from scratch, there is an easier solution using husky.

Heading to your project, add husky by running npm i -D husky. Now we can test husky by adding some hook to our package.json file

{
  "husky": {
    "hooks": {
      "pre-commit": "echo git hooks are awesome!"
    }
  }
}

And then when commiting you should see our hook running

husky > pre-commit (node v10.17.0)
git hooks are awesome!
[master ec5599a] first commit with husky
 1 file changed, 3 insertions(+)

Commitlint

Commitlint, as it's name suggests, helps us to lint our git commits.

First, add commitlint cli to our project by running npm i -D @commitlint/cli

Now you can choose from various conventions listed here, for this blogpost i'm going to use angular's convention which follows the commit template of

type(scope?): subject  #scope is optional

Adding it by running npm i -D @commitlint/config-conventional Lastly, we need to create commitlint config file named commitlint.config.js

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

Now we can test commitlint, for example if we run commitlint with text that does not follow the conventional commit pattern we will get an error

> echo fix | npx commitlint
⧗    input: fix
✖   subject may not be empty [subject-empty]
type may not be empty [type-empty]

✖   found 2 problems, 0 warnings
ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

Putting it all together

What we actually want is that for against every git commit we run, commitlint will lint our commit message, and abort if any errors comes along.

For this we only need to add the following husky hook

{
  .
  .
  "husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  }
}

Now if we try to commit with non-conventional message we should get commitlint's errors and the commit will be aborted

> echo hello >> temp_file
> git commit -am "fix"

husky > commit-msg (node v10.17.0)
⧗   input: fix
✖   subject may not be empty [subject-empty]
type may not be empty [type-empty]

✖   found 2 problems, 0 warnings
ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

husky > commit-msg hook failed (add --no-verify to bypass)

As mentioned in the last line of the output, you can suppress errors by appending --no-verify to our git commands, use with caution.