Stashing Unstaged Changes in Git Pre-commit Hooks

Recently when writing a git pre-commit hook to verify the quality of prospective commits I realised my checks were running against the working directory which included unstaged changes (oops)!

To ensure you only check the code which is actually to be committed remember to first stash your unstaged changes and then re-apply these after your checks have completed. This helps to avoid bad code which would fail your checks from being committed due to checks passing because of additional unstaged changes.

This might look something like this:

git stash save -q --keep-index

# Perform testing...

git stash pop -q

# Exit with status code depending on tests...

This has one problem though - if there is nothing to stash but we then pop, then we could potentially apply previously stashed work by accident. To prevent this we can stash the changes with a unique message and then check for this specific stash entry before popping.

  1. Generate a unique stash name.
  2. Stash the changes.
  3. Retrieve the stash entry number associated with the stash name.
  4. If the number exists then pop that stash entry.
STASH_NAME=pre-commit-$(date +%s)
git stash save -q --keep-index $STASH_NAME

# Perform testing...

STASH_NUM=$(git stash list | grep $STASH_NAME | sed -re 's/stash@\{(.*)\}.*/\1/')

if [ -n "$STASH_NUM" ]
    then
    git stash pop -q stash@{$STASH_NUM}
fi

# Exit with status code depending on tests...