Ancient Programming

What I encounter in my software part of life is in danger of being commented upon here

Best practise when handling tags and branches (using subversion)

Posted by Jacob von Eyben on March 15th, 2008

This is the way I prefer tagging and branching my code when developing and releasing software. I use subversion but the overall guidelines can be applied by any versioning tool - say CVS.
I assume that you keep your source in the recommended structure:

  • trunk
  • tags
  • branches

Versioning

Always use three digits to denote a release: major.minor.bugfix. ex: 1.2.0.

Name your trunk code like this: major.minor-SNAPSHOT, where major.minor denotes the next version to release. ex: The version in production is 1.2.0, you should name the trunk version 1.3-SNAPSHOT. I use snapshot to tell others that such a version is an arbitrary build along the way to a stable 1.3 release (The name ’snapshot’ is inherited from maven).

Releasing

When releasing your code, you should tag the version you release by the version. This gives you a chance to always branch from that specific release if a bugfix is required. Ex: you 1.3-SNAPSHOT is ready to go into production. Tag a version by the name 1.3.0.
Even though some versioning tools allow you to commit to a tag, you should not do so. Tags is an image of the sourcecode at the release time!

At the same time you should change your trunk version t0 1.4-SNAPSHOT.

Branching

If your newly created release contains a bug that can’t wait to be fixed until your next trunk release, you should create a branch. Do so from your release tag.

You should name your branch like this: major_minor_bugfix, where major and minor is the same as the software in production. Ex: 1_3_bugfix.

Merging

I do not recommend having unmerged code on your branch for to long.
I suggest you you merge your software back to trunk for each fix you do. At least you should merge your branch back to trunk when your release a new version.

To assist you in this I suggest your commit message tells what revisions that is involved, - The revision from the branch and the revision on trunk.

Subversion commands

The following is the commands to use in subversion. I assume you use ssh to access subversion and the subversion repository is located at ancientprogramming.com in the directory /var/subversion:

Tagging in subversion

$ svn copy svn+ssh://username@ancientprogramming.com/var/subversion/project/trunk \
svn+ssh://username@ancientprogramming.com/var/subversion/project/tags/1.0.0

Branching in subversion

Similar to tagging except the path.

$ svn copy svn+ssh://username@ancientprogramming.com/var/subversion/project/tags/1.0.0 \
svn+ssh://username@ancientprogramming.com/var/subversion/project/branches/1.0-bugfix

Merging

I will split this into two cases. The case where you merge from the branch the first time and the following merges.

First merge from a branch

First you want to know what revision you are to merge from.That is the revision your branch was created at. You find that revision by executing the following command in your branch checkout:

$ svn log –stop-on-copy

That will list all your changes created on your branch since it was created. You can see the revision where your branch where created in the log output.

Knowing the revision you are ready to merge your changes. Change to a working copy of your trunk code and make sure your checkout is up to date by executing and findout the revision to merge into:

$ svn up

This will update your trunk copy and output the revision you are to merge into.
Now merge the changes by using the following command on your trunk working copy:

$ svn merge -r rev1:rev2 \
svn+ssh://username@ancientprogramming.com/var/subversion/project/branches/1.0-bugfix

where rev1 equals the revision your branch was created and rev2 equals the revision on your trunk working copy.

Fix any conficts and commit your code. It is important that your commit message contains the to revisions you merged. I suggest you write the following. That message is important in later merges:

$ svn commit -m ‘Merged branches/1.0-bugfix rev1:rev2′

Following merges from branch

The next time you would like to merge, you execute the following in your working copy of your trunk code to find the revision to merge from:

$ svn log | grep -i merge

This assume that your commit message when merging contains the text merge - as we did in the first case.
The revision to use is the revision you merged into the last time +1.

Ex your log message looks something like this: ‘Merged project/brances/1_2_bugfix r1631:r1682 into head’, the revision to use is 1683.

With that version just repeat the steps from the ‘First merge from a branch’.

I suggest you read here to find more about branching and merging in subversion.

6 Responses to “Best practise when handling tags and branches (using subversion)”

  1. Tech Per Says:

    Good post, I agree with most of it.

    The example on branching is not that educational, as it copies from trunk into 1.0-bugfix. It would have been more educational to show copying from the tag 1.0.0 to 1.0-bugfix.

  2. jeyben Says:

    You are so right. As I write In the section ‘branching’:

    … Do so from your release tag.

    but my example doesn’t match my words. I have corrected it.

  3. Bram Bruneel Says:

    Hi,

    When I release, I branch from the trunk into a major.minor branch. This way I can adjust my pom.xml in the branch so it has the correct release scm urls and more importanly a correct version id, one without SNAPSHOT. Modifying the pom.xml in a tag is not really clean.

    When that is ok I tag (major.minor.bugfix) from my branch. All bugfixes are then done on my branch or merged into the branch. After one or more fix(es) are in the branch you can tag again.

    Regards,
    Bram

  4. Clay McCoy Says:

    I’m always surprised that the Subversion convention of trunk/tags/branches top level directories is still considered a best practice. Especially when there is nothing fundamentally different about tags and branches in this case. They are both just copies that can be committed to. I’m constantly surprised how few people realize this, and how the Subversion culture enforces this misunderstanding.

    The only way to have a true immutable tag is to reference the revision number. Doing this with svn:externals or piston is a nice way to group specific versions of projects for a release.

    So the main Subversion best practice that I recommend is to use revision numbers more. Use them for tags, since it is the only way to really lock down what you are depending on. Use them for internal release numbers for similar reasons rather than coming up with an alternate numbering strategy (which I have never seen work). Use them for your build. Or use an SCM solution that has real tags and branches (among other advantages) like Git.

    I used to work with a guy who didn’t understand SCM (even though it was his job). He would constantly call for code freezes when he wanted to do a release. He never understood why I would get frustrated with him for expecting the developers to actually stop developing because he didn’t understand how to manage the SCM appropriately.

  5. [轉載]Subversion 從入門到精通 - 國際認證-考試信息 Says:

    [...] Subversion 實務好習慣 【Best practise when handling tags and branches (using subversion) 】Posted by jeyben:操作 tags 與 [...]

  6. Jacob von Eyben Says:

    @Clay McCoy:
    You have a point, as a specific revision can’t be changed, hence is perfect as a reference to a specific version of the software.

    One rinkle I found about using revisions as a unique marker of a version is that a revision is only unique inside a specific repository.
    If you - like I had to do lately - migrate (dump/load) a sourcetree into an existing repository, you code will be recommitted and retrieve new revision numbers. Then you need another unique identifier (I know that a copy in the tags doesn’t force uniqueness)

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>