Adam Singer

Veni, vidi, expertus sum- I came, I saw, I tested

What you wish for

As I depart the Version Control team, I’d like to make one final note about a particular request we’ve heard often. Many folks want us to get the latest version of a file when they check it out for editing. On the surface, this does seem like a good idea. However, I’ll try to explain here why you don’t really want what you think you want.

Let’s examine a few simple timelines.

Timeline 1: Single file edit

In the simple case, let’s say you have two developers: Alice and Bob. After some changeset, let’s say 10, both users have the latest version of all files. Alice checks out file “Program.cs”, makes a change, and checks in to create changeset 11. Bob then tries to check out Program.cs. In the current implementation, he has the changeset 10 version of Program.cs, not the changeset 11 version, and will have to merge his changes with Alice’s when he checks in changeset 12. The merge may not be very difficult, or it might have many conflicts, but Bob is eventually able to perform the integration, (re)run any necessary tests since he’s now integrated Alice’s changes, and then check in.

Timeline 2: Multiple file edit

Now, let’s get a little more complicated. Alice checks out both Program.cs and MainWindow.cs, edits them, and checks in to create changeset 11. Alice may have actually changed the APIs between Program.cs and MainWindow.cs or she may just have modified some of the internal functionality in each. Again, afterwards, Bob tries to edit Program.cs. He still only has the changeset 10 version, so will have to merge his changes when he checks in changeset 12. Seeing the resolve dialog when he tries to check in warns him “somebody else made a change!”

If, however, Team Foundation Version Control silently performed a get operation to bring Program.cs up to changeset 11, Bob’s workspace would have mismatched versions of Program.cs and MainWindow.cs. Suppose that one of Alice’s changes in Program.cs relied on a change in MainWindow.cs – Bob’s new code in Program.cs assumes the old MainWindow.cs behavior, and now when he checks in Program.cs itself is in a bad state. In the case of API change, on the other hand, Bob’s project just went from building successfully to not building at all even though he hasn’t even made his changes yet. If poor Bob doesn’t try to build until after making his changes, he’s then under the impression that his code changes broke the build rather than the automatic “Get Latest on Checkout” that TFVC performed.

That’s pretty lame, no? Poor old Bob now has a headache and he has to track down the cause of the build break. And when he finally figures it out, he then may run another get latest manually, picking up Cheri’s changeset 12 and Daniel’s changeset 13, each of which may conflict with Bob’s existing pending changes and/or have other dependencies to worry about. We’ve just turned the snowball into an avalanche. If Bob was three files into a six file fix, he’s now forced to deal with integrating other people’s changes when what he really wanted to do was finish making his changes. Without the forced Get Latest on Checkout, Bob would have been able to have two separate phases for “make the fix” and “integrate with other people’s changes”.

Timeline 3: Concurrent file edit

As hairy as that scenario got, let’s take it one step further and see why the fix doesn’t actually avoid the problem. Suppose that we actually do have the Get Latest on Checkout in place. At changeset 10, Alice and Bob have the latest version. Then, both users check out Program.cs for editing. Since they both have the latest version, nothing is done to update their workspaces. Alice checks in changeset 11, and then Bob tries to check in changeset 12. Bob still has to perform a merge of his changes with Alices even though we added the extra capability.

Therefore, by adding this capability to TFVC we’ve not only introduced other potential mid-fix merge issues, but we’ve also failed to fully resolve the original problem since Bob will still have to perform a merge operation prior to checkin.

In practice, I’ve found that the files I don’t have the latest version of when I check out are just a few of the shared helpers and central infrastructure. These are the components that are most likely to hit the “Bob checks out before Alice checks in” scenario anyway since many people might be making minor changes at any given time. If even one of them checks in a change after you began editing you’ll have to merge when you try to checkin and you haven’t saved any effort with the extra step of Get Latest on Checkout.

Therefore, even though it’s been one of the most asked-for features, I don’t think the users who think they want it actually want it. Most likely, it will still get added, just like you can disable multiple checkout for a project – not generally a good idea IMHO, but it’s there. I’d also like to say that, though I’m certainly far from a merge guru, I’ve come to stop fearing the three-way-merge process. It’s actually quite simple and generally all of the work other than clicking “Auto Merge All” is done for you.

In conclusion, be careful what you wish for. You just might get it.