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 MainC:\ws1>cd MainC:\ws1\Main>echo foo > foo.txtC:\ws1\Main>h add foo.txtfoo.txt
C:\ws1\Main>h checkin /iadd foo.txtChangeset #286 checked in.
C:\ws1\Main>cd ..C:\ws1>h branch Main Beta1Beta1
Beta1:foo.txt
C:\ws1>h checkin /ibranch Beta1
Beta1:branch foo.txtChangeset #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.txtC:\ws1>h add main\NewFeature.txtMain:NewFeature.txt
C:\ws1>h checkin /iMain:add NewFeature.txtChangeset #288 checked in.
C:\ws1>echo BugFix > Beta1\Bugfix.txtC:\ws1>h add Beta1\Bugfix.txtBeta1:Bugfix.txt
C:\ws1>h checkin /iBeta1:add Bugfix.txtChangeset #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 Mainmerge, branch: $/Beta1/Bugfix.txt;C289 -> $/Main/Bugfix.txt
C:\ws1>h checkin /iMain:merge, branch Bugfix.txtChangeset #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.txtMain:foo.txt
C:\ws1>echo SeeminglyMinorFix >> main\foo.txtC:\ws1>h checkin /iMain:edit foo.txtChangeset #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 /candidateChgSet 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~C290Resolved C:\ws1\Beta1\NewFeature.txt as AcceptYours
C:\ws1>h statusFile name Change Local path-------------- --------------------- ------------------------------$/Beta1NewFeature.txt merge, branch, delete C:\ws1\Beta1\NewFeature.txt
1 change(s)
C:\ws1>h checkin /iBeta1:merge, branch, delete NewFeature.txtChangeset #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~C291merge, edit: $/Main/foo.txt;C290~C292 -> $/Beta1/foo.txt;C287
C:\ws1>h checkin /iBeta1:merge, edit foo.txtChangeset #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!