I am about to establish a rule at work here that all svn:externals references should come from the one of the other project's tag, never from its trunk or from any of its branches. Is this a reasonable rule or do you see problems / issues with this approach? I am trying to achieve a stable development environment and I wonder if this rule would make development slower or more difficult.
I think it comes down to how mature your software development practices are. Do you have change-management processes? Automated builds and reporting? Etc. The safest thing to do is to link to a tagged-build of the project (i.e. lib's, dll's, jar's, etc).
If the external project has weekly releases with frequent bug fixes, it could be both helpful and a hinderance. I found that without a good configuration management policy, linking to tags make it easy to miss critical updates. And, by the time you get around to "upgrading" that dependency, there may be a lot of small changes that add up to a lot of work.
On relatively stable projects, this is a good idea. The only problem is that not all IDE's make it clear that a source directory is an external refernce. In that case, it becomes very easy for developers to check-in changes to that tag. From what I recall, Subversion hasn't implemented "read only" yet, though I've been using an older version.
And the decision to actually allow externals? Makes sure you're doing it for the right reasons. It is often better to simply checkout from the original place and or, checkin the dependencies in multiple places. I've been burnt by external references in the past. If you're going to branch they become a real problem unless you "freeze" the external when you do.
But to answer your question, it makes a lot of sense to have a specific location where all externals are placed and referenced. That means that you can control the content of that location and people know that when they put something there then it will be used as an external and thus depended on by a lot of projects.
Your concern is that a project with "svn:externals" can change without any commits to that project. That's a problem because it's hard to discover the breaking change or to roll back to a good version.
So yes, demanding that svn:external references are stable is a good rule. Only allowing references to tags is one way to achieve that. Another way is to use the -r syntax to pin the external to a fixed revision. Example from the subversion book:
third-party/skins -r148 http://svn.example.com/skinproj
This will also protect you against changes in tags, a bad practice which is more common than I like.
That being said, there still is a trade-off between stability and continuous integration. Often you need the changes and bug-fixes in the external dependencies anyway. In that case you want to be notified by your CI server as quickly as possible that some change in the dependencies broke your project, so that the problem can be fixed ASAP. Most continuous integration servers have support for checking externals.
For this reason I think it's OK to keep the externals in trunk tracking the trunk HEAD of your dependencies (if you have a CI server). Just pin your externals to fixed revisions when tagging and when creating stable maintenance branches.
It depends how stable you consider trunk to be.
- If your trunk is something that's always ready for release, then you really don't want your externals pointing to trunk.
- If you have release branches that are only changed by merging in revisions from trunk, then you really don't want your externals pointing to trunk.
- If for any reason you want a revision in trunk that says "I'm now using this version of this external", thus taking control of all changes to your project code, then you don't want your externals pointing to trunk.
However, it's fine for a developer to switch the working copies of their externals to a trunk. It's also fine to point to trunk within a development branch. It may be ok to point to trunk before the first stable release of a project.
My personal take is to treat trunk very carefully as it has a special meaning to me - it's the complete history of the project. Anything that gets released must go through trunk, by definition. If you can change trunk without having a revision recorded against the change (which is effectively what happens if you point to an external to trunk), you've lost control over when you release that revision, and when you incorporate that revision into your project.
Remembering to change all your references to specific revisions when you branch from trunk can be a trial. Hudson can make things more visible with its tagging support, but little else helps.
Pointing to trunk can also lead to the "untouchable library" problem.
When it comes to CI, there's no reason why you can't do CI on all the components as well as the final integrated projects. By choosing when to merge in the latest library, you choose when you want to do the integration work.
However, it would be nice to have some mechanism which says "Your project is using an out of date library, the latest version is X". This is not possible at the moment.
Also, if you have nested externals, pushing a change from a base library through 5 layers of references until it reaches the main project is a pain.