Simple SVN Merging

Today I had a big SVN merge to do - i'm at the end of a development cycle and I needed to merge my branch of changes back into trunk. I dug out my crib sheet for merging and tweeted that I had - and a few people asked me to blog it so here it is.

diff the relevant paths until the + and - shoe the operations you want to perform to your working copy

change into the equivalent directory on your working copy and replace the word "diff" with the word "merge"

That's it.

Seems like a bit of a short blog post for something that a lot of people find painful, so here's what I actually did, in more depth.

Example

  1. I had the branch I'd been working on checked out. I committed all changes and triple-checked that I had done that
  2. I ran svn log --stop-on-copy and noted the revision number which was the commit where I created the branch
  3. Next I took a checkout of trunk so that I could break things in my own space
  4. I changed into the new checkout and from the root of it, figured out what I should be diffing, piped it to more and read through the output to make sure I really was applying what I thought I was applying. svn diff -r[branch create rev]:HEAD http://path/to/repo/branch/ | more
  5. Then I ran the same command again but without the |more and with diff now replaced by merge
  6. I then checked my working copy, if there were conflicts I'd have resolved them, checked the system still worked, that sort of thing
  7. Committed my changes

I hope that helps - the same principle applies whether you are applying one fix or many fixes to trunk or branches - the key is to think about what it is you want to merge, and make sure the diff looks right. You can play with the diff without breaking anything for as long as you need to (which today was just as well because the first thing I tried was completely not the right one!) and once it looks plausible - merge those changes in and then untangle anything which has gone wrong from there. Hope this helps!

10 thoughts on “Simple SVN Merging

  1. Thanks for this. I'll have to play as I find the whole stop-on-copy stuff very magical.

    At the moment, we just do:[geshi lang=bash]
    svn merge --reintegrate https://blah/branches/branch_name
    [/geshi]into a checkout of the trunk. We then resolve conflicts, test and commit.

    The only downside I'm aware of is that after a reintegrate, continuing to use the branch causes all sorts of issues. If you need it still, then delete and re-create it. Fortunately, that's not an issue with our development process as we'd use a new branch name for the next bit of work.

    Regards,

    Rob...

    • One snag...

      If you use --reintegrate you kill the branch. This can be a problem if you revert the merge. How do you re-edit the branch to try again?

      The only way I could figure out was to export from the branch and drop the code into a new branch. You then copy changes from the dead branch to take the problematic bits out. Painful.

      Hopefully the --reintegrate flag will die off once subversion mergeinfo works properly.

      yours, Marcus

  2. As Rob also pointed out ... the new-ish Reintegrate Merge in SVN really makes that previously complicated step, rather simple.

  3. Rob, Eli: Thanks for your comments. I am much happier looking at the dry-run of the changes and then merging those, not sure about the reintegrate merge stuff. Also I often patch odd changes between branches/trunk and it sounds like I would break this quite quickly ... will look it up though if you find it useful.

  4. That might have worked in your specific situation, but for bigger changesets, you're almost certainly guaranteed to run into weird conflicts etc with this method, especially if there were many changes to trunk while you were developing in the meantime.

    As the SVN manual states, the recommended process is this:

    * regularly keep your branch in sync with trunk (or whatever location you branched from) by doing *svn merge -r 1234:1345*, where _1345_ is _HEAD_, and _1234_ is the revision of the commit you made last time you merged (note that _1234_ itself will not be merged from trunk)
    * once you're ready to merge, get branch in sync with trunk one last time, and note the current revision number (lets say that is _1456_)
    - switch to a clean copy of trunk, and run *svn merge https://.../trunk@1456 https://.../branches/blah@1456* (do not use _HEAD_ - you're in for bad surprises if someone else modified one of the files in the meantime)

    This will apply the differences between trunk and branch blah at the given revision, which is exactly what you want to merge back. As I said above, the other method may cause trouble; I've been there before - you might even lose changes from the branch in the process.

  5. David: You make an excellent point there. I usually merge trunk changes out to my branch if the branch is out for a while, I was more focussing on the act of getting branch changes into trunk. I agree though, having the branch already including as many trunk changes as possible is a very good recommendation! Doing more than just branching and then a single merge back is what makes me nervous about the merge-reintegrate flag although I'm open to being told it does actually work.

    • That does work, yes, but you still need to sync trunk changes to your branch, of course. The nice thing is that it does not require you to keep track of revisions that have already been merged. Instead, whenever you're bored for a moment, you do
      svn merge https://.../trunk
      in a clean branch working copy, and it will figure out what revisions to sync over.
      Once that is done, you can to the --reintegrate merge in a clean trunk copy to have your branch merged back.

      That's an SVN 1.5 feature, and I'm hearing there are still a couple of problems with it when it comes to moving of files etc. Most people so far use svnmerge.py, which essentially does the same thing. I always merge by hand, as I don't find it particularly difficult, but I guess it's all a matter of taste :)

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

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