DevOps has become an integral component in the world of software development for firms trying to simplify their development and deployment processes. Among the several DevOps technologies available, there is one that is sometimes neglected yet is really effective.
That vital technology is none other than “Git Hooks.”
Git Hooks are great tools to automate tasks, enforce coding standards, perform continuous deployments, and run tests.
Let us see how we can use Git Hooks to revolutionize our DevOps practices!
Let us look at the official definition first -
Hooks are programs you can place in a hooks directory to trigger actions at certain points in git’s execution.
Fortunately, that is a really simple definition!
Let us try to address some of the questions that readers might have about the definition.
Q) What is a Hooks directory? Where is it located?
A hooks directory is a directory in a Git repository that contains executable programs or Hooks that Git will execute. By default, the hooks directory is $GIT_DIR/hooks
. Users can also configure it using the core.hooksPath
configuration variable.
Q) What are Git’s execution points?
Git execution points are steps in the Git workflow at which hooks can be run. Pre-commit, Post-commit, Pre-push, Post-receive, Pre-rebase, and Post-merge are some examples of Git execution points.
To sum up this section, we can have the following definition for Git Hooks -
Git executes scripts known as "hooks" before or after particular operations like committing, pushing, or merging code. They allow you to automate tasks, enforce policies, and interact with the codebase during the development process. Git hooks are stored in the
.git/hooks
directory of your Git repository
Let's attempt to build a straightforward Git hook that would impose the "TASK*" regular expression on any commit message.
Create a new directory git_hooks_tut
, and initialize a new git repository inside it.
~/projects$ mkdir git_hooks_tut
~/projects$ cd git_hooks_tut
~/projects/git_hooks_tut$ git init
Initialized empty Git repository
Let us go into the hooks directory and investigate its content.
~/projects/git_hooks_tut$ cd .git/hooks
~/projects/git_hooks_tut/.git/hooks$ ls
applypatch-msg.sample pre-applypatch.sample pre-push.sample
commit-msg.sample pre-commit.sample pre-rebase.sample
fsmonitor-watchman.sample pre-merge-commit.sample pre-receive.sample
post-update.sample prepare-commit-msg.sample update.sample
The hooks directory comes with some sample scripts. The .sample
extension stops them from running by default. All you need to do to "install" a hook is to get rid of the .sample
extension.
Or, if you're starting from scratch with a new script, you may just add a new file with a name that matches one of the filenames listed above, but without the .sample
extension.
For our use case, we will need to have a commit-msg hook. Go ahead and create a new script named commit-msg
.
~/projects/git_hooks_tut/.git/hooks$ touch commit-msg
Let us add the logic to ensure our commit message pattern to commit-msg
script.
#!/bin/sh
commit_msg_file=$1
commit_msg=$(cat "$commit_msg_file")
# Check if the commit message starts with "TASK"
if ! echo "$commit_msg" | grep -q "^TASK"; then
echo "Commit message must start with 'TASK'"
exit 1
fi
Lastly, make the commit-msg
script executable. Non-executable scripts are skipped by git even if they are present in the hooks directory.
~/projects/git_hooks_tut/.git/hooks$ chmod +x commit-msg
And with that setup, our hooks are complete! Let us test it now.
We will now create a new file and try to commit it; first, with an invalid message format, and then with a valid message format.
~/projects/git_hooks_tut/.git/hooks$ cd ../..
~/projects/git_hooks_tut$ touch README
~/projects/git_hooks_tut$ ls
README
~/projects/git_hooks_tut$ git add README
~/projects/git_hooks_tut$ git commit -m "Added Readme File"
Commit message must start with 'TASK'
~/projects/git_hooks_tut$ git commit -m "TASK-0000: Added Readme File"
[master (root-commit) 7f3648a] TASK-000: Added Readme File
Things are working ideally!
Git allows us to create hooks for a number of execution points. Some of these are as follows -
Pre-Commit Hook: This hook is executed before a commit is created. It allows us to validate the changes that are being committed.
Pre-Receive Hook: The pre-receive hook is run on the remote repository prior to any references being modified, allowing you to apply custom rules or policies.
Post-Receive Hook: This hook is also executed on the remote repository after the updation of the references. It can be used to send notifications and/or perform additional tasks.
Pre-Push Hook: This hook is executed before a push is made. This can be used to enforce certain policies that discourage pushing certain types of commits.
Prepare-Commit-Msg Hook: The prepare-commit-msg hook is executed after a commit message is created, allowing you to modify or enhance the commit message.
There are various other hooks present to better customize Git, they can be found on Git docs.
Git hooks, if used properly, are a tool of great potential! We, the developers, often undermine the strength of such tools that could solve many complex tasks.
Employing Git Hooks enhances DevOps at any level could be a great way for organizations looking to integrate DevOps in their development cycles.
Congratulations on reaching this far! I hope you learned something new today.