blog’s amazing Rotating Header Image

Ask git to check if your code is error free!

How about syntax checking your work before issuing a commit? I’m sure you know how it feels when those tiny last minute changes - hey it needs no testing! – just break your app after deployment.

If git is your version control system of choice, make sure you don’t miss the pre-commit hook feature, which was designed to run (tada!) pre-commit tasks: typically for syntax checks to avoid such errors leaking into the repository.

We also use this method to syntax check our PHP scripts both under Windows and Linux using this hook script:

#!/usr/bin/php
<?php
$files = array();
exec('git diff-index --cached --name-only HEAD', $files );

// dont redirect stderr to stdin, we will get the errors twice, redirect it to dev/null
if ( PHP_OS == 'WINNT' )
  $redirect = ' 2> NUL';
else
  $redirect = ' 2> /dev/null';
$exitcode = 0;

foreach( $files as $file ) {

  if ( !preg_match('/\.php$/i', $file ) )
    continue;

  exec('php -l ' . escapeshellarg( $file ) . $redirect, $output, $return );
  if ( !$return ) // php -l gives a 0 error code if everything went well
    continue;

  $exitcode = 1; // abort the commit
  array_shift( $output ); // first line is always blank
  array_pop( $output ); // the last line is always "Errors parsing httpdocs/test.php"

  echo implode("\n", $output ), "\n"; // an extra newline to make it look good
}

exit( $exitcode );

?>

Actually that’s not rocket science: we’re simply invoking the PHP CLI here to lint (syntax check) the affected scripts.

Installing the pre-commit hook script

It’s also a no-brainer: just paste this script into a file named .git/hooks/pre-commit, and adjust PHP path in the first line after the #! characters.

There’s no global hooks directory for Git, so you’ll need to copy this script into all projects to enjoy the comfort all the time. However, there’s a directory holding entire Git repository templates under /usr/share/git-core/templates/hooks or \Program Files\Git\share\git-core\templates\hooks if you’re on Windows.

We’ve found that on Windows (mSysGit) there’s no support for directory names with a space (neither entire path in quotes), so you may need to use the short format for the path at the top like:

#!/progra~1/php/php.exe

(should you use x64 Windows and x86 PHP, you may need to use #!/progra~2/php/php.exe instead).

Post-commit?

A bonus tip for you patient readers: if you want to keep your repos clean, just setup a post-commit hook including git gc – this way the cleanup and optimization processes will run after every single commit. That’s as easy as:

#!/bin/sh
git gc

(The above actually works under Windows too without any changes thanks to mSysGit).

By now I’m sure you already know where to put it: .git/hooks/post-commit :)

You can even fork the script on github at: http://gist.github.com/383768!

Bookmark and Share

One Comment

  1. Sérgio Carvalho says:

    Cool idea. Here’s my version, in bash script (won’t work on windows without some black magic):
    #!/bin/bash
    FAILED_LINT=$(git diff-index –cached –name-only HEAD | egrep ‘\.php$’ | xargs –replace -n 1 sh -c ‘php -l “{}” > /dev/null 2> /dev/null || echo ” {}”‘)
    if [ -n "$FAILED_LINT" ]
    then
    echo -e “Some input files failed lint, commit aborted: \n$FAILED_LINT”
    exit 1
    fi

Leave a Reply