explaining in a pull request later" can introduce some awkwardness. if I push a test suite that only runs a single test because I left that
.only() in there, and it suddenly passes something that's been failing for days and you've been slowly chipping away at, it's not a good look.
To the rescue comes Git pre-push hooks. These are different from pre-commit hooks in that they let you make as many stupid, profanely-worded, incoherent local commits as you want, but will only stop you if you try to push them. You could do a lot with these, like run your latest code against your test suite or linting. I decided to stop myself from pushing code that contains
.only(). Here's how I did it:
#!/bin/bash mochaSkip=`git grep -e "\.only" --or -e "\.skip" HEAD` if [ "$mochaSkip" ] then commit=`git log --pretty=format:'%Cred%h%Creset %s' -G "(.only|.skip)" | head -n1` echo "Found Mocha test suite skip. This change was last introduced in:" echo $commit echo "Not pushing. (override with the --no-verify flag)" exit 1 fi exit 0
I'm hardly a wizard with bash scripts and Git hooks, this is largely based off Peter Goldsmith's examples linked to earlier, adapted to suit my needs. Thanks, Peter!
There're a few things in here that aren't immediately obvious if you don't know bash scripts or Git. Here's an attempt at explaining them:
git grep "something" HEADonly searches for "something" in the current committed state (the HEAD). If you committed something earlier but then fixed it, this won't yell at you.
git grep --orlets you search for the instance of one _or_ the other terms.
git log -Glets you search the full repository history with a regular expression. We use this here to find out when the latest commit adding either ".only" or ".skip" was.
--pretty=format:'%Cred%h%Creset %sis a bit indecipherable, but it has meaning.
pretty=formatis a way to format your Git log messages in exactly the format you want. If you have a spare week and are way smarter than me, you can read the official Git docs. I copy/pasted some things until I got what I want:
%Credcolours the text following it red.
%houtputs the short commit hash.
%Cresetturns the red colour off again.
%soutputs the commit message.
exit 1tells the command to exit with a status code of 1 if we found the test suite skips. In Unix land, generally, exit codes that aren't 0 mean something's gone wrong. If a Git hook exits with a status code of anything but 0, it'll stop whatever you're trying to do. In this case, it'll abort the push and you've saved face!
And that's about it. This will save me a few premature pushes in the future—hopefully you may find it useful, or be able to modify this pre-push test to suit your needs!
Here's a quick gif of the hook in action.