git hook syntax check
Trying to make a php syntax check hook for a git repository. I was happy when I found a code snippet that does exactly this.
But it seems that the snippet script has a flaw. It executes
git diff-index --cached --name-only HEAD
to get a list of files in the index. Now it runs php -l for each file on that list. The flaw is that a file might differ between the working copy and the staging area. If the staging area php has a syntax error, but the working copy version doesnt, no syntax error is found and the committ succeeds which was the thing to prevent.
Is this a nontrivial problem to solve, or is there some way to run php -l on the staging-version of each file?
3 Solutions collect form web for “git hook syntax check”
I’m very happy using this php syntax validation hook. Hope it will fit your needs too.
git diff-index --cached --full-index.
I am not sure if there is a problem here.
The snippet you mention probably comes from the blog post Don’t Commit That Error.
And it includes:
Next, we call
git diff-indexwith a few parameters.
First, we add
--cachedto tell Git we only want files that are going to be committed.
Then, we add
--name-onlyto tell Git to only output the name of the files that are being committed.
It seems the files which are about to be committed are precisely the ones a pre-commit hook would want to inspect.
Even if they differ from the files in the working directory, it is their version (in the index) which is to be committed. And it is that same version which will be send to the
php -l process.
Actually, the problem is not in the
git diff-index itself (with or without
--full-index) is in the way you will read the file content in the index
- The “PHP Advent 2008” hook will simply try to access the file from its name (with the risk of accessing the working copy)
exec("php -l " . escapeshellarg($file), $lint_output, $return);
- The “phpbb3” hook (mentioned by takeshkin in his answer) will ask Git for the actual content:
result=$(git cat-file -p $sha | /usr/bin/env $PHP_BIN -l 2>/dev/null)
git cat-file is the key here, to access an object in the Git repo (i.e. not in the “working directory”)
Cause pre-commit hook is not good for working in a team you should use pre-receive hook installed on server side to refuse all commits with invalid php syntax and incorrect coding standard.
I’ve created pre-receive python script for that pupose:
# A server-side git hook script for checking PHP syntax and validating coding standard # Depends on: PHP_CodeSniffer (http://pear.php.net/package/PHP_CodeSniffer/) # Install: copy this script to <server side repo location>/hooks/pre-receive #!/usr/bin/python import os import sys oldrev, newrev, ref = sys.stdin.read().strip().split(' ') test_file = os.popen('mktemp').read().strip() coding_standards = 'PSR2' for line in os.popen('git diff --name-only %s %s' % (oldrev, newrev)).readlines(): extension = line.split('.')[-1].strip() file_name = line.strip() if(extension == 'php'): os.system("git cat-file -p %s:%s > %s" % (newrev, file_name, test_file)) if 0 != os.system('php -l ' + test_file + ' > /dev/null'): print "PHP Syntax error in file %s" % (file_name) sys.exit(1) if 0 != os.system("phpcs -n --standard=%s %s" % (coding_standards, test_file)): print "Coding standards fail in file %s" % (file_name) sys.exit(2)