October 8, 2012

Groovy Goodness: Using Groovy for Git Hooks

Git supports hooks, which are scripts that are fired when certain events happens. The scripts are simply shell scripts and we can use Groovy to run those scripts. We must make Groovy the script language with the hash-bang (#!) header in the Git hook script file. And then we are ready to go and use Groovy as the script language for the Git hooks.

Git hooks are placed in the .git/hooks directory of our project. We create an example script that will use growlnotify to create a notification message with information from the Git commit action. growlnotify is a command-line tool for Mac OSX to send out messages to Growl. Other operating systems also have tools to create notification message from the command-line.

We must create the file post-commit in the directory .git/hooks. The file must have execute rights: $ chmod +x post-commit. In the first line of the file we make sure Groovy is used. In the rest of the script we use Groovy to invoke git log and get information about the commit. Then we create a message and invoke growlnotify with the correct arguments so Growl can show the message.

#!/usr/bin/env groovy

// Arguments for git log command.
def logArgs = ['max-count': '1', 'pretty': 'format:%an commited %s {%h}']

// Invoke git log command.
def gitLog = logArgs.inject(['git', 'log']) { cmd, k, v -> 
    cmd << "--$k=$v" 

// Get git log message to be used as notification message.
def message = gitLog.text

// Set icon and title for message.
def iconPath = '/Users/mrhaki/Pictures/git-icon-black.png'
def title = 'Git commit'

// Notify user of commit with growlnotify.
def notifyArgs = [message: message, title: title, image: iconPath]
notifyArgs.inject(['growlnotify']) { cmd, k, v ->
    cmd << "--$k" << v

In the following screenshot we see the output shown with Growl:

Some script hook files take an argument. We can use the argument in our Groovy code and write code to handle it. In the following example we check if the commit message is empty. If the message is empty we return with an exit code that is not 0. Git will terminate the commit until the script return 0. We write a simple implementation of the commit-msg hook:

#!/usr/bin/env groovy

import static java.lang.System.*

// First argument is the name of the 
// temporary commit message file.
def msgFileName = args[0]

// Get the commit message file.
def msgFile = new File(msgFileName)

// Read commit message from file.
def commitMessage = msgFile.text

if (!commitMessage) {
    err.println 'Commit message is empty'
    exit 1

exit 0

(Written with Groovy 2.0.4 and Git