Git Hooks: A Simple Guide

Git Hooks: A Simple Guide

As of January 2023, Github reported having over 100 million developers and more than 200 million Git repositories, Git hooks have always been in every developer's Git repository which stays hidden without the knowledge of the developer.

This article will teach you everything you need to know about Git hooks and how to get started with using it in 5 minutes, so let’s get started now.

What Are Git Hooks

Git hooks are scripts that run on a periodic basis and are usually run automatically by your Git server., allowing you to perform actions or revert changes in your Git repository. They're most commonly used for preventing merge conflicts and reverting commits, but they can be used for more than just those things.

Locate Hidden Hooks in Your Repository

To get started, create a sample Git repository:

$ mkdir <repo-name>
$ cd <repo-name>
$ git init

Take a look at the .git/hooks directory to see some default scripts:

$ ls .git/hooks/

Types Of Git Hooks

Git hooks can be grouped into two main types:

  1. Client-Side Hooks: Client-side Git Hooks also known as local Git Hooks are prompted by events on the local repository, such as when a developer commits or merges code.

  2. Server-Side Hooks: Server-side Git Hooks also known as remote Git Hooks are run on the network hosting the repository, and they are prompted by events such as receiving pushes.

Examples Of Client-Side Hooks

In this section we will talk about six(6) main client-side hooks:

pre-commit

The pre-commit hook is run first before you even type in a commit message. It’s used to inspect the snapshot that’s about to be committed, to see if you’ve forgotten something, to make sure tests run, or to examine whatever you need to inspect in the code. Exiting non-zero from this hook aborts the commit, although you can bypass it with git commit --no-verify. You can do things like check for code style (run lint or something equivalent), check for trailing whitespace (the default hook does exactly this), or check for appropriate documentation on new methods.

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 takes a few parameters: the path to the file that holds the commit message so far, the type of commit, and the commit SHA-1 if this is an amended commit. This hook generally isn’t useful for normal commits; rather, it’s good for commits where the default message is auto-generated, such as templated commit messages, merge commits, squashed commits, and amended commits. You may use it in conjunction with a commit template to programmatically insert information.

commit-msg

The commit-msg hook takes one parameter, which again is the path to a temporary file that contains the commit message written by the developer. If this script exits non-zero, Git aborts the commit process, so you can use it to validate your project state or commit message before allowing a commit to go through. In the last section of this chapter, we’ll demonstrate using this hook to check that your commit message is conformant to a required pattern.

post-commit

The post-commit hook is called immediately after the commit-msg hook. It can’t change the outcome of the git commit operation, so it’s used primarily for notification purposes.

The script takes no parameters and its exit status does not affect the commit in any way. For most post-commit scripts, you’ll want access to the commit that was just created. You can use git rev-parse HEAD to get the new commit’s SHA1 hash, or you can use git log -1 HEAD to get all of its information.

post-checkout

The post-checkout hook works a lot like the post-commit hook, but it’s called whenever you successfully check out a reference with git checkout. This is nice for clearing out your working directory of generated files that would otherwise cause confusion.

This hook accepts three parameters, and its exit status has no effect on the gitcheckout command.

  1. The ref of the previous HEAD

  2. The ref of the new HEAD

  3. A flag telling you if it was a branch checkout or a file checkout. The flag will be 1 and 0, respectively.

pre-rebase

The pre-rebase hook runs before you rebase anything and can halt the process by exiting non-zero. You can use this hook to disallow rebasing any commits that have already been pushed. The example pre-rebase hook that Git installs does this, although it makes some assumptions that may not match with your workflow.

Examples Of Server-Side Hooks

In this section, we will talk about three(3) main server-side hooks:

pre-recieve

The first script to run when handling a push from a client is pre-receive. It takes a list of references that are being pushed from stdin; if it exits non-zero, none of them are accepted. You can use this hook to do things like make sure none of the updated references are non-fast-forwards, or to do access control for all the refs and files they’re modifying with the push.

update

The update script is very similar to the pre-receive script, except that it’s run once for each branch the pusher is trying to update. If the pusher is trying to push to multiple branches,pre-receive runs only once, whereas update runs once per branch they’re pushing to. Instead of reading from stdin, this script takes three arguments: the name of the reference (branch), the SHA-1 that reference pointed to before the push, and the SHA-1 the user is trying to push. If the update script exits non-zero, only that reference is rejected; other references can still be updated.

post-receive

The post-receive hook runs after the entire process are completed and can be used to update other services or notify users. It takes the same stdin data as the pre-receive hook. Examples include emailing a list, notifying a continuous integration server, or updating a ticket-tracking system – you can even parse the commit messages to see if any tickets need to be opened, modified, or closed. This script can’t stop the push process, but the client doesn’t disconnect until it has been completed, so be careful if you try to do anything that may take a long time.

Why You Need Git Hooks

  1. Automation - Git hooks are scripts that run automatically every time a particular event occurs in a Git repository. They let you customize Git's internal behavior and trigger customizable actions at key points in the development life cycle. So basically, Like any other process, Git also follows a process

  2. To increase productivity - Git hooks can greatly increase your productivity as a developer. For example, being able to push to your staging or production environment without ever leaving Git is just plain awesome. Update your code, make a commit, and push, and your code can be running in any environment you specify. No need to mess with SSH or FTP.

How To Use Git Hooks

In this section, we will write a Git hook that sends emails after every successful commit, we can achieve this using the post-commit hook, let’s get started.

Earlier in this section, we were able to locate hidden hooks in our code you are expected to follow the instruction to move forward.

  1. Create a post-commit file

To create this file make sure you are in your .git/hooks directory

$ touch post-commit
  1. Set the permissions of the post-commit file to 755
$ chomod 755 post-commit
  1. Add #!/bin/bash python and the send email script to the post-commit file.
#!/bin/bash python

import smtplib

# creates SMTP session

s = smtplib.SMTP('smtp.gmail.com', 587)

# start TLS for security
s.starttls()

# Authentication

s.login("sender_email_id", "sender_email_id_password")

# message to be sent

message = "Message_you_need_to_send"

# sending the mail

s.sendmail("sender_email_id", "receiver_email_id", message)

# terminating the session
s.quit()

You will notice in the script we used python to send mail, you can also use any scripting language of your choice using this format #!/bin/bash <scripting language>.

Conclusion

In this article, we learned about Git hooks, common types which are grouped into two(2), and examples of client and server-side hooks.

We also looked at how we can locate hidden hooks in our Git repository and were able to write a hook that sends mail after every successful commit.