About debugging and something else
As Ruby on Rails developers, we use some commands that help us debugging applications like Rails.logger.debug, binding.pry or things such as a simple puts command. The lists gets bigger if we consider console.log or alert for Javascript.
The problem appears when we finish debugging and we forget to remove those lines. We include them in a commit or ever worse: we push them to our remote repo.
I don't really remember how many times I've pushed code with one or more lines of debugging information, so I decided to look up for a way of avoiding making the same mistake again.
Put scripts to work for you
Fortunately, Git has a very powerful native tool called hooks that can help running scripts before, or after, some specific moments during the Git workflow.
What is a Git hook?
A Git hook allows you to execute an script before performing some common actions in the Git workflow, such as doing a commit, pushing to a remote server or rebasing a branch.
In Git 1.8.2, the available hooks are:
- applypatch-msg
- commit-msg
- post-update
- pre-applypatch
- pre-commit
- prepare-commit-msg
- pre-push
- pre-rebase
- update
We can find some sample scripts in all of our Git repos if we take a look at .git/hooks
Git adds the .sample extension so they are not enabled by default
One of the hooks I've been using during the last week gets executed every time I do a git commit to verify using grep if any of the files I'm about to commit contains one of the 'banned' words from the $LIST variable: if found, the script will exit with a status of 1, aborting the commit.
# Based on the git hook created by Mark Story
# http://mark-story.com/posts/view/using-git-commit-hooks-to-prevent-stupid-mistakes
# !/bin/sh
LIST="puts\|debugger\|biding.pry\|logger"
if git rev-parse --verify HEAD >/dev/null 2>&1; then
against=HEAD
else
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
for FILE in `git diff-index --name-status --cached $against -- | cut -c3-` ; do
# Check if the file contains one of the words in LIST
if grep -w $LIST $FILE; then
echo $FILE." has one of the word you don't want to commit. Please remove it"
exit 1
fi
done
exit
As you can see, we can create our own Git hooks and make them as complex as we need: we can run our test automatically and abort a push if the suite doesn't pass by using the pre-push hook and the following script:
# !/bin/sh
SUCESS_OUTPUT="\, 0 failures"
echo "This script will run 'rake' command to make sure your test suite passes before pushing"
echo "You can skip this script by adding '--no-verify' to your regular 'git push [repository] [branch]' command"
echo 'This can take a while...'
exec 5>&1
OUTPUT=$( rake |tee /dev/fd/5)
if echo "$OUTPUT" | grep -q "$SUCESS_OUTPUT"; then
echo 'Test passed! proceeding with the push'
exit
else
echo "Some test did not pass! Failed test are shown above. Push aborted!"
exit 1
fi
Once you put your script into your .git/hooks directory, don't forget to make it executable:
chmod +x hook-name
What if...
As we said before, the script will run every time we perform the action related to the hook but, what if we don't want to run the hook once in a while?
Well, Git also allows us to skip the execution of hooks by adding the --no-verify option at the end of the action:
git commit -m "I don't want to use the hook' --no-verify
git push origin master --no-verify # Don't run test suite
Show me the code
The scripts shown above can be found in my Gist account so, feel free to comment or fork either the pre-push or the pre-commit scripts.
More information
If you want to dig deeper into Git hooks, I really encourage you to read Git Pro by Scott Chacon.
Thanks for reading.