Thursday, August 13, 2009

Managing Your ON Mercurial Gate

Working on my recent projects, I became frustrated with a lack of one-stop-shop for Mercurial for use with OpenSolaris development. My focus is on the ON (Operating System and Networking) Consolidation, of course. As an internal developer, my steps assume access to things like usr/closed. If you are external, you will need to get your closed binaries from the closed binary tarballs.

I did find the HG Workflow document helpful, but not complete for my every day tasks. You should read that as a starting point, as it has lots of good tidbits on backing up your changes and managing project gates.

Please send any corrections or additional tips you might have this way, and I'll update this post.

Setting Up Yourself

First and foremost, make sure you have set up for cadmium and have your .hgrc set up as follows:
$ hgsetup
$ more .hgrc



filemerge.args=-a $base $local $other $output
filemerge.executable = filemerge
filemerge.checkchanged = true
filemerge.premerge = false



username=Valerie Bubb Fenwick

without the style settings, your Change Request Team Advocates will have difficulty reading your "hg outgoing -v" output and will likely put your RTI (Request to Integrate) on hold. I have customized my filemerge utility to be TeamWare's familiar filemerge.
Note: Email addresses used in here need to be real, routable addresses!

Setting Up Your Gate

Our build server leverages ZFS, which I highly recommend, as it gives you the quick ability to create snapshots before doing a major rewhack of your code. Here's what I do on the build server with ZFS:
$ zfs create builds/bubbva/{gate-name}
$ cd /builds/bubbva/{gate-name}
$ hg init
$ hg pull -u ssh://onnv.sfbay//export/onnv-clone/
$ hg update
$ hg reparent ssh://onnv.sfbay//export/onnv-clone/
$ hg clone ssh:// /usr/closed

Now, if you're not using a ZFS pool for doing your development, it's a little easier to setup:
$ hg clone ssh://onnv.sfbay//export/onnv-clone/
$ hg clone ssh:// /usr/closed

Note that the seemingly extraneous slash is not so, it is part of the communication with ssh and is indeed required. I don't know why hg clone won't work with an otherwise empty directory as its target, which would make dong this with a ZFS pool much simpler, but it doesn't.
On the ZFS snapshots, I recommend coding the date into the snapshot name, as the default listing of snapshots does not include that information, which makes it very tricky to figure out "what did I call that snapshot yesterday!?".

Finding Files in the Source

I often find that I know the name of the file I want to modify, but really have no idea of where it resides in the source - or perhaps I just know a partial name, like "softtoken". In teamware, I would always just grep the nametable, but since Mercurial has no equivalent concept, there is nothing quite that fast. Here's what I do now instead:

$ hg manifest | grep

Editing Files

Unlike with SCCS, there is no need to checkout files - just use vi/vim/ed/emacs/xemacs/etc and have at it. If you don't like your changes, simply revert.
$ hg revert
I've had mixed results with this, so find out what the previous revision to your changes was with:
$ hg log | more
If you need to create a new file:

$ hg add

To remove:

$ hg rm

To move (this works on entire directories, as well):

$ hg mv

When you are satisified with your changes:
$ hg commit

Managing Children to Build

It's always a good idea to do builds on both SPARC and x86, even if your changes seem like they're architecturally neutral. In fact, many members of the Change Review Team will require it. Some folks will even recommend you don't build in your "change master" to ensure you haven't forgotten to commit a file or "hg add" a new one. That's not strictly necessary, as long as you've done a build from a child of your main gate on another architecture, though, if you've done a lot of moving things around or creation of new files, you really should do it.
The problem comes from if you have done multiple "recommits" in your build master, this confuses your children. One way you can manage this is to always bring over a fresh build child. That's cumbersome though, at best.
$ hg pull
$ hg update -C

Preparing for Review

First, commit your changes. This will give you a chance to put all the relevant CR IDs into your comments. Unfortunately, every CR will be associated with EVERY file in your changeset. That's just how mercurial works.
$ hg commit
If you're working with simply open source, this convenient option has been provided to prepare and publicly post your webrevs to [1]:
$ hg webrev -O -U
I've been using a wrapper (hgwr, formerly wxwr), originally from Bill Sommerfeld, for webrev for a long time that keeps revisions of reviews available. This is handy so that you can incorporate changes from one code reviewer & post the updated webrev for that reviewer to verify you understood their comments, while not changing the code under another reviewer.
This is great for me, as a developer, as well, because as reviews trickle in, they all refer to a specific line number. If I've already incorporated changes, then the line numbers may have changed significantly. Having the original review source available is invaluable.
If you use this script, or something like it, the -U option to webrev is not useful. Instead you can use scp (MAKE SURE YOU STILL SPECIFIED -O for OpenSource to the wrapper, or your bug links will all be to the internal site):
$ scp -r .
(Note: that trailing ":" is not a typo, but required scp syntax.)
If you're additionally working in closed source, you'll need to utter the following:

$ cd /usr/closed/
$ hg webrev

In case it's not obvious, do not load this webrev to ;)

Resynching With The Clone

This starts with a simple:
$ hg pull -u
but you will always have to merge, even if nobody changed the same files you did. One thing I've learned the hard way about Mercurial is that if it can't open a tool to do a merge (in the case that someone has updated the same file you did) it will simply do the merge for you and do nice things like add a blank line in the middle of an enumerated list...)
So, if like most of us you don't have your workspace on your desktop, but rather on a build machine, you'll want to start this process like this:
$ ssh -X
Which will allow the graphical mergetools, like filemerge, to open when you get to the next step:
$ hg merge
and you'll need to commit again:
$ hg commit

More Unusual Tasks

Finding what changeset changed which lines:
$ hg annotate

Finding out which changesets impacted a file (useful for backing out individiual changes):
$ hg log

Finding History of a File if It's Been Moved

Because Mercurial isn't really a file based source code management system,
when you move a file the history does not move with it. That is, it appears as if it's a new file. You can still pull some of this history (like which changes were introduced under what name):
$ hg history -f
$ hg log -f
$ hg annotate -f

I Made Changes to a File Then Moved It and Want To Back Out the Changes (but not the move)!

Oops - I did this. Once. Because of how poorly mercurial handles file level operations, this is difficult to correct. For example, I made some minor edits to a file, including updating the copyright date, then I moved it. hg revert no longer worked! I was able to manually revert the changes, the file still showed up as changed in my workspace and 'hg outgoing -v'.
While I was told that it would have been acceptable to push this junk, it seemed sloppy to me. Due to the lack of per file controls, it is actually pretty easy to apply your changes to a new workspace using patch(1) and the "patches" provided by webrev, then redoing the moves, as needed.

Ready to Integrate!

Of course, you've read all of the RTI Nits, done all your testing, filed any documentation and test bugs and made sure they can be fixed at the same time as your integration and gotten your RTI (Request to Integrate) approved by a member of the Change Review Team... then you're ready to go! The problem is, so are lots of other people...
This is what I call the Mercurial Push Dance. All it takes is one more implementor heading for the gate at the same time, to begin this nasty tango...
$ ssh -X
(because you will have to merge...)
$ hg commit
$ hg pull -u
$ hg merge
$ hg commit
$ hg recommit

If you had actual conflicts (ie same files changed), CHECK THE MERGES. Run webrev again and make sure only your changes are there. Because the mergetools hooked into Mercurial grab focus when they come up, they are known to grab spare characters and insert them into your code. I've found stray "$" and other things that just wouldn't be a good thing to push.
Rinse & Repeat, until other folks stop beating you to the gate. When you're ready:
$ cd usr/closed
$ hg path default > /tmp/closed-mommy
$ hg reparent ssh://
$ hg push

[Closed gate changes always need to be done first, because once you push to the open gate, the incremental build will start.]
$ cd ../..
$ hg path default > /tmp/open-mommy
$ hg reparent ssh://
$ hg push

After you finish the Tango de la Muerte... I mean, the Mercurial Push Dance and have successfully gotten your bits into the gate, don't forget to:
$ hg reparent `cat /tmp/open-mommy`
$ cd usr/closed
$ hg reparent `cat /tmp/closed-mommy`

[1] These all assume you've set up your SSH key on the site. This is required for posting webrevs and doing integrations into the main gate.
Many thanks to the other developers who hang out on irc.sfbay/#hg-help and, particularly Rich Lowe, Mark J Nelson and David Powell.

No comments:

Post a Comment