Simple Subversion Merges

Subversion merging can be a complex task, one that's decidedly terrifying at times. I'm typically always worried when I perform an svn merge, and so I always consult the red bean manual when I'm about to do one. In the last few weeks I've written a handful of emails explaining how to do it quickly and painlessly, so I thought it beneficial to detail how I do basic merging as a reminder to myself and hopefully as a helpful tutorial for someone looking to make it as painless as possible via a command line interface.

Let's begin with a scenario; one that should be quite familiar (This may be a "no shit" scenario for you, but I want to give us some context.): you're going to publish your website for the first time. You want to publish the site live but your client wants you to develop a new feature. You want to be able to update the production build with bug fixes while you work on the new feature. So, you create a branch in your subversion repository:

svn cp trunk branches/release-1.0_launch

The release-1.0_launch branch will be uploaded to your host (however you might be doing that; FTP, svn check-out, rsync, et al) and remain live while you develop your new features in trunk. That's all find and dandy, but say you fix a number of bugs or quickly have to add a feature to the release-1.0_launch branch. Instead of "hackily" making the same bug fixes in trunk and having to copy and paste the new features, you'll do a merge from the branch to the trunk.

The merging process is basically two steps:

  1. Make sure everything is up to date locally (svn update the repo).

  2. Use svn merge to merge the branch into your trunk.

Where it gets somewhat complex is you need to let subversion know how much you want to merge, i.e. you can merge a number of commits from your branch to your trunk. The syntax is straightforward:

svn merge -r{FROM_REVISION}:{TO_REVISION} branches/release-1.0_launch trunk

Let's say you want to merge all the commits to the branch into the trunk. You can use the --stop-on-copy flag to figure out the revision number was when you copied from trunk:

svn log branches/release-1.0_launch --stop-on-copy

The earliest log number (FROM_REVISION) is where you want to copy from through the most recent commit number (TO_REVISION), which you can use svn update to get. Before you even run merge, definitely make sure you do a svn merge with the --dry-run flag first to make sure nothing alarming will result.

Taking the revision number from the --stop-on-copy and the current HEAD revision from svn update, you'll merge from branch to trunk. For example assuming our FROM_REVISION was "123" and our TO_REVISION was "126"

svn merge -r123:126 --dry-run branches/release-1.0_launch trunk

This merges revisions 123 through the most recent (HEAD) from the branch to the trunk. The --dry-run flag will tell you what should happen. You'll need to remove that to actually perform a merge.

Once you think the files changed in the potential merge look good, remove the --dry-run flag and run it. Running svn status will tell you what's different in the trunk after the merge. You may have to resolve some conflicts with the files in your trunk. One really useful task I use all the time is to get a diff of the changes and pipe it to TextMate:

svn diff | mate

This will open the diff file with TextMate (assuming you've set up the mate command from Textmate > Help > Terminal Usage) with some lovely syntax highlighting; typically makes it much easier to take in the changes with color coding!

Once you've merged and resolved your conflicts, obviously you'll want to run any unit tests and check the project to make sure it's working as expected. After that, commit the trunk with a thoughtful message like "Merged -r123:126 from release-1.0_launch to trunk" so you can look back and see what revisions were specifically merged.

June 30th, 2011 | Permalink