changeset 9569:ceb0f59e1327

Merge with i18n
author Matt Mackall <mpm@selenic.com>
date Thu, 08 Oct 2009 01:16:32 -0500
parents f0417b6ff98a (diff) 620d6b20ef85 (current diff)
children 7e03423def3c
files doc/hgrc.5.txt hgext/churn.py hgext/win32mbcs.py mercurial/commands.py mercurial/dispatch.py mercurial/localrepo.py mercurial/util.py
diffstat 107 files changed, 1791 insertions(+), 1562 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Tue Oct 06 11:18:58 2009 +0300
+++ b/Makefile	Thu Oct 08 01:16:32 2009 -0500
@@ -79,16 +79,16 @@
 
 update-pot: i18n/hg.pot
 
-i18n/hg.pot: $(PYTHON_FILES)
+i18n/hg.pot: $(PYTHON_FILES) help/*.txt
 	$(PYTHON) i18n/hggettext mercurial/commands.py \
-	  hgext/*.py hgext/*/__init__.py > i18n/hg.pot
+	  hgext/*.py hgext/*/__init__.py help/*.txt > i18n/hg.pot
         # All strings marked for translation in Mercurial contain
         # ASCII characters only. But some files contain string
         # literals like this '\037\213'. xgettext thinks it has to
         # parse them even though they are not marked for translation.
         # Extracting with an explicit encoding of ISO-8859-1 will make
         # xgettext "parse" and ignore them.
-	echo $^ | xargs \
+	echo $(PYTHON_FILES) | xargs \
 	  xgettext --package-name "Mercurial" \
 	  --msgid-bugs-address "<mercurial-devel@selenic.com>" \
 	  --copyright-holder "Matt Mackall <mpm@selenic.com> and others" \
--- a/contrib/bash_completion	Tue Oct 06 11:18:58 2009 +0300
+++ b/contrib/bash_completion	Thu Oct 08 01:16:32 2009 -0500
@@ -530,3 +530,20 @@
     return
 }
 
+# shelve
+_hg_shelves()
+{
+    local shelves="$("$hg" unshelve -l . 2>/dev/null)"
+    local IFS=$'\n'
+    COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$shelves' -- "$cur"))
+}
+
+_hg_cmd_shelve()
+{
+    _hg_status "mard"
+}
+
+_hg_cmd_unshelve()
+{
+    _hg_shelves
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/shrink-revlog.py	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+
+"""\
+Reorder a revlog (by default the the manifest file in the current
+repository) to save space.  Specifically, this topologically sorts the
+revisions in the revlog so that revisions on the same branch are adjacent
+as much as possible.  This is a workaround for the fact that Mercurial
+computes deltas relative to the previous revision rather than relative to a
+parent revision.  This is *not* safe to run on a changelog.
+"""
+
+# Originally written by Benoit Boissinot <benoit.boissinot at ens-lyon.org>
+# as a patch to rewrite-log.  Cleaned up, refactored, documented, and
+# renamed by Greg Ward <greg at gerg.ca>.
+
+# XXX would be nice to have a way to verify the repository after shrinking,
+# e.g. by comparing "before" and "after" states of random changesets
+# (maybe: export before, shrink, export after, diff).
+
+import sys, os, tempfile
+import optparse
+from mercurial import ui as ui_, hg, revlog, transaction, node, util
+
+def toposort(rl):
+    write = sys.stdout.write
+
+    children = {}
+    root = []
+    # build children and roots
+    write('reading %d revs ' % len(rl))
+    try:
+        for i in rl:
+            children[i] = []
+            parents = [p for p in rl.parentrevs(i) if p != node.nullrev]
+            # in case of duplicate parents
+            if len(parents) == 2 and parents[0] == parents[1]:
+                del parents[1]
+            for p in parents:
+                assert p in children
+                children[p].append(i)
+
+            if len(parents) == 0:
+                root.append(i)
+
+            if i % 1000 == 0:
+                write('.')
+    finally:
+        write('\n')
+
+    # XXX this is a reimplementation of the 'branchsort' topo sort
+    # algorithm in hgext.convert.convcmd... would be nice not to duplicate
+    # the algorithm
+    write('sorting ...')
+    visit = root
+    ret = []
+    while visit:
+        i = visit.pop(0)
+        ret.append(i)
+        if i not in children:
+            # This only happens if some node's p1 == p2, which can
+            # happen in the manifest in certain circumstances.
+            continue
+        next = []
+        for c in children.pop(i):
+            parents_unseen = [p for p in rl.parentrevs(c)
+                              if p != node.nullrev and p in children]
+            if len(parents_unseen) == 0:
+                next.append(c)
+        visit = next + visit
+    write('\n')
+    return ret
+
+def writerevs(r1, r2, order, tr):
+    write = sys.stdout.write
+    write('writing %d revs ' % len(order))
+    try:
+        count = 0
+        for rev in order:
+            n = r1.node(rev)
+            p1, p2 = r1.parents(n)
+            l = r1.linkrev(rev)
+            t = r1.revision(n)
+            n2 = r2.addrevision(t, tr, l, p1, p2)
+
+            if count % 1000 == 0:
+                write('.')
+            count += 1
+    finally:
+        write('\n')
+    
+def report(olddatafn, newdatafn):
+    oldsize = float(os.stat(olddatafn).st_size)
+    newsize = float(os.stat(newdatafn).st_size)
+
+    # argh: have to pass an int to %d, because a float >= 2^32 
+    # blows up under Python 2.5 or earlier
+    sys.stdout.write('old file size: %12d bytes (%6.1f MiB)\n'
+                     % (int(oldsize), oldsize/1024/1024))
+    sys.stdout.write('new file size: %12d bytes (%6.1f MiB)\n'
+                     % (int(newsize), newsize/1024/1024))
+
+    shrink_percent = (oldsize - newsize) / oldsize * 100
+    shrink_factor = oldsize / newsize
+    sys.stdout.write('shrinkage: %.1f%% (%.1fx)\n'
+                     % (shrink_percent, shrink_factor))
+
+def main():
+
+    # Unbuffer stdout for nice progress output.
+    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+    write = sys.stdout.write
+
+    parser = optparse.OptionParser(description=__doc__)
+    parser.add_option('-R', '--repository',
+                      default=os.path.curdir,
+                      metavar='REPO',
+                      help='repository root directory [default: current dir]')
+    parser.add_option('--revlog',
+                      metavar='FILE',
+                      help='shrink FILE [default: REPO/hg/store/00manifest.i]')
+    (options, args) = parser.parse_args()
+    if args:
+        parser.error('too many arguments')
+
+    # Open the specified repository.
+    ui = ui_.ui()
+    repo = hg.repository(ui, options.repository)
+    if not repo.local():
+        parser.error('not a local repository: %s' % options.repository)
+
+    if options.revlog is None:
+        indexfn = repo.sjoin('00manifest.i')
+    else:
+        if not options.revlog.endswith('.i'):
+            parser.error('--revlog option must specify the revlog index file '
+                         '(*.i), not %s' % options.revlog)
+
+        indexfn = os.path.realpath(options.revlog)
+        store = repo.sjoin('')
+        if not indexfn.startswith(store):
+            parser.error('--revlog option must specify a revlog in %s, not %s'
+                         % (store, indexfn))
+
+    datafn = indexfn[:-2] + '.d'
+    if not os.path.exists(indexfn):
+        parser.error('no such file: %s' % indexfn)
+    if '00changelog' in indexfn:
+        parser.error('shrinking the changelog will corrupt your repository')
+    if not os.path.exists(datafn):
+        # This is just a lazy shortcut because I can't be bothered to
+        # handle all the special cases that entail from no .d file.
+        parser.error('%s does not exist: revlog not big enough '
+                     'to be worth shrinking' % datafn)
+
+    oldindexfn = indexfn + '.old'
+    olddatafn = datafn + '.old'
+    if os.path.exists(oldindexfn) or os.path.exists(olddatafn):
+        parser.error('one or both of\n'
+                     '  %s\n'
+                     '  %s\n'
+                     'exists from a previous run; please clean up before '
+                     'running again'
+                     % (oldindexfn, olddatafn))
+
+    write('shrinking %s\n' % indexfn)
+    prefix = os.path.basename(indexfn)[:-1]
+    (tmpfd, tmpindexfn) = tempfile.mkstemp(dir=os.path.dirname(indexfn),
+                                           prefix=prefix,
+                                           suffix='.i')
+    tmpdatafn = tmpindexfn[:-2] + '.d'
+    os.close(tmpfd)
+
+    r1 = revlog.revlog(util.opener(os.getcwd(), audit=False), indexfn)
+    r2 = revlog.revlog(util.opener(os.getcwd(), audit=False), tmpindexfn)
+
+    # Don't use repo.transaction(), because then things get hairy with
+    # paths: some need to be relative to .hg, and some need to be
+    # absolute.  Doing it this way keeps things simple: everything is an
+    # absolute path.
+    lock = repo.lock(wait=False)
+    tr = transaction.transaction(sys.stderr.write,
+                                 open,
+                                 repo.sjoin('journal'))
+
+    try:
+        try:
+            order = toposort(r1)
+            writerevs(r1, r2, order, tr)
+            report(datafn, tmpdatafn)
+            tr.close()
+        except:
+            # Abort transaction first, so we truncate the files before
+            # deleting them.
+            tr.abort()
+            if os.path.exists(tmpindexfn):
+                os.unlink(tmpindexfn)
+            if os.path.exists(tmpdatafn):
+                os.unlink(tmpdatafn)
+            raise
+    finally:
+        lock.release()
+
+    os.link(indexfn, oldindexfn)
+    os.link(datafn, olddatafn)
+    os.rename(tmpindexfn, indexfn)
+    os.rename(tmpdatafn, datafn)
+    write('note: old revlog saved in:\n'
+          '  %s\n'
+          '  %s\n'
+          '(You can delete those files when you are satisfied that your\n'
+          'repository is still sane.  '
+          'Running \'hg verify\' is strongly recommended.)\n'
+          % (oldindexfn, olddatafn))
+
+try:
+    main()
+except KeyboardInterrupt:
+    sys.exit("interrupted")
--- a/doc/gendoc.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/doc/gendoc.py	Thu Oct 08 01:16:32 2009 -0500
@@ -1,9 +1,10 @@
-import os, sys, textwrap
+import os, sys
 # import from the live mercurial repo
 sys.path.insert(0, "..")
 # fall back to pure modules if required C extensions are not available
 sys.path.append(os.path.join('..', 'mercurial', 'pure'))
 from mercurial import demandimport; demandimport.enable()
+from mercurial import encoding
 from mercurial.commands import table, globalopts
 from mercurial.i18n import _
 from mercurial.help import helptable
@@ -55,9 +56,9 @@
 
 def show_doc(ui):
     def section(s):
-        ui.write("%s\n%s\n\n" % (s, "-" * len(s)))
+        ui.write("%s\n%s\n\n" % (s, "-" * encoding.colwidth(s)))
     def subsection(s):
-        ui.write("%s\n%s\n\n" % (s, '"' * len(s)))
+        ui.write("%s\n%s\n\n" % (s, '"' * encoding.colwidth(s)))
 
     # print options
     section(_("OPTIONS"))
@@ -92,9 +93,7 @@
                     s = "%-*s  %s" % (opts_len, optstr, desc)
                 else:
                     s = optstr
-                s = textwrap.fill(s, initial_indent=4 * " ",
-                                  subsequent_indent=(6 + opts_len) * " ")
-                ui.write("%s\n" % s)
+                ui.write("    %s\n" % s)
             ui.write("\n")
         # aliases
         if d['aliases']:
--- a/doc/hg.1.txt	Tue Oct 06 11:18:58 2009 +0300
+++ b/doc/hg.1.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -95,6 +95,6 @@
 -------
 Copyright \(C) 2005-2009 Matt Mackall.
 Free use of this software is granted under the terms of the GNU General
-Public License (GPL).
+Public License version 2.
 
 .. include:: common.txt
--- a/doc/hgignore.5.txt	Tue Oct 06 11:18:58 2009 +0300
+++ b/doc/hgignore.5.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -106,6 +106,6 @@
 This manual page is copyright 2006 Vadim Gelfer.
 Mercurial is copyright 2005-2009 Matt Mackall.
 Free use of this software is granted under the terms of the GNU General
-Public License (GPL).
+Public License version 2.
 
 .. include:: common.txt
--- a/doc/hgrc.5.txt	Tue Oct 06 11:18:58 2009 +0300
+++ b/doc/hgrc.5.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -946,6 +946,6 @@
 This manual page is copyright 2005 Bryan O'Sullivan.
 Mercurial is copyright 2005-2009 Matt Mackall.
 Free use of this software is granted under the terms of the GNU General
-Public License (GPL).
+Public License version 2.
 
 .. include:: common.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help/dates.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,36 @@
+Some commands allow the user to specify a date, e.g.:
+
+- backout, commit, import, tag: Specify the commit date.
+- log, revert, update: Select revision(s) by date.
+
+Many date formats are valid. Here are some examples::
+
+  "Wed Dec 6 13:18:29 2006" (local timezone assumed)
+  "Dec 6 13:18 -0600" (year assumed, time offset provided)
+  "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
+  "Dec 6" (midnight)
+  "13:18" (today assumed)
+  "3:39" (3:39AM assumed)
+  "3:39pm" (15:39)
+  "2006-12-06 13:18:29" (ISO 8601 format)
+  "2006-12-6 13:18"
+  "2006-12-6"
+  "12-6"
+  "12/6"
+  "12/6/6" (Dec 6 2006)
+
+Lastly, there is Mercurial's internal format::
+
+  "1165432709 0" (Wed Dec 6 13:18:29 2006 UTC)
+
+This is the internal representation format for dates. unixtime is the
+number of seconds since the epoch (1970-01-01 00:00 UTC). offset is
+the offset of the local timezone, in seconds west of UTC (negative if
+the timezone is east of UTC).
+
+The log command also accepts date ranges::
+
+  "<{datetime}" - at or before a given date/time
+  ">{datetime}" - on or after a given date/time
+  "{datetime} to {datetime}" - a date range, inclusive
+  "-{days}" - within a given number of days of today
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help/diffs.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,29 @@
+Mercurial's default format for showing changes between two versions of
+a file is compatible with the unified format of GNU diff, which can be
+used by GNU patch and many other standard tools.
+
+While this standard format is often enough, it does not encode the
+following information:
+
+- executable status and other permission bits
+- copy or rename information
+- changes in binary files
+- creation or deletion of empty files
+
+Mercurial also supports the extended diff format from the git VCS
+which addresses these limitations. The git diff format is not produced
+by default because a few widespread tools still do not understand this
+format.
+
+This means that when generating diffs from a Mercurial repository
+(e.g. with "hg export"), you should be careful about things like file
+copies and renames or other things mentioned above, because when
+applying a standard diff to a different repository, this extra
+information is lost. Mercurial's internal operations (like push and
+pull) are not affected by this, because they use an internal binary
+format for communicating changes.
+
+To make Mercurial produce the git extended diff format, use the --git
+option available for many commands, or set 'git = True' in the [diff]
+section of your hgrc. You do not need to set this option when
+importing diffs in this format or using them in the mq extension.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help/environment.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,76 @@
+HG
+    Path to the 'hg' executable, automatically passed when running
+    hooks, extensions or external tools. If unset or empty, this is
+    the hg executable's name if it's frozen, or an executable named
+    'hg' (with %PATHEXT% [defaulting to COM/EXE/BAT/CMD] extensions on
+    Windows) is searched.
+
+HGEDITOR
+    This is the name of the editor to run when committing. See EDITOR.
+
+    (deprecated, use .hgrc)
+
+HGENCODING
+    This overrides the default locale setting detected by Mercurial.
+    This setting is used to convert data including usernames,
+    changeset descriptions, tag names, and branches. This setting can
+    be overridden with the --encoding command-line option.
+
+HGENCODINGMODE
+    This sets Mercurial's behavior for handling unknown characters
+    while transcoding user input. The default is "strict", which
+    causes Mercurial to abort if it can't map a character. Other
+    settings include "replace", which replaces unknown characters, and
+    "ignore", which drops them. This setting can be overridden with
+    the --encodingmode command-line option.
+
+HGMERGE
+    An executable to use for resolving merge conflicts. The program
+    will be executed with three arguments: local file, remote file,
+    ancestor file.
+
+    (deprecated, use .hgrc)
+
+HGRCPATH
+    A list of files or directories to search for hgrc files. Item
+    separator is ":" on Unix, ";" on Windows. If HGRCPATH is not set,
+    platform default search path is used. If empty, only the .hg/hgrc
+    from the current repository is read.
+
+    For each element in HGRCPATH:
+
+    - if it's a directory, all files ending with .rc are added
+    - otherwise, the file itself will be added
+
+HGUSER
+    This is the string used as the author of a commit. If not set,
+    available values will be considered in this order:
+
+    - HGUSER (deprecated)
+    - hgrc files from the HGRCPATH
+    - EMAIL
+    - interactive prompt
+    - LOGNAME (with '@hostname' appended)
+
+    (deprecated, use .hgrc)
+
+EMAIL
+    May be used as the author of a commit; see HGUSER.
+
+LOGNAME
+    May be used as the author of a commit; see HGUSER.
+
+VISUAL
+    This is the name of the editor to use when committing. See EDITOR.
+
+EDITOR
+    Sometimes Mercurial needs to open a text file in an editor for a
+    user to modify, for example when writing commit messages. The
+    editor it uses is determined by looking at the environment
+    variables HGEDITOR, VISUAL and EDITOR, in that order. The first
+    non-empty one is chosen. If all of them are empty, the editor
+    defaults to 'vi'.
+
+PYTHONPATH
+    This is used by Python to find imported modules and may need to be
+    set appropriately if this Mercurial is not installed system-wide.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help/extensions.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,33 @@
+Mercurial has the ability to add new features through the use of
+extensions. Extensions may add new commands, add options to
+existing commands, change the default behavior of commands, or
+implement hooks.
+
+Extensions are not loaded by default for a variety of reasons:
+they can increase startup overhead; they may be meant for advanced
+usage only; they may provide potentially dangerous abilities (such
+as letting you destroy or modify history); they might not be ready
+for prime time; or they may alter some usual behaviors of stock
+Mercurial. It is thus up to the user to activate extensions as
+needed.
+
+To enable the "foo" extension, either shipped with Mercurial or in
+the Python search path, create an entry for it in your hgrc, like
+this::
+
+  [extensions]
+  foo =
+
+You may also specify the full path to an extension::
+
+  [extensions]
+  myfeature = ~/.hgext/myfeature.py
+
+To explicitly disable an extension enabled in an hgrc of broader
+scope, prepend its path with !::
+
+  [extensions]
+  # disabling extension bar residing in /path/to/extension/bar.py
+  hgext.bar = !/path/to/extension/bar.py
+  # ditto, but no path was supplied for extension baz
+  hgext.baz = !
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help/multirevs.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,13 @@
+When Mercurial accepts more than one revision, they may be specified
+individually, or provided as a topologically continuous range,
+separated by the ":" character.
+
+The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
+revision identifiers. Both BEGIN and END are optional. If BEGIN is not
+specified, it defaults to revision number 0. If END is not specified,
+it defaults to the tip. The range ":" thus means "all revisions".
+
+If BEGIN is greater than END, revisions are treated in reverse order.
+
+A range acts as a closed interval. This means that a range of 3:5
+gives 3, 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help/patterns.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,41 @@
+Mercurial accepts several notations for identifying one or more files
+at a time.
+
+By default, Mercurial treats filenames as shell-style extended glob
+patterns.
+
+Alternate pattern notations must be specified explicitly.
+
+To use a plain path name without any pattern matching, start it with
+"path:". These path names must completely match starting at the
+current repository root.
+
+To use an extended glob, start a name with "glob:". Globs are rooted
+at the current directory; a glob such as "``*.c``" will only match
+files in the current directory ending with ".c".
+
+The supported glob syntax extensions are "``**``" to match any string
+across path separators and "{a,b}" to mean "a or b".
+
+To use a Perl/Python regular expression, start a name with "re:".
+Regexp pattern matching is anchored at the root of the repository.
+
+Plain examples::
+
+  path:foo/bar   a name bar in a directory named foo in the root
+                 of the repository
+  path:path:name a file or directory named "path:name"
+
+Glob examples::
+
+  glob:*.c       any name ending in ".c" in the current directory
+  *.c            any name ending in ".c" in the current directory
+  **.c           any name ending in ".c" in any subdirectory of the
+                 current directory including itself.
+  foo/*.c        any name ending in ".c" in the directory foo
+  foo/**.c       any name ending in ".c" in any subdirectory of foo
+                 including itself.
+
+Regexp examples::
+
+  re:.*\.c$      any name ending in ".c", anywhere in the repository
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help/revisions.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,29 @@
+Mercurial supports several ways to specify individual revisions.
+
+A plain integer is treated as a revision number. Negative integers are
+treated as sequential offsets from the tip, with -1 denoting the tip,
+-2 denoting the revision prior to the tip, and so forth.
+
+A 40-digit hexadecimal string is treated as a unique revision
+identifier.
+
+A hexadecimal string less than 40 characters long is treated as a
+unique revision identifier and is referred to as a short-form
+identifier. A short-form identifier is only valid if it is the prefix
+of exactly one full-length identifier.
+
+Any other string is treated as a tag or branch name. A tag name is a
+symbolic name associated with a revision identifier. A branch name
+denotes the tipmost revision of that branch. Tag and branch names must
+not contain the ":" character.
+
+The reserved name "tip" is a special tag that always identifies the
+most recent revision.
+
+The reserved name "null" indicates the null revision. This is the
+revision of an empty repository, and the parent of revision 0.
+
+The reserved name "." indicates the working directory parent. If no
+working directory is checked out, it is equivalent to null. If an
+uncommitted merge is in progress, "." is the revision of the first
+parent.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help/templates.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,113 @@
+Mercurial allows you to customize output of commands through
+templates. You can either pass in a template from the command
+line, via the --template option, or select an existing
+template-style (--style).
+
+You can customize output for any "log-like" command: log,
+outgoing, incoming, tip, parents, heads and glog.
+
+Three styles are packaged with Mercurial: default (the style used
+when no explicit preference is passed), compact and changelog.
+Usage::
+
+    $ hg log -r1 --style changelog
+
+A template is a piece of text, with markup to invoke variable
+expansion::
+
+    $ hg log -r1 --template "{node}\n"
+    b56ce7b07c52de7d5fd79fb89701ea538af65746
+
+Strings in curly braces are called keywords. The availability of
+keywords depends on the exact context of the templater. These
+keywords are usually available for templating a log-like command:
+
+:author:    String. The unmodified author of the changeset.
+:branches:  String. The name of the branch on which the changeset
+            was committed. Will be empty if the branch name was
+            default.
+:date:      Date information. The date when the changeset was
+            committed.
+:desc:      String. The text of the changeset description.
+:diffstat:  String. Statistics of changes with the following
+            format: "modified files: +added/-removed lines"
+:files:     List of strings. All files modified, added, or removed
+            by this changeset.
+:file_adds: List of strings. Files added by this changeset.
+:file_mods: List of strings. Files modified by this changeset.
+:file_dels: List of strings. Files removed by this changeset.
+:node:      String. The changeset identification hash, as a
+            40-character hexadecimal string.
+:parents:   List of strings. The parents of the changeset.
+:rev:       Integer. The repository-local changeset revision
+            number.
+:tags:      List of strings. Any tags associated with the
+            changeset.
+:latesttag: String. Most recent global tag in the ancestors of this
+            changeset.
+:latesttagdistance: Integer. Longest path to the latest tag.
+
+The "date" keyword does not produce human-readable output. If you
+want to use a date in your output, you can use a filter to process
+it. Filters are functions which return a string based on the input
+variable. You can also use a chain of filters to get the desired
+output::
+
+   $ hg tip --template "{date|isodate}\n"
+   2008-08-21 18:22 +0000
+
+List of filters:
+
+:addbreaks:   Any text. Add an XHTML "<br />" tag before the end of
+              every line except the last.
+:age:         Date. Returns a human-readable date/time difference
+              between the given date/time and the current
+              date/time.
+:basename:    Any text. Treats the text as a path, and returns the
+              last component of the path after splitting by the
+              path separator (ignoring trailing separators). For
+              example, "foo/bar/baz" becomes "baz" and "foo/bar//"
+              becomes "bar".
+:stripdir:    Treat the text as path and strip a directory level,
+              if possible. For example, "foo" and "foo/bar" becomes
+              "foo".
+:date:        Date. Returns a date in a Unix date format, including
+              the timezone: "Mon Sep 04 15:13:13 2006 0700".
+:domain:      Any text. Finds the first string that looks like an
+              email address, and extracts just the domain
+              component. Example: 'User <user@example.com>' becomes
+              'example.com'.
+:email:       Any text. Extracts the first string that looks like
+              an email address. Example: 'User <user@example.com>'
+              becomes 'user@example.com'.
+:escape:      Any text. Replaces the special XML/XHTML characters
+              "&", "<" and ">" with XML entities.
+:fill68:      Any text. Wraps the text to fit in 68 columns.
+:fill76:      Any text. Wraps the text to fit in 76 columns.
+:firstline:   Any text. Returns the first line of text.
+:nonempty:    Any text. Returns '(none)' if the string is empty.
+:hgdate:      Date. Returns the date as a pair of numbers:
+              "1157407993 25200" (Unix timestamp, timezone offset).
+:isodate:     Date. Returns the date in ISO 8601 format:
+              "2009-08-18 13:00 +0200".
+:isodatesec:  Date. Returns the date in ISO 8601 format, including
+              seconds: "2009-08-18 13:00:13 +0200". See also the
+              rfc3339date filter.
+:localdate:   Date. Converts a date to local date.
+:obfuscate:   Any text. Returns the input text rendered as a
+              sequence of XML entities.
+:person:      Any text. Returns the text before an email address.
+:rfc822date:  Date. Returns a date using the same format used in
+              email headers: "Tue, 18 Aug 2009 13:00:13 +0200".
+:rfc3339date: Date. Returns a date using the Internet date format
+              specified in RFC 3339: "2009-08-18T13:00:13+02:00".
+:short:       Changeset hash. Returns the short form of a changeset
+              hash, i.e. a 12-byte hexadecimal string.
+:shortdate:   Date. Returns a date like "2006-09-18".
+:strip:       Any text. Strips all leading and trailing whitespace.
+:tabindent:   Any text. Returns the text, with every line except
+              the first starting with a tab character.
+:urlescape:   Any text. Escapes all "special" characters. For
+              example, "foo bar" becomes "foo%20bar".
+:user:        Any text. Returns the user portion of an email
+              address.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/help/urls.txt	Thu Oct 08 01:16:32 2009 -0500
@@ -0,0 +1,63 @@
+Valid URLs are of the form::
+
+  local/filesystem/path[#revision]
+  file://local/filesystem/path[#revision]
+  http://[user[:pass]@]host[:port]/[path][#revision]
+  https://[user[:pass]@]host[:port]/[path][#revision]
+  ssh://[user[:pass]@]host[:port]/[path][#revision]
+
+Paths in the local filesystem can either point to Mercurial
+repositories or to bundle files (as created by 'hg bundle' or 'hg
+incoming --bundle').
+
+An optional identifier after # indicates a particular branch, tag, or
+changeset to use from the remote repository. See also 'hg help
+revisions'.
+
+Some features, such as pushing to http:// and https:// URLs are only
+possible if the feature is explicitly enabled on the remote Mercurial
+server.
+
+Some notes about using SSH with Mercurial:
+
+- SSH requires an accessible shell account on the destination machine
+  and a copy of hg in the remote path or specified with as remotecmd.
+- path is relative to the remote user's home directory by default. Use
+  an extra slash at the start of a path to specify an absolute path::
+
+    ssh://example.com//tmp/repository
+
+- Mercurial doesn't use its own compression via SSH; the right thing
+  to do is to configure it in your ~/.ssh/config, e.g.::
+
+    Host *.mylocalnetwork.example.com
+      Compression no
+    Host *
+      Compression yes
+
+  Alternatively specify "ssh -C" as your ssh command in your hgrc or
+  with the --ssh command line option.
+
+These URLs can all be stored in your hgrc with path aliases under the
+[paths] section like so::
+
+  [paths]
+  alias1 = URL1
+  alias2 = URL2
+  ...
+
+You can then use the alias for any command that uses a URL (for
+example 'hg pull alias1' would pull from the 'alias1' path).
+
+Two path aliases are special because they are used as defaults when
+you do not provide the URL to a command:
+
+default:
+  When you create a repository with hg clone, the clone command saves
+  the location of the source repository as the new repository's
+  'default' path. This is then used when you omit path from push- and
+  pull-like commands (including incoming and outgoing).
+
+default-push:
+  The push command will look for a path named 'default-push', and
+  prefer it over 'default' if both are defined.
--- a/hgext/acl.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/acl.py	Thu Oct 08 01:16:32 2009 -0500
@@ -60,12 +60,12 @@
 def buildmatch(ui, repo, user, key):
     '''return tuple of (match function, list enabled).'''
     if not ui.has_section(key):
-        ui.debug(_('acl: %s not enabled\n') % key)
+        ui.debug('acl: %s not enabled\n' % key)
         return None
 
     pats = [pat for pat, users in ui.configitems(key)
             if user in users.replace(',', ' ').split()]
-    ui.debug(_('acl: %s enabled, %d entries for user %s\n') %
+    ui.debug('acl: %s enabled, %d entries for user %s\n' %
              (key, len(pats), user))
     if pats:
         return match.match(repo.root, '', pats)
@@ -77,7 +77,7 @@
         raise util.Abort(_('config error - hook type "%s" cannot stop '
                            'incoming changesets') % hooktype)
     if source not in ui.config('acl', 'sources', 'serve').split():
-        ui.debug(_('acl: changes have source "%s" - skipping\n') % source)
+        ui.debug('acl: changes have source "%s" - skipping\n' % source)
         return
 
     user = None
@@ -99,9 +99,9 @@
         ctx = repo[rev]
         for f in ctx.files():
             if deny and deny(f):
-                ui.debug(_('acl: user %s denied on %s\n') % (user, f))
+                ui.debug('acl: user %s denied on %s\n' % (user, f))
                 raise util.Abort(_('acl: access denied for changeset %s') % ctx)
             if allow and not allow(f):
-                ui.debug(_('acl: user %s not allowed on %s\n') % (user, f))
+                ui.debug('acl: user %s not allowed on %s\n' % (user, f))
                 raise util.Abort(_('acl: access denied for changeset %s') % ctx)
-        ui.debug(_('acl: allowing changeset %s\n') % ctx)
+        ui.debug('acl: allowing changeset %s\n' % ctx)
--- a/hgext/churn.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/churn.py	Thu Oct 08 01:16:32 2009 -0500
@@ -153,7 +153,7 @@
     maxname = max(len(k) for k, v in rate)
 
     ttywidth = util.termwidth()
-    ui.debug(_("assuming %i character terminal\n") % ttywidth)
+    ui.debug("assuming %i character terminal\n" % ttywidth)
     width = ttywidth - maxname - 2 - 6 - 2 - 2
 
     for date, count in rate:
--- a/hgext/color.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/color.py	Thu Oct 08 01:16:32 2009 -0500
@@ -160,25 +160,26 @@
     return retval
 
 _patch_effects = { 'applied': ['blue', 'bold', 'underline'],
-                   'missing': ['red', 'bold'],
-                   'unapplied': ['black', 'bold'], }
-
-def colorwrap(orig, s):
+                    'missing': ['red', 'bold'],
+                    'unapplied': ['black', 'bold'], }
+def colorwrap(orig, *args):
     '''wrap ui.write for colored diff output'''
-    lines = s.split('\n')
-    for i, line in enumerate(lines):
-        stripline = line
-        if line and line[0] in '+-':
-            # highlight trailing whitespace, but only in changed lines
-            stripline = line.rstrip()
-        for prefix, style in _diff_prefixes:
-            if stripline.startswith(prefix):
-                lines[i] = render_effects(stripline, _diff_effects[style])
-                break
-        if line != stripline:
-            lines[i] += render_effects(
-                line[len(stripline):], _diff_effects['trailingwhitespace'])
-    orig('\n'.join(lines))
+    def _colorize(s):
+        lines = s.split('\n')
+        for i, line in enumerate(lines):
+            stripline = line
+            if line and line[0] in '+-':
+                # highlight trailing whitespace, but only in changed lines
+                stripline = line.rstrip()
+            for prefix, style in _diff_prefixes:
+                if stripline.startswith(prefix):
+                    lines[i] = render_effects(stripline, _diff_effects[style])
+                    break
+            if line != stripline:
+                lines[i] += render_effects(
+                    line[len(stripline):], _diff_effects['trailingwhitespace'])
+        return '\n'.join(lines)
+    orig(*[_colorize(s) for s in args])
 
 def colorshowpatch(orig, self, node):
     '''wrap cmdutil.changeset_printer.showpatch with colored output'''
@@ -235,6 +236,13 @@
         # The mq extension is not enabled
         pass
 
+    try:
+        rec = extensions.find('record')
+        _setupcmd(ui, 'record', rec.cmdtable, colordiff, _diff_effects)
+    except KeyError:
+        # The record extension is not enabled
+        pass
+
 def _setupcmd(ui, cmd, table, func, effectsmap):
     '''patch in command to command table and load effect map'''
     def nocolor(orig, *args, **opts):
@@ -256,7 +264,7 @@
     entry = extensions.wrapcommand(table, cmd, nocolor)
     entry[1].extend([
         ('', 'color', 'auto', _("when to colorize (always, auto, or never)")),
-        ('', 'no-color', None, _("don't colorize output")),
+        ('', 'no-color', None, _("don't colorize output (DEPRECATED)")),
     ])
 
     for status in effectsmap:
--- a/hgext/convert/__init__.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/convert/__init__.py	Thu Oct 08 01:16:32 2009 -0500
@@ -142,23 +142,8 @@
     converted, and that any directory reorganization in the CVS
     sandbox is ignored.
 
-    Because CVS does not have changesets, it is necessary to collect
-    individual commits to CVS and merge them into changesets. CVS
-    source uses its internal changeset merging code by default but can
-    be configured to call the external 'cvsps' program by setting::
-
-      --config convert.cvsps='cvsps -A -u --cvs-direct -q'
-
-    This option is deprecated and will be removed in Mercurial 1.4.
-
     The options shown are the defaults.
 
-    Internal cvsps is selected by setting ::
-
-      --config convert.cvsps=builtin
-
-    and has a few more configurable options:
-
     --config convert.cvsps.cache=True         (boolean)
         Set to False to disable remote log caching, for testing and
         debugging purposes.
@@ -178,9 +163,10 @@
         add the most recent revision on the branch indicated in the
         regex as the second parent of the changeset.
 
-    The hgext/convert/cvsps wrapper script allows the builtin
+    An additional "debugcvsps" Mercurial command allows the builtin
     changeset merging code to be run without doing a conversion. Its
-    parameters and output are similar to that of cvsps 2.1.
+    parameters and output are similar to that of cvsps 2.1. Please see
+    the command help for more details.
 
     Subversion Source
     -----------------
--- a/hgext/convert/common.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/convert/common.py	Thu Oct 08 01:16:32 2009 -0500
@@ -266,7 +266,7 @@
 
     def _run(self, cmd, *args, **kwargs):
         cmdline = self._cmdline(cmd, *args, **kwargs)
-        self.ui.debug(_('running: %s\n') % (cmdline,))
+        self.ui.debug('running: %s\n' % (cmdline,))
         self.prerun()
         try:
             return util.popen(cmdline)
@@ -365,7 +365,7 @@
             return
         for i, line in enumerate(fp):
             try:
-                key, value = line[:-1].rsplit(' ', 1)
+                key, value = line.splitlines()[0].rsplit(' ', 1)
             except ValueError:
                 raise util.Abort(_('syntax error in %s(%d): key/value pair expected')
                                  % (self.path, i+1))
--- a/hgext/convert/cvs.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/convert/cvs.py	Thu Oct 08 01:16:32 2009 -0500
@@ -22,21 +22,11 @@
             raise NoRepo("%s does not look like a CVS checkout" % path)
 
         checktool('cvs')
-        self.cmd = ui.config('convert', 'cvsps', 'builtin')
-        cvspsexe = self.cmd.split(None, 1)[0]
-        self.builtin = cvspsexe == 'builtin'
-        if not self.builtin:
-            ui.warn(_('warning: support for external cvsps is deprecated and '
-                      'will be removed in Mercurial 1.4\n'))
-
-        if not self.builtin:
-            checktool(cvspsexe)
 
         self.changeset = None
         self.files = {}
         self.tags = {}
         self.lastbranch = {}
-        self.parent = {}
         self.socket = None
         self.cvsroot = open(os.path.join(cvs, "Root")).read()[:-1]
         self.cvsrepo = open(os.path.join(cvs, "Repository")).read()[:-1]
@@ -50,19 +40,13 @@
         self.changeset = {}
 
         maxrev = 0
-        cmd = self.cmd
         if self.rev:
             # TODO: handle tags
             try:
                 # patchset number?
                 maxrev = int(self.rev)
             except ValueError:
-                try:
-                    # date
-                    util.parsedate(self.rev, ['%Y/%m/%d %H:%M:%S'])
-                    cmd = '%s -d "1970/01/01 00:00:01" -d "%s"' % (cmd, self.rev)
-                except util.Abort:
-                    raise util.Abort(_('revision %s is not a patchset number or date') % self.rev)
+                raise util.Abort(_('revision %s is not a patchset number') % self.rev)
 
         d = os.getcwd()
         try:
@@ -71,116 +55,36 @@
             state = 0
             filerevids = {}
 
-            if self.builtin:
-                # builtin cvsps code
-                self.ui.status(_('using builtin cvsps\n'))
-
-                cache = 'update'
-                if not self.ui.configbool('convert', 'cvsps.cache', True):
-                    cache = None
-                db = cvsps.createlog(self.ui, cache=cache)
-                db = cvsps.createchangeset(self.ui, db,
-                      fuzz=int(self.ui.config('convert', 'cvsps.fuzz', 60)),
-                      mergeto=self.ui.config('convert', 'cvsps.mergeto', None),
-                      mergefrom=self.ui.config('convert', 'cvsps.mergefrom', None))
-
-                for cs in db:
-                    if maxrev and cs.id>maxrev:
-                        break
-                    id = str(cs.id)
-                    cs.author = self.recode(cs.author)
-                    self.lastbranch[cs.branch] = id
-                    cs.comment = self.recode(cs.comment)
-                    date = util.datestr(cs.date)
-                    self.tags.update(dict.fromkeys(cs.tags, id))
-
-                    files = {}
-                    for f in cs.entries:
-                        files[f.file] = "%s%s" % ('.'.join([str(x) for x in f.revision]),
-                                                  ['', '(DEAD)'][f.dead])
+            cache = 'update'
+            if not self.ui.configbool('convert', 'cvsps.cache', True):
+                cache = None
+            db = cvsps.createlog(self.ui, cache=cache)
+            db = cvsps.createchangeset(self.ui, db,
+                fuzz=int(self.ui.config('convert', 'cvsps.fuzz', 60)),
+                mergeto=self.ui.config('convert', 'cvsps.mergeto', None),
+                mergefrom=self.ui.config('convert', 'cvsps.mergefrom', None))
 
-                    # add current commit to set
-                    c = commit(author=cs.author, date=date,
-                             parents=[str(p.id) for p in cs.parents],
-                             desc=cs.comment, branch=cs.branch or '')
-                    self.changeset[id] = c
-                    self.files[id] = files
-            else:
-                # external cvsps
-                for l in util.popen(cmd):
-                    if state == 0: # header
-                        if l.startswith("PatchSet"):
-                            id = l[9:-2]
-                            if maxrev and int(id) > maxrev:
-                                # ignore everything
-                                state = 3
-                        elif l.startswith("Date:"):
-                            date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
-                            date = util.datestr(date)
-                        elif l.startswith("Branch:"):
-                            branch = l[8:-1]
-                            self.parent[id] = self.lastbranch.get(branch, 'bad')
-                            self.lastbranch[branch] = id
-                        elif l.startswith("Ancestor branch:"):
-                            ancestor = l[17:-1]
-                            # figure out the parent later
-                            self.parent[id] = self.lastbranch[ancestor]
-                        elif l.startswith("Author:"):
-                            author = self.recode(l[8:-1])
-                        elif l.startswith("Tag:") or l.startswith("Tags:"):
-                            t = l[l.index(':')+1:]
-                            t = [ut.strip() for ut in t.split(',')]
-                            if (len(t) > 1) or (t[0] and (t[0] != "(none)")):
-                                self.tags.update(dict.fromkeys(t, id))
-                        elif l.startswith("Log:"):
-                            # switch to gathering log
-                            state = 1
-                            log = ""
-                    elif state == 1: # log
-                        if l == "Members: \n":
-                            # switch to gathering members
-                            files = {}
-                            oldrevs = []
-                            log = self.recode(log[:-1])
-                            state = 2
-                        else:
-                            # gather log
-                            log += l
-                    elif state == 2: # members
-                        if l == "\n": # start of next entry
-                            state = 0
-                            p = [self.parent[id]]
-                            if id == "1":
-                                p = []
-                            if branch == "HEAD":
-                                branch = ""
-                            if branch:
-                                latest = 0
-                                # the last changeset that contains a base
-                                # file is our parent
-                                for r in oldrevs:
-                                    latest = max(filerevids.get(r, 0), latest)
-                                if latest:
-                                    p = [latest]
+            for cs in db:
+                if maxrev and cs.id>maxrev:
+                    break
+                id = str(cs.id)
+                cs.author = self.recode(cs.author)
+                self.lastbranch[cs.branch] = id
+                cs.comment = self.recode(cs.comment)
+                date = util.datestr(cs.date)
+                self.tags.update(dict.fromkeys(cs.tags, id))
 
-                            # add current commit to set
-                            c = commit(author=author, date=date, parents=p,
-                                       desc=log, branch=branch)
-                            self.changeset[id] = c
-                            self.files[id] = files
-                        else:
-                            colon = l.rfind(':')
-                            file = l[1:colon]
-                            rev = l[colon+1:-2]
-                            oldrev, rev = rev.split("->")
-                            files[file] = rev
+                files = {}
+                for f in cs.entries:
+                    files[f.file] = "%s%s" % ('.'.join([str(x) for x in f.revision]),
+                                              ['', '(DEAD)'][f.dead])
 
-                            # save some information for identifying branch points
-                            oldrevs.append("%s:%s" % (oldrev, file))
-                            filerevids["%s:%s" % (rev, file)] = id
-                    elif state == 3:
-                        # swallow all input
-                        continue
+                # add current commit to set
+                c = commit(author=cs.author, date=date,
+                           parents=[str(p.id) for p in cs.parents],
+                           desc=cs.comment, branch=cs.branch or '')
+                self.changeset[id] = c
+                self.files[id] = files
 
             self.heads = self.lastbranch.values()
         finally:
--- a/hgext/convert/cvsps.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/convert/cvsps.py	Thu Oct 08 01:16:32 2009 -0500
@@ -199,7 +199,7 @@
 
     cmd = [util.shellquote(arg) for arg in cmd]
     ui.note(_("running %s\n") % (' '.join(cmd)))
-    ui.debug(_("prefix=%r directory=%r root=%r\n") % (prefix, directory, root))
+    ui.debug("prefix=%r directory=%r root=%r\n" % (prefix, directory, root))
 
     pfp = util.popen(' '.join(cmd))
     peek = pfp.readline()
@@ -378,7 +378,7 @@
               e.revision[-1] == 1 and      # 1.1 or 1.1.x.1
               len(e.comment) == 1 and
               file_added_re.match(e.comment[0])):
-            ui.debug(_('found synthetic revision in %s: %r\n')
+            ui.debug('found synthetic revision in %s: %r\n'
                      % (e.rcs, e.comment[0]))
             e.synthetic = True
 
--- a/hgext/convert/darcs.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/convert/darcs.py	Thu Oct 08 01:16:32 2009 -0500
@@ -75,7 +75,7 @@
         self.parents[child] = []
 
     def after(self):
-        self.ui.debug(_('cleaning up %s\n') % self.tmppath)
+        self.ui.debug('cleaning up %s\n' % self.tmppath)
         shutil.rmtree(self.tmppath, ignore_errors=True)
 
     def xml(self, cmd, **kwargs):
@@ -85,6 +85,17 @@
         self.checkexit(fp.close())
         return etree.getroot()
 
+    def manifest(self):
+        man = []
+        output, status = self.run('show', 'files', no_directories=True,
+                                  repodir=self.tmppath)
+        self.checkexit(status)
+        for line in output.split('\n'):
+            path = line[2:]
+            if path:
+                man.append(path)
+        return man
+
     def getheads(self):
         return self.parents[None]
 
@@ -107,18 +118,35 @@
             output, status = self.run('revert', all=True, repodir=self.tmppath)
             self.checkexit(status, output)
 
-    def getchanges(self, rev):
-        self.pull(rev)
+    def getchanges(self, rev):        
         copies = {}
         changes = []
+        man = None
         for elt in self.changes[rev].find('summary').getchildren():
             if elt.tag in ('add_directory', 'remove_directory'):
                 continue
             if elt.tag == 'move':
-                changes.append((elt.get('from'), rev))
-                copies[elt.get('from')] = elt.get('to')
+                if man is None:
+                    man = self.manifest()
+                source, dest = elt.get('from'), elt.get('to')
+                if source in man:
+                    # File move
+                    changes.append((source, rev))
+                    changes.append((dest, rev))
+                    copies[dest] = source
+                else:
+                    # Directory move, deduce file moves from manifest
+                    source = source + '/'
+                    for f in man:
+                        if not f.startswith(source):
+                            continue
+                        fdest = dest + '/' + f[len(source):]
+                        changes.append((f, rev))
+                        changes.append((fdest, rev))
+                        copies[fdest] = f
             else:
                 changes.append((elt.text.strip(), rev))
+        self.pull(rev)
         self.lastrev = rev
         return sorted(changes), copies
 
--- a/hgext/convert/gnuarch.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/convert/gnuarch.py	Thu Oct 08 01:16:32 2009 -0500
@@ -125,7 +125,7 @@
                     break
 
     def after(self):
-        self.ui.debug(_('cleaning up %s\n') % self.tmppath)
+        self.ui.debug('cleaning up %s\n' % self.tmppath)
         shutil.rmtree(self.tmppath, ignore_errors=True)
 
     def getheads(self):
@@ -195,7 +195,7 @@
         return os.system(cmdline)
 
     def _update(self, rev):
-        self.ui.debug(_('applying revision %s...\n') % rev)
+        self.ui.debug('applying revision %s...\n' % rev)
         changeset, status = self.runlines('replay', '-d', self.tmppath,
                                               rev)
         if status:
@@ -205,7 +205,7 @@
             self._obtainrevision(rev)
         else:
             old_rev = self.parents[rev][0]
-            self.ui.debug(_('computing changeset between %s and %s...\n')
+            self.ui.debug('computing changeset between %s and %s...\n'
                           % (old_rev, rev))
             self._parsechangeset(changeset, rev)
 
@@ -254,10 +254,10 @@
         return changes, copies
 
     def _obtainrevision(self, rev):
-        self.ui.debug(_('obtaining revision %s...\n') % rev)
+        self.ui.debug('obtaining revision %s...\n' % rev)
         output = self._execute('get', rev, self.tmppath)
         self.checkexit(output)
-        self.ui.debug(_('analyzing revision %s...\n') % rev)
+        self.ui.debug('analyzing revision %s...\n' % rev)
         files = self._readcontents(self.tmppath)
         self.changes[rev].add_files += files
 
--- a/hgext/convert/hg.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/convert/hg.py	Thu Oct 08 01:16:32 2009 -0500
@@ -55,12 +55,12 @@
         self.filemapmode = False
 
     def before(self):
-        self.ui.debug(_('run hg sink pre-conversion action\n'))
+        self.ui.debug('run hg sink pre-conversion action\n')
         self.wlock = self.repo.wlock()
         self.lock = self.repo.lock()
 
     def after(self):
-        self.ui.debug(_('run hg sink post-conversion action\n'))
+        self.ui.debug('run hg sink post-conversion action\n')
         self.lock.release()
         self.wlock.release()
 
@@ -248,8 +248,7 @@
         return self.lastctx
 
     def parents(self, ctx):
-        return [p.node() for p in ctx.parents()
-                if p and self.keep(p.node())]
+        return [p for p in ctx.parents() if p and self.keep(p.node())]
 
     def getheads(self):
         if self.rev:
@@ -275,20 +274,20 @@
             if self.ignoreerrors:
                 # calling getcopies() is a simple way to detect missing
                 # revlogs and populate self.ignored
-                self.getcopies(ctx, files)
+                self.getcopies(ctx, parents, files)
             return [(f, rev) for f in files if f not in self.ignored], {}
         if self._changescache and self._changescache[0] == rev:
             m, a, r = self._changescache[1]
         else:
-            m, a, r = self.repo.status(parents[0], ctx.node())[:3]
+            m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
         # getcopies() detects missing revlogs early, run it before
         # filtering the changes.
-        copies = self.getcopies(ctx, m + a)
+        copies = self.getcopies(ctx, parents, m + a)
         changes = [(name, rev) for name in m + a + r
                    if name not in self.ignored]
         return sorted(changes), copies
 
-    def getcopies(self, ctx, files):
+    def getcopies(self, ctx, parents, files):
         copies = {}
         for name in files:
             if name in self.ignored:
@@ -297,6 +296,14 @@
                 copysource, copynode = ctx.filectx(name).renamed()
                 if copysource in self.ignored or not self.keep(copynode):
                     continue
+                # Ignore copy sources not in parent revisions
+                found = False
+                for p in parents:
+                    if copysource in p:
+                        found = True
+                        break
+                if not found:
+                    continue
                 copies[name] = copysource
             except TypeError:
                 pass
@@ -309,7 +316,7 @@
 
     def getcommit(self, rev):
         ctx = self.changectx(rev)
-        parents = [hex(p) for p in self.parents(ctx)]
+        parents = [p.hex() for p in self.parents(ctx)]
         if self.saverev:
             crev = rev
         else:
@@ -332,7 +339,7 @@
             changes = [], ctx.manifest().keys(), []
         else:
             i = i or 0
-            changes = self.repo.status(parents[i], ctx.node())[:3]
+            changes = self.repo.status(parents[i].node(), ctx.node())[:3]
         changes = [[f for f in l if f not in self.ignored] for l in changes]
 
         if i == 0:
@@ -348,10 +355,10 @@
         self.convertfp.flush()
 
     def before(self):
-        self.ui.debug(_('run hg source pre-conversion action\n'))
+        self.ui.debug('run hg source pre-conversion action\n')
 
     def after(self):
-        self.ui.debug(_('run hg source post-conversion action\n'))
+        self.ui.debug('run hg source post-conversion action\n')
 
     def hasnativeorder(self):
         return True
--- a/hgext/convert/subversion.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/convert/subversion.py	Thu Oct 08 01:16:32 2009 -0500
@@ -22,6 +22,7 @@
 from common import commandline, converter_source, converter_sink, mapfile
 
 try:
+    raise ImportError("SVN support disabled due to license incompatibility")
     from svn.core import SubversionException, Pool
     import svn
     import svn.client
@@ -152,11 +153,13 @@
 def issvnurl(url):
     try:
         proto, path = url.split('://', 1)
-        path = urllib.url2pathname(path)
+        if proto == 'file':
+            path = urllib.url2pathname(path)
     except ValueError:
         proto = 'file'
         path = os.path.abspath(url)
-    path = path.replace(os.sep, '/')
+    if proto == 'file':
+        path = path.replace(os.sep, '/')
     check = protomap.get(proto, lambda p, p2: False)
     while '/' in path:
         if check(path, proto):
@@ -531,7 +534,7 @@
         """
         if not path.startswith(self.rootmodule):
             # Requests on foreign branches may be forbidden at server level
-            self.ui.debug(_('ignoring foreign branch %r\n') % path)
+            self.ui.debug('ignoring foreign branch %r\n' % path)
             return None
 
         if not stop:
@@ -559,7 +562,7 @@
                     if not path.startswith(p) or not paths[p].copyfrom_path:
                         continue
                     newpath = paths[p].copyfrom_path + path[len(p):]
-                    self.ui.debug(_("branch renamed from %s to %s at %d\n") %
+                    self.ui.debug("branch renamed from %s to %s at %d\n" %
                                   (path, newpath, revnum))
                     path = newpath
                     break
@@ -567,7 +570,7 @@
             stream.close()
 
         if not path.startswith(self.rootmodule):
-            self.ui.debug(_('ignoring foreign branch %r\n') % path)
+            self.ui.debug('ignoring foreign branch %r\n' % path)
             return None
         return self.revid(dirent.created_rev, path)
 
@@ -579,7 +582,7 @@
         prevmodule = self.prevmodule
         if prevmodule is None:
             prevmodule = ''
-        self.ui.debug(_("reparent to %s\n") % svnurl)
+        self.ui.debug("reparent to %s\n" % svnurl)
         svn.ra.reparent(self.ra, svnurl)
         self.prevmodule = module
         return prevmodule
@@ -612,14 +615,14 @@
                 copyfrom_path = self.getrelpath(ent.copyfrom_path, pmodule)
                 if not copyfrom_path:
                     continue
-                self.ui.debug(_("copied to %s from %s@%s\n") %
+                self.ui.debug("copied to %s from %s@%s\n" %
                               (entrypath, copyfrom_path, ent.copyfrom_rev))
                 copies[self.recode(entrypath)] = self.recode(copyfrom_path)
             elif kind == 0: # gone, but had better be a deleted *file*
-                self.ui.debug(_("gone from %s\n") % ent.copyfrom_rev)
+                self.ui.debug("gone from %s\n" % ent.copyfrom_rev)
                 pmodule, prevnum = self.revsplit(parents[0])[1:]
                 parentpath = pmodule + "/" + entrypath
-                self.ui.debug(_("entry %s\n") % parentpath)
+                self.ui.debug("entry %s\n" % parentpath)
 
                 # We can avoid the reparent calls if the module has
                 # not changed but it probably does not worth the pain.
@@ -646,7 +649,7 @@
                             del copies[childpath]
                         entries.append(childpath)
                 else:
-                    self.ui.debug(_('unknown path in revision %d: %s\n') % \
+                    self.ui.debug('unknown path in revision %d: %s\n' % \
                                   (revnum, path))
             elif kind == svn.core.svn_node_dir:
                 # If the directory just had a prop change,
@@ -679,7 +682,7 @@
                 if not copyfrompath:
                     continue
                 copyfrom[path] = ent
-                self.ui.debug(_("mark %s came from %s:%d\n")
+                self.ui.debug("mark %s came from %s:%d\n"
                               % (path, copyfrompath, ent.copyfrom_rev))
                 children = self._find_children(ent.copyfrom_path, ent.copyfrom_rev)
                 children.sort()
@@ -703,7 +706,7 @@
             """Return the parsed commit object or None, and True if
             the revision is a branch root.
             """
-            self.ui.debug(_("parsing revision %d (%d changes)\n") %
+            self.ui.debug("parsing revision %d (%d changes)\n" %
                           (revnum, len(orig_paths)))
 
             branched = False
@@ -732,7 +735,7 @@
                             self.ui.note(_('found parent of branch %s at %d: %s\n') %
                                          (self.module, prevnum, prevmodule))
                 else:
-                    self.ui.debug(_("no copyfrom path, don't know what to do.\n"))
+                    self.ui.debug("no copyfrom path, don't know what to do.\n")
 
             paths = []
             # filter out unrelated paths
@@ -785,7 +788,7 @@
                         lastonbranch = True
                         break
                     if not paths:
-                        self.ui.debug(_('revision %d has no entries\n') % revnum)
+                        self.ui.debug('revision %d has no entries\n' % revnum)
                         continue
                     cset, lastonbranch = parselogentry(paths, revnum, author,
                                                        date, message)
@@ -867,7 +870,7 @@
                 return relative
 
         # The path is outside our tracked tree...
-        self.ui.debug(_('%r is not under %r, ignoring\n') % (path, module))
+        self.ui.debug('%r is not under %r, ignoring\n' % (path, module))
         return None
 
     def _checkpath(self, path, revnum):
--- a/hgext/extdiff.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/extdiff.py	Thu Oct 08 01:16:32 2009 -0500
@@ -42,9 +42,9 @@
 '''
 
 from mercurial.i18n import _
-from mercurial.node import short
+from mercurial.node import short, nullid
 from mercurial import cmdutil, util, commands
-import os, shlex, shutil, tempfile
+import os, shlex, shutil, tempfile, re
 
 def snapshot(ui, repo, files, node, tmproot):
     '''snapshot files as of some revision
@@ -69,7 +69,7 @@
     for fn in files:
         wfn = util.pconvert(fn)
         if not wfn in ctx:
-            # skipping new file after a merge ?
+            # File doesn't exist; could be a bogus modify
             continue
         ui.note('  %s\n' % wfn)
         dest = os.path.join(base, wfn)
@@ -96,59 +96,102 @@
 
     revs = opts.get('rev')
     change = opts.get('change')
+    args = ' '.join(diffopts)
+    do3way = '$parent2' in args
 
     if revs and change:
         msg = _('cannot specify --rev and --change at the same time')
         raise util.Abort(msg)
     elif change:
         node2 = repo.lookup(change)
-        node1 = repo[node2].parents()[0].node()
+        node1a, node1b = repo.changelog.parents(node2)
     else:
-        node1, node2 = cmdutil.revpair(repo, revs)
+        node1a, node2 = cmdutil.revpair(repo, revs)
+        if not revs:
+            node1b = repo.dirstate.parents()[1]
+        else:
+            node1b = nullid
+
+    # Disable 3-way merge if there is only one parent
+    if do3way:
+        if node1b == nullid:
+            do3way = False
 
     matcher = cmdutil.match(repo, pats, opts)
-    modified, added, removed = repo.status(node1, node2, matcher)[:3]
-    if not (modified or added or removed):
-        return 0
+    mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3])
+    if do3way:
+        mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[:3])
+    else:
+        mod_b, add_b, rem_b = set(), set(), set()
+    modadd = mod_a | add_a | mod_b | add_b
+    common = modadd | rem_a | rem_b
+    if not common:
+       return 0
 
     tmproot = tempfile.mkdtemp(prefix='extdiff.')
-    dir2root = ''
     try:
-        # Always make a copy of node1
-        dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0]
-        changes = len(modified) + len(removed) + len(added)
+        # Always make a copy of node1a (and node1b, if applicable)
+        dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
+        dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot)[0]
+        if do3way:
+            dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
+            dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot)[0]
+        else:
+            dir1b = None
+
+        fns_and_mtime = []
 
         # If node2 in not the wc or there is >1 change, copy it
-        if node2 or changes > 1:
-            dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot)
+        dir2root = ''
+        if node2:
+            dir2 = snapshot(ui, repo, modadd, node2, tmproot)[0]
+        elif len(common) > 1:
+            #we only actually need to get the files to copy back to the working
+            #dir in this case (because the other cases are: diffing 2 revisions
+            #or single file -- in which case the file is already directly passed
+            #to the diff tool).
+            dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot)
         else:
             # This lets the diff tool open the changed file directly
             dir2 = ''
             dir2root = repo.root
-            fns_and_mtime = []
 
         # If only one change, diff the files instead of the directories
-        if changes == 1 :
-            if len(modified):
-                dir1 = os.path.join(dir1, util.localpath(modified[0]))
-                dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0]))
-            elif len(removed) :
-                dir1 = os.path.join(dir1, util.localpath(removed[0]))
-                dir2 = os.devnull
-            else:
-                dir1 = os.devnull
-                dir2 = os.path.join(dir2root, dir2, util.localpath(added[0]))
+        # Handle bogus modifies correctly by checking if the files exist
+        if len(common) == 1:
+            common_file = util.localpath(common.pop())
+            dir1a = os.path.join(dir1a, common_file)
+            if not os.path.isfile(os.path.join(tmproot, dir1a)):
+                dir1a = os.devnull
+            if do3way:
+                dir1b = os.path.join(dir1b, common_file)
+                if not os.path.isfile(os.path.join(tmproot, dir1b)):
+                    dir1b = os.devnull
+            dir2 = os.path.join(dir2root, dir2, common_file)
 
-        cmdline = ('%s %s %s %s' %
-                   (util.shellquote(diffcmd), ' '.join(diffopts),
-                    util.shellquote(dir1), util.shellquote(dir2)))
-        ui.debug(_('running %r in %s\n') % (cmdline, tmproot))
+        # Function to quote file/dir names in the argument string
+        # When not operating in 3-way mode, an empty string is returned for parent2
+        replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b, child=dir2)
+        def quote(match):
+            key = match.group()[1:]
+            if not do3way and key == 'parent2':
+                return ''
+            return util.shellquote(replace[key])
+
+        # Match parent2 first, so 'parent1?' will match both parent1 and parent
+        regex = '\$(parent2|parent1?|child)'
+        if not do3way and not re.search(regex, args):
+            args += ' $parent1 $child'
+        args = re.sub(regex, quote, args)
+        cmdline = util.shellquote(diffcmd) + ' ' + args
+
+        ui.debug('running %r in %s\n' % (cmdline, tmproot))
         util.system(cmdline, cwd=tmproot)
 
         for copy_fn, working_fn, mtime in fns_and_mtime:
             if os.path.getmtime(copy_fn) != mtime:
-                ui.debug(_('file changed while diffing. '
-                         'Overwriting: %s (src: %s)\n') % (working_fn, copy_fn))
+                ui.debug('file changed while diffing. '
+                         'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
                 util.copyfile(copy_fn, working_fn)
 
         return 1
@@ -173,11 +216,11 @@
     that revision is compared to the working directory, and, when no
     revisions are specified, the working directory files are compared
     to its parent.'''
-    program = opts['program'] or 'diff'
-    if opts['program']:
-        option = opts['option']
-    else:
-        option = opts['option'] or ['-Npru']
+    program = opts.get('program')
+    option = opts.get('option')
+    if not program:
+        program = 'diff'
+        option = option or ['-Npru']
     return dodiff(ui, repo, program, option, pats, opts)
 
 cmdtable = {
--- a/hgext/hgcia.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/hgcia.py	Thu Oct 08 01:16:32 2009 -0500
@@ -229,10 +229,10 @@
     n = bin(node)
     cia = hgcia(ui, repo)
     if not cia.user:
-        ui.debug(_('cia: no user specified'))
+        ui.debug('cia: no user specified')
         return
     if not cia.project:
-        ui.debug(_('cia: no project specified'))
+        ui.debug('cia: no project specified')
         return
     if hooktype == 'changegroup':
         start = repo.changelog.rev(n)
--- a/hgext/hgk.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/hgk.py	Thu Oct 08 01:16:32 2009 -0500
@@ -308,7 +308,7 @@
     os.chdir(repo.root)
     optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
     cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
-    ui.debug(_("running %s\n") % cmd)
+    ui.debug("running %s\n" % cmd)
     util.system(cmd)
 
 cmdtable = {
--- a/hgext/inotify/__init__.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/inotify/__init__.py	Thu Oct 08 01:16:32 2009 -0500
@@ -17,28 +17,7 @@
 
 def serve(ui, repo, **opts):
     '''start an inotify server for this repository'''
-    timeout = opts.get('timeout')
-    if timeout:
-        timeout = float(timeout) * 1e3
-
-    class service(object):
-        def init(self):
-            try:
-                self.master = server.master(ui, repo.dirstate,
-                                            repo.root, timeout)
-            except server.AlreadyStartedException, inst:
-                raise util.Abort(str(inst))
-
-        def run(self):
-            try:
-                self.master.run()
-            finally:
-                self.master.shutdown()
-
-    service = service()
-    logfile = ui.config('inotify', 'log')
-    cmdutil.service(opts, initfn=service.init, runfn=service.run,
-                    logfile=logfile)
+    server.start(ui, repo.dirstate, repo.root, opts)
 
 def debuginotify(ui, repo, **opts):
     '''debugging information for inotify extension
--- a/hgext/inotify/client.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/inotify/client.py	Thu Oct 08 01:16:32 2009 -0500
@@ -31,10 +31,11 @@
                                'removing it)\n'))
                 os.unlink(os.path.join(self.root, '.hg', 'inotify.sock'))
             if err[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart:
-                self.ui.debug(_('(starting inotify server)\n'))
+                self.ui.debug('(starting inotify server)\n')
                 try:
                     try:
-                        server.start(self.ui, self.dirstate, self.root)
+                        server.start(self.ui, self.dirstate, self.root,
+                                     dict(daemon=True, daemon_pipefds=''))
                     except server.AlreadyStartedException, inst:
                         # another process may have started its own
                         # inotify server while this one was starting.
@@ -50,7 +51,7 @@
                                        'server: %s\n') % err[-1])
             elif err[0] in (errno.ECONNREFUSED, errno.ENOENT):
                 # silently ignore normal errors if autostart is False
-                self.ui.debug(_('(inotify server not running)\n'))
+                self.ui.debug('(inotify server not running)\n')
             else:
                 self.ui.warn(_('failed to contact inotify server: %s\n')
                          % err[-1])
--- a/hgext/inotify/server.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/inotify/server.py	Thu Oct 08 01:16:32 2009 -0500
@@ -7,7 +7,7 @@
 # GNU General Public License version 2, incorporated herein by reference.
 
 from mercurial.i18n import _
-from mercurial import osutil, util
+from mercurial import cmdutil, osutil, util
 import common
 import errno, os, select, socket, stat, struct, sys, tempfile, time
 
@@ -823,52 +823,29 @@
             sys.exit(0)
         pollable.run()
 
-def start(ui, dirstate, root):
-    def closefds(ignore):
-        # (from python bug #1177468)
-        # close all inherited file descriptors
-        # Python 2.4.1 and later use /dev/urandom to seed the random module's RNG
-        # a file descriptor is kept internally as os._urandomfd (created on demand
-        # the first time os.urandom() is called), and should not be closed
-        try:
-            os.urandom(4)
-            urandom_fd = getattr(os, '_urandomfd', None)
-        except AttributeError:
-            urandom_fd = None
-        ignore.append(urandom_fd)
-        for fd in range(3, 256):
-            if fd in ignore:
-                continue
+def start(ui, dirstate, root, opts):
+    timeout = opts.get('timeout')
+    if timeout:
+        timeout = float(timeout) * 1e3
+
+    class service(object):
+        def init(self):
             try:
-                os.close(fd)
-            except OSError:
-                pass
-
-    m = master(ui, dirstate, root)
-    sys.stdout.flush()
-    sys.stderr.flush()
+                self.master = master(ui, dirstate, root, timeout)
+            except AlreadyStartedException, inst:
+                raise util.Abort(str(inst))
 
-    pid = os.fork()
-    if pid:
-        return pid
-
-    closefds(pollable.instances.keys())
-    os.setsid()
-
-    fd = os.open('/dev/null', os.O_RDONLY)
-    os.dup2(fd, 0)
-    if fd > 0:
-        os.close(fd)
+        def run(self):
+            try:
+                self.master.run()
+            finally:
+                self.master.shutdown()
 
-    fd = os.open(ui.config('inotify', 'log', '/dev/null'),
-                 os.O_RDWR | os.O_CREAT | os.O_TRUNC)
-    os.dup2(fd, 1)
-    os.dup2(fd, 2)
-    if fd > 2:
-        os.close(fd)
+    runargs = None
+    if 'inserve' not in sys.argv:
+        runargs = [sys.argv[0], 'inserve', '-R', root]
 
-    try:
-        m.run()
-    finally:
-        m.shutdown()
-        os._exit(0)
+    service = service()
+    logfile = ui.config('inotify', 'log')
+    cmdutil.service(opts, initfn=service.init, runfn=service.run,
+                    logfile=logfile, runargs=runargs)
--- a/hgext/keyword.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/keyword.py	Thu Oct 08 01:16:32 2009 -0500
@@ -244,12 +244,14 @@
             return t2 != text
         return revlog.revlog.cmp(self, node, text)
 
-def _status(ui, repo, kwt, unknown, *pats, **opts):
+def _status(ui, repo, kwt, *pats, **opts):
     '''Bails out if [keyword] configuration is not active.
     Returns status of working directory.'''
     if kwt:
-        match = cmdutil.match(repo, pats, opts)
-        return repo.status(match=match, unknown=unknown, clean=True)
+        unknown = (opts.get('unknown') or opts.get('all')
+                   or opts.get('untracked'))
+        return repo.status(match=cmdutil.match(repo, pats, opts), clean=True,
+                           unknown=unknown)
     if ui.configitems('keyword'):
         raise util.Abort(_('[keyword] patterns cannot match'))
     raise util.Abort(_('no [keyword] patterns configured'))
@@ -259,7 +261,7 @@
     if repo.dirstate.parents()[1] != nullid:
         raise util.Abort(_('outstanding uncommitted merge'))
     kwt = kwtools['templater']
-    status = _status(ui, repo, kwt, False, *pats, **opts)
+    status = _status(ui, repo, kwt, *pats, **opts)
     modified, added, removed, deleted = status[:4]
     if modified or added or removed or deleted:
         raise util.Abort(_('outstanding uncommitted changes'))
@@ -354,7 +356,7 @@
     repo.commit(text=msg)
     ui.status(_('\n\tkeywords expanded\n'))
     ui.write(repo.wread(fn))
-    ui.debug(_('\nremoving temporary repository %s\n') % tmpdir)
+    ui.debug('\nremoving temporary repository %s\n' % tmpdir)
     shutil.rmtree(tmpdir, ignore_errors=True)
 
 def expand(ui, repo, *pats, **opts):
@@ -380,30 +382,32 @@
     See "hg help keyword" on how to construct patterns both for
     inclusion and exclusion of files.
 
-    Use -u/--untracked to list untracked files as well.
-
-    With -a/--all and -v/--verbose the codes used to show the status
+    With -A/--all and -v/--verbose the codes used to show the status
     of files are::
 
       K = keyword expansion candidate
-      k = keyword expansion candidate (untracked)
+      k = keyword expansion candidate (not tracked)
       I = ignored
-      i = ignored (untracked)
+      i = ignored (not tracked)
     '''
     kwt = kwtools['templater']
-    status = _status(ui, repo, kwt, opts.get('untracked'), *pats, **opts)
+    status = _status(ui, repo, kwt, *pats, **opts)
+    cwd = pats and repo.getcwd() or ''
     modified, added, removed, deleted, unknown, ignored, clean = status
-    files = sorted(modified + added + clean)
+    files = []
+    if not (opts.get('unknown') or opts.get('untracked')) or opts.get('all'):
+        files = sorted(modified + added + clean)
     wctx = repo[None]
     kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
-    kwuntracked = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
-    cwd = pats and repo.getcwd() or ''
-    kwfstats = (not opts.get('ignore') and
-                (('K', kwfiles), ('k', kwuntracked),) or ())
+    kwunknown = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
+    if not opts.get('ignore') or opts.get('all'):
+        showfiles = kwfiles, kwunknown
+    else:
+        showfiles = [], []
     if opts.get('all') or opts.get('ignore'):
-        kwfstats += (('I', [f for f in files if f not in kwfiles]),
-                     ('i', [f for f in unknown if f not in kwuntracked]),)
-    for char, filenames in kwfstats:
+        showfiles += ([f for f in files if f not in kwfiles],
+                      [f for f in unknown if f not in kwunknown])
+    for char, filenames in zip('KkIi', showfiles):
         fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
         for f in filenames:
             ui.write(fmt % repo.pathto(f, cwd))
@@ -545,9 +549,12 @@
                  _('hg kwexpand [OPTION]... [FILE]...')),
     'kwfiles':
         (files,
-         [('a', 'all', None, _('show keyword status flags of all files')),
+         [('A', 'all', None, _('show keyword status flags of all files')),
           ('i', 'ignore', None, _('show files excluded from expansion')),
-          ('u', 'untracked', None, _('additionally show untracked files')),
+          ('u', 'unknown', None, _('only show unknown (not tracked) files')),
+          ('a', 'all', None,
+           _('show keyword status flags of all files (DEPRECATED)')),
+          ('u', 'untracked', None, _('only show untracked files (DEPRECATED)')),
          ] + commands.walkopts,
          _('hg kwfiles [OPTION]... [FILE]...')),
     'kwshrink': (shrink, commands.walkopts,
--- a/hgext/mq.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/mq.py	Thu Oct 08 01:16:32 2009 -0500
@@ -321,7 +321,7 @@
             if bad:
                 raise util.Abort(bad)
         guards = sorted(set(guards))
-        self.ui.debug(_('active guards: %s\n') % ' '.join(guards))
+        self.ui.debug('active guards: %s\n' % ' '.join(guards))
         self.active_guards = guards
         self.guards_dirty = True
 
--- a/hgext/notify.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/notify.py	Thu Oct 08 01:16:32 2009 -0500
@@ -43,6 +43,7 @@
   diffstat = True        # add a diffstat before the diff content
   sources = serve        # notify if source of incoming changes in this list
                          # (serve == ssh or http, push, pull, bundle)
+  merge = False          # send notification for merges (default True)
   [email]
   from = user@host.com   # email address to send as if none given
   [web]
@@ -111,6 +112,7 @@
         self.test = self.ui.configbool('notify', 'test', True)
         self.charsets = mail._charsets(self.ui)
         self.subs = self.subscribers()
+        self.merge = self.ui.configbool('notify', 'merge', True)
 
         mapfile = self.ui.config('notify', 'style')
         template = (self.ui.config('notify', hooktype) or
@@ -165,11 +167,14 @@
     def url(self, path=None):
         return self.ui.config('web', 'baseurl') + (path or self.root)
 
-    def node(self, ctx):
-        '''format one changeset.'''
+    def node(self, ctx, **props):
+        '''format one changeset, unless it is a suppressed merge.'''
+        if not self.merge and len(ctx.parents()) > 1:
+            return False
         self.t.show(ctx, changes=ctx.changeset(),
                     baseurl=self.ui.config('web', 'baseurl'),
-                    root=self.repo.root, webroot=self.root)
+                    root=self.repo.root, webroot=self.root, **props)
+        return True
 
     def skipsource(self, source):
         '''true if incoming changes from this source should be skipped.'''
@@ -276,23 +281,36 @@
     ctx = repo[node]
 
     if not n.subs:
-        ui.debug(_('notify: no subscribers to repository %s\n') % n.root)
+        ui.debug('notify: no subscribers to repository %s\n' % n.root)
         return
     if n.skipsource(source):
-        ui.debug(_('notify: changes have source "%s" - skipping\n') % source)
+        ui.debug('notify: changes have source "%s" - skipping\n' % source)
         return
 
     ui.pushbuffer()
+    data = ''
+    count = 0
     if hooktype == 'changegroup':
         start, end = ctx.rev(), len(repo)
-        count = end - start
         for rev in xrange(start, end):
-            n.node(repo[rev])
-        n.diff(ctx, repo['tip'])
+            if n.node(repo[rev]):
+                count += 1
+            else:
+                data += ui.popbuffer()
+                ui.note(_('notify: suppressing notification for merge %d:%s\n') %
+                        (rev, repo[rev].hex()[:12]))
+                ui.pushbuffer()
+        if count:
+            n.diff(ctx, repo['tip'])
     else:
-        count = 1
-        n.node(ctx)
+        if not n.node(ctx):
+            ui.popbuffer()
+            ui.note(_('notify: suppressing notification for merge %d:%s\n') %
+                    (ctx.rev(), ctx.hex()[:12]))
+            return
+        count += 1
         n.diff(ctx)
 
-    data = ui.popbuffer()
-    n.send(ctx, count, data)
+    data += ui.popbuffer()
+    if count:
+        n.send(ctx, count, data)
--- a/hgext/rebase.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/rebase.py	Thu Oct 08 01:16:32 2009 -0500
@@ -35,7 +35,7 @@
     if not first:
         ancestor.ancestor = newancestor
     else:
-        repo.ui.debug(_("first revision, do not change ancestor\n"))
+        repo.ui.debug("first revision, do not change ancestor\n")
     stats = merge.update(repo, rev, True, True, False)
     return stats
 
@@ -149,7 +149,7 @@
     """Skip commit if collapsing has been required and rev is not the last
     revision, commit otherwise
     """
-    repo.ui.debug(_(" set parents\n"))
+    repo.ui.debug(" set parents\n")
     if collapse and not last:
         repo.dirstate.setparents(repo[p1].node())
         return None
@@ -187,23 +187,23 @@
 def rebasenode(repo, rev, target, state, skipped, targetancestors, collapse,
                extrafn):
     'Rebase a single revision'
-    repo.ui.debug(_("rebasing %d:%s\n") % (rev, repo[rev]))
+    repo.ui.debug("rebasing %d:%s\n" % (rev, repo[rev]))
 
     p1, p2 = defineparents(repo, rev, target, state, targetancestors)
 
-    repo.ui.debug(_(" future parents are %d and %d\n") % (repo[p1].rev(),
+    repo.ui.debug(" future parents are %d and %d\n" % (repo[p1].rev(),
                                                             repo[p2].rev()))
 
     # Merge phase
     if len(repo.parents()) != 2:
         # Update to target and merge it with local
         if repo['.'].rev() != repo[p1].rev():
-            repo.ui.debug(_(" update to %d:%s\n") % (repo[p1].rev(), repo[p1]))
+            repo.ui.debug(" update to %d:%s\n" % (repo[p1].rev(), repo[p1]))
             merge.update(repo, p1, False, True, False)
         else:
-            repo.ui.debug(_(" already in target\n"))
+            repo.ui.debug(" already in target\n")
         repo.dirstate.write()
-        repo.ui.debug(_(" merge against %d:%s\n") % (repo[rev].rev(), repo[rev]))
+        repo.ui.debug(" merge against %d:%s\n" % (repo[rev].rev(), repo[rev]))
         first = repo[rev].rev() == repo[min(state)].rev()
         stats = rebasemerge(repo, rev, first)
 
@@ -211,7 +211,7 @@
             raise util.Abort(_('fix unresolved conflicts with hg resolve then '
                                                 'run hg rebase --continue'))
     else: # we have an interrupted rebase
-        repo.ui.debug(_('resuming interrupted rebase\n'))
+        repo.ui.debug('resuming interrupted rebase\n')
 
     # Keep track of renamed files in the revision that is going to be rebased
     # Here we simulate the copies and renames in the source changeset
@@ -234,7 +234,7 @@
     else:
         if not collapse:
             repo.ui.note(_('no changes, revision %d skipped\n') % rev)
-            repo.ui.debug(_('next revision set to %s\n') % p1)
+            repo.ui.debug('next revision set to %s\n' % p1)
             skipped.add(rev)
         state[rev] = p1
 
@@ -280,7 +280,7 @@
     mqrebase = {}
     for p in repo.mq.applied:
         if repo[p.rev].rev() in state:
-            repo.ui.debug(_('revision %d is an mq patch (%s), finalize it.\n') %
+            repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
                                         (repo[p.rev].rev(), p.name))
             mqrebase[repo[p.rev].rev()] = (p.name, isagitpatch(repo, p.name))
 
@@ -290,7 +290,7 @@
         # We must start import from the newest revision
         for rev in sorted(mqrebase, reverse=True):
             if rev not in skipped:
-                repo.ui.debug(_('import mq patch %d (%s)\n')
+                repo.ui.debug('import mq patch %d (%s)\n'
                               % (state[rev], mqrebase[rev][0]))
                 repo.mq.qimport(repo, (), patchname=mqrebase[rev][0],
                             git=mqrebase[rev][1],rev=[str(state[rev])])
@@ -311,7 +311,7 @@
         newrev = repo[v].hex()
         f.write("%s:%s\n" % (oldrev, newrev))
     f.close()
-    repo.ui.debug(_('rebase status stored\n'))
+    repo.ui.debug('rebase status stored\n')
 
 def clearstatus(repo):
     'Remove the status files'
@@ -342,7 +342,7 @@
             else:
                 oldrev, newrev = l.split(':')
                 state[repo[oldrev].rev()] = repo[newrev].rev()
-        repo.ui.debug(_('rebase status resumed\n'))
+        repo.ui.debug('rebase status resumed\n')
         return originalwd, target, state, collapse, keep, keepbranches, external
     except IOError, err:
         if err.errno != errno.ENOENT:
@@ -392,12 +392,12 @@
             cwd = repo['.'].rev()
 
         if cwd == dest:
-            repo.ui.debug(_('already working on current\n'))
+            repo.ui.debug('already working on current\n')
             return None
 
         targetancestors = set(repo.changelog.ancestors(dest))
         if cwd in targetancestors:
-            repo.ui.debug(_('already working on the current branch\n'))
+            repo.ui.debug('already working on the current branch\n')
             return None
 
         cwdancestors = set(repo.changelog.ancestors(cwd))
@@ -405,7 +405,7 @@
         rebasingbranch = cwdancestors - targetancestors
         source = min(rebasingbranch)
 
-    repo.ui.debug(_('rebase onto %d starting from %d\n') % (dest, source))
+    repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source))
     state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
     external = nullrev
     if collapse:
@@ -429,8 +429,8 @@
     if opts.get('rebase'):
         if opts.get('update'):
             del opts['update']
-            ui.debug(_('--update and --rebase are not compatible, ignoring '
-                                        'the update flag\n'))
+            ui.debug('--update and --rebase are not compatible, ignoring '
+                     'the update flag\n')
 
         cmdutil.bail_if_changed(repo)
         revsprepull = len(repo)
--- a/hgext/record.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/record.py	Thu Oct 08 01:16:32 2009 -0500
@@ -463,7 +463,7 @@
                 fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
                                                dir=backupdir)
                 os.close(fd)
-                ui.debug(_('backup %r as %r\n') % (f, tmpname))
+                ui.debug('backup %r as %r\n' % (f, tmpname))
                 util.copyfile(repo.wjoin(f), tmpname)
                 backups[f] = tmpname
 
@@ -481,7 +481,7 @@
             # 3b. (apply)
             if dopatch:
                 try:
-                    ui.debug(_('applying patch\n'))
+                    ui.debug('applying patch\n')
                     ui.debug(fp.getvalue())
                     pfiles = {}
                     patch.internalpatch(fp, ui, 1, repo.root, files=pfiles,
@@ -512,7 +512,7 @@
             # 5. finally restore backed-up files
             try:
                 for realname, tmpname in backups.iteritems():
-                    ui.debug(_('restoring %r to %r\n') % (tmpname, realname))
+                    ui.debug('restoring %r to %r\n' % (tmpname, realname))
                     util.copyfile(tmpname, repo.wjoin(realname))
                     os.unlink(tmpname)
                 os.rmdir(backupdir)
--- a/hgext/win32mbcs.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/win32mbcs.py	Thu Oct 08 01:16:32 2009 -0500
@@ -142,6 +142,6 @@
         for f in funcs.split():
             wrapname(f, wrapper)
         wrapname("mercurial.osutil.listdir", wrapperforlistdir)
-        ui.debug(_("[win32mbcs] activated with encoding: %s\n")
+        ui.debug("[win32mbcs] activated with encoding: %s\n"
                  % encoding.encoding)
 
--- a/hgext/zeroconf/__init__.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/hgext/zeroconf/__init__.py	Thu Oct 08 01:16:32 2009 -0500
@@ -109,12 +109,13 @@
     def __init__(self, conf, baseui=None):
         super(hgwebdirzc, self).__init__(conf, baseui)
         prefix = self.ui.config("web", "prefix", "").strip('/') + '/'
-        for r, p in self.repos:
+        for repo, path in self.repos:
             u = self.ui.copy()
-            u.readconfig(os.path.join(p, '.hg', 'hgrc'))
-            n = os.path.basename(r)
-            path = (prefix + r).strip('/')
-            publish(n, "hgweb", path, int(u.config("web", "port", 8000)))
+            u.readconfig(os.path.join(path, '.hg', 'hgrc'))
+            name = os.path.basename(repo)
+            path = (prefix + repo).strip('/')
+            desc = u.config('web', 'description', name)
+            publish(name, desc, path, int(u.config("web", "port", 8000)))
 
 # listen
 
@@ -136,25 +137,24 @@
     Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l)
     time.sleep(1)
     server.close()
-    for v in l.found.values():
-        n = v.name[:v.name.index('.')]
-        n.replace(" ", "-")
-        u = "http://%s:%s%s" % (socket.inet_ntoa(v.address), v.port,
-                                 v.properties.get("path", "/"))
-        yield "zc-" + n, u
+    for value in l.found.values():
+        name = value.name[:value.name.index('.')]
+        url = "http://%s:%s%s" % (socket.inet_ntoa(value.address), value.port,
+                                  value.properties.get("path", "/"))
+        yield "zc-" + name, url
 
 def config(orig, self, section, key, default=None, untrusted=False):
     if section == "paths" and key.startswith("zc-"):
-        for n, p in getzcpaths():
-            if n == key:
-                return p
+        for name, path in getzcpaths():
+            if name == key:
+                return path
     return orig(self, section, key, default, untrusted)
 
 def configitems(orig, self, section, untrusted=False):
-    r = orig(self, section, untrusted)
+    repos = orig(self, section, untrusted)
     if section == "paths":
-        r += getzcpaths()
-    return r
+        repos += getzcpaths()
+    return repos
 
 extensions.wrapfunction(ui.ui, 'config', config)
 extensions.wrapfunction(ui.ui, 'configitems', configitems)
--- a/i18n/hggettext	Tue Oct 06 11:18:58 2009 +0300
+++ b/i18n/hggettext	Thu Oct 08 01:16:32 2009 -0500
@@ -112,6 +112,11 @@
             print poentry(path, lineno, func.__doc__)
 
 
+def rawtext(path):
+    src = open(path).read()
+    print poentry(path, 1, src)
+
+
 if __name__ == "__main__":
     # It is very important that we import the Mercurial modules from
     # the source tree where hggettext is executed. Otherwise we might
@@ -120,4 +125,7 @@
     sys.path.insert(0, os.getcwd())
     from mercurial import demandimport; demandimport.enable()
     for path in sys.argv[1:]:
-        docstrings(path)
+        if path.endswith('.txt'):
+            rawtext(path)
+        else:
+            docstrings(path)
--- a/mercurial/bdiff.c	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/bdiff.c	Thu Oct 08 01:16:32 2009 -0500
@@ -151,7 +151,7 @@
 	}
 
 	/* compute popularity threshold */
-	t = (bn >= 4000) ? bn / 1000 : bn + 1;
+	t = (bn >= 31000) ? bn / 1000 : 1000000 / (bn + 1);
 
 	/* match items in a to their equivalence class in b */
 	for (i = 0; i < an; i++) {
--- a/mercurial/cmdutil.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/cmdutil.py	Thu Oct 08 01:16:32 2009 -0500
@@ -546,24 +546,26 @@
 
     return errors
 
-def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None):
+def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
+    runargs=None):
     '''Run a command as a service.'''
 
     if opts['daemon'] and not opts['daemon_pipefds']:
         rfd, wfd = os.pipe()
-        args = sys.argv[:]
-        args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
+        if not runargs:
+            runargs = sys.argv[:]
+        runargs.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
         # Don't pass --cwd to the child process, because we've already
         # changed directory.
-        for i in xrange(1,len(args)):
-            if args[i].startswith('--cwd='):
-                del args[i]
+        for i in xrange(1,len(runargs)):
+            if runargs[i].startswith('--cwd='):
+                del runargs[i]
                 break
-            elif args[i].startswith('--cwd'):
-                del args[i:i+2]
+            elif runargs[i].startswith('--cwd'):
+                del runargs[i:i+2]
                 break
         pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
-                         args[0], args)
+                         runargs[0], runargs)
         os.close(wfd)
         os.read(rfd, 1)
         if parentfn:
@@ -650,9 +652,8 @@
             return
 
         log = self.repo.changelog
-        changes = log.read(changenode)
-        date = util.datestr(changes[2])
-        extra = changes[5]
+        date = util.datestr(ctx.date())
+        extra = ctx.extra()
         branch = extra.get("branch")
 
         hexfunc = self.ui.debugflag and hex or short
@@ -672,9 +673,10 @@
             self.ui.write(_("parent:      %d:%s\n") % parent)
 
         if self.ui.debugflag:
+            mnode = ctx.manifestnode()
             self.ui.write(_("manifest:    %d:%s\n") %
-                          (self.repo.manifest.rev(changes[0]), hex(changes[0])))
-        self.ui.write(_("user:        %s\n") % changes[1])
+                          (self.repo.manifest.rev(mnode), hex(mnode)))
+        self.ui.write(_("user:        %s\n") % ctx.user())
         self.ui.write(_("date:        %s\n") % date)
 
         if self.ui.debugflag:
@@ -683,8 +685,8 @@
                                   files):
                 if value:
                     self.ui.write("%-12s %s\n" % (key, " ".join(value)))
-        elif changes[3] and self.ui.verbose:
-            self.ui.write(_("files:       %s\n") % " ".join(changes[3]))
+        elif ctx.files() and self.ui.verbose:
+            self.ui.write(_("files:       %s\n") % " ".join(ctx.files()))
         if copies and self.ui.verbose:
             copies = ['%s (%s)' % c for c in copies]
             self.ui.write(_("copies:      %s\n") % ' '.join(copies))
@@ -694,7 +696,7 @@
                 self.ui.write(_("extra:       %s=%s\n")
                               % (key, value.encode('string_escape')))
 
-        description = changes[4].strip()
+        description = ctx.description().strip()
         if description:
             if self.ui.verbose:
                 self.ui.write(_("description:\n"))
@@ -743,6 +745,9 @@
                                          'parent': '{rev}:{node|formatnode} ',
                                          'manifest': '{rev}:{node|formatnode}',
                                          'filecopy': '{name} ({source})'})
+        # Cache mapping from rev to a tuple with tag date, tag
+        # distance and tag name
+        self._latesttagcache = {-1: (0, 0, 'null')}
 
     def use_template(self, t):
         '''set template string to use'''
@@ -760,6 +765,30 @@
             return []
         return parents
 
+    def _latesttaginfo(self, rev):
+        '''return date, distance and name for the latest tag of rev'''
+        todo = [rev]
+        while todo:
+            rev = todo.pop()
+            if rev in self._latesttagcache:
+                continue
+            ctx = self.repo[rev]
+            tags = [t for t in ctx.tags() if self.repo.tagtype(t) == 'global']
+            if tags:
+                self._latesttagcache[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
+                continue
+            try:
+                # The tuples are laid out so the right one can be found by comparison.
+                pdate, pdist, ptag = max(
+                    self._latesttagcache[p.rev()] for p in ctx.parents())
+            except KeyError:
+                # Cache miss - recurse
+                todo.append(rev)
+                todo.extend(p.rev() for p in ctx.parents())
+                continue
+            self._latesttagcache[rev] = pdate, pdist + 1, ptag
+        return self._latesttagcache[rev]
+
     def _show(self, ctx, copies, props):
         '''show a single changeset or file revision'''
 
@@ -877,6 +906,11 @@
                 removes += i[2]
             return '%s: +%s/-%s' % (files, adds, removes)
 
+        def showlatesttag(**args):
+            return self._latesttaginfo(ctx.rev())[2]
+        def showlatesttagdistance(**args):
+            return self._latesttaginfo(ctx.rev())[1]
+
         defprops = {
             'author': ctx.user(),
             'branches': showbranches,
@@ -894,6 +928,8 @@
             'tags': showtags,
             'extras': showextras,
             'diffstat': showdiffstat,
+            'latesttag': showlatesttag,
+            'latesttagdistance': showlatesttagdistance,
             }
         props = props.copy()
         props.update(defprops)
--- a/mercurial/commands.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/commands.py	Thu Oct 08 01:16:32 2009 -0500
@@ -1548,7 +1548,7 @@
             doc = doc()
 
         ui.write("%s\n\n" % header)
-        ui.write("%s\n" % minirst.format(doc, textwidth))
+        ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
 
     def helpext(name):
         try:
@@ -1619,9 +1619,7 @@
         ui.write(_("\nadditional help topics:\n\n"))
         topics = []
         for names, header, doc in help.helptable:
-            names = [(-len(name), name) for name in names]
-            names.sort()
-            topics.append((names[0][1], header))
+            topics.append((sorted(names, key=len, reverse=True)[0], header))
         topics_len = max([len(s[0]) for s in topics])
         for t, desc in topics:
             ui.write(" %-*s  %s\n" % (topics_len, t, desc))
@@ -1791,7 +1789,7 @@
                 else:
                     # launch the editor
                     message = None
-                ui.debug(_('message:\n%s\n') % message)
+                ui.debug('message:\n%s\n' % message)
 
                 wp = repo.parents()
                 if opts.get('exact'):
@@ -3095,7 +3093,7 @@
 
 globalopts = [
     ('R', 'repository', '',
-     _('repository root directory or symbolic path name')),
+     _('repository root directory or name of overlay bundle file')),
     ('', 'cwd', '', _('change working directory')),
     ('y', 'noninteractive', None,
      _('do not prompt, assume \'yes\' for any required answers')),
--- a/mercurial/context.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/context.py	Thu Oct 08 01:16:32 2009 -0500
@@ -299,6 +299,7 @@
     def files(self): return self._changectx.files()
     def description(self): return self._changectx.description()
     def branch(self): return self._changectx.branch()
+    def extra(self): return self._changectx.extra()
     def manifest(self): return self._changectx.manifest()
     def changectx(self): return self._changectx
 
--- a/mercurial/copies.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/copies.py	Thu Oct 08 01:16:32 2009 -0500
@@ -144,16 +144,16 @@
             elif of in ma:
                 diverge.setdefault(of, []).append(f)
 
-    repo.ui.debug(_("  searching for copies back to rev %d\n") % limit)
+    repo.ui.debug("  searching for copies back to rev %d\n" % limit)
 
     u1 = _nonoverlap(m1, m2, ma)
     u2 = _nonoverlap(m2, m1, ma)
 
     if u1:
-        repo.ui.debug(_("  unmatched files in local:\n   %s\n")
+        repo.ui.debug("  unmatched files in local:\n   %s\n"
                       % "\n   ".join(u1))
     if u2:
-        repo.ui.debug(_("  unmatched files in other:\n   %s\n")
+        repo.ui.debug("  unmatched files in other:\n   %s\n"
                       % "\n   ".join(u2))
 
     for f in u1:
@@ -169,7 +169,7 @@
             diverge2.update(fl) # reverse map for below
 
     if fullcopy:
-        repo.ui.debug(_("  all copies found (* = to merge, ! = divergent):\n"))
+        repo.ui.debug("  all copies found (* = to merge, ! = divergent):\n")
         for f in fullcopy:
             note = ""
             if f in copy: note += "*"
@@ -180,7 +180,7 @@
     if not fullcopy or not checkdirs:
         return copy, diverge
 
-    repo.ui.debug(_("  checking for directory renames\n"))
+    repo.ui.debug("  checking for directory renames\n")
 
     # generate a directory move map
     d1, d2 = _dirs(m1), _dirs(m2)
@@ -216,7 +216,7 @@
         return copy, diverge
 
     for d in dirmove:
-        repo.ui.debug(_("  dir %s -> %s\n") % (d, dirmove[d]))
+        repo.ui.debug("  dir %s -> %s\n" % (d, dirmove[d]))
 
     # check unaccounted nonoverlapping files against directory moves
     for f in u1 + u2:
@@ -227,7 +227,7 @@
                     df = dirmove[d] + f[len(d):]
                     if df not in copy:
                         copy[f] = df
-                        repo.ui.debug(_("  file %s -> %s\n") % (f, copy[f]))
+                        repo.ui.debug("  file %s -> %s\n" % (f, copy[f]))
                     break
 
     return copy, diverge
--- a/mercurial/demandimport.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/demandimport.py	Thu Oct 08 01:16:32 2009 -0500
@@ -127,6 +127,8 @@
     # imported by profile, itself imported by hotshot.stats,
     # not available under Windows
     'resource',
+    # this trips up many extension authors
+    'gtk',
     ]
 
 def enable():
--- a/mercurial/dirstate.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/dirstate.py	Thu Oct 08 01:16:32 2009 -0500
@@ -38,6 +38,9 @@
 class dirstate(object):
 
     def __init__(self, opener, ui, root):
+        '''Create a new dirstate object.  opener is an open()-like callable
+        that can be used to open the dirstate file; root is the root of the
+        directory tracked by the dirstate.'''
         self._opener = opener
         self._root = root
         self._rootdir = os.path.join(root, '')
@@ -47,6 +50,8 @@
 
     @propertycache
     def _map(self):
+        '''Return the dirstate contents as a map from filename to
+        (state, mode, size, time).'''
         self._read()
         return self._map
 
@@ -169,12 +174,14 @@
         return path
 
     def __getitem__(self, key):
-        ''' current states:
-        n  normal
-        m  needs merging
-        r  marked for removal
-        a  marked for addition
-        ?  not tracked'''
+        '''Return the current state of key (a filename) in the dirstate.
+        States are:
+          n  normal
+          m  needs merging
+          r  marked for removal
+          a  marked for addition
+          ?  not tracked
+        '''
         return self._map.get(key, ("?",))[0]
 
     def __contains__(self, key):
@@ -373,13 +380,9 @@
             return
         st = self._opener("dirstate", "w", atomictemp=True)
 
-        try:
-            gran = int(self._ui.config('dirstate', 'granularity', 1))
-        except ValueError:
-            gran = 1
-        if gran > 0:
-            hlimit = util.fstat(st).st_mtime
-            llimit = hlimit - gran
+        # use the modification time of the newly created temporary file as the
+        # filesystem's notion of 'now'
+        now = int(util.fstat(st).st_mtime)
 
         cs = cStringIO.StringIO()
         copymap = self._copymap
@@ -389,9 +392,19 @@
         for f, e in self._map.iteritems():
             if f in copymap:
                 f = "%s\0%s" % (f, copymap[f])
-            if gran > 0 and e[0] == 'n' and llimit < e[3] <= hlimit:
-                # file was updated too recently, ignore stat data
-                e = (e[0], 0, -1, -1)
+
+            if e[0] == 'n' and e[3] == now:
+                # The file was last modified "simultaneously" with the current
+                # write to dirstate (i.e. within the same second for file-
+                # systems with a granularity of 1 sec). This commonly happens
+                # for at least a couple of files on 'update'.
+                # The user could change the file without changing its size
+                # within the same second. Invalidate the file's stat data in
+                # dirstate, forcing future 'status' calls to compare the
+                # contents of the file. This prevents mistakenly treating such
+                # files as clean.
+                e = (e[0], 0, -1, -1)   # mark entry as 'unset'
+
             e = pack(_format, e[0], e[1], e[2], e[3], len(f))
             write(e)
             write(f)
@@ -411,11 +424,11 @@
 
     def walk(self, match, unknown, ignored):
         '''
-        walk recursively through the directory tree, finding all files
-        matched by the match function
+        Walk recursively through the directory tree, finding all files
+        matched by match.
 
-        results are yielded in a tuple (filename, stat), where stat
-        and st is the stat result if the file was found in the directory.
+        Return a dict mapping filename to stat-like object (either
+        mercurial.osutil.stat instance or return value of os.stat()).
         '''
 
         def fwarn(f, msg):
@@ -553,12 +566,38 @@
         return results
 
     def status(self, match, ignored, clean, unknown):
+        '''Determine the status of the working copy relative to the
+        dirstate and return a tuple of lists (unsure, modified, added,
+        removed, deleted, unknown, ignored, clean), where:
+
+          unsure:
+            files that might have been modified since the dirstate was
+            written, but need to be read to be sure (size is the same
+            but mtime differs)
+          modified:
+            files that have definitely been modified since the dirstate
+            was written (different size or mode)
+          added:
+            files that have been explicitly added with hg add
+          removed:
+            files that have been explicitly removed with hg remove
+          deleted:
+            files that have been deleted through other means ("missing")
+          unknown:
+            files not in the dirstate that are not ignored
+          ignored:
+            files not in the dirstate that are ignored
+            (by _dirignore())
+          clean:
+            files that have definitely not been modified since the
+            dirstate was written
+        '''
         listignored, listclean, listunknown = ignored, clean, unknown
         lookup, modified, added, unknown, ignored = [], [], [], [], []
         removed, deleted, clean = [], [], []
 
         dmap = self._map
-        ladd = lookup.append
+        ladd = lookup.append            # aka "unsure"
         madd = modified.append
         aadd = added.append
         uadd = unknown.append
--- a/mercurial/dispatch.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/dispatch.py	Thu Oct 08 01:16:32 2009 -0500
@@ -217,7 +217,7 @@
 
     def __call__(self, ui, *args, **opts):
         if self.shadows:
-            ui.debug(_("alias '%s' shadows command\n") % self.name)
+            ui.debug("alias '%s' shadows command\n" % self.name)
 
         return self.fn(ui, *args, **opts)
 
--- a/mercurial/filemerge.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/filemerge.py	Thu Oct 08 01:16:32 2009 -0500
@@ -140,7 +140,7 @@
     binary = isbin(fcd) or isbin(fco) or isbin(fca)
     symlink = 'l' in fcd.flags() + fco.flags()
     tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
-    ui.debug(_("picked tool '%s' for %s (binary %s symlink %s)\n") %
+    ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
                (tool, fd, binary, symlink))
 
     if not tool or tool == 'internal:prompt':
@@ -170,13 +170,13 @@
     else:
         ui.status(_("merging %s\n") % fd)
 
-    ui.debug(_("my %s other %s ancestor %s\n") % (fcd, fco, fca))
+    ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
 
     # do we attempt to simplemerge first?
     if _toolbool(ui, tool, "premerge", not (binary or symlink)):
         r = simplemerge.simplemerge(ui, a, b, c, quiet=True)
         if not r:
-            ui.debug(_(" premerge successful\n"))
+            ui.debug(" premerge successful\n")
             os.unlink(back)
             os.unlink(b)
             os.unlink(c)
--- a/mercurial/help.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/help.py	Thu Oct 08 01:16:32 2009 -0500
@@ -5,7 +5,8 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2, incorporated herein by reference.
 
-from i18n import _
+from i18n import gettext, _
+import sys, os
 import extensions, util
 
 
@@ -49,41 +50,7 @@
     return result
 
 def extshelp():
-    doc = _(r'''
-    Mercurial has the ability to add new features through the use of
-    extensions. Extensions may add new commands, add options to
-    existing commands, change the default behavior of commands, or
-    implement hooks.
-
-    Extensions are not loaded by default for a variety of reasons:
-    they can increase startup overhead; they may be meant for advanced
-    usage only; they may provide potentially dangerous abilities (such
-    as letting you destroy or modify history); they might not be ready
-    for prime time; or they may alter some usual behaviors of stock
-    Mercurial. It is thus up to the user to activate extensions as
-    needed.
-
-    To enable the "foo" extension, either shipped with Mercurial or in
-    the Python search path, create an entry for it in your hgrc, like
-    this::
-
-      [extensions]
-      foo =
-
-    You may also specify the full path to an extension::
-
-      [extensions]
-      myfeature = ~/.hgext/myfeature.py
-
-    To explicitly disable an extension enabled in an hgrc of broader
-    scope, prepend its path with !::
-
-      [extensions]
-      # disabling extension bar residing in /path/to/extension/bar.py
-      hgext.bar = !/path/to/extension/bar.py
-      # ditto, but no path was supplied for extension baz
-      hgext.baz = !
-    ''')
+    doc = loaddoc('extensions')()
 
     exts, maxlength = extensions.enabled()
     doc += listexts(_('enabled extensions:'), exts, maxlength)
@@ -93,441 +60,33 @@
 
     return doc
 
-helptable = (
-    (["dates"], _("Date Formats"),
-     _(r'''
-    Some commands allow the user to specify a date, e.g.:
-
-    - backout, commit, import, tag: Specify the commit date.
-    - log, revert, update: Select revision(s) by date.
-
-    Many date formats are valid. Here are some examples::
-
-      "Wed Dec 6 13:18:29 2006" (local timezone assumed)
-      "Dec 6 13:18 -0600" (year assumed, time offset provided)
-      "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
-      "Dec 6" (midnight)
-      "13:18" (today assumed)
-      "3:39" (3:39AM assumed)
-      "3:39pm" (15:39)
-      "2006-12-06 13:18:29" (ISO 8601 format)
-      "2006-12-6 13:18"
-      "2006-12-6"
-      "12-6"
-      "12/6"
-      "12/6/6" (Dec 6 2006)
-
-    Lastly, there is Mercurial's internal format::
-
-      "1165432709 0" (Wed Dec 6 13:18:29 2006 UTC)
-
-    This is the internal representation format for dates. unixtime is
-    the number of seconds since the epoch (1970-01-01 00:00 UTC).
-    offset is the offset of the local timezone, in seconds west of UTC
-    (negative if the timezone is east of UTC).
-
-    The log command also accepts date ranges::
-
-      "<{datetime}" - at or before a given date/time
-      ">{datetime}" - on or after a given date/time
-      "{datetime} to {datetime}" - a date range, inclusive
-      "-{days}" - within a given number of days of today
-    ''')),
-
-    (["patterns"], _("File Name Patterns"),
-     _(r'''
-    Mercurial accepts several notations for identifying one or more
-    files at a time.
-
-    By default, Mercurial treats filenames as shell-style extended
-    glob patterns.
-
-    Alternate pattern notations must be specified explicitly.
-
-    To use a plain path name without any pattern matching, start it
-    with "path:". These path names must completely match starting at
-    the current repository root.
-
-    To use an extended glob, start a name with "glob:". Globs are
-    rooted at the current directory; a glob such as "``*.c``" will
-    only match files in the current directory ending with ".c".
-
-    The supported glob syntax extensions are "``**``" to match any
-    string across path separators and "{a,b}" to mean "a or b".
-
-    To use a Perl/Python regular expression, start a name with "re:".
-    Regexp pattern matching is anchored at the root of the repository.
-
-    Plain examples::
-
-      path:foo/bar   a name bar in a directory named foo in the root
-                     of the repository
-      path:path:name a file or directory named "path:name"
-
-    Glob examples::
-
-      glob:*.c       any name ending in ".c" in the current directory
-      *.c            any name ending in ".c" in the current directory
-      **.c           any name ending in ".c" in any subdirectory of the
-                     current directory including itself.
-      foo/*.c        any name ending in ".c" in the directory foo
-      foo/**.c       any name ending in ".c" in any subdirectory of foo
-                     including itself.
-
-    Regexp examples::
-
-      re:.*\.c$      any name ending in ".c", anywhere in the repository
-
-    ''')),
-
-    (['environment', 'env'], _('Environment Variables'),
-     _(r'''
-HG
-    Path to the 'hg' executable, automatically passed when running
-    hooks, extensions or external tools. If unset or empty, this is
-    the hg executable's name if it's frozen, or an executable named
-    'hg' (with %PATHEXT% [defaulting to COM/EXE/BAT/CMD] extensions on
-    Windows) is searched.
-
-HGEDITOR
-    This is the name of the editor to run when committing. See EDITOR.
-
-    (deprecated, use .hgrc)
-
-HGENCODING
-    This overrides the default locale setting detected by Mercurial.
-    This setting is used to convert data including usernames,
-    changeset descriptions, tag names, and branches. This setting can
-    be overridden with the --encoding command-line option.
+def loaddoc(topic):
+    """Return a delayed loader for help/topic.txt."""
 
-HGENCODINGMODE
-    This sets Mercurial's behavior for handling unknown characters
-    while transcoding user input. The default is "strict", which
-    causes Mercurial to abort if it can't map a character. Other
-    settings include "replace", which replaces unknown characters, and
-    "ignore", which drops them. This setting can be overridden with
-    the --encodingmode command-line option.
-
-HGMERGE
-    An executable to use for resolving merge conflicts. The program
-    will be executed with three arguments: local file, remote file,
-    ancestor file.
-
-    (deprecated, use .hgrc)
-
-HGRCPATH
-    A list of files or directories to search for hgrc files. Item
-    separator is ":" on Unix, ";" on Windows. If HGRCPATH is not set,
-    platform default search path is used. If empty, only the .hg/hgrc
-    from the current repository is read.
-
-    For each element in HGRCPATH:
-
-    - if it's a directory, all files ending with .rc are added
-    - otherwise, the file itself will be added
-
-HGUSER
-    This is the string used as the author of a commit. If not set,
-    available values will be considered in this order:
-
-    - HGUSER (deprecated)
-    - hgrc files from the HGRCPATH
-    - EMAIL
-    - interactive prompt
-    - LOGNAME (with '@hostname' appended)
-
-    (deprecated, use .hgrc)
-
-EMAIL
-    May be used as the author of a commit; see HGUSER.
-
-LOGNAME
-    May be used as the author of a commit; see HGUSER.
-
-VISUAL
-    This is the name of the editor to use when committing. See EDITOR.
-
-EDITOR
-    Sometimes Mercurial needs to open a text file in an editor for a
-    user to modify, for example when writing commit messages. The
-    editor it uses is determined by looking at the environment
-    variables HGEDITOR, VISUAL and EDITOR, in that order. The first
-    non-empty one is chosen. If all of them are empty, the editor
-    defaults to 'vi'.
-
-PYTHONPATH
-    This is used by Python to find imported modules and may need to be
-    set appropriately if this Mercurial is not installed system-wide.
-    ''')),
-
-    (['revs', 'revisions'], _('Specifying Single Revisions'),
-     _(r'''
-    Mercurial supports several ways to specify individual revisions.
-
-    A plain integer is treated as a revision number. Negative integers
-    are treated as sequential offsets from the tip, with -1 denoting
-    the tip, -2 denoting the revision prior to the tip, and so forth.
-
-    A 40-digit hexadecimal string is treated as a unique revision
-    identifier.
-
-    A hexadecimal string less than 40 characters long is treated as a
-    unique revision identifier and is referred to as a short-form
-    identifier. A short-form identifier is only valid if it is the
-    prefix of exactly one full-length identifier.
-
-    Any other string is treated as a tag or branch name. A tag name is
-    a symbolic name associated with a revision identifier. A branch
-    name denotes the tipmost revision of that branch. Tag and branch
-    names must not contain the ":" character.
-
-    The reserved name "tip" is a special tag that always identifies
-    the most recent revision.
-
-    The reserved name "null" indicates the null revision. This is the
-    revision of an empty repository, and the parent of revision 0.
-
-    The reserved name "." indicates the working directory parent. If
-    no working directory is checked out, it is equivalent to null. If
-    an uncommitted merge is in progress, "." is the revision of the
-    first parent.
-    ''')),
-
-    (['mrevs', 'multirevs'], _('Specifying Multiple Revisions'),
-     _(r'''
-    When Mercurial accepts more than one revision, they may be
-    specified individually, or provided as a topologically continuous
-    range, separated by the ":" character.
-
-    The syntax of range notation is [BEGIN]:[END], where BEGIN and END
-    are revision identifiers. Both BEGIN and END are optional. If
-    BEGIN is not specified, it defaults to revision number 0. If END
-    is not specified, it defaults to the tip. The range ":" thus means
-    "all revisions".
-
-    If BEGIN is greater than END, revisions are treated in reverse
-    order.
+    def loader():
+        if hasattr(sys, 'frozen'):
+            module = sys.executable
+        else:
+            module = __file__
+        base = os.path.dirname(module)
 
-    A range acts as a closed interval. This means that a range of 3:5
-    gives 3, 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
-    ''')),
-
-    (['diffs'], _('Diff Formats'),
-     _(r'''
-    Mercurial's default format for showing changes between two
-    versions of a file is compatible with the unified format of GNU
-    diff, which can be used by GNU patch and many other standard
-    tools.
-
-    While this standard format is often enough, it does not encode the
-    following information:
-
-    - executable status and other permission bits
-    - copy or rename information
-    - changes in binary files
-    - creation or deletion of empty files
-
-    Mercurial also supports the extended diff format from the git VCS
-    which addresses these limitations. The git diff format is not
-    produced by default because a few widespread tools still do not
-    understand this format.
-
-    This means that when generating diffs from a Mercurial repository
-    (e.g. with "hg export"), you should be careful about things like
-    file copies and renames or other things mentioned above, because
-    when applying a standard diff to a different repository, this
-    extra information is lost. Mercurial's internal operations (like
-    push and pull) are not affected by this, because they use an
-    internal binary format for communicating changes.
-
-    To make Mercurial produce the git extended diff format, use the
-    --git option available for many commands, or set 'git = True' in
-    the [diff] section of your hgrc. You do not need to set this
-    option when importing diffs in this format or using them in the mq
-    extension.
-    ''')),
-    (['templating', 'templates'], _('Template Usage'),
-     _(r'''
-    Mercurial allows you to customize output of commands through
-    templates. You can either pass in a template from the command
-    line, via the --template option, or select an existing
-    template-style (--style).
-
-    You can customize output for any "log-like" command: log,
-    outgoing, incoming, tip, parents, heads and glog.
+        for dir in ('.', '..'):
+            docdir = os.path.join(base, dir, 'help')
+            if os.path.isdir(docdir):
+                break
 
-    Three styles are packaged with Mercurial: default (the style used
-    when no explicit preference is passed), compact and changelog.
-    Usage::
-
-        $ hg log -r1 --style changelog
-
-    A template is a piece of text, with markup to invoke variable
-    expansion::
-
-        $ hg log -r1 --template "{node}\n"
-        b56ce7b07c52de7d5fd79fb89701ea538af65746
-
-    Strings in curly braces are called keywords. The availability of
-    keywords depends on the exact context of the templater. These
-    keywords are usually available for templating a log-like command:
-
-    :author:    String. The unmodified author of the changeset.
-    :branches:  String. The name of the branch on which the changeset
-                was committed. Will be empty if the branch name was
-                default.
-    :date:      Date information. The date when the changeset was
-                committed.
-    :desc:      String. The text of the changeset description.
-    :diffstat:  String. Statistics of changes with the following
-                format: "modified files: +added/-removed lines"
-    :files:     List of strings. All files modified, added, or removed
-                by this changeset.
-    :file_adds: List of strings. Files added by this changeset.
-    :file_mods: List of strings. Files modified by this changeset.
-    :file_dels: List of strings. Files removed by this changeset.
-    :node:      String. The changeset identification hash, as a
-                40-character hexadecimal string.
-    :parents:   List of strings. The parents of the changeset.
-    :rev:       Integer. The repository-local changeset revision
-                number.
-    :tags:      List of strings. Any tags associated with the
-                changeset.
-
-    The "date" keyword does not produce human-readable output. If you
-    want to use a date in your output, you can use a filter to process
-    it. Filters are functions which return a string based on the input
-    variable. You can also use a chain of filters to get the desired
-    output::
-
-       $ hg tip --template "{date|isodate}\n"
-       2008-08-21 18:22 +0000
-
-    List of filters:
+        path = os.path.join(docdir, topic + ".txt")
+        return gettext(open(path).read())
+    return loader
 
-    :addbreaks:   Any text. Add an XHTML "<br />" tag before the end of
-                  every line except the last.
-    :age:         Date. Returns a human-readable date/time difference
-                  between the given date/time and the current
-                  date/time.
-    :basename:    Any text. Treats the text as a path, and returns the
-                  last component of the path after splitting by the
-                  path separator (ignoring trailing separators). For
-                  example, "foo/bar/baz" becomes "baz" and "foo/bar//"
-                  becomes "bar".
-    :stripdir:    Treat the text as path and strip a directory level,
-                  if possible. For example, "foo" and "foo/bar" becomes
-                  "foo".
-    :date:        Date. Returns a date in a Unix date format, including
-                  the timezone: "Mon Sep 04 15:13:13 2006 0700".
-    :domain:      Any text. Finds the first string that looks like an
-                  email address, and extracts just the domain
-                  component. Example: 'User <user@example.com>' becomes
-                  'example.com'.
-    :email:       Any text. Extracts the first string that looks like
-                  an email address. Example: 'User <user@example.com>'
-                  becomes 'user@example.com'.
-    :escape:      Any text. Replaces the special XML/XHTML characters
-                  "&", "<" and ">" with XML entities.
-    :fill68:      Any text. Wraps the text to fit in 68 columns.
-    :fill76:      Any text. Wraps the text to fit in 76 columns.
-    :firstline:   Any text. Returns the first line of text.
-    :nonempty:    Any text. Returns '(none)' if the string is empty.
-    :hgdate:      Date. Returns the date as a pair of numbers:
-                  "1157407993 25200" (Unix timestamp, timezone offset).
-    :isodate:     Date. Returns the date in ISO 8601 format:
-                  "2009-08-18 13:00 +0200".
-    :isodatesec:  Date. Returns the date in ISO 8601 format, including
-                  seconds: "2009-08-18 13:00:13 +0200". See also the
-                  rfc3339date filter.
-    :localdate:   Date. Converts a date to local date.
-    :obfuscate:   Any text. Returns the input text rendered as a
-                  sequence of XML entities.
-    :person:      Any text. Returns the text before an email address.
-    :rfc822date:  Date. Returns a date using the same format used in
-                  email headers: "Tue, 18 Aug 2009 13:00:13 +0200".
-    :rfc3339date: Date. Returns a date using the Internet date format
-                  specified in RFC 3339: "2009-08-18T13:00:13+02:00".
-    :short:       Changeset hash. Returns the short form of a changeset
-                  hash, i.e. a 12-byte hexadecimal string.
-    :shortdate:   Date. Returns a date like "2006-09-18".
-    :strip:       Any text. Strips all leading and trailing whitespace.
-    :tabindent:   Any text. Returns the text, with every line except
-                  the first starting with a tab character.
-    :urlescape:   Any text. Escapes all "special" characters. For
-                  example, "foo bar" becomes "foo%20bar".
-    :user:        Any text. Returns the user portion of an email
-                  address.
-    ''')),
-
-    (['urls'], _('URL Paths'),
-     _(r'''
-    Valid URLs are of the form::
-
-      local/filesystem/path[#revision]
-      file://local/filesystem/path[#revision]
-      http://[user[:pass]@]host[:port]/[path][#revision]
-      https://[user[:pass]@]host[:port]/[path][#revision]
-      ssh://[user[:pass]@]host[:port]/[path][#revision]
-
-    Paths in the local filesystem can either point to Mercurial
-    repositories or to bundle files (as created by 'hg bundle' or 'hg
-    incoming --bundle').
-
-    An optional identifier after # indicates a particular branch, tag,
-    or changeset to use from the remote repository. See also 'hg help
-    revisions'.
-
-    Some features, such as pushing to http:// and https:// URLs are
-    only possible if the feature is explicitly enabled on the remote
-    Mercurial server.
-
-    Some notes about using SSH with Mercurial:
-
-    - SSH requires an accessible shell account on the destination
-      machine and a copy of hg in the remote path or specified with as
-      remotecmd.
-    - path is relative to the remote user's home directory by default.
-      Use an extra slash at the start of a path to specify an absolute
-      path::
-
-        ssh://example.com//tmp/repository
-
-    - Mercurial doesn't use its own compression via SSH; the right
-      thing to do is to configure it in your ~/.ssh/config, e.g.::
-
-        Host *.mylocalnetwork.example.com
-          Compression no
-        Host *
-          Compression yes
-
-      Alternatively specify "ssh -C" as your ssh command in your hgrc
-      or with the --ssh command line option.
-
-    These URLs can all be stored in your hgrc with path aliases under
-    the [paths] section like so::
-
-      [paths]
-      alias1 = URL1
-      alias2 = URL2
-      ...
-
-    You can then use the alias for any command that uses a URL (for
-    example 'hg pull alias1' would pull from the 'alias1' path).
-
-    Two path aliases are special because they are used as defaults
-    when you do not provide the URL to a command:
-
-    default:
-      When you create a repository with hg clone, the clone command
-      saves the location of the source repository as the new
-      repository's 'default' path. This is then used when you omit
-      path from push- and pull-like commands (including incoming and
-      outgoing).
-
-    default-push:
-      The push command will look for a path named 'default-push', and
-      prefer it over 'default' if both are defined.
-    ''')),
+helptable = (
+    (["dates"], _("Date Formats"), loaddoc('dates')),
+    (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
+    (['environment', 'env'], _('Environment Variables'), loaddoc('environment')),
+    (['revs', 'revisions'], _('Specifying Single Revisions'), loaddoc('revisions')),
+    (['mrevs', 'multirevs'], _('Specifying Multiple Revisions'), loaddoc('multirevs')),
+    (['diffs'], _('Diff Formats'), loaddoc('diffs')),
+    (['templating', 'templates'], _('Template Usage'), loaddoc('templates')),
+    (['urls'], _('URL Paths'), loaddoc('urls')),
     (["extensions"], _("Using additional features"), extshelp),
 )
--- a/mercurial/hg.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/hg.py	Thu Oct 08 01:16:32 2009 -0500
@@ -327,12 +327,8 @@
             dir_cleanup.cleanup()
 
 def _showstats(repo, stats):
-    stats = ((stats[0], _("updated")),
-             (stats[1], _("merged")),
-             (stats[2], _("removed")),
-             (stats[3], _("unresolved")))
-    note = ", ".join([_("%d files %s") % s for s in stats])
-    repo.ui.status("%s\n" % note)
+    repo.ui.status(_("%d files updated, %d files merged, "
+                     "%d files removed, %d files unresolved\n") % stats)
 
 def update(repo, node):
     """update the working directory to node, merging linear changes"""
@@ -357,7 +353,7 @@
     _showstats(repo, stats)
     if stats[3]:
         repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
-                         "or 'hg up --clean' to abandon\n"))
+                         "or 'hg update -C' to abandon\n"))
     elif remind:
         repo.ui.status(_("(branch merge, don't forget to commit)\n"))
     return stats[3] > 0
--- a/mercurial/httprepo.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/httprepo.py	Thu Oct 08 01:16:32 2009 -0500
@@ -35,7 +35,7 @@
         self._url, authinfo = url.getauthinfo(path)
 
         self.ui = ui
-        self.ui.debug(_('using %s\n') % self._url)
+        self.ui.debug('using %s\n' % self._url)
 
         self.urlopener = url.opener(ui, authinfo)
 
@@ -56,7 +56,7 @@
                 self.caps = set(self.do_read('capabilities').split())
             except error.RepoError:
                 self.caps = set()
-            self.ui.debug(_('capabilities: %s\n') %
+            self.ui.debug('capabilities: %s\n' %
                           (' '.join(self.caps or ['none'])))
         return self.caps
 
@@ -68,21 +68,21 @@
     def do_cmd(self, cmd, **args):
         data = args.pop('data', None)
         headers = args.pop('headers', {})
-        self.ui.debug(_("sending %s command\n") % cmd)
+        self.ui.debug("sending %s command\n" % cmd)
         q = {"cmd": cmd}
         q.update(args)
         qs = '?%s' % urllib.urlencode(q)
         cu = "%s%s" % (self._url, qs)
         try:
             if data:
-                self.ui.debug(_("sending %s bytes\n") % len(data))
+                self.ui.debug("sending %s bytes\n" % len(data))
             resp = self.urlopener.open(urllib2.Request(cu, data, headers))
         except urllib2.HTTPError, inst:
             if inst.code == 401:
                 raise util.Abort(_('authorization failed'))
             raise
         except httplib.HTTPException, inst:
-            self.ui.debug(_('http error while sending %s command\n') % cmd)
+            self.ui.debug('http error while sending %s command\n' % cmd)
             self.ui.traceback()
             raise IOError(None, inst)
         except IndexError:
@@ -105,7 +105,7 @@
         if not (proto.startswith('application/mercurial-') or
                 proto.startswith('text/plain') or
                 proto.startswith('application/hg-changegroup')):
-            self.ui.debug(_("requested URL: '%s'\n") % url.hidepassword(cu))
+            self.ui.debug("requested URL: '%s'\n" % url.hidepassword(cu))
             raise error.RepoError(_("'%s' does not appear to be an hg repository")
                                   % safeurl)
 
--- a/mercurial/i18n.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/i18n.py	Thu Oct 08 01:16:32 2009 -0500
@@ -16,7 +16,7 @@
 
 base = os.path.dirname(module)
 for dir in ('.', '..'):
-    localedir = os.path.normpath(os.path.join(base, dir, 'locale'))
+    localedir = os.path.join(base, dir, 'locale')
     if os.path.isdir(localedir):
         break
 
--- a/mercurial/localrepo.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/localrepo.py	Thu Oct 08 01:16:32 2009 -0500
@@ -527,7 +527,7 @@
 
         for mf, fn, cmd in self.filterpats[filter]:
             if mf(filename):
-                self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
+                self.ui.debug("filtering %s through %s\n" % (filename, cmd))
                 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
                 break
 
@@ -724,14 +724,14 @@
 
             # find source in nearest ancestor if we've lost track
             if not crev:
-                self.ui.debug(_(" %s: searching for copy revision for %s\n") %
+                self.ui.debug(" %s: searching for copy revision for %s\n" %
                               (fname, cfname))
                 for ancestor in self['.'].ancestors():
                     if cfname in ancestor:
                         crev = ancestor[cfname].filenode()
                         break
 
-            self.ui.debug(_(" %s: copy %s:%s\n") % (fname, cfname, hex(crev)))
+            self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
             meta["copy"] = cfname
             meta["copyrev"] = hex(crev)
             fparent1, fparent2 = nullid, newfparent
@@ -1294,22 +1294,22 @@
                 if n[0] in seen:
                     continue
 
-                self.ui.debug(_("examining %s:%s\n")
+                self.ui.debug("examining %s:%s\n"
                               % (short(n[0]), short(n[1])))
                 if n[0] == nullid: # found the end of the branch
                     pass
                 elif n in seenbranch:
-                    self.ui.debug(_("branch already found\n"))
+                    self.ui.debug("branch already found\n")
                     continue
                 elif n[1] and n[1] in m: # do we know the base?
-                    self.ui.debug(_("found incomplete branch %s:%s\n")
+                    self.ui.debug("found incomplete branch %s:%s\n"
                                   % (short(n[0]), short(n[1])))
                     search.append(n[0:2]) # schedule branch range for scanning
                     seenbranch.add(n)
                 else:
                     if n[1] not in seen and n[1] not in fetch:
                         if n[2] in m and n[3] in m:
-                            self.ui.debug(_("found new changeset %s\n") %
+                            self.ui.debug("found new changeset %s\n" %
                                           short(n[1]))
                             fetch.add(n[1]) # earliest unknown
                         for p in n[2:4]:
@@ -1324,11 +1324,11 @@
 
             if r:
                 reqcnt += 1
-                self.ui.debug(_("request %d: %s\n") %
+                self.ui.debug("request %d: %s\n" %
                             (reqcnt, " ".join(map(short, r))))
                 for p in xrange(0, len(r), 10):
                     for b in remote.branches(r[p:p+10]):
-                        self.ui.debug(_("received %s:%s\n") %
+                        self.ui.debug("received %s:%s\n" %
                                       (short(b[0]), short(b[1])))
                         unknown.append(b)
 
@@ -1341,15 +1341,15 @@
                 p = n[0]
                 f = 1
                 for i in l:
-                    self.ui.debug(_("narrowing %d:%d %s\n") % (f, len(l), short(i)))
+                    self.ui.debug("narrowing %d:%d %s\n" % (f, len(l), short(i)))
                     if i in m:
                         if f <= 2:
-                            self.ui.debug(_("found new branch changeset %s\n") %
+                            self.ui.debug("found new branch changeset %s\n" %
                                               short(p))
                             fetch.add(p)
                             base[i] = 1
                         else:
-                            self.ui.debug(_("narrowed branch search to %s:%s\n")
+                            self.ui.debug("narrowed branch search to %s:%s\n"
                                           % (short(p), short(i)))
                             newsearch.append((p, i))
                         break
@@ -1368,10 +1368,10 @@
             else:
                 raise util.Abort(_("repository is unrelated"))
 
-        self.ui.debug(_("found new changesets starting at ") +
+        self.ui.debug("found new changesets starting at " +
                      " ".join([short(f) for f in fetch]) + "\n")
 
-        self.ui.debug(_("%d total queries\n") % reqcnt)
+        self.ui.debug("%d total queries\n" % reqcnt)
 
         return base.keys(), list(fetch), heads
 
@@ -1388,7 +1388,7 @@
             base = {}
             self.findincoming(remote, base, heads, force=force)
 
-        self.ui.debug(_("common changesets up to ")
+        self.ui.debug("common changesets up to "
                       + " ".join(map(short, base.keys())) + "\n")
 
         remain = set(self.changelog.nodemap)
@@ -1608,7 +1608,7 @@
         if self.ui.verbose or source == 'bundle':
             self.ui.status(_("%d changesets found\n") % len(nodes))
         if self.ui.debugflag:
-            self.ui.debug(_("list of changesets:\n"))
+            self.ui.debug("list of changesets:\n")
             for node in nodes:
                 self.ui.debug("%s\n" % hex(node))
 
@@ -1994,7 +1994,7 @@
         - number of heads stays the same: 1
         """
         def csmap(x):
-            self.ui.debug(_("add changeset %s\n") % short(x))
+            self.ui.debug("add changeset %s\n" % short(x))
             return len(cl)
 
         def revmap(x):
@@ -2040,7 +2040,7 @@
                 f = changegroup.getchunk(source)
                 if not f:
                     break
-                self.ui.debug(_("adding %s revisions\n") % f)
+                self.ui.debug("adding %s revisions\n" % f)
                 fl = self.file(f)
                 o = len(fl)
                 chunkiter = changegroup.chunkiter(source)
@@ -2073,7 +2073,7 @@
 
         if changesets > 0:
             # forcefully update the on-disk branch cache
-            self.ui.debug(_("updating the branch cache\n"))
+            self.ui.debug("updating the branch cache\n")
             self.branchtags()
             self.hook("changegroup", node=hex(cl.node(clstart)),
                       source=srctype, url=url)
@@ -2122,7 +2122,7 @@
             except (ValueError, TypeError):
                 raise error.ResponseError(
                     _('Unexpected response from remote server:'), l)
-            self.ui.debug(_('adding %s (%s)\n') % (name, util.bytecount(size)))
+            self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
             # for backwards compat, name was partially encoded
             ofp = self.sopener(store.decodedir(name), 'w')
             for chunk in util.filechunkiter(fp, limit=size):
--- a/mercurial/merge.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/merge.py	Thu Oct 08 01:16:32 2009 -0500
@@ -161,8 +161,8 @@
             act("divergent renames", "dr", of, fl)
 
     repo.ui.note(_("resolving manifests\n"))
-    repo.ui.debug(_(" overwrite %s partial %s\n") % (overwrite, bool(partial)))
-    repo.ui.debug(_(" ancestor %s local %s remote %s\n") % (pa, p1, p2))
+    repo.ui.debug(" overwrite %s partial %s\n" % (overwrite, bool(partial)))
+    repo.ui.debug(" ancestor %s local %s remote %s\n" % (pa, p1, p2))
 
     m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
     copied = set(copy.values())
@@ -252,7 +252,7 @@
             f2, fd, flags, move = a[2:]
             if f == '.hgsubstate': # merged internally
                 continue
-            repo.ui.debug(_("preserving %s for resolve of %s\n") % (f, fd))
+            repo.ui.debug("preserving %s for resolve of %s\n" % (f, fd))
             fcl = wctx[f]
             fco = mctx[f2]
             fca = fcl.ancestor(fco) or repo.filectx(f, fileid=nullrev)
@@ -263,7 +263,7 @@
     # remove renamed files after safely stored
     for f in moves:
         if util.lexists(repo.wjoin(f)):
-            repo.ui.debug(_("removing %s\n") % f)
+            repo.ui.debug("removing %s\n" % f)
             os.unlink(repo.wjoin(f))
 
     audit_path = util.path_auditor(repo.root)
@@ -299,7 +299,7 @@
                     merged += 1
             util.set_flags(repo.wjoin(fd), 'l' in flags, 'x' in flags)
             if f != fd and move and util.lexists(repo.wjoin(f)):
-                repo.ui.debug(_("removing %s\n") % f)
+                repo.ui.debug("removing %s\n" % f)
                 os.unlink(repo.wjoin(f))
         elif m == "g": # get
             flags = a[2]
--- a/mercurial/minirst.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/minirst.py	Thu Oct 08 01:16:32 2009 -0500
@@ -310,9 +310,11 @@
                              subsequent_indent=subindent)
 
 
-def format(text, width):
+def format(text, width, indent=0):
     """Parse and format the text according to width."""
     blocks = findblocks(text)
+    for b in blocks:
+        b['indent'] += indent
     blocks = findliteralblocks(blocks)
     blocks = findsections(blocks)
     blocks = findbulletlists(blocks)
--- a/mercurial/patch.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/patch.py	Thu Oct 08 01:16:32 2009 -0500
@@ -93,12 +93,12 @@
                 hgpatch = False
                 ignoretext = False
 
-                ui.debug(_('found patch at byte %d\n') % m.start(0))
+                ui.debug('found patch at byte %d\n' % m.start(0))
                 diffs_seen += 1
                 cfp = cStringIO.StringIO()
                 for line in payload[:m.start(0)].splitlines():
                     if line.startswith('# HG changeset patch'):
-                        ui.debug(_('patch generated by hg export\n'))
+                        ui.debug('patch generated by hg export\n')
                         hgpatch = True
                         # drop earlier commit message content
                         cfp.seek(0)
@@ -1155,7 +1155,7 @@
                 return internalpatch(patchname, ui, strip, cwd, files, eolmode)
             except NoHunks:
                 patcher = util.find_exe('gpatch') or util.find_exe('patch') or 'patch'
-                ui.debug(_('no valid hunks found; trying with %r instead\n') %
+                ui.debug('no valid hunks found; trying with %r instead\n' %
                          patcher)
                 if util.needbinarypatch():
                     args.append('--binary')
--- a/mercurial/posix.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/posix.py	Thu Oct 08 01:16:32 2009 -0500
@@ -13,6 +13,7 @@
 nulldev = '/dev/null'
 normpath = os.path.normpath
 samestat = os.path.samestat
+rename = os.rename
 expandglobs = False
 
 umask = os.umask(0)
@@ -165,17 +166,11 @@
         return inst.errno != errno.ESRCH
 
 def explain_exit(code):
-    """return a 2-tuple (desc, code) describing a process's status"""
-    if os.WIFEXITED(code):
-        val = os.WEXITSTATUS(code)
-        return _("exited with status %d") % val, val
-    elif os.WIFSIGNALED(code):
-        val = os.WTERMSIG(code)
-        return _("killed by signal %d") % val, val
-    elif os.WIFSTOPPED(code):
-        val = os.WSTOPSIG(code)
-        return _("stopped by signal %d") % val, val
-    raise ValueError(_("invalid exit code"))
+    """return a 2-tuple (desc, code) describing a subprocess status
+    (codes from kill are negative - not os.system/wait encoding)"""
+    if code >= 0:
+        return _("exited with status %d") % code, code
+    return _("killed by signal %d") % -code, -code
 
 def isowner(st):
     """Return True if the stat object st is from the current user."""
--- a/mercurial/sshrepo.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/sshrepo.py	Thu Oct 08 01:16:32 2009 -0500
@@ -75,7 +75,7 @@
             if lines[-1] == "1\n" and l == "\n":
                 break
             if l:
-                ui.debug(_("remote: "), l)
+                ui.debug("remote: ", l)
             lines.append(l)
             max_noise -= 1
         else:
@@ -113,7 +113,7 @@
     __del__ = cleanup
 
     def do_cmd(self, cmd, **args):
-        self.ui.debug(_("sending %s command\n") % cmd)
+        self.ui.debug("sending %s command\n" % cmd)
         self.pipeo.write("%s\n" % cmd)
         for k, v in args.iteritems():
             self.pipeo.write("%s %d\n" % (k, len(v)))
--- a/mercurial/streamclone.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/streamclone.py	Thu Oct 08 01:16:32 2009 -0500
@@ -46,10 +46,9 @@
         # get consistent snapshot of repo, lock during scan
         lock = repo.lock()
         try:
-            repo.ui.debug(_('scanning\n'))
+            repo.ui.debug('scanning\n')
             for name, ename, size in repo.store.walk():
-                # for backwards compat, name was partially encoded
-                entries.append((store.encodedir(name), size))
+                entries.append((name, size))
                 total_bytes += size
         finally:
             lock.release()
@@ -57,11 +56,12 @@
         raise StreamException(2)
 
     yield '0\n'
-    repo.ui.debug(_('%d files, %d bytes to transfer\n') %
+    repo.ui.debug('%d files, %d bytes to transfer\n' %
                   (len(entries), total_bytes))
     yield '%d %d\n' % (len(entries), total_bytes)
     for name, size in entries:
-        repo.ui.debug(_('sending %s (%d bytes)\n') % (name, size))
-        yield '%s\0%d\n' % (name, size)
+        repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
+        # partially encode name over the wire for backwards compat
+        yield '%s\0%d\n' % (store.encodedir(name), size)
         for chunk in util.filechunkiter(repo.sopener(name), limit=size):
             yield chunk
--- a/mercurial/subrepo.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/subrepo.py	Thu Oct 08 01:16:32 2009 -0500
@@ -167,7 +167,7 @@
         self._repo.ui.note(_('removing subrepo %s\n') % self._path)
         hg.clean(self._repo, node.nullid, False)
 
-    def get(self, state):
+    def _get(self, state):
         source, revision = state
         try:
             self._repo.lookup(revision)
@@ -178,9 +178,13 @@
             other = hg.repository(self._repo.ui, srcurl)
             self._repo.pull(other)
 
+    def get(self, state):
+        self._get(state)
+        source, revision = state
         hg.clean(self._repo, revision, False)
 
     def merge(self, state):
+        self._get(state)
         hg.merge(self._repo, state[1], remind=False)
 
     def push(self, force):
--- a/mercurial/url.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/url.py	Thu Oct 08 01:16:32 2009 -0500
@@ -197,7 +197,7 @@
                                                 proxyuser, proxypasswd or ''),
                 proxypath, proxyquery, proxyfrag))
             proxies = {'http': proxyurl, 'https': proxyurl}
-            ui.debug(_('proxying through http://%s:%s\n') %
+            ui.debug('proxying through http://%s:%s\n' %
                       (proxyhost, proxyport))
         else:
             proxies = {}
@@ -504,7 +504,7 @@
     if authinfo is not None:
         passmgr.add_password(*authinfo)
         user, passwd = authinfo[2:4]
-        ui.debug(_('http auth: user %s, password %s\n') %
+        ui.debug('http auth: user %s, password %s\n' %
                  (user, passwd and '*' * len(passwd) or 'not set'))
 
     handlers.extend((urllib2.HTTPBasicAuthHandler(passmgr),
--- a/mercurial/util.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/util.py	Thu Oct 08 01:16:32 2009 -0500
@@ -16,7 +16,7 @@
 from i18n import _
 import error, osutil, encoding
 import cStringIO, errno, re, shutil, sys, tempfile, traceback
-import os, stat, time, calendar, random, textwrap
+import os, stat, time, calendar, textwrap
 import imp
 
 # Python compatibility
@@ -357,41 +357,26 @@
         if val is True:
             return '1'
         return str(val)
-    oldenv = {}
-    for k in environ:
-        oldenv[k] = os.environ.get(k)
-    if cwd is not None:
-        oldcwd = os.getcwd()
     origcmd = cmd
     if os.name == 'nt':
         cmd = '"%s"' % cmd
-    try:
-        for k, v in environ.iteritems():
-            os.environ[k] = py2shell(v)
-        os.environ['HG'] = hgexecutable()
-        if cwd is not None and oldcwd != cwd:
-            os.chdir(cwd)
-        rc = os.system(cmd)
-        if sys.platform == 'OpenVMS' and rc & 1:
-            rc = 0
-        if rc and onerr:
-            errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
-                                explain_exit(rc)[0])
-            if errprefix:
-                errmsg = '%s: %s' % (errprefix, errmsg)
-            try:
-                onerr.warn(errmsg + '\n')
-            except AttributeError:
-                raise onerr(errmsg)
-        return rc
-    finally:
-        for k, v in oldenv.iteritems():
-            if v is None:
-                del os.environ[k]
-            else:
-                os.environ[k] = v
-        if cwd is not None and oldcwd != cwd:
-            os.chdir(oldcwd)
+    env = dict(os.environ)
+    env.update((k, py2shell(v)) for k, v in environ.iteritems())
+    env['HG'] = hgexecutable()
+    rc = subprocess.call(cmd, shell=True, close_fds=closefds,
+                         env=env, cwd=cwd)
+    if sys.platform == 'OpenVMS' and rc & 1:
+        rc = 0
+    if rc and onerr:
+        errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
+                            explain_exit(rc)[0])
+        if errprefix:
+            errmsg = '%s: %s' % (errprefix, errmsg)
+        try:
+            onerr.warn(errmsg + '\n')
+        except AttributeError:
+            raise onerr(errmsg)
+    return rc
 
 def checksignature(func):
     '''wrap a function with code to check for calling errors'''
@@ -414,37 +399,6 @@
         return False
     return True
 
-def rename(src, dst):
-    """forcibly rename a file"""
-    try:
-        os.rename(src, dst)
-    except OSError, err: # FIXME: check err (EEXIST ?)
-
-        # On windows, rename to existing file is not allowed, so we
-        # must delete destination first. But if a file is open, unlink
-        # schedules it for delete but does not delete it. Rename
-        # happens immediately even for open files, so we rename
-        # destination to a temporary name, then delete that. Then
-        # rename is safe to do.
-        # The temporary name is chosen at random to avoid the situation
-        # where a file is left lying around from a previous aborted run.
-        # The usual race condition this introduces can't be avoided as
-        # we need the name to rename into, and not the file itself. Due
-        # to the nature of the operation however, any races will at worst
-        # lead to the rename failing and the current operation aborting.
-
-        def tempname(prefix):
-            for tries in xrange(10):
-                temp = '%s-%08x' % (prefix, random.randint(0, 0xffffffff))
-                if not os.path.exists(temp):
-                    return temp
-            raise IOError, (errno.EEXIST, "No usable temporary filename found")
-
-        temp = tempname(dst)
-        os.rename(dst, temp)
-        os.unlink(temp)
-        os.rename(src, dst)
-
 def unlink(f):
     """unlink and remove the directory if it is empty"""
     os.unlink(f)
@@ -1267,6 +1221,11 @@
                 return array.array('h', arri)[1]
             except ValueError:
                 pass
+            except IOError, e: 
+                if e[0] == errno.EINVAL: 
+                    pass 
+                else: 
+                    raise 
     except ImportError:
         pass
     return 80
--- a/mercurial/verify.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/verify.py	Thu Oct 08 01:16:32 2009 -0500
@@ -173,6 +173,7 @@
         elif size > 0:
             storefiles.add(f)
 
+    lrugetctx = util.lrucachefunc(repo.changectx)
     files = sorted(set(filenodes) | set(filelinkrevs))
     for f in files:
         try:
@@ -224,6 +225,16 @@
             # check renames
             try:
                 if rp:
+                    if lr is not None and ui.verbose:
+                        ctx = lrugetctx(lr)
+                        found = False
+                        for pctx in ctx.parents():
+                            if rp[0] in pctx:
+                                found = True
+                                break
+                        if not found:
+                            warn(_("warning: copy source of '%s' not"
+                                   " in parents of %s") % (f, ctx))
                     fl2 = repo.file(rp[0])
                     if not len(fl2):
                         err(lr, _("empty or missing copy source revlog %s:%s")
--- a/mercurial/windows.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/mercurial/windows.py	Thu Oct 08 01:16:32 2009 -0500
@@ -7,7 +7,7 @@
 
 from i18n import _
 import osutil, error
-import errno, msvcrt, os, re, sys
+import errno, msvcrt, os, re, sys, random
 
 nulldev = 'NUL:'
 umask = 002
@@ -283,6 +283,44 @@
     except OSError:
         pass
 
+def rename(src, dst):
+    '''atomically rename file src to dst, replacing dst if it exists'''
+    try:
+        os.rename(src, dst)
+    except OSError, err: # FIXME: check err (EEXIST ?)
+
+        # On windows, rename to existing file is not allowed, so we
+        # must delete destination first. But if a file is open, unlink
+        # schedules it for delete but does not delete it. Rename
+        # happens immediately even for open files, so we rename
+        # destination to a temporary name, then delete that. Then
+        # rename is safe to do.
+        # The temporary name is chosen at random to avoid the situation
+        # where a file is left lying around from a previous aborted run.
+        # The usual race condition this introduces can't be avoided as
+        # we need the name to rename into, and not the file itself. Due
+        # to the nature of the operation however, any races will at worst
+        # lead to the rename failing and the current operation aborting.
+
+        def tempname(prefix):
+            for tries in xrange(10):
+                temp = '%s-%08x' % (prefix, random.randint(0, 0xffffffff))
+                if not os.path.exists(temp):
+                    return temp
+            raise IOError, (errno.EEXIST, "No usable temporary filename found")
+
+        temp = tempname(dst)
+        os.rename(dst, temp)
+        try:
+            os.unlink(temp)
+        except:
+            # Some rude AV-scanners on Windows may cause the unlink to
+            # fail. Not aborting here just leaks the temp file, whereas
+            # aborting at this point may leave serious inconsistencies.
+            # Ideally, we would notify the user here.
+            pass
+        os.rename(src, dst)
+
 try:
     # override functions with win32 versions if possible
     from win32 import *
--- a/setup.py	Tue Oct 06 11:18:58 2009 +0300
+++ b/setup.py	Thu Oct 08 01:16:32 2009 -0500
@@ -246,7 +246,7 @@
         packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
 
 datafiles = []
-for root in ('templates', 'i18n'):
+for root in ('templates', 'i18n', 'help'):
     for dir, dirs, files in os.walk(root):
         dirs[:] = [x for x in dirs if not x.startswith('.')]
         files = [x for x in files if not x.startswith('.')]
--- a/tests/hghave	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/hghave	Thu Oct 08 01:16:32 2009 -0500
@@ -47,9 +47,6 @@
     re = r'Concurrent Versions System.*?server'
     return matchoutput('cvs --version 2>&1', re)
 
-def has_cvsps():
-    return matchoutput('cvsps -h -q 2>&1', r'cvsps version', True)
-
 def has_darcs():
     return matchoutput('darcs --version', r'2\.[2-9]', True)
 
@@ -128,8 +125,10 @@
         matchoutput('rst2html.py --version', r'^rst2html.py \(Docutils')
 
 def has_svn():
-    return matchoutput('svn --version 2>&1', r'^svn, version') and \
-        matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
+    #return matchoutput('svn --version 2>&1', r'^svn, version') and \
+        #matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
+    # disabled until licensing issue is resolved
+    return False
 
 def has_svn_bindings():
     try:
@@ -184,7 +183,6 @@
     "bzr": (has_bzr, "Canonical's Bazaar client"),
     "bzr114": (has_bzr114, "Canonical's Bazaar client >= 1.14"),
     "cvs": (has_cvs, "cvs client/server"),
-    "cvsps": (has_cvsps, "cvsps utility"),
     "darcs": (has_darcs, "darcs client"),
     "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
     "execbit": (has_executablebit, "executable bit"),
--- a/tests/test-add.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-add.out	Thu Oct 08 01:16:32 2009 -0500
@@ -20,7 +20,7 @@
 warning: conflicts during merge.
 merging a failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 M a
 ? a.orig
 % should fail
--- a/tests/test-command-template	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-command-template	Thu Oct 08 01:16:32 2009 -0500
@@ -127,4 +127,49 @@
 echo 'x = "f' >> t
 hg log
 
+cd ..
+
+echo '# latesttag'
+hg init latesttag
+cd latesttag
+
+echo a > file
+hg ci -Am a -d '0 0'
+
+echo b >> file
+hg ci -m b -d '1 0'
+
+echo c >> head1
+hg ci -Am h1c -d '2 0'
+
+hg update -q 1
+echo d >> head2
+hg ci -Am h2d -d '3 0'
+
+echo e >> head2
+hg ci -m h2e -d '4 0'
+
+hg merge -q
+hg ci -m merge -d '5 0'
+
+echo '# No tag set'
+hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+
+echo '# one common tag: longuest path wins'
+hg tag -r 1 -m t1 -d '6 0' t1
+hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+
+echo '# one ancestor tag: more recent wins'
+hg tag -r 2 -m t2 -d '7 0' t2
+hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+
+echo '# two branch tags: more recent wins'
+hg tag -r 3 -m t3 -d '8 0' t3
+hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+
+echo '# merged tag overrides'
+hg tag -r 5 -m t5 -d '9 0' t5
+hg tag -r 3 -m at3 -d '10 0' at3
+hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+
 echo '# done'
--- a/tests/test-command-template.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-command-template.out	Thu Oct 08 01:16:32 2009 -0500
@@ -672,4 +672,55 @@
 1e4e1b8f71e05681d422154f5421e385fec3454f
 # error on syntax
 abort: t:3: unmatched quotes
+# latesttag
+adding file
+adding head1
+adding head2
+created new head
+# No tag set
+5: null+5
+4: null+4
+3: null+3
+2: null+3
+1: null+2
+0: null+1
+# one common tag: longuest path wins
+6: t1+4
+5: t1+3
+4: t1+2
+3: t1+1
+2: t1+1
+1: t1+0
+0: null+1
+# one ancestor tag: more recent wins
+7: t2+3
+6: t2+2
+5: t2+1
+4: t1+2
+3: t1+1
+2: t2+0
+1: t1+0
+0: null+1
+# two branch tags: more recent wins
+8: t3+5
+7: t3+4
+6: t3+3
+5: t3+2
+4: t3+1
+3: t3+0
+2: t2+0
+1: t1+0
+0: null+1
+# merged tag overrides
+10: t5+5
+9: t5+4
+8: t5+3
+7: t5+2
+6: t5+1
+5: t5+0
+4: at3:t3+1
+3: at3:t3+0
+2: t2+0
+1: t1+0
+0: null+1
 # done
--- a/tests/test-commit-unresolved.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-commit-unresolved.out	Thu Oct 08 01:16:32 2009 -0500
@@ -6,7 +6,7 @@
 warning: conflicts during merge.
 merging A failed!
 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 
 % Correct the conflict without marking the file as resolved
 abort: unresolved merge conflicts (see hg resolve)
--- a/tests/test-conflict.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-conflict.out	Thu Oct 08 01:16:32 2009 -0500
@@ -4,7 +4,7 @@
 warning: conflicts during merge.
 merging a failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 e7fe8eb3e180+0d24b7662d3e+ tip
 <<<<<<< local
 something else
--- a/tests/test-convert-cvs	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-cvs	Thu Oct 08 01:16:32 2009 -0500
@@ -1,10 +1,10 @@
 #!/bin/sh
 
-"$TESTDIR/hghave" cvs cvsps || exit 80
+"$TESTDIR/hghave" cvs || exit 80
 
 cvscall()
 {
-    cvs -f $@
+    cvs -f "$@"
 }
 
 hgcat()
@@ -12,12 +12,9 @@
     hg --cwd src-hg cat -r tip "$1"
 }
 
-# Test legacy configuration with external cvsps
 echo "[extensions]" >> $HGRCPATH
 echo "convert = " >> $HGRCPATH
 echo "graphlog = " >> $HGRCPATH
-echo "[convert]" >> $HGRCPATH
-echo "cvsps=cvsps -A -u --cvs-direct -q" >> $HGRCPATH
 
 echo % create cvs repository
 mkdir cvsrepo
@@ -95,11 +92,29 @@
 
 echo % convert again
 hg convert src src-hg | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
-hgcat a
 hgcat b/c
 
 echo % convert again with --filemap
 hg convert --filemap filemap src src-filemap | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
 hgcat b/c
 hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
+
+echo % commit a new revision with funny log message
+cd src
+sleep 1
+echo e >> a
+cvscall -q commit -m'funny
+----------------------------
+log message' . | grep '<--' |\
+    sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g'
+cd ..
+
+echo % convert again
+hg convert src src-hg | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
+
+echo "graphlog = " >> $HGRCPATH
 hg -R src-hg glog --template '{rev} ({branches}) {desc} files: {files}\n'
+
+echo % testing debugcvsps
+cd src
+hg debugcvsps | sed -e 's/Author:.*/Author:/' -e 's/Date:.*/Date:/' 
--- a/tests/test-convert-cvs-branch	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-cvs-branch	Thu Oct 08 01:16:32 2009 -0500
@@ -14,7 +14,6 @@
 echo "convert = " >> $HGRCPATH
 echo "graphlog = " >> $HGRCPATH
 echo "[convert]" >> $HGRCPATH
-echo "cvsps=builtin" >> $HGRCPATH
 echo "cvsps.cache=0" >> $HGRCPATH
 
 echo % create cvs repository
--- a/tests/test-convert-cvs-branch.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-cvs-branch.out	Thu Oct 08 01:16:32 2009 -0500
@@ -25,7 +25,6 @@
 initializing destination src-hg repository
 connecting to cvsrepo
 scanning source...
-using builtin cvsps
 collecting CVS rlog
 7 log entries
 creating changesets
--- a/tests/test-convert-cvs-builtincvsps	Tue Oct 06 11:18:58 2009 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-#!/bin/sh
-
-"$TESTDIR/hghave" cvs || exit 80
-
-cvscall()
-{
-    cvs -f "$@"
-}
-
-hgcat()
-{
-    hg --cwd src-hg cat -r tip "$1"
-}
-
-echo "[extensions]" >> $HGRCPATH
-echo "convert = " >> $HGRCPATH
-echo "graphlog = " >> $HGRCPATH
-echo "[convert]" >> $HGRCPATH
-echo "cvsps=builtin" >> $HGRCPATH
-
-echo % create cvs repository
-mkdir cvsrepo
-cd cvsrepo
-CVSROOT=`pwd`
-export CVSROOT
-CVS_OPTIONS=-f
-export CVS_OPTIONS
-cd ..
-
-cvscall -q -d "$CVSROOT" init
-
-echo % create source directory
-mkdir src-temp
-cd src-temp
-echo a > a
-mkdir b
-cd b
-echo c > c
-cd ..
-
-echo % import source directory
-cvscall -q import -m import src INITIAL start
-cd ..
-
-echo % checkout source directory
-cvscall -q checkout src
-
-echo % commit a new revision changing b/c
-cd src
-sleep 1
-echo c >> b/c
-cvscall -q commit -mci0 . | grep '<--' |\
-    sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g'
-cd ..
-
-echo % convert fresh repo
-hg convert src src-hg | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
-hgcat a
-hgcat b/c
-
-echo % convert fresh repo with --filemap
-echo include b/c > filemap
-hg convert --filemap filemap src src-filemap | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
-hgcat b/c
-hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
-
-echo % commit new file revisions
-cd src
-echo a >> a
-echo c >> b/c
-cvscall -q commit -mci1 . | grep '<--' |\
-    sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g'
-cd ..
-
-echo % convert again
-hg convert src src-hg | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
-hgcat a
-hgcat b/c
-
-echo % convert again with --filemap
-hg convert --filemap filemap src src-filemap | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
-hgcat b/c
-hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
-
-echo % commit branch
-cd src
-cvs -q update -r1.1 b/c
-cvs -q tag -b branch
-cvs -q update -r branch > /dev/null
-echo d >> b/c
-cvs -q commit -mci2 . | grep '<--' |\
-    sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g'
-cd ..
-
-echo % convert again
-hg convert src src-hg | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
-hgcat b/c
-
-echo % convert again with --filemap
-hg convert --filemap filemap src src-filemap | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
-hgcat b/c
-hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
-
-echo % commit a new revision with funny log message
-cd src
-sleep 1
-echo e >> a
-cvscall -q commit -m'funny
-----------------------------
-log message' . | grep '<--' |\
-    sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g'
-cd ..
-
-echo % convert again
-hg convert src src-hg | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g'
-
-echo "graphlog = " >> $HGRCPATH
-hg -R src-hg glog --template '{rev} ({branches}) {desc} files: {files}\n'
-
-echo % testing debugcvsps
-cd src
-hg debugcvsps | sed -e 's/Author:.*/Author:/' -e 's/Date:.*/Date:/' 
--- a/tests/test-convert-cvs-builtincvsps.out	Tue Oct 06 11:18:58 2009 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,261 +0,0 @@
-% create cvs repository
-% create source directory
-% import source directory
-N src/a
-N src/b/c
-
-No conflicts created by this import
-
-% checkout source directory
-U src/a
-U src/b/c
-% commit a new revision changing b/c
-checking in src/b/c,v
-% convert fresh repo
-initializing destination src-hg repository
-connecting to cvsrepo
-scanning source...
-using builtin cvsps
-collecting CVS rlog
-5 log entries
-creating changesets
-3 changeset entries
-sorting...
-converting...
-2 Initial revision
-1 import
-0 ci0
-updating tags
-a
-c
-c
-% convert fresh repo with --filemap
-initializing destination src-filemap repository
-connecting to cvsrepo
-scanning source...
-using builtin cvsps
-collecting CVS rlog
-5 log entries
-creating changesets
-3 changeset entries
-sorting...
-converting...
-2 Initial revision
-1 import
-filtering out empty revision
-rolling back last transaction
-0 ci0
-updating tags
-c
-c
-2 update tags files: .hgtags
-1 ci0 files: b/c
-0 Initial revision files: b/c
-% commit new file revisions
-checking in src/a,v
-checking in src/b/c,v
-% convert again
-connecting to cvsrepo
-scanning source...
-using builtin cvsps
-collecting CVS rlog
-7 log entries
-creating changesets
-4 changeset entries
-sorting...
-converting...
-0 ci1
-a
-a
-c
-c
-c
-% convert again with --filemap
-connecting to cvsrepo
-scanning source...
-using builtin cvsps
-collecting CVS rlog
-7 log entries
-creating changesets
-4 changeset entries
-sorting...
-converting...
-0 ci1
-c
-c
-c
-3 ci1 files: b/c
-2 update tags files: .hgtags
-1 ci0 files: b/c
-0 Initial revision files: b/c
-% commit branch
-U b/c
-T a
-T b/c
-checking in src/b/c,v
-% convert again
-connecting to cvsrepo
-scanning source...
-using builtin cvsps
-collecting CVS rlog
-8 log entries
-creating changesets
-5 changeset entries
-sorting...
-converting...
-0 ci2
-c
-d
-% convert again with --filemap
-connecting to cvsrepo
-scanning source...
-using builtin cvsps
-collecting CVS rlog
-8 log entries
-creating changesets
-5 changeset entries
-sorting...
-converting...
-0 ci2
-c
-d
-4 ci2 files: b/c
-3 ci1 files: b/c
-2 update tags files: .hgtags
-1 ci0 files: b/c
-0 Initial revision files: b/c
-% commit a new revision with funny log message
-checking in src/a,v
-% convert again
-connecting to cvsrepo
-scanning source...
-using builtin cvsps
-collecting CVS rlog
-9 log entries
-creating changesets
-6 changeset entries
-sorting...
-converting...
-0 funny
-o  6 (branch) funny
-|  ----------------------------
-|  log message files: a
-o  5 (branch) ci2 files: b/c
-
-o  4 () ci1 files: a b/c
-|
-o  3 () update tags files: .hgtags
-|
-o  2 () ci0 files: b/c
-|
-| o  1 (INITIAL) import files:
-|/
-o  0 () Initial revision files: a b/c
-
-% testing debugcvsps
-collecting CVS rlog
-9 log entries
-creating changesets
-8 changeset entries
----------------------
-PatchSet 1 
-Date:
-Author:
-Branch: HEAD
-Tag: (none) 
-Branchpoints: INITIAL 
-Log:
-Initial revision
-
-Members: 
-	a:INITIAL->1.1 
-
----------------------
-PatchSet 2 
-Date:
-Author:
-Branch: HEAD
-Tag: (none) 
-Branchpoints: INITIAL, branch 
-Log:
-Initial revision
-
-Members: 
-	b/c:INITIAL->1.1 
-
----------------------
-PatchSet 3 
-Date:
-Author:
-Branch: INITIAL
-Tag: start 
-Log:
-import
-
-Members: 
-	a:1.1->1.1.1.1 
-	b/c:1.1->1.1.1.1 
-
----------------------
-PatchSet 4 
-Date:
-Author:
-Branch: HEAD
-Tag: (none) 
-Log:
-ci0
-
-Members: 
-	b/c:1.1->1.2 
-
----------------------
-PatchSet 5 
-Date:
-Author:
-Branch: HEAD
-Tag: (none) 
-Branchpoints: branch 
-Log:
-ci1
-
-Members: 
-	a:1.1->1.2 
-
----------------------
-PatchSet 6 
-Date:
-Author:
-Branch: HEAD
-Tag: (none) 
-Log:
-ci1
-
-Members: 
-	b/c:1.2->1.3 
-
----------------------
-PatchSet 7 
-Date:
-Author:
-Branch: branch
-Tag: (none) 
-Log:
-ci2
-
-Members: 
-	b/c:1.1->1.1.2.1 
-
----------------------
-PatchSet 8 
-Date:
-Author:
-Branch: branch
-Tag: (none) 
-Log:
-funny
-----------------------------
-log message
-
-Members: 
-	a:1.2->1.2.2.1 
-
--- a/tests/test-convert-cvs-detectmerge	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-cvs-detectmerge	Thu Oct 08 01:16:32 2009 -0500
@@ -34,7 +34,6 @@
 echo "convert = " >> $HGRCPATH
 echo "graphlog = " >> $HGRCPATH
 echo "[convert]" >> $HGRCPATH
-echo "cvsps=builtin" >> $HGRCPATH
 echo "cvsps.cache=0" >> $HGRCPATH
 echo "cvsps.mergefrom=\[MERGE from (\S+)\]" >> $HGRCPATH
 
--- a/tests/test-convert-cvs-detectmerge.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-cvs-detectmerge.out	Thu Oct 08 01:16:32 2009 -0500
@@ -77,7 +77,6 @@
 initializing destination proj.hg repository
 connecting to *REPO*
 scanning source...
-using builtin cvsps
 collecting CVS rlog
 12 log entries
 creating changesets
--- a/tests/test-convert-cvs-synthetic	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-cvs-synthetic	Thu Oct 08 01:16:32 2009 -0500
@@ -8,8 +8,6 @@
 echo "[extensions]" >> $HGRCPATH
 echo "convert = " >> $HGRCPATH
 echo "graphlog = " >> $HGRCPATH
-echo "[convert]" >> $HGRCPATH
-echo "cvsps=builtin" >> $HGRCPATH
 
 echo % create cvs repository with one project
 mkdir cvsrepo
--- a/tests/test-convert-cvs-synthetic.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-cvs-synthetic.out	Thu Oct 08 01:16:32 2009 -0500
@@ -66,7 +66,6 @@
 initializing destination proj.hg repository
 connecting to *REPO*
 scanning source...
-using builtin cvsps
 collecting CVS rlog
 15 log entries
 creating changesets
@@ -102,7 +101,6 @@
 initializing destination proj.hg2 repository
 connecting to *REPO*
 scanning source...
-using builtin cvsps
 collecting CVS rlog
 15 log entries
 creating changesets
--- a/tests/test-convert-cvs.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-cvs.out	Thu Oct 08 01:16:32 2009 -0500
@@ -12,10 +12,13 @@
 % commit a new revision changing b/c
 checking in src/b/c,v
 % convert fresh repo
-warning: support for external cvsps is deprecated and will be removed in Mercurial 1.4
 initializing destination src-hg repository
 connecting to cvsrepo
 scanning source...
+collecting CVS rlog
+5 log entries
+creating changesets
+3 changeset entries
 sorting...
 converting...
 2 Initial revision
@@ -26,10 +29,13 @@
 c
 c
 % convert fresh repo with --filemap
-warning: support for external cvsps is deprecated and will be removed in Mercurial 1.4
 initializing destination src-filemap repository
 connecting to cvsrepo
 scanning source...
+collecting CVS rlog
+5 log entries
+creating changesets
+3 changeset entries
 sorting...
 converting...
 2 Initial revision
@@ -47,9 +53,12 @@
 checking in src/a,v
 checking in src/b/c,v
 % convert again
-warning: support for external cvsps is deprecated and will be removed in Mercurial 1.4
 connecting to cvsrepo
 scanning source...
+collecting CVS rlog
+7 log entries
+creating changesets
+4 changeset entries
 sorting...
 converting...
 0 ci1
@@ -59,9 +68,12 @@
 c
 c
 % convert again with --filemap
-warning: support for external cvsps is deprecated and will be removed in Mercurial 1.4
 connecting to cvsrepo
 scanning source...
+collecting CVS rlog
+7 log entries
+creating changesets
+4 changeset entries
 sorting...
 converting...
 0 ci1
@@ -78,19 +90,24 @@
 T b/c
 checking in src/b/c,v
 % convert again
-warning: support for external cvsps is deprecated and will be removed in Mercurial 1.4
 connecting to cvsrepo
 scanning source...
+collecting CVS rlog
+8 log entries
+creating changesets
+5 changeset entries
 sorting...
 converting...
 0 ci2
-a
 c
 d
 % convert again with --filemap
-warning: support for external cvsps is deprecated and will be removed in Mercurial 1.4
 connecting to cvsrepo
 scanning source...
+collecting CVS rlog
+8 log entries
+creating changesets
+5 changeset entries
 sorting...
 converting...
 0 ci2
@@ -101,15 +118,137 @@
 2 update tags files: .hgtags
 1 ci0 files: b/c
 0 Initial revision files: b/c
+% commit a new revision with funny log message
+checking in src/a,v
+% convert again
+connecting to cvsrepo
+scanning source...
+collecting CVS rlog
+9 log entries
+creating changesets
+6 changeset entries
+sorting...
+converting...
+0 funny
+o  6 (branch) funny
+|  ----------------------------
+|  log message files: a
 o  5 (branch) ci2 files: b/c
+
+o  4 () ci1 files: a b/c
 |
-| o  4 () ci1 files: a b/c
-| |
-| o  3 () update tags files: .hgtags
-| |
-| o  2 () ci0 files: b/c
-|/
+o  3 () update tags files: .hgtags
+|
+o  2 () ci0 files: b/c
+|
 | o  1 (INITIAL) import files:
 |/
 o  0 () Initial revision files: a b/c
 
+% testing debugcvsps
+collecting CVS rlog
+9 log entries
+creating changesets
+8 changeset entries
+---------------------
+PatchSet 1 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Branchpoints: INITIAL 
+Log:
+Initial revision
+
+Members: 
+	a:INITIAL->1.1 
+
+---------------------
+PatchSet 2 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Branchpoints: INITIAL, branch 
+Log:
+Initial revision
+
+Members: 
+	b/c:INITIAL->1.1 
+
+---------------------
+PatchSet 3 
+Date:
+Author:
+Branch: INITIAL
+Tag: start 
+Log:
+import
+
+Members: 
+	a:1.1->1.1.1.1 
+	b/c:1.1->1.1.1.1 
+
+---------------------
+PatchSet 4 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Log:
+ci0
+
+Members: 
+	b/c:1.1->1.2 
+
+---------------------
+PatchSet 5 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Branchpoints: branch 
+Log:
+ci1
+
+Members: 
+	a:1.1->1.2 
+
+---------------------
+PatchSet 6 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Log:
+ci1
+
+Members: 
+	b/c:1.2->1.3 
+
+---------------------
+PatchSet 7 
+Date:
+Author:
+Branch: branch
+Tag: (none) 
+Log:
+ci2
+
+Members: 
+	b/c:1.1->1.1.2.1 
+
+---------------------
+PatchSet 8 
+Date:
+Author:
+Branch: branch
+Tag: (none) 
+Log:
+funny
+----------------------------
+log message
+
+Members: 
+	a:1.2->1.2.2.1 
+
--- a/tests/test-convert-cvsnt-mergepoints	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-cvsnt-mergepoints	Thu Oct 08 01:16:32 2009 -0500
@@ -29,8 +29,6 @@
 echo "[extensions]" >> $HGRCPATH
 echo "convert = " >> $HGRCPATH
 echo "graphlog = " >> $HGRCPATH
-echo "[convert]" >> $HGRCPATH
-echo "cvsps=builtin" >> $HGRCPATH
 
 echo "% create cvs repository"
 mkdir cvsmaster
--- a/tests/test-convert-darcs	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-darcs	Thu Oct 08 01:16:32 2009 -0500
@@ -43,7 +43,19 @@
 darcs pull -a ../darcs-clone
 sleep 1
 echo e > a
+echo f > f
+mkdir dir
+echo d > dir/d
+echo d > dir/d2
 darcs record -a -l -m p2
+
+echo % test file and directory move
+darcs mv f ff
+# Test remove + move
+darcs remove dir/d2
+rm dir/d2
+darcs mv dir dir2
+darcs record -a -l -m p3
 cd ..
 
 glog()
--- a/tests/test-convert-darcs.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-darcs.out	Thu Oct 08 01:16:32 2009 -0500
@@ -10,15 +10,20 @@
 ./a
 Finished pulling and applying.
 Finished recording patch 'p2'
+% test file and directory move
+Finished recording patch 'p3'
 initializing destination darcs-repo-hg repository
 scanning source...
 sorting...
 converting...
-3 p0
-2 p1.2
-1 p1.1
-0 p2
-o  3 "p2" files: a
+4 p0
+3 p1.2
+2 p1.1
+1 p2
+0 p3
+o  4 "p3" files: dir/d dir/d2 dir2/d f ff
+|
+o  3 "p2" files: a dir/d dir/d2 f
 |
 o  2 "p1.1" files:
 |
@@ -28,3 +33,5 @@
 
 7225b30cdf38257d5cc7780772c051b6f33e6d6b 644   a
 1e88685f5ddec574a34c70af492f95b6debc8741 644   b
+d278f41640da5fc303a4cf9894af31c2983fc11d 644   dir2/d
+ef5c76581d78340f568d5f48d679bf307452cbc9 644   ff
--- a/tests/test-convert-hg-source	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-hg-source	Thu Oct 08 01:16:32 2009 -0500
@@ -38,6 +38,25 @@
 hg out ../orig
 cd ..
 
+echo '% check shamap LF and CRLF handling'
+cat > rewrite.py <<EOF
+import sys
+# Interlace LF and CRLF
+lines = [(l.rstrip() + ((i % 2) and '\n' or '\r\n'))
+         for i, l in enumerate(file(sys.argv[1]))]
+file(sys.argv[1], 'wb').write(''.join(lines))
+EOF
+python rewrite.py new/.hg/shamap
+cd orig
+hg up -qC 1
+echo foo >> foo
+hg ci -qm 'change foo again'
+hg up -qC 2
+echo foo >> foo
+hg ci -qm 'change foo again again'
+cd ..
+hg convert --datesort orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
+
 echo % init broken repository
 hg init broken
 cd broken
--- a/tests/test-convert-hg-source.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-hg-source.out	Thu Oct 08 01:16:32 2009 -0500
@@ -20,6 +20,12 @@
 comparing with ../orig
 searching for changes
 no changes found
+% check shamap LF and CRLF handling
+scanning source...
+sorting...
+converting...
+1 change foo again again
+0 change foo again
 % init broken repository
 created new head
 % break it
--- a/tests/test-convert-svn-sink.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert-svn-sink.out	Thu Oct 08 01:16:32 2009 -0500
@@ -265,7 +265,7 @@
 warning: conflicts during merge.
 merging b failed!
 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 assuming destination b-hg
 initializing svn repo 'b-hg'
 initializing svn wc 'b-hg-wc'
--- a/tests/test-convert.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-convert.out	Thu Oct 08 01:16:32 2009 -0500
@@ -117,23 +117,8 @@
     starting directory will be converted, and that any directory
     reorganization in the CVS sandbox is ignored.
 
-    Because CVS does not have changesets, it is necessary to collect
-    individual commits to CVS and merge them into changesets. CVS source uses
-    its internal changeset merging code by default but can be configured to
-    call the external 'cvsps' program by setting:
-
-      --config convert.cvsps='cvsps -A -u --cvs-direct -q'
-
-    This option is deprecated and will be removed in Mercurial 1.4.
-
     The options shown are the defaults.
 
-    Internal cvsps is selected by setting
-
-      --config convert.cvsps=builtin
-
-    and has a few more configurable options:
-
     --config convert.cvsps.cache=True         (boolean)
         Set to False to disable remote log caching, for testing and debugging
         purposes.
@@ -153,9 +138,10 @@
         recent revision on the branch indicated in the regex as the second
         parent of the changeset.
 
-    The hgext/convert/cvsps wrapper script allows the builtin changeset
+    An additional "debugcvsps" Mercurial command allows the builtin changeset
     merging code to be run without doing a conversion. Its parameters and
-    output are similar to that of cvsps 2.1.
+    output are similar to that of cvsps 2.1. Please see the command help for
+    more details.
 
     Subversion Source
     -----------------
--- a/tests/test-encoding	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-encoding	Thu Oct 08 01:16:32 2009 -0500
@@ -29,30 +29,31 @@
 HGENCODING=latin-1 hg ci -d "1000000 0" -m 'latin1 branch'
 rm .hg/branch
 
-echo % ascii
+echo "% hg log (ascii)"
 hg --encoding ascii log
-echo % latin-1
+echo "% hg log (latin-1)"
 hg --encoding latin-1 log
-echo % utf-8
+echo "% hg log (utf-8)"
 hg --encoding utf-8 log
-echo % ascii
+echo "% hg tags (ascii)"
 HGENCODING=ascii hg tags
-echo % latin-1
+echo "% hg tags (latin-1)"
 HGENCODING=latin-1 hg tags
-echo % utf-8
+echo "% hg tags (utf-8)"
 HGENCODING=utf-8 hg tags
-echo % ascii
+echo "% hg branches (ascii)"
 HGENCODING=ascii hg branches
-echo % latin-1
+echo "% hg branches (latin-1)"
 HGENCODING=latin-1 hg branches
-echo % utf-8
+echo "% hg branches (utf-8)"
 HGENCODING=utf-8 hg branches
 
 echo '[ui]' >> .hg/hgrc
 echo 'fallbackencoding = koi8-r' >> .hg/hgrc
-echo % utf-8
+echo "% hg log (utf-8)"
 HGENCODING=utf-8 hg log
 
+echo "% hg log (dolphin)"
 HGENCODING=dolphin hg log
 
 HGENCODING=ascii hg branch `cat latin-1-tag`
--- a/tests/test-encoding.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-encoding.out	Thu Oct 08 01:16:32 2009 -0500
@@ -14,7 +14,7 @@
 abort: decoding near ' encoded: é': 'ascii' codec can't decode byte 0xe9 in position 20: ordinal not in range(128)!
 % these should work
 marked working directory as branch é
-% ascii
+% hg log (ascii)
 changeset:   5:db5520b4645f
 branch:      ?
 tag:         tip
@@ -48,7 +48,7 @@
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     latin-1 e': ? = u'\xe9'
 
-% latin-1
+% hg log (latin-1)
 changeset:   5:db5520b4645f
 branch:      é
 tag:         tip
@@ -82,7 +82,7 @@
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     latin-1 e': é = u'\xe9'
 
-% utf-8
+% hg log (utf-8)
 changeset:   5:db5520b4645f
 branch:      é
 tag:         tip
@@ -116,25 +116,25 @@
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     latin-1 e': é = u'\xe9'
 
-% ascii
+% hg tags (ascii)
 tip                                5:db5520b4645f
 ?                                  3:770b9b11621d
-% latin-1
+% hg tags (latin-1)
 tip                                5:db5520b4645f
 é                                  3:770b9b11621d
-% utf-8
+% hg tags (utf-8)
 tip                                5:db5520b4645f
 é                                  3:770b9b11621d
-% ascii
+% hg branches (ascii)
 ?                              5:db5520b4645f
 default                        4:9cff3c980b58 (inactive)
-% latin-1
+% hg branches (latin-1)
 é                              5:db5520b4645f
 default                        4:9cff3c980b58 (inactive)
-% utf-8
+% hg branches (utf-8)
 é                              5:db5520b4645f
 default                        4:9cff3c980b58 (inactive)
-% utf-8
+% hg log (utf-8)
 changeset:   5:db5520b4645f
 branch:      é
 tag:         tip
@@ -168,6 +168,7 @@
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     latin-1 e': И = u'\xe9'
 
+% hg log (dolphin)
 abort: unknown encoding: dolphin, please check your locale settings
 abort: decoding near 'é': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)!
 abort: branch name not in UTF-8!
--- a/tests/test-extension.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-extension.out	Thu Oct 08 01:16:32 2009 -0500
@@ -44,7 +44,7 @@
  debugextension   only debugcommands
 
 global options:
- -R --repository      repository root directory or symbolic path name
+ -R --repository      repository root directory or name of overlay bundle file
     --cwd             change working directory
  -y --noninteractive  do not prompt, assume 'yes' for any required answers
  -q --quiet           suppress output
@@ -74,7 +74,7 @@
  debugextension   only debugcommands
 
 global options:
- -R --repository      repository root directory or symbolic path name
+ -R --repository      repository root directory or name of overlay bundle file
     --cwd             change working directory
  -y --noninteractive  do not prompt, assume 'yes' for any required answers
  -q --quiet           suppress output
--- a/tests/test-gendoc	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-gendoc	Thu Oct 08 01:16:32 2009 -0500
@@ -3,10 +3,19 @@
 "$TESTDIR/hghave" rst2html || exit 80
 RST2HTML=$(which rst2html 2> /dev/null || which rst2html.py)
 
-echo "checking for syntax errors in gendoc.py"
-python $TESTDIR/../doc/gendoc.py > gendoc.txt || exit
+HGENCODING=UTF-8
+export HGENCODING
 
-# We run rst2html over the file without adding "--halt warning" to
-# make it report all errors instead of stopping on the first one.
-echo "checking for parse errors with rst2html"
-$RST2HTML gendoc.txt /dev/null
+for PO in C $TESTDIR/../i18n/*.po; do
+    LOCALE=$(basename $PO .po)
+    echo
+    echo "% extracting documentation from $LOCALE"
+    echo ".. -*- coding: utf-8 -*-" > gendoc-$LOCALE.txt
+    echo "" >> gendoc-$LOCALE.txt
+    LC_ALL=$LOCALE python $TESTDIR/../doc/gendoc.py >> gendoc-$LOCALE.txt || exit
+
+    # We run rst2html over the file without adding "--halt warning" to
+    # make it report all errors instead of stopping on the first one.
+    echo "checking for parse errors with rst2html"
+    $RST2HTML gendoc-$LOCALE.txt /dev/null
+done
--- a/tests/test-gendoc.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-gendoc.out	Thu Oct 08 01:16:32 2009 -0500
@@ -1,2 +1,30 @@
-checking for syntax errors in gendoc.py
+
+% extracting documentation from C
+checking for parse errors with rst2html
+
+% extracting documentation from da
+checking for parse errors with rst2html
+
+% extracting documentation from de
+checking for parse errors with rst2html
+
+% extracting documentation from el
+checking for parse errors with rst2html
+
+% extracting documentation from fr
 checking for parse errors with rst2html
+
+% extracting documentation from it
+checking for parse errors with rst2html
+
+% extracting documentation from ja
+checking for parse errors with rst2html
+
+% extracting documentation from pt_BR
+checking for parse errors with rst2html
+
+% extracting documentation from zh_CN
+checking for parse errors with rst2html
+
+% extracting documentation from zh_TW
+checking for parse errors with rst2html
--- a/tests/test-http	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-http	Thu Oct 08 01:16:32 2009 -0500
@@ -5,6 +5,11 @@
 hg init test
 cd test
 echo foo>foo
+mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
+echo foo>foo.d/foo
+echo bar>foo.d/bAr.hg.d/BaR
+echo bar>foo.d/baR.d.hg/bAR
+
 hg commit -A -m 1
 hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=../hg1.pid
 hg serve -p $HGPORT1 -d --pid-file=../hg2.pid
--- a/tests/test-http.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-http.out	Thu Oct 08 01:16:32 2009 -0500
@@ -1,4 +1,7 @@
 adding foo
+adding foo.d/bAr.hg.d/BaR
+adding foo.d/baR.d.hg/bAR
+adding foo.d/foo
 abort: cannot start server at ':20060':
 % clone via stream
 streaming all changes
@@ -10,31 +13,31 @@
 checking manifests
 crosschecking files in changesets and manifests
 checking files
-1 files, 1 changesets, 1 total revisions
+4 files, 1 changesets, 4 total revisions
 % try to clone via stream, should use pull instead
 requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
+added 1 changesets with 4 changes to 4 files
 updating working directory
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+4 files updated, 0 files merged, 0 files removed, 0 files unresolved
 % clone via pull
 requesting all changes
 adding changesets
 adding manifests
 adding file changes
-added 1 changesets with 1 changes to 1 files
+added 1 changesets with 4 changes to 4 files
 updating working directory
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+4 files updated, 0 files merged, 0 files removed, 0 files unresolved
 checking changesets
 checking manifests
 crosschecking files in changesets and manifests
 checking files
-1 files, 1 changesets, 1 total revisions
+4 files, 1 changesets, 4 total revisions
 adding bar
 % pull
-changegroup hook: HG_NODE=cfbd11a1fa315300a080c3de8fe36b0fc5820acf HG_SOURCE=pull HG_URL=http://localhost/ 
+changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=http://localhost/ 
 pulling from http://localhost/
 searching for changes
 adding changesets
--- a/tests/test-inotify-issue1208.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-inotify-issue1208.out	Thu Oct 08 01:16:32 2009 -0500
@@ -1,5 +1,5 @@
 % fail
-could not talk to new inotify server: No such file or directory
+abort: could not start server: File exists
 abort: could not start server: File exists
 % inserve
 % status
--- a/tests/test-keyword	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-keyword	Thu Oct 08 01:16:32 2009 -0500
@@ -48,6 +48,11 @@
 echo % cat
 cat a b
 
+echo % no kwfiles
+hg kwfiles
+echo % untracked candidates
+hg -v kwfiles --unknown
+
 echo % addremove
 hg addremove
 echo % status
@@ -162,6 +167,10 @@
 
 echo % kwfiles
 hg kwfiles
+echo % ignored files
+hg -v kwfiles --ignore
+echo % all files
+hg kwfiles --all
 
 echo % diff --rev
 hg diff --rev 1 | grep -v 'b/c'
--- a/tests/test-keyword.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-keyword.out	Thu Oct 08 01:16:32 2009 -0500
@@ -42,6 +42,9 @@
 do not process $Id:
 xxx $
 ignore $Id$
+% no kwfiles
+% untracked candidates
+k a
 % addremove
 adding a
 adding b
@@ -181,6 +184,14 @@
 % kwfiles
 a
 c
+% ignored files
+I b
+I sym
+% all files
+K a
+K c
+I b
+I sym
 % diff --rev
 diff -r ef63ca68695b c
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -400,7 +411,7 @@
 warning: conflicts during merge.
 merging m failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 % keyword stays outside conflict zone
 $Id$
 <<<<<<< local
--- a/tests/test-merge-internal-tools-pattern.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-merge-internal-tools-pattern.out	Thu Oct 08 01:16:32 2009 -0500
@@ -9,7 +9,7 @@
 created new head
 # merge using internal:fail tool
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 line 1
 line 2
 third line
--- a/tests/test-merge-tools.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-merge-tools.out	Thu Oct 08 01:16:32 2009 -0500
@@ -17,7 +17,7 @@
 warning: conflicts during merge.
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 <<<<<<< local
 revision 1
@@ -37,7 +37,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -69,7 +69,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -86,7 +86,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -103,7 +103,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -120,7 +120,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -185,7 +185,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -204,7 +204,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -223,7 +223,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -244,7 +244,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -260,7 +260,7 @@
 # hg update -C 1
 # hg merge -r 2 --config ui.merge=internal:fail
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -323,7 +323,7 @@
 # hg merge -r 2 --config ui.merge=internal:dump
 merging f
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -354,7 +354,7 @@
 merging f
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
@@ -518,7 +518,7 @@
 was merge successful (yn)? n
 merging f failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 # cat f
 revision 1
 space
--- a/tests/test-merge7.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-merge7.out	Thu Oct 08 01:16:32 2009 -0500
@@ -11,7 +11,7 @@
 warning: conflicts during merge.
 merging test.txt failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 pulling from ../test-a
 searching for changes
 adding changesets
@@ -31,7 +31,7 @@
 warning: conflicts during merge.
 merging test.txt failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 one
 <<<<<<< local
 two-point-five
--- a/tests/test-merge9.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-merge9.out	Thu Oct 08 01:16:32 2009 -0500
@@ -7,7 +7,7 @@
 merging bar failed!
 merging foo and baz to baz
 1 files updated, 1 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 U bar
 R baz
 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
@@ -15,7 +15,7 @@
 merging bar failed!
 merging baz and foo to baz
 1 files updated, 1 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 % show unresolved
 U bar
 R baz
--- a/tests/test-notify.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-notify.out	Thu Oct 08 01:16:32 2009 -0500
@@ -35,6 +35,7 @@
   diffstat = True        # add a diffstat before the diff content
   sources = serve        # notify if source of incoming changes in this list
                          # (serve == ssh or http, push, pull, bundle)
+  merge = False          # send notification for merges (default True)
   [email]
   from = user@host.com   # email address to send as if none given
   [web]
--- a/tests/test-resolve.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-resolve.out	Thu Oct 08 01:16:32 2009 -0500
@@ -4,5 +4,5 @@
 created new head
 % failing merge
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 % resolve -l, should be empty
--- a/tests/test-subrepo.out	Tue Oct 06 11:18:58 2009 +0300
+++ b/tests/test-subrepo.out	Thu Oct 08 01:16:32 2009 -0500
@@ -87,7 +87,7 @@
 warning: conflicts during merge.
 merging t failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
+use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 % should conflict