Well friends, it’s time for my uber-geeky D&D post. I figure that if you can bear listening to me blab about version control software, banjos, and canned tuna… you can listen to my review of the new 4th Edition D&D rulebooks that came out this summer.

My affair with D&D has been on-and-off my whole life. I played 1st edition in 2nd and 3rd grade, then lost interest. I somehow missed the entire 2nd edition of the game completely. When the 3rd edition came out in 2000, I had just gotten back into the game by playing in NASCRAG touraments, so it was like learning the game all over. And now, eight years later, it’s time for the owners-du-jour to do another round of tax collection: everyone buy new books, relearn the rules.

As usual, the internet is full of people screaming about how the game has been ruined and destroyed, how Wizards of the Coast is evil and greedy and oppressing the freedom of gamers everywhere, forcing us into a treadmill of upgrades. Just like what happened back in 2000. :-) This time around, the biggest screams have been “OMG they dumbed it down into a video game!” There’s a grain of truth to the accusation, but I decided to give the new rules a good sincere try before condemning them. So I invited some friends over. Everyone rolled up a character, and we did a three-hour test game.

The verdict is: I really like 4th Edition. It was super fun. And everyone who played was raving about it as well. We’re talking about continuing the game now. The common quote was how somehow the new rules (with all the “powers”) essentially made 1st-level combat feel like 5th level. No more 1st-level magic users with 3 hit points and 11 AC expending a single magic missile, then hiding in a closet until the next morning. Nope, the 1st level wizard was kicking ass just as much as the paladin, and having a blast!

The new edition seems to be mainly a rewrite of combat rules, and done such that combat is much much much more fun. Not less complex, but way more entertaining. No more endless rounds of “I swing my sword for the 17th time” — it’s all about doing funky ‘powers’ each round, which keeps things interesting. (The comparison to World of Warcraft is justified here!) However, my players weren’t spacing out when it wasn’t their turn — instead, they were on the edge of their seats to see what kind of crazy stunts their allies were going to do. When was the last time you saw that happen?

The other big change is that using a battlemat and miniatures is sort of a requirement now. In 3rd edition, the board-game aspect was an optional enhancement, one which made combat more visually accessible and strategic. In 4th edition, many powers are described in terms of the grid (”explodes in a radius-3 burst”), so it’s kind of hard to not have one now. Maybe this doesn’t bug me, because I’ve always used a battlemat anyway.

If anything is to be criticized, it’s the writing and artwork in the new rulebooks. The art is cheap and cheesy looking. Imagine the worst fantasy art you can, and then take it down a notch. It’s almost like the cover paintings on bodice-ripping romance novels. And the writing is horrible as well: a much bigger font, with writing style apparently targeting 9 year olds. I think it’s noble that the new owners want to indoctrinate a “new generation” of roleplaying gamers, but in the process the books have turned into what reads like a cartoonish self-mockery of the entire genre. For example, here’s a lovely excerpt from the new Player’s Handbook:

“Imagine a world of bold warriors, mighty wizards, and terrible monsters [...] ancient ruins, vast caverns, and great wild wastes where only the bravest heroes dare to tread. Imagine a world of swords and magic, a world of elves and goblins, a world of giants and dragons [...]”

Gag me with a spoon.

Ultimately, though, if you’re an experienced D&D player, this corny writing doesn’t matter at all. There’s nothing stopping you from running a dark campaign, creating characters of real depth and motives, and doing serious roleplaying as you’ve always done. The only “new” thing here is excitement of combat; the storytelling and improv acting hasn’t been taken away.

As I was reading the rulebooks, I took notes as I went. You can read my notes here which compare the old and new rules. I hope they’re useful to people thinking of trying out the new edition!

I’m off to OSCON in Portland tomorrow, and Fitz and I are scheduled to give four joint presentations. I’m sure I’ll have blog updates forthcoming!


Fetching the log for slow or very big repositories can take quite a while. And of course, it requires you to be connected to the repository. You can't show the log messages if you're not online - very annoying if the network is down or you're in a place where you don't even have network access.

read more


We have had a lot of people request that we provide RPMs for 64-bit Linux.  As of today, you can now download those RPMs from our Subversion "community" downloads section:

http://www.collab.net/downloads/community/

CollabNet hosts two kinds of Subversion downloads.  Our "CollabNet Subversion" binaries and "Community" binaries.  The CollabNet Subversion binaries are built and certified by CollabNet and we provide commercial support and SLA's for those binaries.  The community binaries are essentially binaries we have created but have not certified and we do not provide any SLA for them.  We certainly provide help in our discussion forums and we have even made changes to the binaries in the past based on comments we receive from the community.

We do intend to add 64-bit Linux support to our official CollabNet Subversion binaries.  We just are not ready to do so yet.  Once we add a package to CollabNet Subversion it falls under the SLA we provide our customers, and so we cannot add a package until we are ready to provide that level of support.  In the case of 64-bit Linux we have to make sure the necessary hardware is in place, in sufficient quantity, across all areas of the company that need access to it in order to provide our SLA to our customers.

CollabNet engineering has been preparing 64-bit RPMs since early in the Subversion 1.5 development lifecycle, and we of course did so when 1.5.0 was released last month. With so many users requesting 64-bit binaries, we have been looking for a way to deliver these RPMs to the users that need them.  The community download site gives us this opportunity, just as it did when we wanted to provide the community with binaries for OSX.

The RPMs carry the branding of CollabNet Subversion and are identical in packaging to our 32-bit RPMs.  Again, this is because we are preparing for the day when they will be added to our officially certified packages.  If you are experiencing any problems or difficulties with the packages, please post to our discussion forum.


This post covers several topics related to merging with Subversion 1.5.  The goal is to explain the problem of reflective merges, how the new reintegrate option helps, and also some problems that currently exist with that option.

Reflective/Cyclic Merges

This is easiest to explain with an example.  Suppose you are working on a feature branch copied from your trunk.  During the development process you regularly merge ''all'' new changes from trunk to your branch so that the branch stays in "synch" with the work occurring on trunk.  When you eventually merge your branch back to trunk, that is called a reflective (or cyclic) merge.  This type of merge is problematic for Subversion, let's look at why.

Revisions and Merge Tracking

Subversion is based on revisions.  Every commit to the repository creates a new revision and a merge is ultimately just a commit.  Subversion 1.5's merge tracking feature is all about recording which revisions were merged to which paths.  In the previous reflective merge example, this is too coarse of a solution to always yield the right results.  Recall that in our example we regularly merged changes from trunk to our branch.  Each of those merges winds up as a commit (revision) on our branch.  When it comes time to merge our branch back to trunk, all merge tracking can do is help decide whether to include or exclude those "synched" revisions.  The problem is that neither answer is always right.

If we exclude the revisions that were merges from trunk, then we also exclude any work we did to resolve conflicts as part of those merges.  Even worse, we might have carelessly committed unrelated changes as part of the merge (it happens) so those changes would also be excluded.

If we include those synched revisions, then we merge back changes that already exist in trunk.  This yields unnecessary and confusing conflicts.

The only way to truly solve this is to invent a new merge algorithm in Subversion that does not rely simply on revisions.  In discussing the problem it was suggested that this might require designing a new repository format as well.  As part of the 1.5 development cycle some preliminary work was done to explore a new algorithm within our existing design.  Ultimately we decided a new algorithm was not in scope for this release and to ship without it (the release cycle was long enough as is).  We hope to revisit this work for 1.6 or a future release to see if it pans out as a solution.

Reintegrate to the Rescue

Setting aside the issue of new algorithms for a moment, it turns out Subversion already has a technique that does the right thing with reflective merges.  It is the one we used prior to 1.5 and is called a 2-URL merge.  Going back to our original example, suppose the last time we merged trunk to our branch, we merged all the changes up to revision 100.  To properly merge our branch back to trunk, we start with a trunk working copy and run this command:

     svn merge url://trunk@100 url://feature-branch .

This tells Subversion to calculate the differences between trunk at r100 and the feature-branch at HEAD, and merge those differences into our working copy.  Since this is essentially just producing a diff, it includes our conflict resolution work, and does not include any changes that exist in both places.  In other words, we get the result we want.

The new reintegrate option is a shorthanded version of the 2-URL merge.  With it you can just run this command:

     svn merge --reintegrate url://feature-branch .

Internally, when you use this option, it calculates the url://trunk@100 part and then executes the EXACT SAME merge API that the 2-URL merge does.  This is important to remember when discussing some of the problems with this new option, because you can generally use the old 2-URL syntax to resolve the problem.  In other words, reintegrate is just a new syntax plus some safety checks (more on this later).  If these checks fail and cannot easily be corrected, then you can use the older syntax.

One big problem in general with the 2-URL merge process is that it will do whatever you tell it.  You can very easily make mistakes that the command won't catch.  Suppose we left off the @100 in our example and that r101 and r102 were committed to trunk since we last synchronized with it.  When the 2-URL merge runs, it calculates the differences between trunk@HEAD and branch@HEAD.  To the merge process, it would look like the branch removed the changes that happened in r101 and r102 and the merge would remove them from your working copy!  Depending on the change in those revisions, you might not notice this and wind up committing the removal of those changes as part of the merge.  There are a lot of other variations on this problem (such as getting the URL wrong), but most of those problems are at least more obvious and you could just revert the merge.

Because of this problem with the 2-URL merge process, when the reintegrate option was added we decided it should do some safety checks before it will run.  Some of these are fairly tame, such as making sure the working copy is at a single revision, with no switched children, and is not a sparse checkout (i.e. working copy depth is infinity).  If reintegrate errors out because of any of these problems, you can generally just use svn update or switch to "fix" your working copy.  Since reintegrate needs to calculate the base URL and revision for the merge, it also does an ancestry check to ensure the merge source is related to the merge target.

The most controversial reintegrate check is that the merge source does not have any subtree mergeinfo.  Mergeinfo (technically the versioned property svn:mergeinfo) stores merge tracking information.  Normally mergeinfo is set only on the merge target.  Subtree mergeinfo occurs when a merge target has some subtree that was previously a merge target itself (e.g. we merged from a file in trunk to a file in our branch, creating mergeinfo on that file.  This type of merge is fittingly called a subtree merge).  When reintegrating the branch back to trunk the reintegrate safety checks fail because the branch has subtree mergeinfo.  The reason for this check is that a 2-URL merge in this situation doesn't always give the right results.

Problems with Reintegrate and Renamed Files

Most of the problems with reintegrate stem from this check for subtree mergeinfo.  When this check fails, the error you see on the command line is something like this:

svn: Cannot reintegrate from 'url://feature-branch' yet:
Some revisions have been merged under it that have not been merged
into the reintegration target; merge them first, then retry.

The biggest problem is that, unlike when the other checks fail, both this problem itself and the way out of it are less obvious.  If you really did some subtree merges then these checks save you from making a mistake.  Unfortunately there is a very common case people are running into where it only ''appears'' like a subtree merge was performed: When you rename/move something, mergeinfo is created on the new path and this blocks reintegrate from working.  The reasons why copy/move create mergeinfo are beyond the scope of this post, but suffice it to say that we think in the majority of cases the mergeinfo needn't be created.  So the fix we will look at (hopefully in time for 1.5.1) is to be smarter about when copy/move creates mergeinfo.  If those subcommands minimize their creation of mergeinfo, then that would greatly reduce the occurrence of this specific problem when using reintegrate (at least for your future copy/move operations).

If you are running into this problem today, there are a couple of things you can do.

  1. You might want to just manually remove the subtree mergeinfo.  You can do this by running the command:

    svn propdel svn:mergeinfo FOO

    You could run this command after the move, and before you commit, so that the problem never exists in the first place.  Or it can be run later to fix the problem after you realize you have it.

    Generally, the only time mergeinfo needs to be created is when copying/moving a path such that its nearest parent with mergeinfo is different in the path's source and destination.  This is because a path without explicit mergeinfo (when a path has the svn:mergeinfo property set on it it is said to have explicit mergeinfo) simply inherits the mergeinfo of its nearest parent with explicit mergeinfo.  In other words, the svn:mergeinfo property is inheritable and if a copied path inherits mergeinfo from the ''same'' place in both its source and destination, then there is nothing gained by setting explicit mergeinfo on the destination and you can safely delete that mergeinfo.

    In many cases, all mergeinfo exists on the root of your branch.  If you move a path within the branch, then its nearest parent with mergeinfo (the root of the branch) does not change and the path does not need new mergeinfo.  If however, you previously did a subtree merge and then move a path from outside the subtree into the subtree (or vice-versa) then the path inherits different mergeinfo.  In this case the destination path should keep its explicit mergeinfo.

  2. You can also use the old 2-URL merge syntax in this situation.

Additional Reintegrate Problems

Closely related to the previous problem is when subtree mergeinfo is merged into branches or carried into branches when the branch is created (rather than being created in the branch as above).  If you rename a path in trunk (which currently creates mergeinfo), every branch you then create from trunk from then onward also has this subtree mergeinfo.  Alternatively, if you copy trunk to a branch, then copy a path within trunk (again creating mergeinfo), then synch up your branch, then the branch get's subtree mergeinfo merged into it.  In either case this effectively means you can never use reintegrate, at least not unless you can delete the svn:mergeinfo property from the subtree's that have it.

So in addition to being smarter about creating the mergeinfo, we need to examine whether reintegrate can safely ignore subtree mergeinfo in some cases and allow the reintegrate merge to proceed.  For example, what if we create a branch from trunk and some subtree mergeinfo comes into the branch when it is created.  As long as the subtree mergeinfo that exists on the branch remains equivalent with what is in trunk, it's probably safe to allow a reintegration merge.  Of course these sorts of checks start to get real complicated so we are less sure there are easy solutions here, but hopefully there are some that might make their way into 1.6.  One solution that might be worth considering is whether we ought to do this check in the first place?

Branch Management and Reintegrate

An important thing to point out, and I am not sure if the documentation currently does, is that once a branch is reintegrated, it should really be deleted.  If more work needs to happen, create it again with a fresh copy.  There are two reasons for this:

  1. Remember our example with reflective merges?  Once you merge your branch to trunk, if you later want to synch all the changes with trunk back to the branch, you are now in this same reflective merge scenario with your branch!  You can no longer use the simple "svn merge url://trunk"  syntax you were using previously so you have to use 2-URL merges to get your trunk changes into your branch.
  2. If you do not merge trunk changes back to your branch because of the previous point, then when you go to reintegrate again, it will still see r100 (to use our example), as the last trunk revision merged to the branch.  So when it diffs trunk@100 with your current branch, it will not "see" that in r103 you merged the branch to trunk and it will try to merge everything again.

The bottom line is that if you recreate your branches you will not run into this.  svn delete followed by svn copy runs fast, and does not take up any repository disk space.  You do not even have to do anything special to your working copy.  So just do it!

Future Solutions

This post has largely been focused on some problems we have been seeing and were aware of when we released 1.5.  I wanted to get this post out so that we can aid users in understanding the root of the problems.  That said, I do not want to leave you with an impression of "doom and gloom".  The fact is that overall the new 1.5 merge process works quite well and is a substantial improvement over previous versions.  And while the current reintegrate solution for reflective merges can only take us so far without a new merge algorithm, if you understand the process, you can develop a workflow that largely avoids the noted limitations.  There are also a few other other merge bugs we didn't cover here but fixes for these are targeted for the the upcoming 1.5.1 release (which is tentatively scheduled for release late this month).

It is also worth noting that now that merge tracking is "in the wild", the development community has real world data and use cases to work with, making it a lot easier to evaluate new algorithms and bug fixes.  This should help us get fixes out on the 1.5.x line more quickly.  The lack of large, real world repositories using merge tracking was a problem during the development of 1.5.0 as those simply did not exist (outside of Subversion's own repository).

Finally, I just want to point out that I have turned off comments on this post.  I suspect this post will raise a number of questions and I'd just prefer to handle these in a proper discussion forum.  I have created a thread to post comments and questions related to this post in the Subversion forum on openCollabNet.  Please post your comments and questions to that thread.


As many folks know, I’m a huge fan of Interactive Fiction (text adventures). I’ve been working on a z-machine interpreter for Android, as well one that runs in python.

As of today, my iPhone is able to download ‘legitimate’ apps from the AppStore, and there’s still no z-machine interpreter available. For over a year now, there’s been one which requires a jailbroken iPhone out there, but jailbreaking isn’t an option for me (since Google owns my phone.)

My hopes got up when I discovered that the author of Zoom (the best z-machine app for Mac OS X) is actively working on a legitimate iPhone port. However, something he posted really disturbs me:

“A more serious issue is that Apple’s SDK license prohibits downloading code to interpret: this means that it would be impossible to load any games that were not bundled with the interpreter. I think this is probably a fatal problem: it seems doubtful that many IF authors will be willing to pay the $99 required to get their work onto the iPhone - plus it would mean no Zork, ever.”

While it sure is convenient that iPhone users only have one place to check for apps, this really scares me. I’m guessing that the license is intended to prevent people from distributing generic JVM or CLR machines that can download and run any old code, thereby circumventing Apple’s ability to vet applications. But clearly their Safari web browser already downloads and interprets Javascript apps, right? Where does one draw the line? We’re talking about a VM to play text-adventures — would Apple consider the fetching of text-adventures dangerous?

More and more, it’s clear to me that Apple is just as evil as Microsoft, they’re just not as big and powerful (yet)… and they have better taste. Maybe I should give up on issue and just wait for my Android phone at the end of the year. It will be a truly open OS, and I’ll be able to download and run whatever the heck I want.


Well, AnkhSVN 2.0 officially began last November when the original team of AnkhSVN developers and CollabNet got together to jointly develop the next iteration.  The purpose of CollabNet's involvement was to provide some commercial backing to help solidify development resources and to help invigorate the community around AnkhSVN.  In fact, the Microsoft open source folks are involved with the project as well providing free MSVS licenses for the developers, a tech support contact, roadmap discussions with customers, and co-marketing activities that you'll see in the near future, like webinars.  (Sam Ramji, Sr. Director of Platform Strategy at MS, talked about this at EclipseCon.)  The fruits of the venture are finally available with AnkhSVN 2.0.

AnkhSVN 2.0 is a near rewrite of the original AnkhSVN.  If you look at the AnkhSVN 2.0 Roadmap you'll see that the whole delivery mechanism of AnkhSVN was changed from a Visual Studio Add-In to a full Source Control Provider Integation Package.  (This means no more home-grown SCM layer maintained by AnkhSVN.  AnkhSVN now hooks into the VisualStudio.NET SCC APIs to provide much better integration and performance.)  AnkhSVN also adds Subversion 1.5 support by using SharpSvn as the underlying Subversion client API.  While those two architectural changes don't do much for adding new features, other than Subversion 1.5 support, what does AnkhSVN 2.0 bring to the table?  Well, below is a short list of what is new in AnkhSVN:

  • Pending changes window; subversion status and commands available in one place
  • Full support for Visual Studio 2005 and 2008; AnkhSVN is now a SCC package instead of just an addin
  • Better log viewer
  • Merge support
  • Property editor
  • AnkhSVN now supports most project types previously unsupported via the SCC api
  • All solution explorer actions (rename, copy&paste, drag&drop) keep subversion history now
  • Enhanced build process and setup
  • Automatic check for updates
  • And last but certainly not least end user documentation

The list above is not complete, nor does it fully explain the benefits of AnkhSVN 2.0.  Expect to see huge performance increases above AnkhSVN 1.x, better badging/glyphs, more tools and a more complete Subversion client interface.  For more information on AnkhSVN and its 2.0 release, please use the following resources:

AnkhSVN 2.0 is a major improvement in the AnkhSVN line.  Expect to see more new features in the near future and as always, AnkhSVN is an open source project so feel free to contact us to report bugs, suggest new features or to provide any other feedback.


Both the StExBar and the SkTimeStamp extensions are now available for x64 OS. So if you're using a 64-bit Windows, grab the new versions!

If you're using a 32-bit Windows, you should also get the new versions because I fixed some small bugs there too.


read more


I’m done with a nice 12-day vacation. I was definitely on the verge of burning out; unproductive at the office and cranky at home all the time. I really needed to step back and forget about computers for a while.

What I did instead:

  • Went on a family vacation to Dubuque, Iowa, a mere 3 hour drive from Chicago.
    • Stayed in a hotel-waterpark with wife and 2 year old. Waterpark every day.
    • Horse-carriage rides.
    • Mississippi paddleboat rides.
    • Mississippi Aquarium Museum.
    • Lots of ice cream.
  • Finally finished reading Watership Down.
  • Started reading The Compassionate Carnivore, which gives me a warm fuzzy feeling that I’m not alone in being a freerange-itarian.
  • Read the through the new 4th edition D&D Player’s Handbook. I’m a geek. I like roleplaying games. Sue me.
  • Went to the Indiana Dunes — at a friend’s house — for the 4th of July.
  • Went to the Bristol Renaissance Faire
  • Shot 300 photos. A few of them were pretty good.
  • Beta-tested an excellent new text-adventure game written by a friend; it should be available to the public by August 1st.
  • Played my banjo at the usual Friday night jam.

Time to go back to Google; I’m continuing to lead a team whose goal is to make Google Code’s Subversion service as fast and scalable as possible.


Packed and ready to goSince moving from Utah almost 2 years ago, I’ve been aching to get back into the mountains for a few days. Our previous attempt as a family notwithstanding, I’ve been looking forward to a chance for some serious mountain hiking and backpacking for a while. Rooming with Bruce this summer has been fortuitous in that we both enjoy the outdoors, having done a few hikes while living together previously as roommates at BYU.

The Plan was to spend this entire week in the Trinity Alps Wilderness in Northern California. (In spite of what people in the Bay Area will say, there really is a substantial part of California farther to the north.) The Trinity Alps are part of a relatively-unknown area which contains large amounts of virgin timber and several dozen high alpine lakes, the perfect place to disappear from civilization for a week.

Unfortunately, we managed to pick the weekend when the entire state of California turned into a giant campfire. With packs loaded and ready to go, we drove over 12 hours during the course of a 24-hour period, looking for a place to go backpacking, from Oregon to Yosemite, but to no avail. I refer the interested reader to Bruce’s fascinating writeup and analysis for more information, but suffice it to say I’m spending the evening writing this post instead of counting the stars in the Milky Way. Bummer.


Well, as of this morning Joanna and I are now officially home owners.  After far too much stressing over the last few months about obtaining a mortgage and getting appraisals and whatnot we finally closed on our house.  We signed and initialed a ridiculous number of forms ("Here, this one is in triplicate, please initial all 15 pages and sign and date at the bottom of page 14"), and handed over the largest check I've ever held, but it's done and we're extremely happy about it.

It's a little weird, we've been living here since November so we don't have the traditional "get the keys at the closing and run over to unlock the door and go into your house for the first time" kind of experience.  On the bright side, we don't actually have to move anything in, which is always nice ;-)


Bike and meWhile I’ve been in California this summer, I’ve been pretty car-less and with gas prices the way that they are, I’m not complaining. Instead of a car, I have a new bike, a Trek 2.3. I have wanted a road bike for a long time, and this summer turned out to be a opportune time to get one.

Of course, I decided to go ahead and register for the Marin Century, even though I hadn’t done any regular riding for the last two years. My daily commute is around 7 miles, round trip, which gives me a chance to do push myself, but I really enjoy the longer rides as well. This morning, I decided to go for a 65-mile jaunt around the South Bay: over Dumbarton Bridge, out through Newark and Milpitas, down around San Jose and back through Cupertino and Los Altos. There weren’t any major climbs, but it turned out to be quite the ride, and has given me some confidence for riding a century only 5 weeks hence.

On an unfortunate note, I did forget the sunscreen today, so I’m sporting some rather odd tan burn lines.