Intro to Client Side Git Hooks
Tags: git, bash, beginners, tutorial
Published: 2019-08-12 15:20:09

---
title: Intro to Client Side Git Hooks
published: true
description: Create our own `pre-commit` hook as an introduction to custom client-side Git Hooks.
tags: git, bash, beginner, tutorial
---

Automation is everything when it comes to the process of deploying code. Even the smallest improvements over time can have a massive impact on the amount of manual processes you have to endure in building and shipping your software.

There are a lot of places to inject automation in the process of writing, building, and deploying code. When writing code on a team and on increasingly large projects those challenges and opportunities only grow. Things like linting, automated tests, and GitHub checks help you reduce [toil](https://landing.google.com/sre/sre-book/chapters/eliminating-toil/) when pushing, reviewing, merging, and delivering code.

<img width="976" alt="Screen Shot 2019-08-12 at 10 20 40 AM" src="https://user-images.githubusercontent.com/10855762/62872161-e1500e00-bcea-11e9-8490-0533a31fc589.png">

There are many solutions to these problems, and most focus on the most clear gatekeeper when it comes to deploying code - the build step. Your build should be able to detect problems automatically without human intervention. Everything from code style to performance to server health can be tested and certified in a build before you ever push code to production. The build enforces your rules and keeps developers honest in a way manual intervention never will be able to.

However, there are checks that can save even more time when pushed forward into the pre-build process.

A good example is developers committing and pushing bad code. Not *merging* bad code, but just simply writing bad code and commiting it to source control in their own feature branches. This might not seem like a huge problem - after all protected branches mean you can enforce correctness with build checks before approving merges - but it can introduce manual effort and cause frustration for developers, both of which are things that could easily be avoided with client-side git protection.

## Introducing Git Hooks

[Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) are a way to run scripts when certain Git commands are run. There are hooks on both client-side Git processes and server-side processes where you can react to changes in the Git workflow. We'll focus on the client-side hooks, where we can protect ourselves before we're even done with a commit.

### Client-side Git Hooks

The client-side hooks include hooks for multiple Git processes including committing, email workflows, and other processes like `checkout` and `merge`.  For now, let's focus on the commit workflow *(but [check out the rest of the list](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks), there's a lot you can do!)*.

* `pre-commit` - runs on `git commit` even before the commit message is generated
* `prepare-commit-msg` - runs before the commit message editor opens but after the default message is generated
* `commit-msg` - runs after message creation, to validate the temporary file containing the commit message

These client-side `commit` hooks really fall into two categories:

1. The code in your commit
2. Formatting/enforcing a proper commit message

We'll start with the first category, using `pre-commit` to analyze the code we're about to commit before we even consider completing the commit with a message.

### Writing a Git `pre-commit` hook

First, you need to designate a location for your hooks in your repository.  For our example, we're going to create a directory called `.githooks` in the root of our repository using these commands:

```bash
mkdir .githooks
cd .githooks
touch areYouSure.sh
```

Open up `areYouSure.sh` in your favorite editor. Writing a hook is both extremely simple and overwhelmingly open-ended. You just need a script that returns an exit code, 0 for success and non-0 for failure. Anything that isn't 0 aborts the commit altogether.

Let's write a very simple script that just asks our developer if they're sure they want to commit.

```bash
#!/usr/bin/env bash

# Check that we want to commit.

read -p "Are you sure you want to commit this (y/n)? " answer
case ${answer:0:1} in
    y|Y )
        exit 0 # If yes, success!
    ;;
    * )
        exit 1 # If no, sorry yo.
    ;;
esac
```

Finally, make sure you make this new file executable by running 

```bash
chmod +x .githooks/areYouSure.sh
```

Now let's figure out how we can have Git actually run this script automatically as part of the `pre-commit` hook.

### Add a custom `pre-commit` step

In our `.githooks` directory we'll create a new script to handle our custom `pre-commit` actions with these commands:

```bash
cd .githooks
touch pre-commit
```

Open the new `pre-commit` file in your favorite editor. Let's update it to do the basic things we need.

```bash
#!/bin/sh

# Specify the directory for the hooks.
# We'll use the current one (.githooks)
hookDir=$(dirname $0)

# Specify the hooks you want to run during
# the pre-commit process:
"$hookDir/areYouSure.sh"
# && "hookDir/add-your-own-scripts-here"
```

This script will specify the directory where we'll store our hooks (the current `.githooks` directory) and then it will specify the scripts that should run as part of `pre-commit`. In our example we just have the single `areYouSure.sh` script.

> You could code your script code directly into `pre-commit`. We are instead abstracting this code into its own script to enhance readability, reusability, and to enable us to easily add more scripts to our `pre-commit` step in the future.

Finally, make sure you make this new file executable by running 

```bash
chmod +x .githooks/pre-commit
```

### Tell Git to use our custom hooks

After you've completed the steps above, you should have a new `.githooks` directory containing the `pre-commit` script and our new custom script `areYouSure.sh`. We can go ahead and commit these files to source control. If you do this now, you'll notice that you don't get our 'are you sure' popup in the command line.

The reason our hooks aren't run, is we still need to configure Git to let it know we have a new location for `pre-commit` for this repository.  To do that, run this command in the root of your repo:

```bash
git config core.hooksPath .githooks
```

This tells Git to configure the hooks path for this repo to our custom `.githooks` directory. Now, whenever git runs the `pre-commit` step it will defer to our custom actions in our own `pre-commit` script.

Now, when you start a new `git commit`, you should see our `areYouSure.sh` prompt. A `Yes` answer should continue your commit (moving on to commit message steps) while a `No` answer should abort your commit.

### Next Steps

Congrats! 🎉  You have successfully written and configured a custom `pre-commit` hook in your repository!

Now, you can continue to improve your `pre-commit` workflow by simply adding new scripts to `.githooks` and specifying which hooks you want to run in your custom `pre-commit` script.

A few resources to help continue your Git Hooks journey:

* [GitHooks.com](https://githooks.com)
* [pre-commit](https://pre-commit.com) - a framework for pulling custom `pre-commit` scripts from remote repos
* Learn about [server-side git hooks to enforce policy](https://git-scm.com/book/en/v2/Customizing-Git-An-Example-Git-Enforced-Policy#_an_example_git_enforced_policy) and some starter [server-side scripts](https://github.com/github/platform-samples/tree/master/pre-receive-hooks)

Thanks for reading, if you have questions or thoughts on `pre-commit` hooks or want to share the awesome stuff you've done with git automation - let me know in the comments!

> *I originally published this post on AJ.dev, [read it there](https://ajkueterman.dev/posts/intro-to-custom-client-git-hooks-pre-commit/).*