Subversion 1.5 merge-tracking in a nutshell
As I’ve mentioned in other posts, the Subversion project is on the verge of releasing version 1.5, a culmination of nearly two years of work. The release is jam-packed with some huge new features, but the one everyone’s excited about is “merge tracking”.
Merge-tracking is when your version control system keeps track of how lines of development (branches) diverge and re-form together. Historically, open source tools such as CVS and Subversion haven’t done this at all; they’ve relied on “advanced” users carefully examining history and typing arcane commands with just the right arguments. Branching and merging is possible, but it sure ain’t easy. Of course, distributed version control systems have now started to remove the fear and paranoia around branching and merging—they’re actually designed around merging as a core competency. While Subversion 1.5 doesn’t make it merging as easy as a system like Git or Mercurial, it certainly solves common points of pain. As a famous quote goes, “it makes easy things easy, and hard things possible.” Subversion is now beginning to match features in larger, commercial tools such as Clearcase and Perforce.
My collaborators and I are gearing up to release a 2nd Edition of the free online Subversion book soon (and you should be able to buy it from O’Reilly in hardcopy this summer.) If you want gritty details about how merging works, you can glance over Chapter 4 right now, but I thought a “nutshell” summary would make a great short blog post, just to show people how easy the common case now is.
- Make a branch for your experimental work:
$ svn cp trunkURL branchURL
$ svn switch branchURL - Work on the branch for a while:
# ...edit files
$ svn commit
# ...edit files
$ svn commit - Sync your branch with the trunk, so it doesn’t fall behind:
$ svn merge trunkURL
--- Merging r3452 through r3580 into '.':
U button.c
U integer.c
...$ svn commit
- Repeat the prior two steps until you’re done coding.
- Merge your branch back into the trunk:
$ svn switch trunkURL
$ svn merge --reintegrate branchURL
--- Merging differences between repository URLs into '.':
U button.c
U integer.c
...$ svn commit
- Go have a beer, and live in fear of feature branches no more.
Notice how I never had to type a single revision number in my example: Subversion 1.5 knows when the branch was created, which changes need to be synced from branch to trunk, and which changes need to be merged back into the trunk when I’m done. It’s all magic now. This is how it should have been in the first place. 🙂
Subversion 1.5 isn’t officially released yet, but we’re looking for people to test one of our final release candidate source tarballs. CollabNet has also created some nice binary packages for testing, as part of their early adopter program. Try it out and report any bugs!
Fantastic. This really is how it should have been done all along.
To use this merge-tracking feature, do I just need to install 1.5 locally, or must it also be installed on the Subversion server I use?
@Ian: merge-tracking requires *both* a 1.5 client and 1.5 server. Full details are available at:
http://subversion.tigris.org/svn_1.5_releasenotes.html
Word of warning, though: if you touch an existing working copy with a 1.5 client, the working copy is ‘auto upgraded’ such that older clients can’t read it anymore. Same situation on the server side, except that you need to deliberately run ‘svnadmin upgrade’ on the repository to move it up to 1.5 format.
Ben,
That is great news! I see 1.5 is currently on rc5, are there many more rc in queue before the release or are we near the end?
This might just stop a few people defecting to Git. Excellent news!
Well, finally SVN branches will stop being useless for me. Now if SVN only supported disconnected operations…
Wow, that looks so much more sane. Great stuff.
@Nick: Each “rc” is believed to be the last (else, it wouldn’t really be a (r)elease (c)andidate. But don’t let the “5” scare you — we had quite a few false starts that never saw public release, and since we don’t ever re-use release numbers (even if the tarballs are DOA), the RC number ratcheted up a bit faster than usual.
Great capsule summary, Ben! I think I would have included an explicit “commit” as the first step of each merge or switch sequence, though, to point up the value of keeping the commits pure (and reverts possible).
Neat!
How will this work, when one keeps merging the same branch back into trunk? Like I do, with each bug fix currently. Like this:
Release 1.3.0 of my product, which i then TAG.
A bug is reported. I do a 1_3_bugfix BRANCH, copied from 1.3.0 TAG. Fix the bug, TAG a 1.3.1 from branch, release and merge the branch bugfix back into trunk.
A while passes, and shit, a new bug is discovered. I fix the bug right on the branch, TAG a 1.3.2, release and …
This is when I usually need to merge only the 1.3.2 changes back, using revision numbers.
Will this just be a –reintegrate, even though I have reintegrated before?
Cause if it is, .. me like it 🙂
@Tech Per: Read chapter 4 in the 1.5 book:
“Now that your branch is merged to trunk, you have a couple of options. You can keep working on your branch, repeating the whole process of occasionally syncing with the trunk and eventually using –reintegrate to merge it back again. Or, if you’re really done with the branch, you can destroy your working copy of it and then remove it from the repository”
@Sandy: Thanks! I am already loving it. Gotta get 1.5 when it comes out. If I dare upgrade my repo 🙂
Great! This will make our lifes a lot easier. I’m really looking forward to the 2nd edition od the Subversion book” and release 1.5.
Wow. Subversion is my favorite centralized version control system. Now I have even a better reason to love it more. It is almost perfect for my needs.
I’m wondering what is the difference between this new feature and using svnmerge.py (of which I have become quite adept, so I already wasn’t afraid of feature branches!)?
My biggest issue is usually with renames, where it will usually lose the changes to the file if you’re not very careful.
I have a follow-up question to items 13 and 14 above in light of the statement in the current (r3212) Subversion book: “At the time of writing (Subversion 1.5), once a –reintegrate merge is done from branch to trunk, the branch is no longer usable for further work. It’s not able to correctly absorb new trunk changes, nor can it be properly reintegrated to trunk again.” Based on this statement the ability to repeatedly reintegrate described in #14 is not currently available.
Item 13 describes the workflow I want to use on my project. Is it still a planned objective that will be achieved in a later svn release?
Thank you.
@MarkB: try posting your question to the dev@subversion.tigris.org list.
Why is the “–reintegrate” option necessary?
See http://svnbook.red-bean.com/nightly/en/svn.branchmerge.basicmerging.html#svn.branchemerge.basicmerging.stayinsync
“When merging your branch back to the trunk, however, the underlying mathematics is quite different. Your feature branch is now a mishmosh of both duplicated trunk changes and private branch changes, so there’s no simple contiguous range of revisions to copy over. By specifying the –reintegrate option, you’re asking Subversion to carefully replicate only those changes unique to your branch. (And in fact, it does this by comparing the latest trunk tree with the latest branch tree: the resulting difference is exactly your branch changes!)”
Thanks, Ben. I get that part, but what I don’t understand is why svn can’t figure out that you’re doing a reintegration on its own. If the feature branch keeps metadata on its own merge history, shouldn’t it be able to detect you’re doing a reintegration on its own? Also, I would generally like to keep a feature branch around for a week or two after reintegration just in case; is that planned for the future?
Great feature! Works quite well, I did have a problem while trying to reintegrate:
svn: Cannot reintegrate from ‘*url*’ yet:
Some revisions have been merged under it that have not been merged
into the reintegration target; merge them first, then retry.
Pretty confusing message, I was able to fix it by removing all mergeinfo properties from the branch manually..
I have a question for you. With our scenario for locking down code for testing and user acceptance testing before it goes to prod, we may run into some syncing issues. It’s best to draw a picture:
http://ferventcoder.com/archive/2008/10/23/call-for-input-branch-development-syncing-issue.aspx
What an excellent blog, I’ve added your feed to my RSS reader. 🙂