All of us programmers have made this mistake before: we’ve submitted code that we thought was correct only to have it fail during compilation because of a simple syntax error. Just between you and me (and the rest of the interwebs), I did this last week. Then I thought to myself that it would be good to come up with a tool to help ensure it didn’t happen again. I’m proud to say that on the Git front, I have fixed my problem.
Enter Git Hooks, a way to add scripts to various parts of the Git workflow. Using what is called the pre-commit hook, I was able to write up a quick bash script that goes through all the changed files in Git staging area, check if they are Python files (based on the .py file extension), and then run those Python files through Pylint to look for various errors, including syntax and type errors.
So here is my git hook:
#!/bin/bash files_modified=`git diff-index --name-only HEAD` for f in $files_modified; do if [[ $f == *.py ]]; then pylint -E $f if [ $? != 0 ]; then echo "Code fails pylint check." exit 1 fi fi done exit
Feel free to copy this and modify it for your own needs. My gift to you; no charge. But an occasional “Thank you Bryce” email is always nice. I also accept lavish gifts of cash or ThinkGeek merchandise.
One quick thing before I let you get back to your busy lives. If you have an older version of Pylint than 0.24, the “-E” flag might need to be changed to “-e”.

Hi, just stumbled over this
Hi,
just stumbled over this when searching for something else, we have a very similar script using pyflakes for the development of Unknown Horizons. It also checks for newly added "print" lines, as these are often just for debugging. If errors are detected a tkinter popup is shown that lets you decide if you want to cancel the commit, console IO is not possible in hooks, therefore this gui version is used.
Implemented in python, newest version always here:
https://github.com/unknown-horizons/unknown-horizons/blob/master/development/pre-commit
Cheers!
Hey Nihathrael, Thanks for
Hey Nihathrael,
Thanks for the post and the link. That is one extremely impressive pre-commit script.
sh or bash?
Maybe it's only me, but had to change #!/bin/sh to #!/bin/bash on my debian squeeze to get it working.
I got this error before change:
.git/hooks/pre-commit: 13: [[: not foundI'm sorry to hear that the
I'm sorry to hear that the script didn't work for you Fizyk. I know it's not much of a consolation, but it seems to work just fine on my OSX box. I wonder if it might be some different versions of /bin/sh. For my machine I have version 3.2.8. Is your version different?
Change for portability
Note that you are using bash-specific shell syntax, so you really should change the snippet to begin '#!/bin/bash' - which will also work fine on Mac OS X.
It just so happens that Mac OS X uses bash as the default shell, so /bin/sh will get you a bash interpreter, but other Unices (such as Debian) use a different default shell.
Basically this works for you only by happy coincidence, technically what you've done is incorrect (or at least not portable).
Great script otherwise though - thanks.
Matt is correct. /bin/sh on
Matt is correct. /bin/sh on MacOSX is it's own executable. That is why I was able to get the version number when trying to help Fizyk with his/her problem. I know on various linux boxes that /bin/sh is a sym link to /bin/bash and that could be the root of Fizyk's problem.
On recent Debians /bin/sh
On recent Debians /bin/sh isn't bash at all, it's ash - a lightweight Bourne compatible shell which doesn't support bash extensions. That's why the script as written won't work on Debian, whereas if you said #!/bin/bash it would.
Basically if you are using bash-specific shell extensions it is good practice to specify this by explicitly invoking bash in the header (and arguably it is incorrect to do otherwise).
Sean, I've taken your advise
Sean, I've taken your advise an updated the script to use /bin/bash instead of /bin/sh. Thank you for taking the time to explain why the /bin/sh won't work for Debian machines.
Great. For the record the
Great. For the record the default shell on recent Debians is called 'dash' not 'ash' - I misremembered, but otherwise it's as I described. Thanks again for the scriptlet, a useful addition to my repos.
no, /bin/sh is the executable
no, /bin/sh is the executable your shell will use to execute the script. If you're using bash as your shell, it needs to be /bin/bash
Maybe pyflakes instead of pylint?
Pyflakes is a lot faster than pylint - as as you are only checking for the existence of errors - then it probably has all the functionality that you need at this point. (Pylint does a lot more - so for example if you wanted to enforce style guidelines - you would need pylint)
Hey Mark, thank you for the
Hey Mark, thank you for the recommendation for Pyflakes. I didn't know about it till you said something and I will definitely look into that project deeper.
Why use bash and not python?
Why use bash and not python?
Because it would be more
Because it would be more complex and crappy in Python, using subprocess pipes, string parsing and so on. it's much simpler and much more straightforward in shell script.
To be honest I didn't think
To be honest I didn't think about trying to put this in python. It's certainly possible to do and it would possibly be a good second part to this post. Thank you for the idea.
But what if the check script
But what if the check script contains syntax errors? ;-)
Post new comment