Enforcing code standards in git before commit is accepted

Jake A. Smith picture Jake A. Smith · Jul 31, 2013 · Viewed 10k times · Source

Alright, here's the scenario: A team of developers wants to ensure all new code matches the defined coding standards and all the unit tests are passing before a commit is accepted. Here's the trick, all of the tests need to run on a dedicated testing machine and we do not have access to modify the git server so this must be done using a local commit hook on each dev machine.

While the specs are pretty strict (we're not switching to windows or subversion, for example) this is a real world problem so there is some flexibility if you have a solution that almost fits.

  • We're using Git and *nix.
  • The updated code needs to be sent to another server to run the test suite.
  • A list of modified files needs to be provided to ensure they match the coding standard.
  • Its a rather large codebase, so we should send the smallest amount of information necessary to ensure identical copies of the codebase.
  • If the tests fail a message needs to be displayed with the error and the commit should be blocked.
  • Assume we trust our dev team and its okay to allow the tests to be bypassed with --no-verify option.

The question: What is the best way to get the test server to sync up with the local environment to run the tests? Some sort of hash-to-hash matching with a git patch for the new commit? Skip Git altogether and just do an rsync? Something else altogether?

Update 8/7/13: I shot myself in the foot by even mentioning the remote repo. The point isn't to block the code from being pushed to the shared / remote repo, its to prevent the local commit from even happening. Whether or not this would be considered a best practice is not really the point in this case, as this is specific to a small team of developers who all want this exact functionality. The question is about the best way to achieve the goal.

Answer

onionjake picture onionjake · Aug 3, 2013

Local commit hooks are definitely not what you want here.

Your requirement that 'we do not have access to modify the git server so this must be done using a local commit hook on each dev machine' is completely bogus. You can always set up another repository that is your 'test remote' which you have full control over (which will then sync up with the git server you have no control over).

Once you set up this test remote, you can add hooks to run your tests on any push. The effort to type git push test-remote my-branch to get test results is pretty minimal.

Continuous integration with Git

Also check out Jenkins, gitlab, etc...


Update after 8/7/13:

So you really want to do some 'tests' on a remote server to prevent commits. If you want to prevent based on the content of the commit itself, use the pre-commit hook. See this question for how to get a list of changed files. Once you have those changed files, you can get them to a remote server using scp or rsync and run a test command with ssh.

If you need to check the commit message use the commit-msg hook.

Here is a good tutorial on hooks: http://git-scm.com/book/en/Customizing-Git-Git-Hooks

It also mentions a few reasons why it might be a bad idea.

They’re often used to enforce certain policies, although it’s important to note that these scripts aren’t transferred during a clone. You can enforce policy on the server side to reject pushes of commits that don’t conform to some policy, but it’s entirely up to the developer to use these scripts on the client side. So, these are scripts to help developers, and they must be set up and maintained by them, although they can be overridden or modified by them at any time.