SVN common code with externals
At the moment I'm trying to set up a repository for multiple products using the same code. The best solution would be to make real libs of the shared code and use them that way. However this takes way to much time at the moment. The idea is to have a single repository with the following tree
-trunk-Project1
-Project2
-Shared
Project 1 and 2 both 开发者_StackOverflowhave a external to include the shared code. The external points to a specific revision to not break project2 build while working on project1 and the shared code. From this a problem arises.
When a change is made to the shared code and I do a commit (with tortoise SVN) the changes are picked up for both the project1 and the shared code and are nicely commited to SVN as a single revision. However when I or a colleague does an update the project will not build because the svn external is pointing to the "old" revision.
This can be fixed by updating the external and committing it (leave the build broken in between). We could temporary remove the specific revision from the external, but we have to add it again when development ends. Is there a way to do this automatically?
I think you have a few choices. First is to use a single module with branches as Martin proposes. You would have a branch for each active project, or for a thread of development. Changes to shared code would be picked up when you merge back to trunk.
e.g.
Module
|
+ trunk
| + Project1
| + Project2
| + Shared
|
+ branches
|
+ Project1Development
| + Project1 [active development here]
| + Project2
| + Shared [active development here]
|
+ Project2Development
+ Project1
+ Project2 [active development here]
+ Shared [active development here]
Secondly you could branch Shared so that you do not need to pin an external to it. This is what you'd have in your repository
Project1
|
+ trunk [svn:external to a branch of Shared]
Project2
|
+ trunk [svn:external to a branch of Shared]
Shared
|
+ trunk
|
+ branches
|
+ Project1Development
|
+ Project2Development
Each project would use its own view of trunk. The danger here is that the branches get too long - you would need to be disciplined about merging them and deleting them, perhaps after every release. Shared's branches should only be created when project-specific changes to shared are needed.
Thirdly you continue to use externals as you are now and take the pain of pinning revisions. I would rearrange your repo to be like the second figure above if you are doing this - what you have with externals within a project smells a little.
You should use svn:external when you have more than one repository and need to mix source from all repositories to build your project. Based on your question I would say you only have 1 repository, hence no need for svn:external.
You could use branches. Project1 and project2 both make changes to shared in their own branch. You would have to make good working agreements to integrate changes on branches as often as possible to the trunk (smaller diff's are easier to merge) and to make sure that the build on trunk never breaks.
I can recommend Henrik Kniberg's paper on Version Control, it covers this subject nicely.
Your problem is that Project1 and Project 2 require specific versions of Shared. So you need to make that explicit in your layout.
For example, you could do this:
-trunk - Project 1 - Project1Share - Project 2 - Project2Share - Shared
And have Project1Share and Project2Share as versioned externals pointing to specific revisions of Shared, and "Shared" being the latest revision of that shared library code.
The shared module can be in a different repos altogether of course.
Since your subprojects depend on specific revisions of the shared code, you cannot avoid managing the specific version to build against your sub-projects: so you need to make it explicit.
If the rule is that Project1 always builds against the latest version of shared, and project2 against specific versions, then the project1shared external can be unversioned and the project2 one versioned.
All good answers so far - but there's another option: use tags. When development is finished, you want to re-link the externals to P1 and P2 both point to the new Shared project. Until then, you want P1 and P2 to point to the old, known-working version of Shared.
So, continue to work on trunk with externals pointing to the HEAD Shared revision. when you're done, branch the entire lot to a tags directory (call it ReleaseX for example), which will contain working code for all those versions. then you can continue to work on trunk without worrying that you're breaking the 'finished' version you've released.
If you release P1 and P2 at different times, you can still use this approach - when you put the project into the tags branch, you set its externals to the current version of the Shared project. When the next project gets tagged (and the Shared project gets updated), the old project will still point to the correct version of Shared, until its next release is tagged and so on.
精彩评论