Some more merge examples

Buck had a post awhile back on the basics of branch and merge. I wanted to give a few more examples of what you can do with the merge feature from the command line. The version control commands are in bold text, and the output from the server in italics.

1. We'll create a basic tree structure, "Main" with one file, and branch it for a release called "Beta1".

C:\ws1>md Main
C:\ws1>cd Main
C:\ws1\Main>echo foo > foo.txt
C:\ws1\Main>h add foo.txt
foo.txt

C:\ws1\Main>h checkin /i
add foo.txt
Changeset #286 checked in.

C:\ws1\Main>cd ..
C:\ws1>h branch Main Beta1
Beta1

Beta1:
foo.txt

C:\ws1>h checkin /i
branch Beta1

Beta1:
branch foo.txt
Changeset #287 checked in.

2. Now let's add a new file to Main simulating a new feature, and another one to Beta1 simulating a bugfix. I realize that both are as likely to modify files as add or remove them, but we'll get into that later.

C:\ws1>echo NewFeature > Main\NewFeature.txt
C:\ws1>h add main\NewFeature.txt
Main:
NewFeature.txt

C:\ws1>h checkin /i
Main:
add NewFeature.txt
Changeset #288 checked in.

C:\ws1>echo BugFix > Beta1\Bugfix.txt
C:\ws1>h add Beta1\Bugfix.txt
Beta1:
Bugfix.txt

C:\ws1>h checkin /i
Beta1:
add Bugfix.txt
Changeset #289 checked in.

3. Now I can talk about some of the features of merge -- some of this is probably 'old hat' to some of you, but I want to make sure I call out some of the main capabilities of our merge engine. Take a look at our simulated state. I've branched Main for a Beta1 release, and since then, I've added a feature to Main and fixed a bug in the Beta1 branch. Typically, I'd now want to merge the bugfix into Main, but I probably don't want to merge the new feature into Beta1, as this sort of branch is often only open for bugfixes leading up to the release, or updates/patches after release. So, how do I do that?

The first thing to note about merge is that we support merging in both directions. Let's merge that fix back into Main.

C:\ws1>h merge Beta1 Main
merge, branch: $/Beta1/Bugfix.txt;C289 -> $/Main/Bugfix.txt

C:\ws1>h checkin /i
Main:
merge, branch Bugfix.txt
Changeset #290 checked in.

This kind of merge, where you move changes from the target of the branch to the source, is often called a "reverse" merge (you'll often hear RI or "Reverse Integration" inside MS for reasons I won't go into).

For basic "content" merges, where the item has only changed in one of the branches, it's really that simple. Things get more interesting if the file has changed in both branches, of course, or if other change types (rename, delete, etc.) are involved. That'll be the subject of a future blog post, if there's interest.

4. For the "bugfix only" branch example above, it's hard to imagine doing a "forward" merge, if your developers are remembering to check fixes into Beta1. But maybe a fix gets checked into main and then "promoted" as worthy of being in the Beta1 release.

C:\ws1>h edit main\foo.txt
Main:
foo.txt

C:\ws1>echo SeeminglyMinorFix >> main\foo.txt
C:\ws1>h checkin /i
Main:
edit foo.txt
Changeset #291 checked in.

So now, we want to merge the bugfix, but NOT the new feature. Can we do that? Absolutely!

5. First, we need to identify what changesets can be merged from Main to Beta1.

C:\ws1>h merge main beta1 /candidate
ChgSet Author Date
-------- -------------------------------- ----------
288 crathjen 01/27/2005
290 crathjen 01/27/2005
291 crathjen 01/27/2005

"merge /candidate" tells you which changes in Main have not yet been merged to beta1 (to see the reverse, you'd just reverse the arguments). So, we want to merge 291 (the 'promoted bugfix'), but not 288 (the new feature).

<aside> You might be wondering why 290 shows up in the list - that changeset merged the Beta1 bugfix into main. It's because you don't have to choose between the merge source and target versions of the file; you can make additional changes before checking in the merge (maybe you have to tweak a makefile to both reflect the new content but still have the right includes, or maybe you have a different namespace in each branch, things like that). </aside>

6. First, let's tell the system that we don't ever want to merge 288 and 290 into Beta1. The command to do this is merge with the "/discard" option.

C:\ws1>h merge /discard main beta1 /version:C288~C290
Resolved C:\ws1\Beta1\NewFeature.txt as AcceptYours

C:\ws1>h status
File name Change Local path
-------------- --------------------- ------------------------------
$/Beta1
NewFeature.txt merge, branch, delete C:\ws1\Beta1\NewFeature.txt

1 change(s)

C:\ws1>h checkin /i
Beta1:
merge, branch, delete NewFeature.txt
Changeset #292 checked in.

I put the "h status" output in Courier so as not to mangle the output formatting. The output may seem a little strange, but we've basically told the server to branch the file, but to delete it as well, because we don't want the add to be merged. We still need to merge the branch/delete (instead of just leaving it out), otherwise we'd just try to branch the file again next time we tried to merge any range of changesets that includes 288. The "AcceptYours" output is the clue that we're keeping the merge target's version of a file, which is all "/discard" is about if you boil it down enough - keep the merge target the same, and note that these changes have been accounted for.

7. Now we need to merge the bugfix. We can merge one or more changesets by using the version parameter.

C:\ws1>h merge main beta1 /version:C290~C291
merge, edit: $/Main/foo.txt;C290~C292 -> $/Beta1/foo.txt;C287

C:\ws1>h checkin /i
Beta1:
merge, edit foo.txt
Changeset #293 checked in.

Most of this behavior is also accessible via the merge (and resolve) dialogs in the Visual Studio UI, as well, though discard at least isn't quite as automatic. I'll go into that in another post (again, if there's interest).

Update: Wow, I'm in over my head when it comes to the .Text WYSIWYG editor. I'll stick to HTML!