OpenSolaris

  subsites:   Code Reviews   Gates   Issues   Defects   Polls   Test   PKG   Planet   Mail
You are not signed in. Sign in or register.

Things you should know

The ON gate will be under Mercurial control starting with build 97

You need to be familiar with the uses of Mercurial and the tools by that point, preferably sooner.

The Mercurial ON gate is made up of two Mercurial repositories

ssh://onnv.sfbay.sun.com//export/gate-hg
ssh://hg.opensolaris.org/hg/onnv/onnv-gate

These repositories are equivalent, and contain the open source portions of the ON gate.

ssh://onnv.sfbay.sun.com//export/gate-hg/usr/closed

This is the repository for the closed code.

Most tools operate on only one repository at a time

… except nightly(1)

nightly(1) is an exception to this, it will bringover usr/closed if you have CLOSED_BRINGOVER_WS (or CLOSED_CLONE_WS) set in your env file, and update usr/closed if you already have it in your workspace.

webrev(1) especially does not cross between repositories

This is a feature. If you touch both open and closed code, you create two webrevs, one of which you can publish completely, one of which should never leave the SWAN. No risk of accidentally publishing closed code because you forgot -O

No ID keywords

Mercurial has no native concept of ID keywords (%I%, $Id$, etc). You should not add keywords to any file, for any reason. They will not be expanded. The CRT will not accept RTIs which depend upon SCCS keywords.

What you should do instead

Nothing

In almost all cases, these keywords serve no useful purpose.

  • They only reflect the information of one file (no good for binary versioning)

  • We adjust the ELF .comment section in the build (no good with #pragma ident)

Instead of using keywords to identify binaries, there are other means to discover the version of files delivered to users:

  • Packaging information

  • what(1)

  • mdb(1)'s ::showrev -v

We're serious about doing nothing

We don't make this recommendation lightly. This is something that we hashed over extensively. Arguably, the folks most affected by this change work in Sun's RPE organization, and they're on board with no keywords.

If you want some background reading, please go through these threads (and probably others):

If you're really convinced that you must embed your own versioning text

Iff it is absolutely critical to expose such information, you can use the hg id command:

$ MY_VERSION=$(hg id)
$ echo $MY_VERSION
53efa13dec6f+ tip
$

You should only do this with good reason. Expect your RTI Advocate to question you about why you are doing it, and to require you to justify your choice.

Getting real work done with Mercurial

Populate your workspace (bringover, clone)

Get the open source

hg clone ssh://anon at hg dot opensolaris dot org/hg/onnv/onnv-gate your-ws

For ON: get the closed source or the closed binaries

hg clone ssh://onnv.sfbay.sun.com//export/gate-hg/usr/closed your-ws/usr/closed

…or just download the closed binaries.

Have nightly create or update your workspace for you

If you don't include -n on the command line or in your NIGHTLY_OPTIONS, then nightly(1) will create or update your repository for you.

If $CODEMGR_WS exists, then nightly(1) will pull from $BRINGOVER_WS into $CODEMGR_WS. $BRINGOVER_WS defaults to $CLONE_WS. Then, if the repository $CODEMGR_WS/usr/closed exists and $CLOSED_BRINGOVER_WS is set in your environment file, nightly(1) will also pull from $CLOSED_BRINGOVER_WS to update $CODEMGR_WS/usr/closed.

If $CODEMGR_WS does not exist, then nightly(1) will create it as a clone of $BRINGOVER_WS. It will NOT, however, create a new $CLOSED_BRINGOVER_WS if one does not already exist.

Build

Build as you always have, nothing has changed in this regard.

Making changes

Make your changes as you normally would. There is no explicit "edit" step required by Mercurial.

Mercurial does not lock files in your workspace for editing, and Cadmium (a Mercurial extension providing wx-like functionality, useful for OpenSolaris development) does not make use of a statically maintained list of changed files (as wx(1) would). You can make changes freely in your workspace without any required bookkeeping.

The hg status command will tell you what you have changed in your repository.

Commit your changes

You may commit changes as and when you choose, as with TeamWare a commit is local to a repository until you choose to push it to others.

For small fixes you may choose to only commit when you're done with your work, or perhaps prior to a merge before you file your RTI.

For larger workspaces it's generally best to commit at appropriate intervals in your work.

Cadmium's hg backup command (described below) is not really intended to return you to a point-in-time snapshot of your ongoing work, but to recover a lost (or destroyed) workspace. It is recommended that you move around within your workspace's history using the hg update command to move to prior revisions as necessary. You should do this with both the main and usr/closed repositories at the same time, of course.

Check for nits

As with wx(1), Cadmium provides a command that will run a sub-set of the pre-putback checks on your workspace. You may find it useful to run hg nits (cf. wx nits) at intervals to keep your changes generally tidy as you work. Remember that Cadmium does not cross Mercurial repository boundaries, so must run this separately for usr/closed.

This will check CDDL blocks, copyrights, C style, header format, Java style, permissions, and (absence of) keywords.

Backup your work

You'll want to backup your work at regular intervals, in case of disaster (disk failure, plagues of beetles, possession by the demons of stupidity, and such).

hg backup will save the changes (both committed and uncommitted) in the working copy of <your-repo> to a subdirectory named <your-repo> in the cdm.backup directory within your home directory, by default.

As stated above (see "Commit your changes"), these commands do not cross repository boundaries, so you must take separate backups for usr/closed, if appropriate.

When backing up usr/closed, the backup will be named <your-repo>-closed, so, for instance:

your-repo -> ~/cdm.backup/your-ws
your-repo/usr/closed -> ~/cdm.backup/your-ws-closed

hg backup takes a -t flag which, like wx, will only take a backup if changes have been made since the most recent. Backups are ordered by generation number (a monotonically increasing digit).

To restore your workspace, clone the parent and restore from your backup:

your-machine:.../your-repo% hg backup
your-machine:~% hg clone ssh://machine//your-parent your-repo-restore
your-machine:~% cd your-repo-restore
your-machine:.../your-repo-restore% hg restore ~/cdm.backup/your-repo

you will need to restore usr/closed separately, if appropriate.

hg restore takes a -g flag with which you can specify the generation from which you want to restore.

Merging with the parent

Unlike TeamWare, Mercurial merges the lines of history, rather than only file contents. Therefore, you will need to perform merges even if there are no conflicting file changes (though the merges will be simple then, of course).

This will no doubt come as a shock, initially.

You should always update and merge usr/closed in conjunction with merging the rest of your workspace.

By default, if your ~.hgrc was configured with hgsetup(1), we will default to use TeamWare's filemerge(1) for merges, if TeamWare is in your $PATH, and meld or gpyfm if it is not, and you have one of them.

Merging with committed changes

If your workspace has committed changes, and you pull from your parent workspace, you will likely find that you now have two "heads" (revisions with no children) in your workspace, and that you received output from Mercurial suggesting that you may wish to merge them with hg merge. You almost certainly do.

$ hg pull -u
pulling from /home/mjnelson/work/scm/hg_merge/repo_2
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
not updating, since new heads added
(run 'hg heads' to see heads, 'hg merge' to merge)
$

When you run the hg merge command, Mercurial will merge the two heads, starting your merge application as necessary to resolve content changes in individual files, and asking you questions as necessary to resolve name changes. When complete, your working copy will represent the still uncommitted merge.

You should commit your merge soon after you are finished performing it, perhaps after some verification that you merged correctly.

Merging with uncommitted changes

If you have uncommitted changes in your workspace, you will also need to merge when you use hg pull -u or hg pull && hg update to update your workspace.

If the pull added two heads, it means you have both committed and uncommited changes in your repository. In this case, your changes will be as they were, and you may continue working in that state until you see fit to commit, and then hg merge to merge with the extra head.

If you have only uncommitted changes in your respository, then there is no need to merge the history of your workspace and its parent. In this case, hg update (or the -u part of hg pull -u) will behave similarly to the resolution of a regular merge; your merge application will be start, or you might be asked questions about name conflicts.

$ hg pull -u
pulling from /home/mjnelson/work/scm/hg_merge/repo_1
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$

Best practices

Don't make other changes along with a merge

It is to your advantage for a merge changeset to only represent a merge, rather than a merge and some other changes you happened to be making at the time. This keeps a clear distinction between each change and makes it easy to backout a specific change if required.

Always commit your work before you merge.

As we've seen above, if updating your workspace from its parent would cause their histories to diverge, then you will need to merge your changes with the parent. You should commit your changes to your workspace before doing the merge, such that your merge changeset is entirely separate from any ongoing work in your workspace.

Recommitting your work into a single changeset

As with TeamWare, you may not integrate your changes into the gate with merge changesets, uninteresting interim changes, etc.

In most cases, you're going to need to make these go away before you push your changes out.

The command to do this is hg recommit (much like wx redelget, etc.)

recommit will take your changes to date, and create a single changeset containing those changes.

You may specify a checkin comment on the command line (-m), a file containing your checkin comments (-l), or, if neither are specified, hg recommit will pop up your $EDITOR with a buffer containing all the checkin comments you have used thus far, for you to edit into a form suitable for integration.

The same comment format is used with Mercurial as with TeamWare: a bug ID or ARC case reference, followed by its synopsis.

XXX: Example (of all 3)

hg recommit will perform certain sanity checks as it runs.

You may not recommit if you have uncommitted changes in your workspace

You must commit them, when appropriate, then recommit.

You may not recommit if your workspace has more than one head, or branch

You must merge your changes such that your workspace contains only a single head (hg heads), and then recommit.

recommit will also offer to take a backup if there have been changes since your last backup, before actually recommitting your changes. For the sake of all that is good and sane, say "yes."

You will need to use hg recommit separately, in usr/closed.

Best Practices

In general, you should recommit your work as late as possible (though prior to filing an RTI), this way your full local history is available to you, and backed up, should you need to refer to it at a later point.

Even though Cadmium will ask whether you wish to backup before recomitting a workspace, you should always answer Yes.

Run the pre-putback checks on your workspace

Cadmium's hg pbchk command will run a full set of pre-putback checks on your workspace (cf. wx pbchk).

This includes checking CDDL blocks, checkin comments, copyrights, C, Header and Java style checks, checks for executable files which you intend to integrate, that you have not added any tags, that you have not added any branches, nor changed the name of the main branch, that your work does not include SCCS ID keywords, and that your RTI is approved.

In most cases, each and every one of these checks should pass. You should already know if you will be exempt from one or more of these rules.

You must also run this separately within usr/closed.

If passed the Hg global option -q, pbchk and nits will be silent about passing checks, only providing output for checks that fail.

Integrating your changes (putback, push)

Your RTI is approved, your workspace passes pbchk, your testing is complete. Now all you have to do is integrate.

You must push changes first from usr/closed (if appropriate) and then from your main workspace when you integrate. You should never allow them to be out of sync. So you'll want to push both in quick succession.

XXX: Notes about gate hooks, etc, etc, etc.

Running a project gate

Most of how you choose to run your project gates is entirely your own decision, these are merely recommendations, though it is probably worth your time to read them anyway.

Of course, when your project integrates you will have to follow most of the steps outlined in the previous section too.

Syncing up with your parent gate

At intervals, you're going to want to sync your project gate with its parent (onnv-gate, for instance). You probably want to do this on a regular schedule and at suitable points, what this schedule or these points are is entirely up to you, though we would advice you not merge constantly, both for the sake of providing you a stable basis for work, and to avoid filling your project gate history with minor merges. Merging as builds close may work fine in many cases, others may have different preferences.

Syncing with the parent is different in the case of the project gate, as you wish to preserve history of the merge, among other things.

Clone a fresh child of your project gate

You should never do real work directly within your project gate, do the work in a child and push the changes to your gate when you are finished, as normal.

Pull from your project gate's parent at the point you wish to sync up with

your-machine:.../your-gate-merge% hg pull -r <revision or tag> your-gate-<parent>

Merge the head from your project with the head from the parent

your-machine:.../your-gate-merge% hg merge
Note
The above did not specify the -u flag, so the working copy remained at the head of your project, this way your project is the first side of the merge, and the parent the second.

Commit your merge

Commit the merge, using some sensible message of your choosing, maybe something like sync with onnv_97.

Building the merge

If you intend to run the merge through a full build to verify it, you'd be well served to build in children of the merge workspace, leaving the workspace in which you performed the merge free of detritus.

Make sure everything is as you expect

The first few times through this, you may wish to use Cadmium's hg list and hg pdiffs with the -p option to specify which parent to use, to make sure that the changes relative to your project gate and/or its parent are as you expect.

Push the merge to your project gate

Push the changes out to your project gate.

Warning
DO NOT recommit the merges used to sync your project gate with its parent.

There are multiple reasons for this.

  • They represent valuable history to you and the rest of your project. … so you don't want them to go away.

  • There is no good way to achieve this. If you recommit relative to your project gate, you will not only remove the merge changeset you created, but also the changesets from your project gate's parent since, relative to your project gate, those changes are local to your merge workspace.

    So when you do this, you're throwing out a lot of history from the parent of your project gate.

    This is not fatal, in that when you next sync up, you'll pull all that history again, then merge it again, but you're making work for yourself as well as throwing away information. Eventually, when you plan to integrate, you would have to pull all this history (throughout the life of your project), and recommit again against the gate to which you intend your project to integrate.

    Don't do it.

You may notice that the above may take some time, during which others may be changing your project gate, and causing you to possibly have to merge with them.

In our experience this has been fairly rare, and how it should be dealt with is a project specific choice.

Never recommit within your project gate

You should never, ever, recommit the contents of your project within the project gate. This will considerably disrupt each and every person who has a child of your project gate (your co-workers), throw away valuable project history, and serve no practical purpose.

Don't do it, ever.

Backing out undesirable changes

Mercurial's hg backout command is the best way to achieve this.

It will create an inverse changeset on top of the change to be backed out, which you may then need to merge if the changeset to be backed out is not the tip (using the -m flag to backout will start the merge for you).

This will want two commit messages, one for the backout changeset itself, and once for the merge (if necessary).

As with syncing up with your gate's parent, you should perform backouts in a child of your project gate, and then push them to the project gate itself.

If your backout required a merge, you should probably recommit it, as its function is plain enough, and the extra merge in the history is not useful to you.

If the change to be backed out contained changes to the closed portion of your project gate, you will need to perform a similar backout there, too. Never backout only one side of such a change.

XXX: Example

Cherry-picking changes from your project gate's parent

From time to time, you may wish to have changes from the parent in your project gate where a merge would be inconvenient, or outside of the schedule you're using for your merges.

You have several options, which of them is correct is largely up to you. You could merge out of schedule, which is probably better if what you want is large, or depends on other changes.

You can hg export that revision from the parent, and import that diff into a child of your project gate, test, and the push to your project gate.

The latter can be somewhat automated using Mercurial's transplant extension, which is not documented here.

If you choose to do a full merge, it should be performed as all other merges, and as documented above.

Integration

Integrating your project is much like integrating any other change you have made, however there are a few other things which you should do.

Do the integration from a child of your project gate.

Take a fresh child of your project gate, run hg pbchk within that child. If file changes are necessary, integrate those changes into your project gate, and update the child you intend to integrate from.

Once pbchk is clean, beyond checks that depend upon your checkin comments, recommit within the child of your project gate.

Perform any test builds within children of this child, keep the child you intend to integrate from as pristine as possible.

File your RTI.

Once your RTI is accepted, sync this child with your project gate, and retest as necessary.

Integrate from this child.

This leaves your actual project gate untouched, so its history can be kept around as long as you think may be valuable.

Quick Reference

TeamWare command equivalents.

wx(1) command equivalents

Almost all Cadmium commands share the name of their wx counterparts.

Exceptions are:

wx Cadmium
active list (active is a valid alias)
redelget recommit (reci is a valid alias)

Other commands without identical names in Cadmium most likely do not exist. For example, simply use webrev, not hg webrev.

Where to get help

  • Mercurial's built-in help is available via hg help <command> or hg help <extension> (eg. hg help log, hg help cdm).

  • Bryan O'Sullivan (a Mercurial contributor), has written a book "Distributed revision control with Mercurial" which is freely available from:

    You should bookmark it, and perhaps print out the pdf and keep it on your desk for a while.

  • General questions (and questions about OpenSolaris specifics, such as Cadmium and workflow) should be directed to tools dash discuss at opensolaris dot org

  • As a last resort, you may also wish to ask the SCM Migration project, also on opensolaris.org