I've posted on resolve before, but I figured it'd be nice to come back and see where things stand in the Beta3->RTM timeframe.
When you run get, checkin, or merge, the system can’t always do what you want it to. There are some basic cases – you tried to checkin but you don’t have the latest version of the file, or you tried to get but one of the files is locally writable – that are relatively straightforward to resolve.
Then there are the 1001 edge cases that make my job interesting. 🙂
We can’t imagine and test every possible scenario, but resolve is one of those commands where we want to get as close as we can. The goal is to make sure your workspace never gets into a state where you can’t work, and to make sure we give you enough data to know how to proceed.
This is one of those posts that has the potential to get complicated (aside: as my fiancé puts it, “Jab myself in the eye with a pencil geeky”); I’ll try to keep it approachable. So, this post will just introduce the types of conflicts and what options you'll be able to choose from when resolving them.
First, one clarification about the way our resolve commands work – you must “generate” a conflict before you can resolve it. The resolve command won’t give you anything to do even if you KNOW there will be a conflict when you attempt a get or checkin; you have to run get or checkin to create the conflict condition first. This sounds a little silly, but it will make more sense once you see it in action. The upshot is that, unless you're using the command line and specify /noprompt for the relevant command, we’ll bring up the resolve dialog for you, so you can go straight into conflict resolution without having to run a separate command.
There are three “classic” types of conflicts: Version conflicts, namespace conflicts, and local/client conflicts. The latter are generally more like “errors”, but we want the resolve mechanism to help the user recover from them, so we generate conflicts.
Version conflicts occur anytime you want to perform an operation on an item, but there’s another version of the same item in the way. The most common (by far) is where you attempt to checkin a change when a newer version exists on the server. Similarly, if you try to get latest and have pending changes on an item with newer versions, you’ll get a version conflict.
Your options depend on exactly what the differences are. If you made ‘non-conflicting’ content changes (yes, we’ve overloaded the word ‘conflict’ along with ‘merge’), we can merge the changes together for you (more on content merging in a future blog post, if there’s interest). We’ll let you manually merge content changes. Finally, you’ll always have the option to discard your changes, or ignore the changes introduced in the newer version(s).
The easiest way to distinguish between the two conflicts is to ask yourself, “Is the conflict dealing with two versions of the same item, or two different items?” If it’s two different items, you’re looking at a namespace collision. The classic scenario is where you try to check in an add, but someone else has checked in a file of the same name since you pended the add (if you tried to pend the add on an existing item, we’d issue and error and refuse up front).
There are lots of other fun and interesting ways to generate namespace conflicts of course. Where either party had an ‘add’ in my example, they could instead have branched from somewhere else, renamed from somewhere else, undeleted (or undeleted from somewhere else), or merged a new item (basically, a branch as part of a larger merge).
Again, your resolution options depend on the circumstances. We always have the standby “Accept Yours” (what you did wins out over what’s on the server), and “Accept Theirs” (the reverse, which is a fancy way of saying “undo my changes”). For rename conflicts, the UI will let you pick a new name for your item in lieu of your original name. The command line will let you keep your name and pend a rename of the server’s item.
There one basic scenario here – you tried to get a file, but there’s a file on disk with the same name that does NOT have the readonly attribute set. This might be because it’s an unrelated/unversioned item, or it might be the same file, but you made changes to it locally without checking out first.
Resolve will let you overwrite the file, or ignore the conflict. That “locally writable check” is a basic way to prevent a ‘get’ from accidentally overwriting local data/changes, but we’re not going to make you attrib the file yourself if you’re sure you want to overwrite it with the server version. If you DO have a version of the file in your workspace, the resolve UI also gives you one more handy option: “Checkout and auto-merge”. This does exactly what it sounds like – checks out the item, and starts a content merge of the local contents with the server contents.
This writable/readonly flag check isn’t a proper substitute for an offline mode, but it does make working disconnected a little easier to deal with than if we didn’t have such a feature. I believe it’s a relatively common convention with other Source Control tools as well.
Whew, that’s a lot to digest. I won’t even get into the additional wackiness that can ensue when you try to do a merge – I’ll save that for a future hypothetical post, if there’s interest.
It’s all right, it’s all right, it’s all right…she moves in mysterious ways