Mr. Boy
Mr. Boy

Reputation: 63738

What is the right way to structure a large multi-application codebase in SVN

We've currently got a single repo with codesion, http://John.svn.cvsdude.com, with a single SVN project http://John.svn.cvsdude.com/MyProject, which contains a few subdirs for individual Visual C++ solutions

This all started as one application and though we did split off separate library projects for future re-use, it's still all the same SVN project. Lets say we aim to have multiple applications with some overlap in libraries used, what's the right/best way to set this up in SVN? Of course one could just keep one SVN project and put app-projects and library-projects as sub-dirs, but it hardly seems right somehow.

Say we have App1, App2, App3 and LibraryA, LibraryB, LibraryC, LibraryD where these are all separate projects/solutions... how would you organise this under one (or more repos)? Is there a best-practice?

Upvotes: 1

Views: 366

Answers (3)

jackr
jackr

Reputation: 1437

this is Jack from CollabNet, Codesion Cloud Services. First, thank you for being a Codesion customer!

You describe your situation in terms of "projects," but that's an ambiguous term, and Subversion itself hasn't any notion of it at all. The real consideration here is not Subversion per se, but your build tools and release policy. You want the configuration that best supports what you want to do.

For example, do all these apps and libraries release all at once? Completely independently? Some mix? Is that answer likely to change?

If they all release at once, then there's important value in making it as easy as possible to identify which versions of each app were released with which versions of other apps. That way, bug reports can be verified, fixes implemented, and patches merged all in a coherent, consistent way. To achieve this, I would not use the "/app/{trunk,tags,branches}" structure that several have suggested, but rather stick with the canonical

/trunk/app1
/trunk/app2
/tags/TAGNAME/app1
/tags/TAGNAME/app2
/branches/BRANCHNAME/app1
/branches/BRANCHNAME/app2

structure. This allows you to branch, tag, and merge the whole tree, all apps and libraries, in a single command:

svn cp URL/trunk URL/tags/TAGNAME

On the other hand, if these things are independent, then you're better off with

/app1/trunk
/app1/tags
/app1/branches
/app2/trunk
/app2/tags
/app2/branches
...

This way, for example, tagging one app doesn't affect another.

In a mixed case, you can still achieve the coordinated branching (when it's appropriate), but you'll have to use branching from within your working copy, and perhaps sparse check-outs (if the working copies are large). Alternately, you can tag or branch the whole repository, even though the tag or branch has no meaning for most of it: Subversion tags and branches are cheap to store, and (if you use the URL-to-URL form of "svn cp") cheap to make; the only reason not to tag things with unrelated tags is, it confuses the humans. But that's a pretty strong reason, so a mixed model is best handled with the "app/trunk" structure, to avoid confusion.

You can find good examples of the "/app/trunk" approach in the Apache Foundation repository. All the Apache projects (including Subversion itself) are stored in a single Subversion repository. There are around 100 projects there, and although there are some interdependencies, they're all pretty much managed independently. You can browse around this giant repo (possibly the largest single Subversion repo in the public world), starting at the root of all ASF projects. There's some diversity in practice, there, but one good example is Subversion itself.

Also worth note: in so far as Subversion is concerned, you can always change this stuff. The "tags" and "branches" are really just copies; you're free to rearrange things as you like, when you like. But there are some cautions:

  • It'll confuse the humans
  • "Tree conflicts" (addition, deletion, moving, or renaming files or directories) can make later merges painful. The function of a merge tool is to save you work. All merge tools eventually, for a hard enough merge, punt the decisions back to the humans; the important question is how much they can get right without that. Tree conflicts cause current Subversion (1.6 or better) to punt way more often than you'll like. So, it's best not to rearrange top-level directories like these too often, and be prepared to intervene and clean up for any merges that cross such rearrangements.

Upvotes: 2

Daniel Lidström
Daniel Lidström

Reputation: 10260

I would recommend the following layout, all in the same repository:

App1\
    trunk
    tags
    branches
App2\
    trunk
    tags
    branches
App3\
    trunk
    tags
    branches
LibraryA\
    trunk
    tags
    branches
LibraryB\
    trunk
    tags
    branches
LibraryC\
    trunk
    tags
    branches
LibraryD\
    trunk
    tags
    branches

Now, I am making a few assumptions about your release schedule. I am assuming that each application and library are released under different schedules. This is a worst-case scenario actually, but my scheme will allow this. Each application needs to have its dependencies pre-compiled and included in its directory in the repository. Here's how App1 would look, given that it has dependencies on Library B and C:

App1\
    trunk\
        deps\
            LibraryB, release 1.1
            LibraryC, release 4.3
    tags
    branches

This means that whenever you branch trunk you will get the necessary libraries along, which greatly simplifies things. Observe that it is the compiled binaries of the libraries, not their sources.

A branch of trunk will use the above versions, and since you're not allowed to modify them, any bugfixes will need to go into App1. Meanwhile, to use the new versions of LibB&C you can update their versions in trunk, when they are released by the libraries team. So, after some time, your repository might look like this:

App1\
     trunk\
         deps\
             LibraryB, release 1.3
             LibraryC, release 4.4
     tags\
         release-1.0\
             deps\
                 LibraryB, release 1.1
                 LibraryC, release 4.3
     branches\
         stable-2.0\
             deps\
                 LibraryB, release 1.2
                 LibraryC, release 4.2

Work in trunk is allowed to use the latest library releases. The release-1.0 is using fixed releases (oldest version here), while the stable branch is using the previous version of the libraries.

The above scheme is something I thought about a lot at my last employer, but never got around to implementing. To make it work you need to have a codebase that is split into applications/libraries and development can take place in parallel. That wasn't really the case for us. But it is a worth-while goal, I strongly believe.

Good luck!

P.S. I strongly recommend against svn:externals. They can make branch management a lot harder. For example, if an external changes and a branch is dependent upon it, you are under risk of messing up that branch (making it uncompilable for example).

Upvotes: 0

Grzegorz Gierlik
Grzegorz Gierlik

Reputation: 11232

I would keep everything in one repository and put each project and library in separate root directory of repository (see Planning Your Repository Organization for details).

Keep in mind that repository structure do not have to be identical to project files structure on disk.

Also I would use svn-externals to share library directories (kept as separate root folders of repository) among various projects.

Upvotes: 2

Related Questions