[Wget] [TitleIndex] [WordIndex

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.

"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).


2017-01-04 00:04