You must understand that svn:externals
are a property on a file, and modifying them requires a commit. If you have a mirror, and you modify the svn:external
, you're creating a new remote version and breaking your mirror. The revisions will no longer line up.
Although it seemed like a neat idea at the time, svn:externals
can be very bad in a project. Imagine a project like this:
http://vegibank.com/svn/trunk/project1
And I have on this directory an svn:external
$ svn pset svn:external "^/trunk/project2/foo foo" .
I do this because the foo
directory is a shared set of files for multiple projects.
Now, I create a tag for project1:
$ svn cp http://vegibank.com/svn/trunk/project1 http://vegibank.com/svn/tags/1.2.3
Looks nice -- except the project1/foo
directory isn't tagged. It's linked to the trunk of project2/foo
.
My assumption with a tag is that the tag never changes, but this isn't true. Work is still being done on project2/foo
on trunk, and that changes what my tag represents. If I have a bug in release 1.2.3, and I decide to checkout my tag to see what could be the problem, I'm not getting necessarily what I released in project1/foo
-- I'm getting the latest from trunk.
A better way to handle this is to create a release repository, build the code that's common between various projects as some sort of pre-compiled artifact and have your project depend upon that version of that artifact. It ends up being no different than a C program dependent upon a particular version of libz.so
or a Java project dependent upon version 1.6 of org.apache.commons.httpd
.
This will eliminate the use of svn:externals
and simplify your mirroring. You could mirror the release repository as well as the source repository.
If you insist upon using svn:external
, don't use the full URL. Instead, use relative URLs.
For example, if you had setup your `svn:external above instead of this:
$ svn pset svn:external "^/trunk/project2/foo foo" .
to do this:
$ svn pset svn:external "../project2/foo foo" . #property on ^/trunk/project1
Now, if I create a tag like this:
$ svn cp http://vegibank.com/svn/trunk http://vegibank.com/svn/tags/1.2.3
I'm tagging both project1
and project2
. Now, my svn:external
refers to http://vegibank.com/svn/tags/1.2.3/project2/foo
.
What you need is a way to enforce svn:externals in this way, and you can use a pre-commit hook to reject any commit that has a svn:external
set that references the trunk
or branches
directory without either specifying an actual revision.