My first experience with version control was VSS. I used it exclusively for SCM tasks until about three years ago when I started teaching at Fairfield U. I learned enough to teach the basics (through Subclipse) to college students who had never even coded before. Eventually, I was lured in further by its better checkout model and the oh-so-shiny TortoiseSVN. I signed up for an account at CVSDude and started hosting my personal projects there (great service). I’ve also migrated three companies with substantial codebases from VSS or SourceGear to Subversion. Along the way, I’ve wrestled with the various ways of structuring a repository. This post will describe what I’ve found to be useful…
There are lots of examples on how to layout your repository. Google around and you’ll find plenty of ideas. What I’ve not found in abundance is how to structure a typical repository within a corporate codebase. If you have only one product, it’s simple. But what about the more common case where a business has several related applications, with a few shared libraries. In this setting, there will be multiple web apps, services, console apps and scripts. But it all goes to support a single product.
For this example, I’ve tried (and seen many others try) the approach where each application has its own development branch. For example:
MyCommonLibrary/trunk MyWebApplication/trunk MyOtherWebApplication/trunk
One big problem with this approach is that branches that cut across applications are hard to manage. One logical branch has many physical branches. While there may be other limitations (excessive use of externals for dependencies) with this structure, this one was enough for me to move to a single branch tree. A single development trunk poses some challenges. The structure below is one I typically use and is the result of studying projects such as Spring.NET
trunk/
/build
/docs
/lib
/thirdparty
/legacy
/db
/migrations
/dml
/ddl
/src
/components
/tests
/webs
/tasks
/services
The structure should be pretty self explanitory, but I’ll describe it briefly.
- build – NAnt or MSBuild common files.
- docs – Help files and the like. Stuff that’s not project documentation.
- lib – Common assemblies. All project references are to assemblies in this structure
- db – Database migrations and any non-migration DDL or DML.
- src – All applications. Common libraries are in components.
While this structure won’t work for everyone, I’ve found it to be a good starting point. It provides some obvious benefits over the alternate structure I described above.
- Keeping dependencies in source control means all working copies should be buildable. No assumed install paths or GAC requirements.
- Project references are easy to manage. All common libraries are in one path. Relative references may be used.
- Organizing the repository by app type (web, task, etc.) allows for solution files to be created by type (e.g., Webs.sln, Tasks.sln)
- It’s easy to structure a Master.sln file at the root of src that includes the entire tree. This solution file is important for having a single buildable solution for CruiseControl.NET
- Branching is easy for cross-cutting changes. This attribute means it’s also easy to setup a build in CC.NET for a branch, since all is relative.