Pre-receive hooks at glance
Git hooks are custom scripts that are fired during various Git operations. Some, like pre-commit hooks, are executed on your workstation before your changes are committed to the repository history. Some are executed server-side, like post-receive hooks that can be used to trigger updates to external services. Pre-receive hooks are executed on the server after the changes are received but before they are accepted. It is generally used to accept or reject Git commits based on specific criteria, which we will explore right now.
When to use Pre-Receive hooks
Generally, pre-receive hooks can be anything that can run server side and return an exit code of 0–when the commit is valid, and a non-zero exit code–to reject the commit. As the script will run for every single push, it needs to be lightweight and run quickly. This makes pre-receive hooks more suited for certain tasks than others.
For instance, pre-receive hooks are great to handle a commit’s metadata, and as such work well for tasks such as:
- Enforce specific commit messages guidelines.
- Check if the author is using their corporate email.
- Block specific file extensions.
- Or even Restrict pushes by IP range!
They do not work so well for uses that expect a “working copy” of the Git repository where files are accessible directly. This applies for tasks such as credentials scanning or coding style checks. For the former, pre-commit hooks are recommended, as they will make sure that compromised credentials never make it to the Git history. For the latter, status checks are preferred. This will allow a submitter to push additional commits to make their code compliant, without imposing additional constraints on intermediate commits or work in progress.
Similarly, as execution speed is key, any form of validation that relies on API requests or long computations would work better as a status check.
Implement a pre-receive hook
First you will need to write a script. Pre-receive hooks process STDIN output–the Git push–so the script will be contained in
while loop. For instance, using bash:
whilereadOLDREV NEWREV REFNAME;do [script contents] done
Once armed with your script, you need to make sure you can run it on your GitHub Enterprise instance. Pre-receive hooks environments are self-contained and cannot access files or utilities on your instance. Unless you use third-party tools or utilities, the default pre-receive environment should be enough. It is included in every GitHub Enterprise instance and already has the following utilities:
If you require specific tools, you will need to create your own 64-bit Linux chroot environment, either using Docker to generate a chroot archive or by creating the
chroot archive manually. Note that while Docker can be used to create compatible environments, it is not used server-side and your pre-receive hook is not running in a Docker image.
Once you’ve generated and uploaded your archive to your GitHub Enterprise instance, commit your pre-receive hook to a dedicated repository–do not include it in an existing repository!
Finally, you need to define a scope for your pre-receive hook. It can be applied to every repository or a select few, disabled or enabled by repositories administrators, enforced–which means the exit code will dictate whether the push will be rejected– or not.
I hope this has helped clarify what pre-receive hooks are, their value, and how to use them. If you have any questions, please feel free to comment below. Also, stay tuned for a more in-depth look at when not to use pre-receive hooks, coming up in a new GitHub Enterprise Best Practices article soon!