Making commits the right way with hooks
Tags: git, changelog, tutorial, javascript
Published: 2020-08-27 00:10:41

# Introduction

This tutorial will show you how to lint staged code and setup git commit hooks with [husky](https://github.com/typicode/husky) so that you never have to spend time on the boring stuff!

# Adding Packages

First things first let's start by adding the necessary packages.

```
yarn -D husky lint-staged commitizen
```

Feel free to view each of these repos in-depth.

* [husky](https://github.com/typicode/husky)
* [lint-staged](https://github.com/okonet/lint-staged)
* [commitizen/cli](https://github.com/commitizen/cz-cli)

## Husky

[Husky](https://github.com/typicode/husky) allows us to use call scripts using `git-hooks` within our projects. There's a [huge list](https://git-scm.com/docs/githooks) of hooks that cover nearly every part of git. For now, we will just use `pre-commit` and `prepare-commit-msg`.

Add the following to your `package.json` file.

```
"husky": {
  "hooks": {
    "pre-commit": "echo Hello World!"
  }
}
```

You can add any `git-hooks` within `hooks`. The key must match a git-hook name, and the value can be any script or command. Committing the changes above should output the following to your console.

```
husky > pre-commit (node v12.16.1)
Hello World!
```

## Lint-Staged

[Lint-staged](https://github.com/okonet/lint-staged) is specifically made to as the name implies, lint staged code before it gets committed.

If you don't use a linter you can skip this step. Although I highly recommend that you start as they are invaluable when used correctly.

Now, add the following to your `package.json` file.

```
"lint-staged": {
  "*.{js}": "eslint --ext .js --ignore-path .gitignore"
}
```

`"*.{js}"` will run the specified command within each file that ends in `.js`. You can add any number of file types. `"*.{js,jsx,ts,tsx}"` will run on all React and TypeScript files.

`eslint --ext .js --ignore-path .gitignore` lints any `.js` packages. Similar with the key, you can list any number of `--ext` files.

You can also run multiple commands by changing the value to an array. So if we want to use [Prettier](https://prettier.io/) to format our code we could do something like this.

```
"*.{js}": [
  "prettier --write",
  "git add",
  "eslint --ext .jsx --ext .js --ignore-path .gitignore"
]
```

After adding the above we need to let husky know to run the command.

```
// Change this
"pre-commit": "echo Hello World!"

// To this
"pre-commit": "lint-staged"
```

Now any staged files ending with `.js` will be linted. The best part is that your code will fail to be committed if any commands fail. Now you can ensure that no one, including yourself, is pushing bad code.

## Commitizen

[commitizen/cli](https://github.com/commitizen/cz-cli) is an amazing tool that walks you through creating a git commit. Then formats it to [conventional-commit](https://www.conventionalcommits.org/en/v1.0.0/) standards.

Get started by running the following command to install the package.

```
yarn add -D cz-conventional-changelog --save-exact
```

Now add this to your package.json file.

```
"config": {
  "commitizen": {
    "path": "cz-conventional-changelog"
  }
}
```

You should now be able to run `yarn cz` to start the cli tool! It'll walk you through a bunch of steps to create a conventional-commit.

Now we just need to apply it to husky. Thankfully commitizen shows us how to call the cli tool with git hooks using `exec < /dev/tty && git cz --hook || true` as the hook command. The git-hook we'll apply it to is `prepare-commit-msg`.

Your husky config should look something like this.

```
"husky": {
  "hooks": {
    "pre-commit": "lint-staged",
    "prepare-commit-msg": "exec < /dev/tty && git cz --hook || true"
  }
}
```

That's it! Now all of your committed code will be linted, and force you to create a conventional-commit! Life becomes a little easier knowing that all committed code follows the same rules.

## Ending Notes

There is a lot more you can do with Husky/Commitizen that isn't covered in this tutorial. I highly recommend you check their docs!

One additional feature that can be used with conventional-commits is generating changelogs for your projects!

Thanks for reading!