How to integrate PHP_CodeSniffer with Git repositories?
At work, we used a SVN server and enforced our project coding standard with a pre-commit hook on the server that ran PHP_CodeSniffer.
Whenever a developer tried to commit some code that does not match the standard, he got it rejected. To be able to check in legacy code, our commit hook recognized special commit message tags like "SKIP_CS". Developers using that were logged and beaten at the end of the week when they used it too often :)
Problems with Git
Now we switched to Git with a self-hosted Gitorious instance as frontend but unfortunately lost the Coding Standard enforcement. Let me explain that:
With Git, you commit locally - thus your pre-commit hooks need to run locally on the developer's machine. In our case, this might be a Linux, Mac or Windows machine - which means that I can't use a bash script. Also, the developer needs to set it up himself because when you clone a Git repository, you do not get hooks from the server. That's not even possible.
Apart from the setup issue there is no way to enforce the check because one can pass the --no-verify commit parameter and the pre-commit hook is not executed.
The only way to enforce the standard is a pre-receive hook on our central Git repository server that all devs push to. Just installing the SVN hook on it isn't the solution, though:
- A push often contains multiple commits, so all that needs to be taken care of, i.e. by checking all of them.
- When the developer tries to push code that does not meet our requirements, we can reject it. But what then? He can't (and should not need to) change his commits.
I think the solution is to create a list of files that were changed in all the commits the developer tries to push and look at their current state. This way, the developer can commit a fix and push it together with the rest of the history to the server.
Several issues remain:
- Files may be renamed. This must be taken care of
- When legacy code is checked in, the developer wants to skip the check. There needs be a way to do that across multiple commits.
Do you have an idea how to solve that problem? Please comment on the question on StackOverflow or send me a mail.