Git Hooks - Commit Example

Whats a Git Hook?

“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.” - https://www.atlassian.com/git/tutorials/git-hooks

Commit Example

My work colleague Chinmay Deshmukh wrote this productivity enhancing git hook. When it comes to git branches and commits our team have a standard of creating the branch as JIRATEAMPREFIX-123-short-description where 123 is the Jira ticket. Then another standard is to unclude the branch name as a prefix in each commit.

We do this manually, Chinmay has had enough of manual so did some bash to help with the commit message (and introduce me to the cool world of git hooks!)

The Script - Bash

Its a simple bash script, note this will only work on Mac or Linux where commands like grep, sed and cat are available.

1
2
3
4
5
6
7
8
9
10
#!/bin/sh
#
# Automatically adds the ticket number to the commit message.
# Please make sure that when naming the branch, apart from the ticket number, there are no other integers present in the name of the branch.
# Eg - "**-NUM-**" where 'NUM' is the ticket number

BRANCH_NAME=$(git branch | grep '*' | sed 's/* //')
TICKET_NUMBER=$(echo $BRANCH_NAME | sed 's/[^0-9]*//g')

echo "[FOO-${TICKET_NUMBER}]"' '$(cat "$1") > "$1"

Looking at each line:

BRANCH_NAME=$(git branch | grep '*' | sed 's/* //')

This is setting the local variable BRANCH_NAME as the result of git branch piped into grep '*' which will select the git branch pre-fixed with * and then finally that is piped into sed 's/* //' which is a stream editor that then replaces * (star space) with nothing.

The next line:

TICKET_NUMBER=$(echo $BRANCH_NAME | sed 's/[^0-9]*//g')

Sets a local variable TICKET_NUMBER and then uses the pipes in the result of BRANCH_NAME into sed 's/[^0-9]*//g' which is again the stream editor and this time its running a regular expression to find the numbers in BRANCH_NAME

The regex is [^0-9]* which is explained below

1
2
3
4
5
[           ~ the [ character marks the beginning of a character class.
^ ~ the caret (^) character matches the beginning of the string.
0-9 ~ the 0-9 characters represent the range of digits from 0 to 9.
] ~ The ] character marks the end of a character class.
* ~ the * character matches zero or more occurrences

Testing Each Line

Its good to understand how things work instead of blindly using them … says the dev that likes to run things past Google Bard 🤷

  1. Some setup
1
2
3
4
5
mkdir test
cd test
git init
touch test.txt ~ create the test.txt file
git status ~ shows the untracked file `test.txt` ... nooice
  1. As we are on master we can just run the checkout command -b command and it will create a new branch with our changes.
1
git checkout -b foo-123-i-did-a-thing-and-stuff
  1. Put the hook in folder test\.git\hooks and call it commit-msg. You will notice there is a commit-msg.sample file in there - nice of GIT to help us out!

  2. Run the git commit command as normal

1
2
git add .                        ~ stage our test.txt file for commit
git commit -m "I am batman" ~ -m means use this string as the commit message
  1. The hook runs automagically as its in the hooks folder named as GIT expects
1
[foo-123-i-did-a-thing-and-stuff] [FOO-123] I am batman

Note that you may need to mark the file as executable with chmod +x commit-msg

The Script - Powershell

I needed the above to work on Windows with updated shebang shenanigans for powershell. Additionally commands like grep, sed and cat are not natively avalible in Windows.

You can use the same steps as above and just replace the script as follows

1
2
3
4
#!/bin/sh
echo
exec pwsh './.git/hooks/commit-msg.ps1' $1
exit

Then create the file commit-msg.ps1 and populate as follows

1
2
3
4
5
6
7
8
#!powershell

$commitMessage = Get-Content $args[0]
$branchName = git branch --show-current
$ticketNumber = $branchName -replace "[^0-9]", ""

Write-Host "[FOO-$ticketNumber] $commitMessage"
exit 0

Note commands like touch are not avalible in Windows, I dunno maybe just create a text file with right click and select new? 💩

The Script - Python

My powershell script stopped working so I gave up and used Python

  1. Install Python globally https://www.python.org/downloads/windows/
  2. Use the script as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python

import subprocess
import re

commit_message_file = ".git/COMMIT_EDITMSG"
branch_name = subprocess.run(['git', 'branch', '--show-current'], capture_output=True, text=True).stdout.strip()
ticket_number = re.sub(r'[^0-9]', '', branch_name)

with open(commit_message_file, 'r+') as f:
commit_message = f.read().strip()
formatted_message = f"[FOO-{ticket_number}] {commit_message}"
f.seek(0)
f.write(formatted_message)
f.truncate()

This script is instead reading the message from COMMIT_EDITMSG, it could be changed to use the $1 parameter but I wrote these at different times so I wasnt thinking about the param.