rc3.org

Strong opinions, weakly held

svnmerge

I am very happy with Subversion as far as version control systems go, but it has one glaring deficiency. When you create branches, it can be extremely difficult to keep track of which changes you’ve merged from one branch to another. This is probably best explained with an example.

Let’s say you have a repository, and it’s setup with trunk (where the main development takes place), branches where you work on versions of the code separate from the trunk, and tags, where you mark development milestones. One common development model for Web applications is to work on new features in the trunk and create a branch for the version of the application that’s actually deployed. You create that branch like this:

svn copy http://sourcecode/svn/myapp/trunk http://sourcecode/svn/myapp/branches/production

Eventually you’ll make changes in the trunk that need to be applied to the branch as well. This is where Subversion falls short. It knows where the branch originated, but it doesn’t provide any way of keeping track of which changes in the trunk have been merged into the branch (or vice versa). Keeping track of this sort of thing by hand is incredibly painful, and it’s exactly the sort of thing computers are good at.

A couple of days ago I discovered svnmerge, which handles this problem rather nicely. It’s a Python script, so it works on just about any platform (as long as you have Python installed), and it uses Subversion properties for data storage. Subversion properties are stored in the repository, so you can share your merge information among multiple users.

When you create a new branch, you just run the svnmerge init command. As the trunk changes, you can use the svnmerge avail command to see which revisions have not yet been merged into that branch. To perform and log the merges, you use svnmerge merge. (svnmerge will merge only the revisions you specify or all of the outstanding revisions.)

If you’re a Subversion user, I strongly recommend checking out svnmerge. The one question I haven’t figured out the answer to is whether svnmerge also keeps track of revisions to the branch that need to be merged back into the trunk, but I’ll get to it.

Note: SVK is another tool which provides this functionality (and a lot of other things). I haven’t had the chance to use it myself, but I hear good things.

4 Comments

  1. I understand what you are saying since I’ve worked on a number of code teams with various version control systems.

    However, I’m wondering if there is something fundamentally wrong with the model you are proposing? What I’m thinking is that it’s preferable to go back to the trunk and re-generate the branches rather than merging duplicate changes into the trunk and the branches. In other words, you should be using a single maintenance point or modular approach to the code change process similar to what you do for design and development.

    For example, perhaps one of the branches is a “free” version that is missing certain features.

    Let’s say to start with the trunk is at version one, say T1 and you generate branch version one from it automatically, i.e. F1.

    Meanwhile, you make corrections and/or improvements to the trunk such that least some of them affect the functionality of the branch version.

    So now the trunk is at version two, say T2. According to my model, you should treat F1 as a dead end and re-generate F2 from T2.

  2. Yeah, that’s another way to do it. I generally use a mix of short lived branches and long lived braches.

    To give another example, the trunk is where the main development is taking place, and I have a branch where I’m porting the code to use updated versions of some libraries. Since it’s a low priority project, I may have that branch in existence for two or three months. Before I can merge that branch back into the trunk, I need to keep merging changes from the trunk into the branch. svnmerge helps in cases like that as well.

  3. I understand.

    That’s a nasty job no matter what.

    I used to work with a version control system that had something called #IFDEF which was a way of flagging certain blocks of source code as conditional depending on the parameters used used to check out the source from the trunk. (I don’t know whether Subversion has a similar feature or not.)

    With this feature you’d work directly with the trunk on this type of project which likely requires lots of little patches all over the place. Say the original trunk is


    oldLibraryMethod()

    You would change this to


    IF DEF newLibrary

    newLibraryMethod()

    ELSE

    oldLibraryMethod()

    ENDIF

    IF DEF newLibrary

    fix needed somewhere else because of change in library

    ELSE

    whatever

    #ENDIF

    This feature was very useful for such things as accommodating coding specific to particular target OS’s.

    This approach might make sense in your example where there might be a long period where you have to be backwards compatible with the old library but also allow for upgrades.

  4. Rafe,

    You’re using svnmerge in exactly the same way as we used it at my last job.

Leave a Reply

Your email address will not be published.

*

© 2024 rc3.org

Theme by Anders NorenUp ↑