Jan 30 Git Hooked

There are many ways to ensure code quality, often in some form of linting and formatting tools alongside a CI tool (TravisCI, Jenkins, Bitbucket pipelines, etc). Something small like a missing semi-colon or inconsistent spacing may not change how your code runs in development, but once you minify for production it could cause errors.

So what if you want to ensure your code passes before you push and blast out that CI build error on Slack, without having to remember to run your linting or code formatting tools manually?

Enter: Git hooks.

Git hooks are scripts that are run based on triggers that get fired at various points in your Git workflow, most commonly before or after committing, pushing, or receiving code. Since this is Javascript January, we’ll stick to the theme, but you can use these same patterns for any language or project you may be working on. This post assumes that you know about linting, especially in Javascript land. If not, check out ESLint and Prettier, my favorite linter and formatter.

If you’re already a Git hook whiz, skip ahead to check out Husky to learn about setting up hooks through your project's package.json.

How to Use a Git Hook

Your git repository is automatically initialized with some example hooks. They live in the root of your repository inside the .git/hooks directory and are named based on the type of trigger you want to run the script on. Your script file can be any executable, though we’ll use shell scripts for our examples.

To use a git hook, simply create the script and make sure it’s executable (chmod +x <filename>). If you’re using one of the sample files, make sure to remove the .sample extension.

Pro-tip: If you want to run the same script on different triggers, simply create the first trigger script and symlink the duplicates.

Your First Git Hooks

The following two examples are a couple of my go-to hooks that any Javascript project I’m working on has. Simple add these to your .git/hooks directory in the appropriate file and make sure the scripts are executable.

Lint and Format Your Code before committing

This hook runs before you commit your code and will only run on your staged Javascript files. It runs Prettier for code formatting then runs ESLint to check for any linting errors. If it passes, your commit will go through. Otherwise, it will alert you and stop the commit process so you can make changes.

Checking Dependencies When Checking Out

This hook runs after you checkout a new branch or commit. It checks to see if your package.json has changed in order to check if any dependencies differ. This works great if you’re working on a feature branch that has new dependencies and you need to switch around. It looks for changes in the whole file and doesn’t account for differences in things like version numbers, so keep that in mind.

Managing Git Hooks

Manual Hook Wrangling

Manually managing your git hooks is one of easiest way to get started, but makes sharing hooks a bit more difficult (don't worry, we'll talk about tips for this later).
Git hooks can be easily managed locally by using a .git-template directory. You can store all of your “default” scripts inside of your template directory and they will automatically be added to your repository each time you run a git init, as long as an existing hook with the same name doesn’t already exist. You can run git init either when starting a project or in an existing project to grab any new Git hooks.

Sharing Git Hooks

The traditional way of managing Git hooks has some drawbacks, particularly that since they’re stored in your .git directory by default. This means they aren’t tracked in your repository.

You could set up a system where your hooks are tracked outside of your .git directory, say in a .hooks directory, then set up a script to symlink your files into your .git/hooks directory (check out a working example here). Alternatively, you can configure Git to simply pull hooks from a different directory altogether by running git config core.hooksPath .hooks (check out another example here).

Side-Stepping Git Hooks Altogether

If you’ve gone through the trouble of setting up linting or code formatting, you’ve probably already set up a script to run with something like npm run lint. With the help of a tool called Husky, we can leverage our scripts that we’ve already set up by using them as Git hooks.