How to automate your work using Git’s add-on scripts?
Git Hooks Brief
Do you know you can automate a part of the work that you do every time during your development?
This includes running lint, test cases, etc. before committing and pushing the code. Git provides an excellent option to achieve this.
That’s called Git Hooks
Git Hooks, being an advanced topic do you know why I call it as Dark part of Git?
Because, being a powerful feature it was not widely adopted by many software development teams (including me, but I follow an alternative. Read further to know what is it & why I’m using that).
Let’s try to explore the below items in this blog
What is Git Hooks?
Why most development teams are not adopting Hooks in their development process?
What is Git Hooks?
Git Hooks is a feature of git that allows to run custom scripts on the occurrence of certain events at the git lifecycle. Some of the events include before-commit, after-commit, before-push, etc.
Why do we need Git Hooks?
Hooks is the tool that makes it much easier for developers to adhere to certain guidelines. These guidelines include running lint before committing, running test cases before pushing the code, etc. Git Hooks can be configured to make the action fail (by returning a non-zero exit code) if something was broken or not good (test case/lint failure).
Where can I find the Hooks configured on my repo?
Git Hooks comes pre-installed with the git repository. Whenever you initialize a git repo ( git init
) or clone a repo from any remote server ( git clone
). You can find all the hooks inside .git/hooks
directory from the root repo.
Every hook will be configured as a file. By default, git creates 12 sample hooks file listed below. The files that end with .sample
are example hook files generated by git.
Okay. That’s fine. I hope your next question will be,
What are all the available hooks which I can use?
Client Side Hooks
prepare-commit-msg
pre-commit
applypatch-msg
commit-msg
fsmonitor-watchman
pre-applypatch
pre-merge-commit
pre-push
pre-rebase
Server Side Hooks
pre-receive
update
post-update
This is not the entire list of all available Git hooks. These are the sample hook files that will be available by default on all git repositories. Head over to Git's official documentation to have a look at all supported hooks.
How to configure a hook?
Let’s take a look at a couple of examples of using it
**prepare-commit-msg**
The prepare-commit-msg
hook is run before the commit message editor is fired up but after the default message is created. It lets you edit the default message before the commit author sees it. This hook is generally used to template the commit message.
The parameters of this hook are,
Path to the file that holds the commit message
Type of commit
Commit SHA-1, if this is an amended commit.
For example, I used to prepend my name in all the commits I made. We follow this across our organization.
Example list of commits having my name ([Arunachalam]) at the beginning
As mentioned earlier, we need to remove .sample
from the file name. Find the code below to template your name while committing
We need to make the script executable. So, running chmod +x
on the file
Made prepare-commit-msg hook file executable
Let’s try to commit our change,
Change a file to test prepare-commit-msg hook
The Nano text editor (system default) opens up immediately after I ran git commit
. From the below screenshot, you can see my name is already written to the commit message file (COMMIT_EDITMSG) and I just need to add the commit message.
My name was prefilled as a template when trying to commit
After saving and exiting the commit message (COMMIT_EDITMSG) file
That’s it. We have successfully setup prepare-commit-msg
hook.
Let’s have a quick look at another simple example with a failure scenario.
The action will be failed if the hook(except a few) returns non-zero values.
Let’s make pre-push
hook fail by returning a non-zero value
pre-push hook will fail due to returning a non-zero value
I’ve 35 commits in my repo (haven’t pushed from the beginning of my blogging series). So, I’m not making any new commits and going to push the existing commits.
Failed to push due to non-zero exit code on pre-push hook
Let’s make pre-push
hook to pass by returning zero
Let’s try to push the commits again and verify if it works.
Commits pushed to the remote repo
Hooray!!!! Our commits are pushed to the remote repo.
The only concern is the error message which we received when exiting with a non-zero value was not so user-friendly. It did not say that it has failed due to an error thrown from pre-push
hook.
error: failed to push some refs to 'git@github.com:arungogosoon/Git-Project.git'
Let’s jump into the next section of our blog
Why most development teams are not adopting Hooks in their development process?
There are many reasons to answer this question. However, I’m outlining a few of the most common causes.
Hooks are local to any given Git repository and are not synced with the remote repository. This means, if you try to clone again, you’ll not see your hooks there. So, it’ll be challenging to manage them across the development team. But, we can overcome this with 2 workarounds.
1. Git allows us to move the hooks folder outside of
.git
folder. We can create a symlink (shortcut) from.git/hooks
folder to the folder where we moved the hooks files. With this approach, we can track the changes in the hooks file and it’ll be synced with the entire team.
2. By using some kind of alternative packages likehusky
.[husky](https://typicode.github.io/husky/#/)
is anpm
package which can be added innode
project.husky
helps us to configure commands to be executed on git hooks in the project configuration file. i.e.,package.json
fileThough we find workarounds to sync the hooks file, the developer can easily skip the hooks validation by adding
--no-verify
with every git command. With this in mind, it’s best to think of Git hooks as a convenient developer tool rather than a strictly enforced development policy. Unless a server-side verification is set up, these cannot be verified.While git hooks are a compelling guardrail to help enforce quality, like any guardrail, they also come with some downsides including slowing down well-disciplined developers, and withholding opportunities for less-disciplined developers to gain that discipline. When a hook is configured to run test cases on every commit, it reduces developer productivity due to the long-running test cases. This happens especially with the compiling & transpiling languages (Eg. Java, Typescript, etc. ). Rather than focusing effort on guardrails to prevent developers from doing the “wrong thing”, focus on building discipline so that developers will learn to do the “right thing”.
Q & A
I have limited experience of using git hooks
with my team.
But, I have an interesting question raised by Kumar from my team.
He asked, “I’m bad at shell scripting, but good at scripting in Python. Is there a way, I can run this hook in python?”
Even I don’t when he asks this question. But, we did a quick search immediately and found that it’s possible.
Just by replacing #!/bin/sh
with the python interpreter location ( #!/usr/bin/env python
) will work. We even tested this and this works fine.
References
Hope you enjoyed reading this article. Give a clap 👏 if you like this article. Subscribe to our newsletter to receive more such insightful articles that get delivered straight to your inbox.
Subscribe to my newsletter
Read articles from 5 Mins Learn directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by