0

I followed this guide on creating git pre-commit hooks, and so far I really like the benefit it's given me.

However, I have a problem when I use it:

  1. I write some code, perhaps something that doesn't pass a rubocop inspection.
  2. I stage it, then attempt to commit it. The pre-commit hook works as intended.
  3. I go and fix the issues that rubocop reported.
  4. I save the changes, but forget to add it to the index.

When I commit, my script just takes the list of files changed that are in git diff --cached --name-only --diff-filter=AM, runs rubocop on each of them, and quits if there's any issues.

Here's my script:

#!/bin/sh

# Set the ruby environment from local/rvm, depending on your machine.
# http://stackoverflow.com/questions/17515769
if [ -d "$HOME/.rvm/bin" ]; then
  PATH="$HOME/.rvm/bin:$PATH"
  [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"

  if [ -f ".ruby-version" ]; then
    rvm use "$(cat .ruby-version)"
  fi

  if [ -f ".ruby-gemset" ]; then
    rvm gemset use "$(cat .ruby-gemset)"
  fi
fi

# http://codeinthehole.com/writing/tips-for-using-a-git-pre-commit-hook/
FILES_PATTERN='\.rb(\..+)?$'
FORBIDDEN='debug'

# Quit if no ruby files are being checked in.
RB_FILES=$(git df --cached --name-only --diff-filter=AM | grep -Ec $FILES_PATTERN)
if [ "$RB_FILES" = "0" ]; then
    exit 0
fi

git diff --cached --name-only --diff-filter=AM | \
    grep -E $FILES_PATTERN | \
    GREP_COLOR='37;41' xargs grep --color --with-filename -n $FORBIDDEN && \
    echo 'Please remove debugging statements before commiting.' && exit 1

# Pull in altered files, check with rubocop.
git diff --cached --name-only --diff-filter=AM | \
    grep -E $FILES_PATTERN | xargs rubocop -f simple | \
    grep 'no offences detected' && exit 0
# If it didn't exit 0 above, warn of issues, output results.
echo 'Rubocop has detected issues with your commit.' && \
    git diff --cached --name-only --diff-filter=AM | \
    grep -E $FILES_PATTERN | xargs rubocop -f simple && exit 1

I don't want to use sed to parse through the results of git diff. Is there an easier way to ensure that I'm checking the index, opposed to the file as it appears on disk?

My instinct tells me that there may be a way to check if there are any files that are both in git diff --name-only --cached --diff-filter=M and git diff --name-only --diff-filter=M, and just quit if that's the case.

Other suggestions are welcome.

yurisich
  • 6,991
  • 7
  • 42
  • 63

1 Answers1

2

If I understood your problem correctly, you need to have files as they are in index at hand.

To do so, you can do git stash -k (keeping index) before running your utility and git stash pop afterwards assuming it won't change anything so that no conflicts would appear.

Yorik.sar
  • 5,269
  • 2
  • 20
  • 20
  • It's a start. It doesn't evaluate anything that isn't on staging (which is good), but it does seem to throw away any changes that I forgot to stage, requiring me to rewrite them. – yurisich Aug 09 '13 at 21:27
  • `git stash pop` should bring back all changes made in working tree but not added to commit. Does it work for you? – Yorik.sar Aug 11 '13 at 06:48
  • Yeah I think I may have missed an `exit [0|1]` when running `git stash pop` or something, because it's much better now. My bash is terrible, thanks. – yurisich Aug 11 '13 at 21:38