Enforcing code standards in git before commit is accepted

北城余情 提交于 2019-12-02 20:59:32

Add a custom git command which:

  1. Temporarily does the commit
  2. Pushes it to the remote server
  3. Runs the tests (using a CI server, post-receive hook, or ssh)
  4. Reverts the commit if the tests fail

Create an executable called git-test-n-commit and place it in your path:

#!/bin/bash
echo "Committing results..."
git commit "$@"
echo "Pushing to remote testing server..."
git push remote-server-git-url remote-branch -f
echo "Running tests"
ssh remote-server 'cd my_repo; run-my-tests' || 
   (echo "Tests failed, undoing commit" && git reset HEAD^)

Then instead of calling git commit ARGS, the developers can call git test-n-commit ARGS. If the tests pass the code will remain committed. If the tests fail it will be as if it was never committed.

Short answer:

DON'T


Long answer:

Not being able to do a commit because of some strange local hooks seems odd to me: you have to separate making a commit (i.e. saving your changes) from publishing this commit.

While it's perfecly reasonable to have a pre-receive hook on the git server you mention that enforces your rules, it would be dramatic for the repos of your devs: every time they want to save their work, try out something new or whatever, they would first have to polish their code before they could do the commit.

This would be counterproductive: people would feel like back in the bad old days when they had to commit anything to the repo and everybody could see their errors, bad coding style and so on. You would lose the freedom that a DVCS gives you: cheap branching, local history while maintaining a central repo for the production code.

Do not enforce anything when doing a local commit.

onionjake

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.

I think the best approach I've seen is git+gerrit+jenkins. The gerrit introduces a notion of a changeset. The jenkins gerrit plugin could build each published changeset (running any kind of tests you would like) and mark them as "verified", then verified changeset could be merged into a master branch. If changeset fails build, committer receives a notification email, then he could amend the commit and update the changeset.

After setting up an intermediate server as others have suggested, set your pre-receive hook up to run a script over the incoming commit and normalise it to your coding standards. Often coding standards are defined by computer-enforcable rules. Don't make your developers go around tweaking whitespace hither and tither when a simple bash script or whatever could do it for them. And if you have a script to do that, why make the developer run it manually when it can be ran automatically on each push to your intermediate repo.

Write a Makefile that:

  1. Copies current files to test server.

  2. Finds the output of the unit tests.

2.1. If there are no anomalies, run 'git commit'

2.2 If there are anomalies, echo an error.

Using Makefiles to do my compiling AND commits has been a godsend. I can automate complex formatting and file cleanup before committing.

Edit:

Of course, Makefiles are not the only things you can do. Ant/Bash/other scripting languages can do this for you.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!