Many Git users, I believe, are familiar with the situation where, after making a commit, something unnecessary is found to have been included in the commit, or the committed code fails tests. Sometimes, this code even ends up being pushed directly to origin.

Who could forget the ‘Push changes immediately to origin/branch_name’ checkbox in SourceTree: Button Push changes immediately to origin/branch_name в SourceTree

I think almost everyone has considered the logical solution of using Git hooks. But is it really that convenient?

To set up Git hooks locally, you need to go into the hidden .git/hooks directory, find the necessary hook, and insert the commands for code checking. It seems simple enough. But that’s only as long as the hooks are needed by you alone. What if you want the hook to be set up automatically right after the project is deployed? And so that a new developer on the project doesn’t stress out the CI system for no reason just because they missed a console.log?

Fortunately, there’s a very convenient solution—a handy npm package called husky. You can install it like any other package using the command

npm install husky --save-dev

After installation, all that’s left is to configure our hooks. To do this, simply add a new husky section to your package.json and specify the necessary commands for the hooks:

{
    "name": "demo",
    "dependencies": {},
    "devDependencies": {
        "husky": "^1.1.2"
    },
    "husky": {
        "hooks": {
            "pre-commit": "gulp lint",
            "pre-push": "gulp test:unit",
            "...": "..."
        }
    }
}

After this, when you attempt to make a commit, the lint command will run first. There’s no need to worry about the path to Node.js, running scripts from the ./node_modules/.bin/gulp test folder, or anything else. Once all dependencies are installed, the hook will be applied automatically.

If you want to change any command, simply make the corresponding changes in package.json and commit those changes, after which the hook will be updated for all developers.

The library also allows configuration through a separate file like .huskyrc, .huskyrc.json, or .huskyrc.js. However, in my opinion, for such a small amount of configuration, it’s unnecessary to place it in a separate file at the root of the project.

How Does It Work?

All npm modules have the capability to run scripts after certain events. For example, after a package is installed (you can read more about this in the documentation). Husky uses the postinstall event, which is always executed after a package is installed, to register its script. This script searches for the .git directory in the parent directories and sets the package’s main module to run on all available hooks. When a hook is triggered later, the Husky module looks for all possible hook command definitions in package.json, .huskyrc, or other files and executes them. That’s the whole magic.