views:

102

answers:

3

One of my web apps has grown over the past few months from a single project file to include several class libraries. The svn structure has sort of grown organically and looks something like this:

repository-root
    site1
        trunk
        tags

    site2
        trunk
        tags

    library1
        trunk   
        tags
        ...

    library2
        trunk

Now that development is ramping up, I'd like to have something like this

repository-root
    site1
        trunk
        tags
           release-20100922
             site1
             library1
             library2
             ...
           release-20110101
             ...

Now, since Site1 and Site2 both reference the class libraries library1 and library2, what's the best way of going about reorganizing the folder structures so that

  • Tags of each site contain a frozen copy of the associated class libraries at the time the site tag was created, and
  • Each site can still reference the class libraries without having to have a separate copy in each site's trunk

I may just be thinking about this wrong. Suggestions?

+1  A: 

Without doing anything special, a possible Subversion directory structure could look like this:

repository-root
    site1
        trunk
        tags
            release-20100922
                site1
    site2
        trunk
        tags

    library1
        trunk   
        tags
            release-20100922
                library1

    library2
        trunk   
        tags
            release-20100922
                library2

You and your developers would have to make sure that you create a consistent release tag on all of the components in a release.

Somewhere under the site1 release-20100922 tag, you could have a txt file that lists the libraries included in the release.

You can structure your tags like you outlined. It would be a manual process, but it can be done.

Gilbert Le Blanc
I like this, except for having to rely on the developers to maintain it. Maybe I could do this with a "tag" script in the build system.
David Lively
+1  A: 

I had a similar problem and solved it by using this repository structure:

repository-root
    trunk
        site1
        site2
        library1
        library2
    tags
        site1
            release-20100922
                site1
                site2
                library1
                library2
        site2
            release-20110101
                site1
                site2
                library1
                library2

Each time I make a release I copy the whole trunk to a new tag. The first subdirectory of tags shows me for which site I made the release. This way I have no problems to identify the correct revisions of the libraries.

Yes, for a release of site1 I have tagged site2, too. But hey, tagging is cheap with subversion.

tangens
I hate having to do this manually, but it may be necessary. The idea is to keep a complete version of the *entire* codebase at the time of release in case I have to roll any of the sites back (which would include their referenced projects).
David Lively
Why the downvote? What's wrong with this solution?
tangens
This is OK until you have 20 sites and 40 libraries, only some of which are used by each site. It's harder to track what's going on, and the time taken for a developer to check out one release tag might start to get prohibitive. But if you only have a couple of sites then no problem.
Paul Stephenson
I'm using this structure for software development with more than 50 projects and libraries. If I really need only a few of the projects or libraries I do a sparse checkout. And each project has its definition file which lists its dependencies to other projects and libraries.
tangens
+4  A: 

svn:externals as "soft source control link" in modular applications.

svn:externals can help you avoid some manual tasks and give a clear idea on what is what (and in what version).

You have several kinda "independent" products called "sites" that rely upon libraries. You got relase cycles for your products AND for your libraries as well. For increased stability you might not want to work with trunk library code anywhere as it might break not only one but multiple sites. On the other hand in more agile approaches a "break early, break often" could be desirable. So having the choice what library code version to use in your mainline development would be a plus.

Additionally your stabilizing/incubation branches (if any in the future) might want to sync with one specific version of the libraries so that reinforced compatibility will be transported into the resulting tags as well.

I would suggest the following Layout:

repository-root
    site1
        trunk (active development, unstable)
             mycode
             library1 -> external of "library1/tags/2.0"
        branches
            2-branch (maintenance, stable)
                mycode
                library1 -> external of "library/tags/1.0"
        tags
            2.0.0
                mycode
                library1 -> external of "library/tags/1.0"
            2.0.1
                mycode
                library1 -> external of "library/tags/1.0"
    library1
        trunk   
        tags
            1.0
            2.0
            ...

There is no need to merge or move arround library source code when you change your mind and decide "Hey using the new 2.0 library1 API in our trunk was a piece of cake maybe we should use the trunk in the future.".

Lets imagine there is a bug in "library1 1.0" so you release "library1 1.1". You will need to make a new bugfix release of your main application as well and ship it out. so you update your "site1 2.0" maintenance branch, test and create a tag.

repository-root
    site1
        trunk (active development, unstable)
             mycode
             library1 -> external of "library1/tags/2.0"
        branches
            2-branch (maintenance, stable)
                mycode
                library1 -> external of "library/tags/1.1" (changed the property)
        tags
            2.0.0
                mycode
                library1 -> external of "library/tags/1.0"
            2.0.1
                mycode
                library1 -> external of "library/tags/1.0"
            2.0.2
                mycode
                library1 -> external of "library/tags/1.1" (inherits property change)
    library1
        trunk   
        tags
            1.0
            1.1
            2.0
            ...

Externals insure that YOU have the choice as to what library changes you want to incorporate and WHEN you want it. This will help to reduce "surprises".

Be aware though that svn:externals slow down your "svn update" commands with each external that has to be checked. Code is underway to improve that though.

Check out the silverstripe public repository for how they are doing things. Works well for them.

svn propget svn:externals http://svn.silverstripe.com/open/phpinstaller/tags/2.4.2/

Hope I could help

Christoph Strasen
This approach works well once everyone in the team understands it. It's also a good idea to use the revision number in the svn:external property, *even when* you're linking to `library1/tags/1.0`, because somebody somewhere *might just* naughtily modify `library1/tags/1.0` and change the behaviour of site1's `2.0.1` the next time a developer checks it out to reproduce a reported bug.
Paul Stephenson