Contents
The Mercurial wiki site is a good place to start for information on installing and using Mercurial. It includes a link to a free book-in-progress on using Mercurial, as well as other documentation, which contain a wealth of information on how to use Mercurial. This page is not intended to replace the resources available on that site, and to use Mercurial to its fullest, you're best off if you start reading over there. This page is intended to help developers get started with using Mercurial in GNU Wget development.
Configuring Mercurial
After you've installed Mercurial, it's a good idea to set up some basic configuration settings. Here's a sample ~/.hgrc file:
[ui] verbose = True username = "John Doe <john@doe.nodomain>" [defaults] log = --style=compact glog = --style=compact fetch = -m 'Automated merge.' [extensions] hgext.fetch = hgext.imerge = hgext.graphlog = hgext.purge = hgext.mq = hgext.patchbomb =
Essentials
Enabling verbose output is generally just a prudent thing to do. Setting username tells Mercurial what identity to associate your commits with. I can't accept changesets as-is if they don't have a usable user id. If this value is not set, Mercurial will use the EMAIL environment variable, if that's set. That may be the better option, as other tools (notably, editors that have support for adding ChangeLog entries, which is an important part of hacking on GNU sources) will understand EMAIL. I don't actually have username set in my ~/.hgrc, as I have EMAIL set and exported in my ~/.bashrc.
It's a good idea to create a test repository with Mercurial with hg init foo, and then start checking some things into it (cd foo; vim bar; hg add bar; hg ci), to verify that the commit logs look right.
Default Command Arguments
The [defaults] section is where you can specify default arguments that are assumed whenever a particular command is used. I prefer the "compact" changelog style over the default one, but YMMV. See the next section for information about the glog and fetch commands.
Enabling Extensions
The [extensions] section is a means for you to tell Mercurial which extensions should be made available for use by default. Mercurial is architected as a core set of functionality in the main program, and a variety of useful and even important tools that are provided as extensions, so you can pick and choose which pieces you really want (or add your own).
Obviously, in order to use extensions, they have to be installed. Most, if not all, the ones I have as examples here ship standard with Mercurial; however, some are new additions that may not be available by default in versions of Mercurial prior to 1.0. Also, be sure that any system-installed /etc/mercurial/hgrc doesn't already activate these extensions (in particular, some systems activate the mq extension by default); funky things can happen on some versions of Mercurial if an extension is activated multiple times, particularly if a different syntax is used to enable it.
A lot of time is spent committing your own changes locally, pulling down new changesets from the public repositories, merging the local changesets with the remote changesets if necessary, and finally updating the local working copy: hg ci; hg pull; hg merge; hg ci; hg update. The fetch command does the pull/merge/commit/update in one fell swoop, committing the merge automatically with a default message. I've found the default message used by hg fetch to include repository path information that wouldn't be applicable to people on machines other than my own, so I added a default commit message in the [defaults] section that doesn't include that info.
imerge is another convenience extension. Normally, hg merge will try to resolve all merge conflicts in one step, in an all-or-nothing kind of thing. hg imerge will let you perform incremental merges, marking things as "resolved" in a Subversion-style way. There are pros and cons to using either imerge or the built-in merge, I find it handy to have both available.
The graphlog extension adds a glog command to Mercurial. This is essentially the same as the log command, except that it includes some very light, ASCII-graphic graphing information that makes it clear where branches and merges have occurred. Note that I added the same --style setting for glog in the [defaults] section as I did for log.
purge adds the purge command, which lets you ask Mercurial to erase any untracked files. I find this useful for ensuring that my current working directory is "pristine", and contains no untracked files (to remove untracked-but-ignored files, the --all switch may be required).
mq is a somewhat advanced-use command, but can be very useful. It allows you to manage a series of patches on top of the actual repository sources. There are a variety of uses and techniques related to this extension, but I won't explain them here. See the ''Distributed Revision Control with Mercurial'' book or MqExtension.
It adds quite a few commands to hg; so you may not wish to include it if you don't plan on using it.
patchbomb provides an email command to hg, which can automatically email diffs to a mailing list. It generally requires some configuration, so see hgrc(5), hg help email, and PatchbombExtension for more information.
"Clean" Wget Repository Clones
I have found it useful to keep a local, "clean" copy of the repository, which I mostly don't modify directly, but just sync with the public repository.
When I want to work on a particular feature, I'll usually clone a new copy of the repository for it. For instance, if I'm working on unit test stuff, I'll do something like hg clone mainline mainline-utests, which will clone a new repository from my existing local copy of the public one.
This is handy for keeping separate projects separate, until I'm ready to push them to the public repository. At that time, I'll typically merge them into my "clean" copy and push them upstream from there:
$ hg fetch # Ensure that we have the latest sources from the official repo $ hg fetch ../mainline-utests $ hg push
(The above example assumes that the fetch extension is enabled as described in the previous section. If not, hg pull && hg up should be used.)
Development Example With Mercurial
Let's work through an example of two developers who are working on Wget sources in Mercurial at the same time. We'll simulate this by creating two repositories for our developers Alice and Bob to work on (cloning from the "clean" repository at mercurial/.
$ hg clone mainline mainline-alice ... $ hg clone mainline mainline-bob ...
Alice is getting sick-and-tired of the Wget maintainer's dictatorial style, and decides to call attention to it in the Wget sources.
$ cd mainline-alice $ emacs src/main.c # Edit the sources $ hg diff # Display not-yet-committed changes to tracked files diff -r 98e1417f19a8 src/main.c --- a/src/main.c Sat Apr 12 23:21:09 2008 -0700 +++ b/src/main.c Mon Apr 14 14:01:13 2008 -0700 @@ -690,7 +690,8 @@ names such as this one. See en_US.po for reference. */ fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"), stdout); - fputs (_("Currently maintained by Micah Cowan <micah@cowan.name>.\n"), + fputs (_("Currently maintained by the tyrannical Micah Cowan " + "<micah@cowan.name>.\n"), stdout); exit (0); } $ hg ci -m "Add an appropriate adjective for the current Wget maintainer." $ # Commit the changes to the local repository, with the supplied # commit message. $ hg tip # Display information about the last commit (current revision) changeset: 2189:28a8553490f5 tag: tip user: Alice Anderson <alice@activism.org> date: Mon Apr 14 14:01:23 2008 -0700 files: src/main.c description: Add an appropriate adjective for the current Wget maintainer.
Alice then makes some additional changes, including adding the ChangeLog entry corresponding to the source-code change she'd made, which she'd forgotten to add in the previous commit. She also adds a new help file, named DESPOTISM, at the top level, and adds a commit message for that in the top-level ChangeLog file.
$ emacs -nw DESPOTISM ChangeLog src/ChangeLog $ hg stat # Display the status of the working copy M ChangeLog M src/ChangeLog A DESPOTISM $ hg ci -m "Add DESPOTISM, forgotten ChangeLog entry for main.c." ChangeLog src/ChangeLog DESPOTISM
Meanwhile, Bob, who's relatively non-confrontational, merely wishes to update the source code with Micah's updated email address.
$ cd ../mainline-bob $ vim src/main.c src/ChangeLog $ hg diff diff -r 98e1417f19a8 src/ChangeLog --- a/src/ChangeLog Sat Apr 12 23:21:09 2008 -0700 +++ b/src/ChangeLog Mon Apr 14 14:22:10 2008 -0700 @@ -1,3 +1,7 @@ +2008-04-14 Bob Bolton <bb@guttersnipe.net> + + * main.c (print_version): Update Micah's new email address. + 2008-04-12 Rabin Vincent <rabin@rab.in> * mswindows.c (fake_fork_child): Don't create a logfile for diff -r 98e1417f19a8 src/main.c --- a/src/main.c Sat Apr 12 23:21:09 2008 -0700 +++ b/src/main.c Mon Apr 14 14:22:10 2008 -0700 @@ -690,7 +690,7 @@ names such as this one. See en_US.po for reference. */ fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"), stdout); - fputs (_("Currently maintained by Micah Cowan <micah@cowan.name>.\n"), + fputs (_("Currently maintained by Micah Cowan <micah@pure-evil.org>.\n"), stdout); exit (0); } $ hg ci -m "Micah's change-of-address." src/ChangeLog src/main.c $ hg push # Push changes upstream. In this case, to our local mainline/.
Note that hg push takes the repository to push to as an argument, but by default will push to the same location from which it was pulled. These paths are configurable in your local repository's config file, which is at repository/.hg/hgrc: see the information on the [paths] section in hgrc(5) for details.
Now, Alice (who has push access to the public repositories) wishes to push her changes to the upstream repo; however, Bob has already pushed his changes, so she needs to pull Bob's new changesets first, before she can push her changes
(If she were to try to push changes without first merging them with Bob's, she'd get an error message:)
$ cd ../mainline-alice $ hg push pushing to ../mainline searching for changes abort: push creates new remote branches! (did you forget to merge? use push -f to force)
(It's usually a bad idea to use -f to force the creation of multiple heads on the public repository: better to merge locally and then push the merged changes.)
So, Alice instead does:
$ hg fetch # Assumes the "fetch" extension is enabled.
This automatically pulls from mainline, and attempts the merge. As with hg push, hg fetch (and the hg pull command it wraps) takes the from which to fetch as its argument; but defaults to the path it was cloned from.
Alice's changes won't merge cleanly with Bob's, however, since they both modify the same line. So it fires up an editor on src/main.c, which has temporary content reflecting both changes:
... fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"), stdout); <<<<<<< .../mainline-alice/src/main.c fputs (_("Currently maintained by the tyrannical Micah Cowan " "<micah@cowan.name>.\n"), ======= fputs (_("Currently maintained by Micah Cowan <micah@pure-evil.org>.\n"), >>>>>>> /tmp/main.c~other.dGzpNi stdout); exit (0); ...
Note that both versions of the line exist.
Alice will need to manually fix the line to reflect both changes. There will also be a merge conflict on src/ChangeLog, since both she and Bob have added entries to the top of the file.
If all goes well, hg fetch will then finish the merge and commit it.
$ hg tip -p # Display the last-commited revision, # along with a patch representation of the changes. # The patch displayed will be relative to the parent, # which in this case was Alice's previous commit. changeset: 2192:44cae4bf8fd1 tag: tip parent: 2190:d79a6b632849 parent: 2191:81e154cef155 user: Alice Anderson <alice@activism.org> date: Mon Apr 14 14:25:40 2008 -0700 files: src/ChangeLog src/main.c description: Automated merge. diff -r d79a6b632849 -r 44cae4bf8fd1 src/ChangeLog --- a/src/ChangeLog Mon Apr 14 14:11:36 2008 -0700 +++ b/src/ChangeLog Mon Apr 14 14:25:40 2008 -0700 @@ -1,6 +1,10 @@ 2008-04-14 Alice Anderson <alice@activism.org> * main.c (print_version): Call out Micah's totalitarian regime! + +2008-04-14 Bob Bolton <bb@guttersnipe.net> + + * main.c (print_version): Update Micah's new email address. 2008-04-12 Rabin Vincent <rabin@rab.in> diff -r d79a6b632849 -r 44cae4bf8fd1 src/main.c --- a/src/main.c Mon Apr 14 14:11:36 2008 -0700 +++ b/src/main.c Mon Apr 14 14:25:40 2008 -0700 @@ -691,7 +691,7 @@ fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"), stdout); fputs (_("Currently maintained by the tyrannical Micah Cowan " - "<micah@cowan.name>.\n"), + "<micah@pure-evil.org>.\n"), stdout); exit (0); }
Alice can now safely push her changes plus the merge against Bob's changes up to the public repository.
Note: using the fallback merge tool can be a sort of clunky way to do merges. See MergeProgram for information about how to use specialized merge tools, such as kdiff3, to handle merge conflict resolutions. The WgetMaintainer has found that the fallback actually works well for many cases, and may actually be easier for some types of conflicts, while tools like kdiff3 are better for some other types.
When merge resolution gets hoary, it's recommended to use hg imerge (from the imerge extension) instead, so you can do incremental resolution, and mark which files are finished merging.
Getting Changes into the Public Repositories
Assuming you don't have push access to the "official" repositories, there are a variety of ways you can get your changes into the official sources.
As mentioned in PatchGuidelines, you can use hg export to generate patches suitable for posting on the mailing list. You can also use the hg email command if you've activated and configured the patchbomb extension, to send the changesets directly to the wget-patches mailing list. This may be a good idea if you plan on sending many patches to the mailing list.
You can use hg bundle to create a binary "bundle" file containing the changesets you're interested in. This has the advantage that, rather than explicitly specifying which revisions to "export", it can be used to compare your local repository with the remote one, and generate a bundle file for the changesets that are in the local one only. However, binary bundle files are not suitable for posting to the mailing list, since it's cumbersome to look at binary files and try to comment on them. They're mainly useful for sending changes to the maintainer that have been specifically requested in that form (and probably already discussed on-list).
Note that hg email has an --outgoing option, which does the same comparison against the remote repository that hg bundle (and hg outgoing) does, and so also has that advantage over hg export.
If you're on a publicly-accessible IP address (in other words, you're not behind an address-translating router or firewall), you can use hg serve to fire up a temporary web server that serves up your repository. This can be handy for letting the WgetMaintainer browse the changes you've made, and pull from if phe is so inclined.
Finally, if you are actively developing for Wget, it's probably worthwhile to ask for push access to a publicly-hosted repository (or, alternatively, to set up public hosting for your repository yourself).