Gruntjs tasks and git pre-push

– 07/23/13

Oftentimes I am working on a gruntjs-based project and have found it useful to run my default grunt task prior to pushing my code to my remote git repository. My default grunt task typically runs a jshint task, a qunit task, a concat task, and an uglify task – all of which you want executing without errors before your code makes it out into the wild.

And, luckily, git has a way to automatically run arbitrary bash code at various places in your git workflow using what’s called git hooks.

Make the hook

Fire up your terminal and run the following commands in the root of your repository

touch .git/hooks/pre-push      # create the file; hooks directory location may vary 
chmod a+x .git/hooks/pre-push  # make it executable

Next, place the following code inside the pre-push file and paste in the following code:

#!/bin/sh

# check for how many uncommitted changes we have
# stash changes
# run grunt task 
# restore stashed files if anything was stashed
# exit with error if grunt fails

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

echo "Running pre-push hook on: " $NAME

# don't run on rebase
if [ $NAME != '(no branch)' ]
then
  
  CHANGES=$(git diff --numstat | wc -l)
  CHANGES_CACHED=$(git diff --cached --numstat | wc -l)
  TOTAL_CHANGES=$(($CHANGES + $CHANGES_CACHED))

  git stash -k   # the "-k" makes git stash all changes, staged & unstaged 
  grunt 

  RETVAL=$?

  if [ $TOTAL_CHANGES -ne "0" ]
  then
    echo "Popping" $TOTAL_CHANGES "changes off the stack..."
    git stash pop -q
  fi      

  if [ $RETVAL -ne 0 ] 
  then
    echo "Grunt task failed, exiting..."
    exit 1
  fi

  echo "Complete."
fi

The code here is actually pretty straight-forward: any time we run git push, the pre-push script gets executed. The script counts the amount of uncommitted changes, stashes the changes, runs the default grunt task and if the grunt task fails, the stash is popped and we exit 1 which tells git to fail the push command. If the grunt task does not fail, the push continues on.

What are your thoughts? Let me know.