How I Use Subversion

Last night I gave a Subversion presentation for the Refresh Baltimore group. The presentation ended up being a bit more of an informal dialog due to time constraints, but that was actually great. I rather enjoy talking with people rather than at them, when appropriate. The audience seemed to be largely front end developers, but many were very new to source control in general and, of course, Subversion in particular.

After the meeting, I thought I’d write a bit about how I use source control within my workflow. It’s the personal experience that folks in the group – myself included – seemed most interested in. The terminology I’ll use will be Subversion-centric since that’s my tool of choice (for the moment), but the philosophies, methodologies and processes should be comfortably analogous to other versioning tools.

Underlying Philosophy

Before getting started, it may be helpful to understand, at a high level, how I use the repository.

For my purposes, I’ve adopted the so-called “branch when needed” philosophy. Following this approach, all day-to-day work is done on the trunk. Most of my changes are reasonably small (or can be completed in small, iterative steps) so this is an easy and logical convention to follow.

At some point or another, though, most projects require some level of refactoring. Then there’s the need to add some large feature whose tentacles may stretch across several of the project’s subsystems. These types of changes, indeed any change that can, will or even threatens to destabilize the trunk for any period of time, should be made in a branch.

Standard development tasks can continue along the trunk without concern for the instability that exists on the branch; changes made to the trunk can be merged into the branch so that the branch remains sync’d with the latest code base and, when the destabilizing development is complete (and stable), the branch can be merged back into the trunk.

My Repository Template

Understanding how I use the repository, it may also be helpful to see what my repository looks like before I commit any code. I have a template repository that looks like this:

.repositorytemplate/ branches/ development/ maintenance/ tags/ build/ release/ trunk/ _meta/ classes/ html/

At the top level, I’ve chosen to stick with the ubiquitous trunk, tags and branches structure. Beneath that, my structure is more customized and meets my needs for both product development and traditional web development. Here’s a quick breakdown:

branches/development

Any branches of the trunk, or of another branch, created for the express purpose of developing against that branch. Branches created for refactoring or feature development, as outlined above, should be created in this directory.

branches/maintenance

Maintenance branches are created “just in case”. More on this below.

tags/*

Tags, for me, are strictly read only and offer a historical snapshot. They may be deleted if they’ve outlived their usefulness, but deletion is rare and updates are unheard of. Tags should remain exactly as they were created and they are created to “pin” the code base at a given milestone. My workflow includes build and release milestones so there’s a tag directory for each.

Again, more on this below.

trunk/html

This is pretty much what it sounds like. When deployed, the trunk/html/ directory is the web root (assuming a web application). Any file that needs to be accessible by URI belongs somewhere in this directory.

trunk/classes

My preference is to keep my class definitions outside of my web root. It makes me feel like my business logic isn’t quite so exposed. That may not be the case, of course, but every little bit helps, right? Using my own site as an example, the trunk/classes directory might contain subdirectories that follow the familiar java classpath pattern: org/robwilkerson/data, org/robwilkerson/util, etc.

trunk/_meta

The trunk/_meta/ directory contains, well, pretty much everything else. It might include the PSDs from design comps, any documentation files (ERDs, use cases, etc.) or anything else. It will always include the DDL scripts used to create or update my database(s) and my Ant build scripts.

This directory is never deployed to any server beyond the development server and should not contain any files or resources required by the application at runtime.

Committing Changes

Everything above is about getting started. This is about working. The key to a useful source control tool is committing changes. For optimal results, commit frequently, commit logical changesets and keep those changesets small.

The more commits you do, the richer your change history will be and the more granular your rollback options will be. When working through bug fixes, fix and commit one bug at a time. Avoid fixing twelve bugs and committing everything in one push. How will you know which changes were made to fix which bug? You’re trying to establish a meaningful timeline and to provide accountability for each change.

While trying to keep your changesets small, though, use good sense. Don’t commit a half-baked change for the sole purpose of keeping the number of modified files low. There are no hard and fast rules on this, but it should feel pretty intuitive once you get started.

When committing changes, it’s important to provide meaningful commit messages. Some changes may require a sentence, others may lend themselves to several paragraphs. When I’m committing changes, I try to write my commit message so that a log view shows why I made each change rather that what the change was. Subversion has a pretty nice diff tool that will happily tell you what was done. The question of why can be much more elusive.

My rule of thumb is to write one sentence about what I did and as much verbiage as I need to describe why I did it.

Branching

In addition to development branches that are created whenever they’re needed, I also create a maintenance branch each time I deploy a project to production. I consider this a “release” and I like to have a maintenance branch for that release.

The reason for the maintenance branch is that while development on the next version of the application continues against the trunk, the maintenance branch sits ready if a nasty bug is found in the version that is currently deployed. The bug can be fixed in the maintenance branch, redeployed with only those changes (not the changes that are being made on the trunk) and, once fully vetted, those changes can be merged into the trunk so you don’t have the same problem in the next release.

Tagging

In addition to “releases”, I also have a concept of a “build” (these are not new concepts, of course, I’m just saying that I use them in my process). Most deployments are staged. Development happens on a development server – in my case, a sandbox on my personal machine – before the code base is pushed to a staging (or QA(Quality Assurance), testing, etc.) server for integration testing and/or UAT.

Each time code is pushed to a non-development environment, I create a build tag to provide a snapshot of the entire code base at the revision from which the build was created. These can be useful from time to time, but are rarely critical. Personally, I just like being able to see the deployment path in one place. I often delete build tags when I feel like they’re no longer necessary.

When a build is being deployed to production, I create a release tag at the same time I create the maintenance branch. The release tag is the “golden snapshot”. Since it marks a release, it is immutable and I’ve never deleted one.

So that’s how I put Subversion to work for me. I’d be interested to see how others make Subversion – or source control in general – work for them.

Subscribe15 Comments on How I Use Subversion

  1. Chad Kieffer said...

    Excellent article Rob. As a frontend developer/designer first, I can say that the points in your “Committing Changes” section are the points to stress to those new to source control. Committing in small increments, writing meaningful commit annotations, and committing only working code that’s been thoroughly tested is paramount to the source control process.

    I hope to write a similar post focusing on my experience adapting to a source control workflow.

  2. Rob Wilkerson said...

    Quite right. My intent was to loosely document my end-to-end process, but that shouldn’t have been done at the expense of an appropriate focus on committing. The rest (branching, tagging, etc.) is useful to me in my own workflow, but utterly useless without a proper strategy for commits.

    And, by the way, it’s about time you start writing again. :-)

  3. Chad Kieffer said...

    Ya, I know. I’m starting to teach my oldest son HTML. A little child labor will do him good and free me up to write again :)

  4. Rob Wilkerson said...

    Ha! Nothing like a good sweatshop joke to elicit a belly laugh at 5:45am. Hopefully you’re teaching him standards via XHTML or HTML5, though. And to separate his presentation from content.

  5. Chad Kieffer said...

    Of course! After a week or two of markup we’ll move onto CSS. He already has a project in mind. Should be fun for him, and me :)

  6. Benjamin Sterling said...

    Rob, I know this is an old post but I finally got subversion and trac installed on my pc, figuring out what version of what apps goes together was a pain.

    Anyway, I’m trying to figure out how you are doing things, you say that the trunk/html is where the website resides. But when you set a site live and need to develop next version and are still working on the trunk, where is the live site residing? Ultimately we don’t people see our work in progress so I am assuming you do something to point to a branch, is this correct?

    Thanks.

  7. Rob Wilkerson said...

    Hey Ben –

    You must be installing on Windows. Doing so on Linux is quite simple (although that may seem counterintuitive). :-)

    Using my own (perhaps half-baked) terminology, /trunk is my “project root”. /trunk/html is my web root as you suggest. I checkout a copy of /trunk to my development environment. When development is complete, I export a copy of /trunk to my production environment. Since everything is just a copy, the code bases “co-exist” happily (mostly because they’re not co-existing at all).

    From the way you’ve worded it, it sounds like you might be trying to point your web root directly to your trunk. If so, that’s not going to work. You really want to be running your production site against a snapshot created by an export.

    I hope I understood your question correctly, but feel free to follow up if I didn’t.

  8. Benjamin Sterling said...

    Yeah, you answered the question and yes, this is on windows :(

    I am just having a hard time visualizing everything I need to do/want to do. If you don’t mind me picking your brain a little more, I have a scenario that I want to achieve. I’ve been reading thru the svnbook and not getting a true picture of how to approach.

    Basically I am already doing more or less the structure you have above minus the svn. And every thing is ran on my local machine and when a project is completed, I ftp it to where ever it is hosted. I would like to set things up so that when I create a new project I get the template you have, but not sure how to do that. Or am I being dense and it is as simple as creating the folders and doing svn cp trunk/ tags/ to move the files around?

    Thanks for your feedback, it’s been a while since I’ve been this lost :)

  9. Rob Wilkerson said...

    Okay, that should be pretty simple. If I understand you correctly, you want to do exactly what I do, so I’ll lay out the steps I took/take:

    1. In some directory on your local machine, create a template directory. On my work machine (Windows), my path is C:\Projects\.template.
    2. In that directory, create your top-level structure (/branches, /tags and /trunk). I’ve zipped up my entire template structure for your use, if you care to just unzip that into your new directory. Note that several directories contain empty text files that can be removed. They were added so that empty directories would be included in the zip file.
    3. Import that directory structure to <path to your repository>/.template.
    4. To create a real project, as you already stated, svn cp -m “Creating initial project structure from template.” <path to your template directory> <path to your target directory>. The target directory should not exist before copying. Subversion will create it. If it already exists, you’ll get unexpected results.

    I should also state that for my purposes, I have one repository containing multiple projects. One of those “projects” is my template. If you’re trying to create a one-project-one-repository structure, this won’t work in exactly the same way.

  10. Benjamin Sterling said...

    Rob you are awesome; after I posted the comment last night a just thru caution to the wind and did exactly what you just said and it worked well. It is amazing what happens when you just do. I am using the on repository approach and I think that will fit my needs.

    I’ve got everything set up in a /root/company/client/project structure (I do a lot of freelance work for a couple of clients hense the structure) and basically svn is a mirror of my test server and that seems to be working well. I will be working on a few projects today so I will see exactly how well it works as the day goes on.

    Thanks for the help, I truly appreciate it.

  11. Chad KIeffer said...

    Hey Rob, I’m finally getting around to building my own project template. Why do you hide your project template directory, why name it .template. I realize that the template probably doesn’t change that often. Do you just not want to see it your project
    directory list?

  12. Rob Wilkerson said...

    Hey Chad –

    To be honest, my intention wasn’t for the nomenclature to be quite so literal. I used .template somewhat symbolically (because it’s indicative of the idea that the project isn’t a “working” project, per se), but mostly so that it would sit atop any svn directory listing (remember, my template isn’t in it’s own repository).

    My checked out version actually lives in a directory named svn_template where I make the few changes that I want/need to make as my process evolves.

    I’m a pretty simple guy and my motives often underscore that simplicity. :-)

  13. Chad Kieffer said...

    Well, I’m a lazy, er, I mean literal kind of guy :) You present a great example here for folks to get started with, thanks again :)

  14. Chad Kieffer said...

    Hey Rob, another pesky question for you. I’m still green in the area of build/release management so forgive me in advance if there’s an obvious answer :)

    I think I’d rather not store builds in my repository. I’ll just package them up and give them a unique name based on HEAD’s rev number + the DATE/TIME built. IMO, committing builds seems to unnecessarily clutter the revision history.

    What are the benefits of committing build revisions for you?

  15. Rob Wilkerson said...

    @Chad

    I think of it as being a little like denormalizing a database. It’s not strictly necessary, but it can be a useful convenience. I like having a tag I can reference at any time. This is particularly true for releases (whose tags I keep around forever), but I also throw in build tags so that I can easily track variations between any given build of the same release.

    Like it sounds like you’re planning, I give each release a version number like 1.1.3.2390 (major.minor.maintenance.revision). I could always track down any given version number, extract the revision number from the version (assuming it’s available somewhere in the code base) then perform whatever operation I need, but I’d rather just open my tags directory in the repository and do what I need to do.

    Call me lazy. :-)