Not much like the Github / Git-flow model. "Branches" are implemented as repositories, and we have a few types of repositories:
- try -- pushes here parse "try syntax" which defines the jobs you want to run; used for testing
- integration -- this is the entry into mozilla-central; patches here are tested but will be backed out by sheriffs if they cause failures (mozilla-inbound and autoland)
- mozilla-central -- the "trunk", latest known-good, branch (nightly is built from here)
- mozilla-aurora, -beta, etc. -- release branches
- pine, alder, ash, etc. -- project branches / twigs
These all share the same version-control history, with different "leaves"; sheriffs regularly merge things from integraiton branches into central, and from central into release branches.
Note that there are older techniques for using Mercurial that revolve around mq
(which is basically a version of the old patches-and-cvs way the kernel was developed). Avoid.
Get the most recent version of Mercurial, not just the most recent your OS has
available. Every bug in Mercurial is fixed in the X.Y.Z release that will be
pushed tomorrow afteronon. If you're OK with it, I would recommend sudo pip install mercurial
on your development system.
Clone https://hg.mozilla.org/mozilla-central to get the source. Clone it
somewhere with a lot of space. Run ./mach mercurial-setup
and, for now at
least, accept all of its defaults. This will install a bunch of extensions!
My extensions:
[extensions]
graphlog =
#prompt = /home/dustin/lib/python/prompt.py
color =
pager =
rebase =
purge =
histedit =
record =
shelve =
progress =
mq =
blackbox =
firefoxtree = ~/.mozbuild/version-control-tools/hgext/firefoxtree
reviewboard = /home/dustin/.mozbuild/version-control-tools/hgext/reviewboard/client.py
bzexport = /home/dustin/.mozbuild/version-control-tools/hgext/bzexport
bzpost = /home/dustin/.mozbuild/version-control-tools/hgext/bzpost
bundleclone = /home/dustin/.mozbuild/version-control-tools/hgext/bundleclone
mqext = /home/dustin/.mozbuild/version-control-tools/hgext/mqext
qimportbz = /home/dustin/.mozbuild/version-control-tools/hgext/qimportbz
push-to-try = /home/dustin/.mozbuild/version-control-tools/hgext/push-to-try
qbackout = /home/dustin/.mozbuild/version-control-tools/hgext/qbackout
# https://bitbucket.org/facebook/hg-experimental/raw/be7a54df7b36f7e9ac93ae05b9ff7621e32c089c/fbhistedit.py
fbhistedit = /home/dustin/.mozbuild/fbhistedit.py
# temporary until this is a full hg feature..
evolve = /home/dustin/.mozbuild/evolve/hgext/evolve.py
Generally you will want to work on top of central
, as it is most likely to be
working.
hg pull central
hg up central
Now create a bookmark for your work. I generally use a bug number. If you need more bookmarks, file more bugs. Bugs are cheap.
hg bookmark bug1234567
you can see your current bookmark with hg bookmark
.
Write your patch. Build with ./mach build
. I don't know much more than that
about building the browser!
Don't forget that Mercurial works on the svn model: changes to files which are
already in the repository will be committed without any kind of hg add
, but
you will need to hg add
new files. Run hg status
to see what's up with
your repository, noting that it's very slow for this large respository!
To commit, hg commit
. The commit message format is:
Bug 1234567: <imperative voice summary>; r?<ircnick>
<longer description of the change>
You can update the most recent changeset with hg commit --amend
.
More, smaller changesets are better. If you can break a change down into some independent but still internally self-consistent changes, do so. Especially if different people might review those different changesets. For exmaple, if your new implementation requires refactoring an existing piece of code to be more flexible, make that refactor a changeset of its own, followed by a changeset including your new implementation.
But managing multiple changesets for a single bug starts to get complicated. A
bit of Mercurial terminology: changesets have "phases", and the interesting
phases here are "draft", "public", and "obsolete". A public changeset has been
pushed to a public repository and can't be changed anymore. A draft changeset
has not been pushed anywhere interesting and can be edited. A obsolete
changeset has been discarded in favor of an updated version -- for exmaple, hg commit --amend
will mark the old changeset as obsolete.
So you will need a command to show the draft changesets on the current
bookmark. You can use this one, which defines hg wip
.
[revsetalias]
wip = reverse((ancestors(.) and not public()) or parents(ancestors(.) and not public()))
[templates]
wip = '{label("log.branch", ifeq(branch, "default", "", branch))} {label("changeset.{phase}", rev)} {label("grep.user", author|user)}{label("log.tag", if(tags," {tags}"))} {label("log.bookmark", if(bookmarks," {bookmarks}"))}\n{label(ifcontains(rev, revset('parents()'), 'desc.here', 'desc.nothere'),desc|firstline)}'
[alias]
wip = log --graph --rev=wip --template=wip
This will show you all draft changesets as well as the public changeset on which they are based.
So you have several draft changesets, say "refactor frobnification", "frobnicate foozles", and "consolidate foozle definitions", and you find an error in the first. You can fix this in two ways.
The first method is to make a single changeset to fix the error, and laterl "roll up" that changeset into the "refactor frobnification" commit. I generally name such roll-up commits starting with "R":
vi testing/frobnification.py
hg commit -m "R refactor frobnification" testing/frobnification.py
Then later, run hg histedit
. This tool shows all of the draft changesets
(just like hg wip
, but in reverse order) and lets you reorder and set actions
for them, as described in the comments at the bottom. Find the "R" commit, set
its action to "r", and move it so it follows immediately after the "refactor
frobnification" commit. When the histedit completes, hg wip
will show only
the three changesets, and hg diff -c .^^
will show your fix merged into the
frobnification refactor.
I often pile up a few "R" commits before histediting. This is easiest when you find an error when you're in the middle of something else, and have a bunch of changed files in your working copy.
The second method is to use hg histedit
directly to edit that commit. This
requires that your working copy be clean. Find the commit in the list, and
change its action to "e". When you run the histedit, hg will stop with all of
the files from that changeset marked as un-committed. You can make the fix, test
all you want, then run hg histedit --continue
which will prompt you to
confirm the commit message.
If you have the fbhistedit
extension installed, I recommend using "f" instead
of "e", as it leaves the existing changeset committed and stops with a clean
working copy. You can then fix the changeset with hg commit --amend
or, if
you decide the fix won't work or accidentally break something else, just clean
out your working copy and start over.
OK, so you've got a nice sequence of microcommits, and your local testing shows them to be correct, but you need to test it on another platform.
The try server enables this. You'll need ti figure out what you want to run --
http://trychooser.pub.build.mozilla.org is probably the easiest way -- and then
use hg push-to-try -m "try: ..."
to push it. This will automatically add an
empty commit containing this syntax (and any uncommitted files in your working
copy), push it to try, and then revert the empty commmit (restoring your
files). It shows a link to treeherder where you can monitor the progress of
your jobs.
Once you're happy with the patchset, it's time to get review. Double-check
that you've flagged all of your commits with r?<ircnic>
for the appropriate
reviewer. If you don't know who's appropriate, ask someone -- generally two or
three degrees of connection are sufficient to find the correct reviewer.
Push your changes with:
hg push -r . review
This will show you a URL for each of the changesets, plus a final "review summary" link. Hit "n" to skip publishing the review request right away, and click that last link. That will take you to your (unpublished) review request, where you can give it your one once-over first to catch any silly mistakes.
Once you're happy with it, publish the review request. Mozreview will make a bunch of updates to the bug, and flag your reviewers there. You can generally expect a review within 24-48 hours, and it's legit to ask nicely if you've gotten silence for longer than that.
Mozreview has several different "kinds" of pages that all look alike. There are "summary" (patchset, all changesets together) and "review request" (changeset) views, and for each there is a view showing comments and updates, and a view showing the diff.
From the summary, you can push changes to try (the effect is the same as hg push-to-try
, but the result is linked from the review request so your
reviewers can look too). After your reviews are all in, you can also land your
changes here.
The diff views show a typical colored diff, and the little floating "+" symbols on the left let you add line comments. Due to some weird beliefs of the upstream maintainers of reviewboard, however, you usually won't see these inlined into the diff like you do in github.
When you add a new line comment, there is a checkbox to "create an issue'. This pretty much means "please address this", and unchecking the box is a way to make a general comment ("I like how you structured this").
A reviewer gives each review request (so, each changeset) a response, which can include a comment and "r?", "r-", "r+", or "" (clearing the flag). There's still some disagreement as to how these are used, but here's what I think:
r+
means "I'm happy to see this landed as-is, or I trust you to make the simple changes I've suggested"r-
means "This needs changes, and I'd like to review again before it lands." Notably, it does not mean "you suck" or "you are totally unqualified to write a patch so go get a new job". I try to include a positive comment with my r-'s.r?
means "I'm still reviewing this" (for example, maybe I've asked a clarifying question)- clearing the review request means I don't think I'm qualified to review this
When a all changesets in a review summary are marked r+ and all issues are either fixed or dropped, mozreview will let you (anyone, really) land the changes. It's OK to land someone else's change if there's a rush, as long as you're willing to keep an eye on it and work with the sheriffs if it causes a problem.
If you get r-'s, you can go back and redraft your patchset -- a lot of histediting is involved here! While you're histediting, be careful with the "MozReview ID" lines in the comments -- those are what tie a changeset to its review request even when the hg revision ID changes. If you merge two changesets together, think carefully about which MozReview ID you keep.
To update the request, just push to review like you did initially. There is currently a bug in mozreview which means that reviewers who have left their review status at "r?" or, I think, cleared the review will not be notified of the new request, so you may need to ping them.
As mentioned above, landing a commit is easy with mozreview. You can also land
a commit from the command line. First, make sure to turn all r?<ircnick>
to
r=<ircnick>
, and that you are accurately representing those reviews. Then
hg pull inbound
hg rebase -d inbound
This pulls the latest commit from inbound and rebases your work on top of it.
hg outgoing -r . inbound
This will show all of the commits that will be landed, just to double-check
hg push -r . inbound
This pushes the commits. If your changes are rejected because there are new
commits on inbound, go back to hg pull inbound
and try again, typing faster
this time.