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 when pushing, reviewing, merging, and delivering code.
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 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, there's a lot you can do!).
-
pre-commit
- runs ongit 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:
- The code in your commit
- 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:
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.
#!/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
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:
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.
#!/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 ourpre-commit
step in the future.
Finally, make sure you make this new file executable by running
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:
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
-
pre-commit - a framework for pulling custom
pre-commit
scripts from remote repos - Learn about server-side git hooks to enforce policy and some starter server-side scripts
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.
Top comments (0)