We would like to implement a policy that will force developers to commit only changes that will compile.
Is there a way to do such thing using pre-commit hook? If not, I'll be happy to hear any recommendation开发者_如何学Python or workaround that will maintain the source integrity.
Having the pre-commit hook kick off a build would be complicated, because the repository does not yet have a revision with the state you want to check at that point. The repository does have a pending transaction which you can inspect with svnlook
; this can be used to implement some rules but there is no easy svnlook export
command to do a full build.
The pre-commit would also have to wait for the build result before rejecting or completing the commit, which will slow things down tremendously. I imagine this will encourage developers to do "one big commit at the end of the day" instead of doing many smaller (=reviewable) commits as appropriate.
solution 1: don't reject, roll back
Do what the rest of the world does: set up a continuous integration server (like CruiseControl, Team Build, etc.) which does a build for each commit. If the build fails, ridiculously loud alarms are triggered an email is send out. Any developers who feel the build failure gets in their way can then easily revert the changes.
solution 2: feature branches and integration manager
The trunk (or some other branch) is considered "blessed". Developers have read access to it but they do not make changes to it directly. Instead, all changes are done on a feature branch where one can commit freely. When a change is ready, the developer makes sure it merges cleanly to the trunk by merging trunk changes and resolving conflicts. He then notifies the integration manager. The integration manager can then perform quality control (like checking that things still build) and does a svn merge --reintegrate
to push the changes to the trunk. A bit heavy weight, but some projects use this process.
Others have addressed weather it's a good idea, so I'll only explain how to do it
in pre-commit, which is a shell script in this example (and usually?) but could be a program if you want:
repo="$1"
tx="$2"
# "magic" is a cut or sed command that fits your repository structure
# to find the tag/branch/etc root you need to compile the project
relative_url=$(svnlook dirs-changed -t "$tx" "$repo" | head -1 | magic)
# get a clean copy of the code
# note that this caches e.g. '.o' files from previous commits
# usually making subsequent builds faster
build_dir="~/testcommit/$relative_url"
mkdir -p "$build_dir"
svn co "file://$repo/$relative_url" "$build_dir"
cd "$build_dir"
svn revert -R .
svn up
# update it to match what the user tries to commit
diff_file="/tmp/testcommit."$$".diff"
svnlook diff -t "$tx" "$repo" > $diff_file
# you may have to adjust 'p1' to fit your repository depth
patch -p1 < $diff_file
# adjust to fit your needs
make
if [ some-test-fails ]
then
# stdout is always discarded
# stderr is shown to the user if the hook fails
echo "error message to the user" 1>&2
exit 1
fi
# allow the commit
exit 0
You probably should not do this. Committing should be fast so that developers can quickly and easily commit many small changes. Trying to do a full build before accepting every commit is going to make the commit process take a significant amount of time and disrupt developers' workflow.
You don't really need a hook for this; you can use your CI server to note that a build failed, and revert the new files. In this way the build would be self-protecting, and it would be kind of funny, IMHO :)
Further, you could just notify the developers/everyone, they their relevant commit fails.
Generally, you solve this via a more elaborate build system (nightly builds, whatever).
I'm interested though, why isn't it possible just to tell them all not to commit until it builds? Are they offshore?
I don't think what you want is possible with SVN.
Tell developers that it's their JOB to commit working code. Their cycle should be:
- Make changes
- svn update
- Run the build, which should include tests
- Repeat 1 through 3 until it builds correctly
- Commit changes with a meaningful comment.
Set up a Continuous Integration server like Hudson that sends out emails when a build is broken. Shame any developer that breaks the build, even yourself. Reprimand any developer that continually breaks the build.
精彩评论