Commits

Matt Mackall  committed d118a4f Merge

merge default into stable for 2.4 code freeze

  • Participants
  • Parent commits 605fe31, d51364b
  • Branches stable
  • Tags 2.4-rc

Comments (0)

Files changed (255)

 MANIFEST.in
 patches
 mercurial/__version__.py
+mercurial/hgpythonlib.h
 mercurial.egg-info
 .DS_Store
 tags

File contrib/bash_completion

     fi
 }
 
+_hg_cmd_rebase() {
+   if [[ "$prev" = @(-s|--source|-d|--dest|-b|--base|-r|--rev) ]]; then
+       _hg_labels
+       return
+   fi
+}
+
 _hg_cmd_strip()
 {
     _hg_labels

File contrib/check-code.py

 uprefix = r"^  \$ "
 utestpats = [
   [
-    (r'^(\S|  $ ).*(\S[ \t]+|^[ \t]+)\n', "trailing whitespace on non-output"),
+    (r'^(\S.*||  [$>] .*)[ \t]\n', "trailing whitespace on non-output"),
     (uprefix + r'.*\|\s*sed[^|>\n]*\n',
      "use regex test output patterns instead of sed"),
     (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
         utestpats[i].append((p, m))
 
 utestfilters = [
+    (r"<<(\S+)((.|\n)*?\n  > \1)", rephere),
     (r"( *)(#([^\n]*\S)?)", repcomment),
 ]
 
     (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
     (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
     (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
-     r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Py2.4'),
+     r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Python 2.4'),
+    (r'(\s+)try:\n((?:\n|\1\s.*\n)*?)\1\s*yield\b.*?'
+     r'((?:\n|\1\s.*\n)+?)\1finally:',
+     'no yield inside try/finally in Python 2.4'),
     (r'.{81}', "line too long"),
     (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
     (r'[^\n]\Z', "no trailing newline"),
      'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
     (r'opener\([^)]*\).read\(',
      "use opener.read() instead"),
-    (r'BaseException', 'not in Py2.4, use Exception'),
-    (r'os\.path\.relpath', 'os.path.relpath is not in Py2.5'),
+    (r'BaseException', 'not in Python 2.4, use Exception'),
+    (r'os\.path\.relpath', 'os.path.relpath is not in Python 2.5'),
     (r'opener\([^)]*\).write\(',
      "use opener.write() instead"),
     (r'[\s\(](open|file)\([^)]*\)\.read\(',
     :f: filepath
     :logfunc: function used to report error
               logfunc(filename, linenumber, linecontent, errormessage)
-    :maxerr: number of error to display before arborting.
+    :maxerr: number of error to display before aborting.
              Set to false (default) to report all errors
 
     return True if no error is found, False otherwise.
                 p, msg = pat
                 ignore = None
 
-            # fix-up regexes for multiline searches
+            # fix-up regexes for multi-line searches
             po = p
             # \s doesn't match \n
             p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)

File contrib/lock-checker.py

+"""Extension to verify locks are obtained in the required places.
+
+This works by wrapping functions that should be surrounded by a lock
+and asserting the lock is held. Missing locks are called out with a
+traceback printed to stderr.
+
+This currently only checks store locks, not working copy locks.
+"""
+import os
+import traceback
+
+def _warnstack(ui, msg, skip=1):
+    '''issue warning with the message and the current stack, skipping the
+    skip last entries'''
+    ui.warn('%s at:\n' % msg)
+    entries = traceback.extract_stack()[:-skip]
+    fnmax = max(len(entry[0]) for entry in entries)
+    for fn, ln, func, _text in entries:
+        ui.warn(' %*s:%-4s in %s\n' % (fnmax, fn, ln, func))
+
+def _checklock(repo):
+    l = repo._lockref and repo._lockref()
+    if l is None or not l.held:
+        _warnstack(repo.ui, 'missing lock', skip=2)
+
+def reposetup(ui, repo):
+    orig = repo.__class__
+    class lockcheckrepo(repo.__class__):
+        def _writejournal(self, *args, **kwargs):
+            _checklock(self)
+            return orig._writejournal(self, *args, **kwargs)
+
+        def transaction(self, *args, **kwargs):
+            _checklock(self)
+            return orig.transaction(self, *args, **kwargs)
+
+        # TODO(durin42): kiilerix had a commented-out lock check in
+        # _writebranchcache and _writerequirements
+
+        def _tag(self, *args, **kwargs):
+            _checklock(self)
+            return orig._tag(self, *args, **kwargs)
+
+        def write(self, *args, **kwargs):
+            assert os.path.lexists(self._join('.hg/wlock'))
+            return orig.write(self, *args, **kwargs)
+
+    repo.__class__ = lockcheckrepo

File contrib/mercurial.el

 (defun hg-complete-repo (string predicate all)
   "Attempt to complete a repository name.
 We complete on either symbolic names from Mercurial's config or real
-directory names from the file system.  We do not penalise URLs."
+directory names from the file system.  We do not penalize URLs."
   (or (if all
 	  (all-completions string hg-repo-completion-table predicate)
 	(try-completion string hg-repo-completion-table predicate))

File contrib/perf.py

     timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
 
 def perffncacheload(ui, repo):
-    from mercurial import scmutil, store
-    s = store.store(set(['store','fncache']), repo.path, scmutil.opener)
+    s = repo.store
     def d():
         s.fncache._load()
     timer(d)
 
 def perffncachewrite(ui, repo):
-    from mercurial import scmutil, store
-    s = store.store(set(['store','fncache']), repo.path, scmutil.opener)
+    s = repo.store
     s.fncache._load()
     def d():
         s.fncache._dirty = True
         s.fncache.write()
     timer(d)
 
+def perffncacheencode(ui, repo):
+    s = repo.store
+    s.fncache._load()
+    def d():
+        for p in s.fncache.entries:
+            s.encode(p)
+    timer(d)
+
 def perfdiffwd(ui, repo):
     """Profile diff of working directory changes"""
     options = {
     'perfcca': (perfcca, []),
     'perffncacheload': (perffncacheload, []),
     'perffncachewrite': (perffncachewrite, []),
+    'perffncacheencode': (perffncacheencode, []),
     'perflookup': (perflookup, []),
     'perfrevrange': (perfrevrange, []),
     'perfnodelookup': (perfnodelookup, []),

File contrib/synthrepo.py

+# synthrepo.py - repo synthesis
+#
+# Copyright 2012 Facebook
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+'''synthesize structurally interesting change history
+
+This extension is useful for creating a repository with properties
+that are statistically similar to an existing repository. During
+analysis, a simple probability table is constructed from the history
+of an existing repository.  During synthesis, these properties are
+reconstructed.
+
+Properties that are analyzed and synthesized include the following:
+
+- Lines added or removed when an existing file is modified
+- Number and sizes of files added
+- Number of files removed
+- Line lengths
+- Topological distance to parent changeset(s)
+- Probability of a commit being a merge
+- Probability of a newly added file being added to a new directory
+- Interarrival time, and time zone, of commits
+
+A few obvious properties that are not currently handled realistically:
+
+- Merges are treated as regular commits with two parents, which is not
+  realistic
+- Modifications are not treated as operations on hunks of lines, but
+  as insertions and deletions of randomly chosen single lines
+- Committer ID (always random)
+- Executability of files
+- Symlinks and binary files are ignored
+'''
+
+import bisect, collections, json, os, random, time
+from mercurial import cmdutil, context, patch, scmutil, url, util
+from mercurial.i18n import _
+from mercurial.node import nullrev, nullid
+
+testedwith = 'internal'
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+
+newfile = set(('new fi', 'rename', 'copy f', 'copy t'))
+
+def zerodict():
+    return collections.defaultdict(lambda: 0)
+
+def roundto(x, k):
+    if x > k * 2:
+        return int(round(x / float(k)) * k)
+    return int(round(x))
+
+def parsegitdiff(lines):
+    filename, mar, lineadd, lineremove = None, None, zerodict(), 0
+    binary = False
+    for line in lines:
+        start = line[:6]
+        if start == 'diff -':
+            if filename:
+                yield filename, mar, lineadd, lineremove, binary
+            mar, lineadd, lineremove, binary = 'm', zerodict(), 0, False
+            filename = patch.gitre.match(line).group(1)
+        elif start in newfile:
+            mar = 'a'
+        elif start == 'GIT bi':
+            binary = True
+        elif start == 'delete':
+            mar = 'r'
+        elif start:
+            s = start[0]
+            if s == '-' and not line.startswith('--- '):
+                lineremove += 1
+            elif s == '+' and not line.startswith('+++ '):
+                lineadd[roundto(len(line) - 1, 5)] += 1
+    if filename:
+        yield filename, mar, lineadd, lineremove, binary
+
+@command('analyze',
+         [('o', 'output', [], _('write output to given file'), _('FILE')),
+          ('r', 'rev', [], _('analyze specified revisions'), _('REV'))],
+         _('hg analyze'))
+def analyze(ui, repo, *revs, **opts):
+    '''create a simple model of a repository to use for later synthesis
+
+    This command examines every changeset in the given range (or all
+    of history if none are specified) and creates a simple statistical
+    model of the history of the repository.
+
+    The model is written out to a JSON file, and can be used by
+    :hg:`synthesize` to create or augment a repository with synthetic
+    commits that have a structure that is statistically similar to the
+    analyzed repository.
+    '''
+
+    revs = list(revs)
+    revs.extend(opts['rev'])
+    if not revs:
+        revs = [':']
+
+    output = opts['output']
+    if not output:
+        output = os.path.basename(repo.root) + '.json'
+
+    if output == '-':
+        fp = sys.stdout
+    else:
+        fp = open(output, 'w')
+
+    revs = scmutil.revrange(repo, revs)
+    revs.sort()
+
+    lineschanged = zerodict()
+    children = zerodict()
+    p1distance = zerodict()
+    p2distance = zerodict()
+    linesinfilesadded = zerodict()
+    fileschanged = zerodict()
+    filesadded = zerodict()
+    filesremoved = zerodict()
+    linelengths = zerodict()
+    interarrival = zerodict()
+    parents = zerodict()
+    dirsadded = zerodict()
+    tzoffset = zerodict()
+
+    progress = ui.progress
+    _analyzing = _('analyzing')
+    _changesets = _('changesets')
+    _total = len(revs)
+
+    for i, rev in enumerate(revs):
+        progress(_analyzing, i, unit=_changesets, total=_total)
+        ctx = repo[rev]
+        pl = ctx.parents()
+        pctx = pl[0]
+        prev = pctx.rev()
+        children[prev] += 1
+        p1distance[rev - prev] += 1
+        parents[len(pl)] += 1
+        tzoffset[ctx.date()[1]] += 1
+        if len(pl) > 1:
+            p2distance[rev - pl[1].rev()] += 1
+        if prev == rev - 1:
+            lastctx = pctx
+        else:
+            lastctx = repo[rev - 1]
+        if lastctx.rev() != nullrev:
+            interarrival[roundto(ctx.date()[0] - lastctx.date()[0], 300)] += 1
+        diff = sum((d.splitlines()
+                    for d in ctx.diff(pctx, opts=dict(git=True))), [])
+        fileadds, diradds, fileremoves, filechanges = 0, 0, 0, 0
+        for filename, mar, lineadd, lineremove, binary in parsegitdiff(diff):
+            if binary:
+                continue
+            added = sum(lineadd.itervalues(), 0)
+            if mar == 'm':
+                if added and lineremove:
+                    lineschanged[roundto(added, 5), roundto(lineremove, 5)] += 1
+                    filechanges += 1
+            elif mar == 'a':
+                fileadds += 1
+                if '/' in filename:
+                    filedir = filename.rsplit('/', 1)[0]
+                    if filedir not in pctx.dirs():
+                        diradds += 1
+                linesinfilesadded[roundto(added, 5)] += 1
+            elif mar == 'r':
+                fileremoves += 1
+            for length, count in lineadd.iteritems():
+                linelengths[length] += count
+        fileschanged[filechanges] += 1
+        filesadded[fileadds] += 1
+        dirsadded[diradds] += 1
+        filesremoved[fileremoves] += 1
+
+    invchildren = zerodict()
+
+    for rev, count in children.iteritems():
+        invchildren[count] += 1
+
+    if output != '-':
+        ui.status(_('writing output to %s\n') % output)
+
+    def pronk(d):
+        return sorted(d.iteritems(), key=lambda x: x[1], reverse=True)
+
+    json.dump(dict(revs=len(revs),
+                   lineschanged=pronk(lineschanged),
+                   children=pronk(invchildren),
+                   fileschanged=pronk(fileschanged),
+                   filesadded=pronk(filesadded),
+                   linesinfilesadded=pronk(linesinfilesadded),
+                   dirsadded=pronk(dirsadded),
+                   filesremoved=pronk(filesremoved),
+                   linelengths=pronk(linelengths),
+                   parents=pronk(parents),
+                   p1distance=pronk(p1distance),
+                   p2distance=pronk(p2distance),
+                   interarrival=pronk(interarrival),
+                   tzoffset=pronk(tzoffset),
+                   ),
+              fp)
+    fp.close()
+
+@command('synthesize',
+         [('c', 'count', 0, _('create given number of commits'), _('COUNT')),
+          ('', 'dict', '', _('path to a dictionary of words'), _('FILE'))],
+         _('hg synthesize [OPTION].. DESCFILE'))
+def synthesize(ui, repo, descpath, **opts):
+    '''synthesize commits based on a model of an existing repository
+
+    The model must have been generated by :hg:`analyze`. Commits will
+    be generated randomly according to the probabilities described in
+    the model.
+
+    When synthesizing new content, commit descriptions, and user
+    names, words will be chosen randomly from a dictionary that is
+    presumed to contain one word per line. Use --dict to specify the
+    path to an alternate dictionary to use.
+    '''
+    try:
+        fp = url.open(ui, descpath)
+    except Exception, err:
+        raise util.Abort('%s: %s' % (descpath, err[0].strerror))
+    desc = json.load(fp)
+    fp.close()
+
+    def cdf(l):
+        vals, probs = zip(*sorted(l, key=lambda x: x[1], reverse=True))
+        t = float(sum(probs, 0))
+        s, cdfs = 0, []
+        for v in probs:
+            s += v
+            cdfs.append(s / t)
+        return vals, cdfs
+
+    lineschanged = cdf(desc['lineschanged'])
+    fileschanged = cdf(desc['fileschanged'])
+    filesadded = cdf(desc['filesadded'])
+    dirsadded = cdf(desc['dirsadded'])
+    filesremoved = cdf(desc['filesremoved'])
+    linelengths = cdf(desc['linelengths'])
+    parents = cdf(desc['parents'])
+    p1distance = cdf(desc['p1distance'])
+    p2distance = cdf(desc['p2distance'])
+    interarrival = cdf(desc['interarrival'])
+    linesinfilesadded = cdf(desc['linesinfilesadded'])
+    tzoffset = cdf(desc['tzoffset'])
+
+    dictfile = opts.get('dict') or '/usr/share/dict/words'
+    try:
+        fp = open(dictfile, 'rU')
+    except IOError, err:
+        raise util.Abort('%s: %s' % (dictfile, err.strerror))
+    words = fp.read().splitlines()
+    fp.close()
+
+    def pick(cdf):
+        return cdf[0][bisect.bisect_left(cdf[1], random.random())]
+
+    def makeline(minimum=0):
+        total = max(minimum, pick(linelengths))
+        c, l = 0, []
+        while c < total:
+            w = random.choice(words)
+            c += len(w) + 1
+            l.append(w)
+        return ' '.join(l)
+
+    wlock = repo.wlock()
+    lock = repo.lock()
+
+    nevertouch = set(('.hgsub', '.hgignore', '.hgtags'))
+
+    progress = ui.progress
+    _synthesizing = _('synthesizing')
+    _changesets = _('changesets')
+
+    count = int(opts['count'])
+    heads = set(map(repo.changelog.rev, repo.heads()))
+    for i in xrange(count):
+        progress(_synthesizing, i, unit=_changesets, total=count)
+
+        node = repo.changelog.node
+        revs = len(repo)
+
+        def pickhead(heads, distance):
+            if heads:
+                lheads = sorted(heads)
+                rev = revs - min(pick(distance), revs)
+                if rev < lheads[-1]:
+                    rev = lheads[bisect.bisect_left(lheads, rev)]
+                else:
+                    rev = lheads[-1]
+                return rev, node(rev)
+            return nullrev, nullid
+
+        r1 = revs - min(pick(p1distance), revs)
+        p1 = node(r1)
+
+        # the number of heads will grow without bound if we use a pure
+        # model, so artificially constrain their proliferation
+        if pick(parents) == 2 or len(heads) > random.randint(1, 20):
+            r2, p2 = pickhead(heads.difference([r1]), p2distance)
+        else:
+            r2, p2 = nullrev, nullid
+
+        pl = [p1, p2]
+        pctx = repo[r1]
+        mf = pctx.manifest()
+        mfk = mf.keys()
+        changes = {}
+        if mfk:
+            for __ in xrange(pick(fileschanged)):
+                for __ in xrange(10):
+                    fctx = pctx.filectx(random.choice(mfk))
+                    path = fctx.path()
+                    if not (path in nevertouch or fctx.isbinary() or
+                            'l' in fctx.flags()):
+                        break
+                lines = fctx.data().splitlines()
+                add, remove = pick(lineschanged)
+                for __ in xrange(remove):
+                    if not lines:
+                        break
+                    del lines[random.randrange(0, len(lines))]
+                for __ in xrange(add):
+                    lines.insert(random.randint(0, len(lines)), makeline())
+                path = fctx.path()
+                changes[path] = context.memfilectx(path,
+                                                   '\n'.join(lines) + '\n')
+            for __ in xrange(pick(filesremoved)):
+                path = random.choice(mfk)
+                for __ in xrange(10):
+                    path = random.choice(mfk)
+                    if path not in changes:
+                        changes[path] = None
+                        break
+        if filesadded:
+            dirs = list(pctx.dirs())
+            dirs.append('')
+        for __ in xrange(pick(filesadded)):
+            path = [random.choice(dirs)]
+            if pick(dirsadded):
+                path.append(random.choice(words))
+            path.append(random.choice(words))
+            path = '/'.join(filter(None, path))
+            data = '\n'.join(makeline()
+                             for __ in xrange(pick(linesinfilesadded))) + '\n'
+            changes[path] = context.memfilectx(path, data)
+        def filectxfn(repo, memctx, path):
+            data = changes[path]
+            if data is None:
+                raise IOError
+            return data
+        if not changes:
+            continue
+        if revs:
+            date = repo['tip'].date()[0] + pick(interarrival)
+        else:
+            date = time.time() - (86400 * count)
+        user = random.choice(words) + '@' + random.choice(words)
+        mc = context.memctx(repo, pl, makeline(minimum=2),
+                            sorted(changes.iterkeys()),
+                            filectxfn, user, '%d %d' % (date, pick(tzoffset)))
+        newnode = mc.commit()
+        heads.add(repo.changelog.rev(newnode))
+        heads.discard(r1)
+        heads.discard(r2)
+
+    lock.release()
+    wlock.release()

File contrib/vim/hgcommand.vim

 "
 " You still can read the documentation at the end of this file. Locate it by
 " searching the "hgcommand-contents" string (and set ft=help to have
-" appropriate syntaxic coloration).
+" appropriate syntactic coloration).
 
 " Section: Plugin header {{{1
 
     " Protect against case and backslash issues in Windows.
     let autoPattern = '\c' . messageFileName
 
-    " Ensure existance of group
+    " Ensure existence of group
     augroup HGCommit
     augroup END
 
 
                                                  *hgcommand-mappings-override*
 
-   The default mappings can be overriden by user-provided instead by mapping
+   The default mappings can be overridden by user-provided instead by mapping
    to <Plug>CommandName.  This is especially useful when these mappings
    collide with other existing mappings (vim will warn of this during plugin
    initialization, but will not clobber the existing mappings).

File contrib/vim/patchreview.vim

 "
 "   0.2.1 - Minor temp directory autodetection logic and cleanup
 "
-"   0.2 - Removed the need for filterdiff by implemeting it in pure vim script
+"   0.2 - Removed the need for filterdiff by implementing it in pure vim script
 "       - Added DiffReview command for reverse (changed repository to
 "         pristine state) reviews.
 "         (PatchReview does pristine repository to patch review)
 "   3) Optional (but recommended for speed)
 "
 "      Install patchutils ( http://cyberelk.net/tim/patchutils/ ) for your
-"      OS. For windows it is availble from Cygwin
+"      OS. For windows it is available from Cygwin
 "
 "         http://www.cygwin.com
 "

File contrib/win32/hgwebdir_wsgi.py

 #   On 64-bit systems, make sure it's assigned a 32-bit app pool.
 #
 # - In the application, setup a wildcard script handler mapping of type
-#   IpsapiModule with the shim dll as its executable. This file MUST reside
+#   IsapiModule with the shim dll as its executable. This file MUST reside
 #   in the same directory as the shim. Remove all other handlers, if you wish.
 #
 # - Make sure the ISAPI and CGI restrictions (configured globally on the

File contrib/wix/templates.wxs

           <File Name="map-cmdline.default" />
           <File Name="map-cmdline.bisect" />
           <File Name="map-cmdline.xml" />
-          <File Name="template-vars.txt" />
         </Component>
 
         <Directory Id="templates.atomdir" Name="atom">

File contrib/zsh_completion

     'urls:URL:_hg_urls'
 }
 
+_hg_add_help_topics=(
+    config dates diffs environment extensions filesets glossary hgignore hgweb
+    merge-tools multirevs obsolescence patterns phases revisions revsets
+    subrepos templating urls
+)
+
+_hg_help_topics() {
+    local topics
+    (( $#_hg_cmd_list )) || _hg_get_commands
+    topics=($_hg_cmd_list $_hg_add_help_topics)
+    _describe -t help_topics 'help topics' topics
+}
+
 # Common options
 _hg_global_opts=(
     '(--repository -R)'{-R+,--repository}'[repository root directory]:repository:_files -/'
   '*'{-I+,--include}'[include names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/'
   '*'{-X+,--exclude}'[exclude names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/')
 
+_hg_clone_opts=(
+  $_hg_remote_opts
+  '(--noupdate -U)'{-U,--noupdate}'[do not update the new working directory]'
+  '--pull[use pull protocol to copy metadata]'
+  '--uncompressed[use uncompressed transfer (fast over LAN)]')
+
+_hg_date_user_opts=(
+  '(--currentdate -D)'{-D,--currentdate}'[record the current date as commit date]'
+  '(--currentuser -U)'{-U,--currentuser}'[record the current user as committer]'
+  '(--date -d)'{-d+,--date}'[record the specified date as commit date]:date:'
+  '(--user -u)'{-u+,--user}'[record the specified user as committer]:user:')
+
+_hg_gitlike_opts=(
+  '(--git -g)'{-g,--git}'[use git extended diff format]')
+
 _hg_diff_opts=(
+  $_hg_gitlike_opts
   '(--text -a)'{-a,--text}'[treat all files as text]'
-  '(--git -g)'{-g,--git}'[use git extended diff format]'
-  "--nodates[omit dates from diff headers]")
+  '--nodates[omit dates from diff headers]')
+
+_hg_mergetool_opts=(
+  '(--tool -t)'{-t+,--tool}'[specify merge tool]:tool:')
 
 _hg_dryrun_opts=(
   '(--dry-run -n)'{-n,--dry-run}'[do not perform actions, just print output]')
 
+_hg_ignore_space_opts=(
+  '(--ignore-all-space -w)'{-w,--ignore-all-space}'[ignore white space when comparing lines]'
+  '(--ignore-space-change -b)'{-b,--ignore-space-change}'[ignore changes in the amount of white space]'
+  '(--ignore-blank-lines -B)'{-B,--ignore-blank-lines}'[ignore changes whose lines are all blank]')
+
 _hg_style_opts=(
   '--style[display using template map file]:'
   '--template[display with template]:')
 
+_hg_log_opts=(
+  $_hg_global_opts $_hg_style_opts $_hg_gitlike_opts
+  '(--limit -l)'{-l+,--limit}'[limit number of changes displayed]:'
+  '(--no-merges -M)'{-M,--no-merges}'[do not show merges]'
+  '(--patch -p)'{-p,--patch}'[show patch]'
+  '--stat[output diffstat-style summary of changes]'
+)
+
 _hg_commit_opts=(
   '(-m --message -l --logfile --edit -e)'{-e,--edit}'[edit commit message]'
   '(-e --edit -l --logfile --message -m)'{-m+,--message}'[use <text> as commit message]:message:'
   '(--ssh -e)'{-e+,--ssh}'[specify ssh command to use]:'
   '--remotecmd[specify hg command to run on the remote side]:')
 
+_hg_branch_bmark_opts=(
+  '(--bookmark -B)'{-B+,--bookmark}'[specify bookmark(s)]:bookmark:_hg_bookmarks'
+  '(--branch -b)'{-b+,--branch}'[specify branch(es)]:branch:_hg_branches'
+)
+
+_hg_subrepos_opts=(
+  '(--subrepos -S)'{-S,--subrepos}'[recurse into subrepositories]')
+
 _hg_cmd() {
   _call_program hg HGPLAIN=1 hg "$_hg_cmd_globals[@]" "$@" 2> /dev/null
 }
 
 _hg_cmd_add() {
-  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts $_hg_subrepos_opts \
   '*:unknown files:_hg_unknown'
 }
 
 }
 
 _hg_cmd_archive() {
-  _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_subrepos_opts \
   '--no-decode[do not pass files through decoders]' \
   '(--prefix -p)'{-p+,--prefix}'[directory prefix for files in archive]:' \
   '(--rev -r)'{-r+,--rev}'[revision to distribute]:revision:_hg_labels' \
 }
 
 _hg_cmd_backout() {
-  _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_mergetool_opts $_hg_pat_opts \
     '--merge[merge with old dirstate parent after backout]' \
     '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \
     '--parent[parent to choose when backing out merge]' \
 _hg_cmd_bisect() {
   _arguments -s -w : $_hg_global_opts \
   '(-)'{-r,--reset}'[reset bisect state]' \
+  '(--extend -e)'{-e,--extend}'[extend the bisect range]' \
   '(--good -g --bad -b --skip -s --reset -r)'{-g,--good}'[mark changeset good]'::revision:_hg_labels \
   '(--good -g --bad -b --skip -s --reset -r)'{-b,--bad}'[mark changeset bad]'::revision:_hg_labels \
   '(--good -g --bad -b --skip -s --reset -r)'{-s,--skip}'[skip testing changeset]' \
 _hg_cmd_bookmarks() {
   _arguments -s -w : $_hg_global_opts \
   '(--force -f)'{-f,--force}'[force]' \
+  '(--inactive -i)'{-i,--inactive}'[mark a bookmark inactive]' \
   '(--rev -r --delete -d --rename -m)'{-r+,--rev}'[revision]:revision:_hg_labels' \
   '(--rev -r --delete -d --rename -m)'{-d,--delete}'[delete a given bookmark]' \
   '(--rev -r --delete -d --rename -m)'{-m+,--rename}'[rename a given bookmark]:bookmark:_hg_bookmarks' \
 
 _hg_cmd_branches() {
   _arguments -s -w : $_hg_global_opts \
-  '(--active -a)'{-a,--active}'[show only branches that have unmerge heads]'
+  '(--active -a)'{-a,--active}'[show only branches that have unmerge heads]' \
+  '(--closed -c)'{-c,--closed}'[show normal and closed branches]'
 }
 
 _hg_cmd_bundle() {
   _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
   '(--force -f)'{-f,--force}'[run even when remote repository is unrelated]' \
   '(2)*--base[a base changeset to specify instead of a destination]:revision:_hg_labels' \
+  '(--branch -b)'{-b+,--branch}'[a specific branch to bundle]' \
+  '(--rev -r)'{-r+,--rev}'[changeset(s) to bundle]:' \
+  '--all[bundle all changesets in the repository]' \
   ':output file:_files' \
   ':destination repository:_files -/'
 }
   _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
   '(--output -o)'{-o+,--output}'[print output to file with formatted name]:filespec:' \
   '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_labels' \
+  '--decode[apply any matching decode filter]' \
   '*:file:_hg_files'
 }
 
 _hg_cmd_clone() {
-  _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
-  '(--noupdate -U)'{-U,--noupdate}'[do not update the new working directory]' \
+  _arguments -s -w : $_hg_global_opts $_hg_clone_opts \
   '(--rev -r)'{-r+,--rev}'[a changeset you would like to have after cloning]:' \
-  '--uncompressed[use uncompressed transfer (fast over LAN)]' \
+  '(--updaterev -u)'{-u+,--updaterev}'[revision, tag or branch to check out]' \
+  '(--branch -b)'{-b+,--branch}'[clone only the specified branch]' \
   ':source repository:_hg_remote' \
   ':destination:_hg_clone_dest'
 }
 
 _hg_cmd_commit() {
-  _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_subrepos_opts \
   '(--addremove -A)'{-A,--addremove}'[mark new/missing files as added/removed before committing]' \
   '(--message -m)'{-m+,--message}'[use <text> as commit message]:text:' \
   '(--logfile -l)'{-l+,--logfile}'[read commit message from <file>]:log file:_files -g \*.txt' \
   '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \
   '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \
   '--amend[amend the parent of the working dir]' \
+  '--close-branch[mark a branch as closed]' \
   '*:file:_hg_files'
 }
 
 
 _hg_cmd_diff() {
   typeset -A opt_args
-  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_diff_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_diff_opts $_hg_ignore_space_opts \
+                     $_hg_pat_opts $_hg_subrepos_opts \
   '*'{-r,--rev}'+[revision]:revision:_hg_revrange' \
   '(--show-function -p)'{-p,--show-function}'[show which function each change is in]' \
-  '(--ignore-all-space -w)'{-w,--ignore-all-space}'[ignore white space when comparing lines]' \
-  '(--ignore-space-change -b)'{-b,--ignore-space-change}'[ignore changes in the amount of white space]' \
-  '(--ignore-blank-lines -B)'{-B,--ignore-blank-lines}'[ignore changes whose lines are all blank]' \
+  '(--change -c)'{-c,--change}'[change made by revision]' \
+  '(--text -a)'{-a,--text}'[treat all files as text]' \
+  '--reverse[produce a diff that undoes the changes]' \
+  '(--unified -U)'{-U,--unified}'[number of lines of context to show]' \
+  '--stat[output diffstat-style summary of changes]' \
   '*:file:->diff_files'
 
   if [[ $state == 'diff_files' ]]
   _arguments -s -w : $_hg_global_opts $_hg_diff_opts \
   '(--outout -o)'{-o+,--output}'[print output to file with formatted name]:filespec:' \
   '--switch-parent[diff against the second parent]' \
+  '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_labels' \
   '*:revision:_hg_labels'
 }
 
+_hg_cmd_forget() {
+  _arguments -s -w : $_hg_global_opts \
+  '*:file:_hg_files'
+}
+
 _hg_cmd_graft() {
-  _arguments -s -w : $_hg_global_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_dryrun_opts \
+                     $_hg_date_user_opts $_hg_mergetool_opts \
   '(--continue -c)'{-c,--continue}'[resume interrupted graft]' \
   '(--edit -e)'{-e,--edit}'[invoke editor on commit messages]' \
   '--log[append graft info to log message]' \
-  '(--currentdate -D)'{-D,--currentdate}'[record the current date as commit date]' \
-  '(--currentuser -U)'{-U,--currentuser}'[record the current user as committer]' \
-  '(--date -d)'{-d,--date}'[record the specified date as commit date]' \
-  '(--user -u)'{-u,--user}'[record the specified user as committer]' \
-  '(--tool -t)'{-t,--tool}'[specify merge tool]' \
-  '(--dry-run -n)'{-n,--dry-run}'[do not perform actions, just print output]' \
   '*:revision:_hg_labels'
 }
 
   '(--line-number -n)'{-n,--line-number}'[print matching line numbers]' \
   '*'{-r+,--rev}'[search in given revision range]:revision:_hg_revrange' \
   '(--user -u)'{-u,--user}'[print user who committed change]' \
+  '(--date -d)'{-d,--date}'[print date of a changeset]' \
   '1:search pattern:' \
   '*:files:_hg_files'
 }
 
 _hg_cmd_heads() {
   _arguments -s -w : $_hg_global_opts $_hg_style_opts \
+  '(--topo -t)'{-t,--topo}'[show topological heads only]' \
+  '(--closed -c)'{-c,--closed}'[show normal and closed branch heads]' \
   '(--rev -r)'{-r+,--rev}'[show only heads which are descendants of rev]:revision:_hg_labels'
 }
 
 _hg_cmd_help() {
   _arguments -s -w : $_hg_global_opts \
-  '*:mercurial command:_hg_commands'
+  '(--extension -e)'{-e,--extension}'[show only help for extensions]' \
+  '(--command -c)'{-c,--command}'[show only help for commands]' \
+  '(--keyword -k)'{-k+,--keyword}'[show topics matching keyword]' \
+  '*:mercurial help topic:_hg_help_topics'
 }
 
 _hg_cmd_identify() {
-  _arguments -s -w : $_hg_global_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
   '(--rev -r)'{-r+,--rev}'[identify the specified rev]:revision:_hg_labels' \
   '(--num -n)'{-n+,--num}'[show local revision number]' \
   '(--id -i)'{-i+,--id}'[show global revision id]' \
   '(--branch -b)'{-b+,--branch}'[show branch]' \
+  '(--bookmark -B)'{-B+,--bookmark}'[show bookmarks]' \
   '(--tags -t)'{-t+,--tags}'[show tags]'
 }
 
 _hg_cmd_import() {
-  _arguments -s -w : $_hg_global_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_commit_opts \
   '(--strip -p)'{-p+,--strip}'[directory strip option for patch (default: 1)]:count:' \
-  '(--message -m)'{-m+,--message}'[use <text> as commit message]:text:' \
   '(--force -f)'{-f,--force}'[skip check for outstanding uncommitted changes]' \
   '--bypass[apply patch without touching the working directory]' \
+  '--no-commit[do not commit, just update the working directory]' \
+  '--exact[apply patch to the nodes from which it was generated]' \
+  '--import-branch[use any branch information in patch (implied by --exact)]' \
+  '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \
+  '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \
+  '(--similarity -s)'{-s+,--similarity}'[guess renamed files by similarity (0<=s<=100)]:' \
   '*:patch:_files'
 }
 
 _hg_cmd_incoming() {
-  _arguments -s -w : $_hg_global_opts $_hg_remote_opts $_hg_style_opts \
-  '(--no-merges -M)'{-M,--no-merges}'[do not show merge revisions]' \
+  _arguments -s -w : $_hg_log_opts $_hg_branch_bmark_opts $_hg_remote_opts \
+                     $_hg_subrepos_opts \
   '(--force -f)'{-f,--force}'[run even when the remote repository is unrelated]' \
-  '(--patch -p)'{-p,--patch}'[show patch]' \
-  '(--rev -r)'{-r+,--rev}'[a specific revision up to which you would like to pull]:revision:_hg_tags' \
+  '(--rev -r)'{-r+,--rev}'[a specific revision up to which you would like to pull]:revision:_hg_labels' \
   '(--newest-first -n)'{-n,--newest-first}'[show newest record first]' \
   '--bundle[file to store the bundles into]:bundle file:_files' \
   ':source:_hg_remote'
 }
 
 _hg_cmd_log() {
-  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_style_opts \
+  _arguments -s -w : $_hg_log_opts $_hg_pat_opts \
   '(--follow --follow-first -f)'{-f,--follow}'[follow changeset or history]' \
   '(-f --follow)--follow-first[only follow the first parent of merge changesets]' \
   '(--copies -C)'{-C,--copies}'[show copied files]' \
   '(--keyword -k)'{-k+,--keyword}'[search for a keyword]:' \
-  '(--limit -l)'{-l+,--limit}'[limit number of changes displayed]:' \
   '*'{-r,--rev}'[show the specified revision or range]:revision:_hg_revrange' \
-  '(--no-merges -M)'{-M,--no-merges}'[do not show merges]' \
   '(--only-merges -m)'{-m,--only-merges}'[show only merges]' \
-  '(--patch -p)'{-p,--patch}'[show patch]' \
   '(--prune -P)'{-P+,--prune}'[do not display revision or any of its ancestors]:revision:_hg_labels' \
+  '(--graph -G)'{-G+,--graph}'[show the revision DAG]' \
   '(--branch -b)'{-b+,--branch}'[show changesets within the given named branch]:branch:_hg_branches' \
+  '(--user -u)'{-u+,--user}'[revisions committed by user]:user:' \
+  '(--date -d)'{-d+,--date}'[show revisions matching date spec]:date:' \
   '*:files:_hg_files'
 }
 
 _hg_cmd_manifest() {
   _arguments -s -w : $_hg_global_opts \
   '--all[list files from all revisions]' \
+  '(--rev -r)'{-r+,--rev}'[revision to display]:revision:_hg_labels' \
   ':revision:_hg_labels'
 }
 
 _hg_cmd_merge() {
-  _arguments -s -w : $_hg_global_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_mergetool_opts \
   '(--force -f)'{-f,--force}'[force a merge with outstanding changes]' \
   '(--rev -r 1)'{-r,--rev}'[revision to merge]:revision:_hg_mergerevs' \
   '(--preview -P)'{-P,--preview}'[review revisions to merge (no merge is performed)]' \
-  '(--tool -t)'{-t,--tool}'[specify merge tool]' \
   ':revision:_hg_mergerevs'
 }
 
 _hg_cmd_outgoing() {
-  _arguments -s -w : $_hg_global_opts $_hg_remote_opts $_hg_style_opts \
-  '(--no-merges -M)'{-M,--no-merges}'[do not show merge revisions]' \
+  _arguments -s -w : $_hg_log_opts $_hg_branch_bmark_opts $_hg_remote_opts \
+                     $_hg_subrepos_opts \
   '(--force -f)'{-f,--force}'[run even when the remote repository is unrelated]' \
-  '(--patch -p)'{-p,--patch}'[show patch]' \
-  '(--rev -r)'{-r+,--rev}'[a specific revision you would like to push]' \
+  '*'{-r,--rev}'[a specific revision you would like to push]:revision:_hg_revrange' \
   '(--newest-first -n)'{-n,--newest-first}'[show newest record first]' \
   ':destination:_hg_remote'
 }
 }
 
 _hg_cmd_pull() {
-  _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_branch_bmark_opts $_hg_remote_opts \
   '(--force -f)'{-f,--force}'[run even when the remote repository is unrelated]' \
   '(--update -u)'{-u,--update}'[update to new tip if changesets were pulled]' \
   '(--rev -r)'{-r+,--rev}'[a specific revision up to which you would like to pull]:revision:' \
 }
 
 _hg_cmd_push() {
-  _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_branch_bmark_opts $_hg_remote_opts \
   '(--force -f)'{-f,--force}'[force push]' \
   '(--rev -r)'{-r+,--rev}'[a specific revision you would like to push]:revision:_hg_labels' \
+  '--new-branch[allow pushing a new branch]' \
   ':destination:_hg_remote'
 }
 
   local context state line
   typeset -A opt_args
 
-  _arguments -s -w : $_hg_global_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_mergetool_opts $_hg_pat_opts \
+  '(--all -a)'{-a,--all}'[select all unresolved files]' \
+  '(--no-status -n)'{-n,--no-status}'[hide status prefix]' \
   '(--list -l --mark -m --unmark -u)'{-l,--list}'[list state of files needing merge]:*:merged files:->resolve_files' \
   '(--mark -m --list -l --unmark -u)'{-m,--mark}'[mark files as resolved]:*:unresolved files:_hg_unresolved' \
   '(--unmark -u --list -l --mark -m)'{-u,--unmark}'[unmark files as resolved]:*:resolved files:_hg_resolved' \
   '(--all -a :)'{-a,--all}'[revert all changes when no arguments given]' \
   '(--rev -r)'{-r+,--rev}'[revision to revert to]:revision:_hg_labels' \
   '(--no-backup -C)'{-C,--no-backup}'[do not save backup copies of files]' \
+  '(--date -d)'{-d+,--date}'[tipmost revision matching date]:date code:' \
   '*:file:->diff_files'
 
   if [[ $state == 'diff_files' ]]
   fi
 }
 
+_hg_cmd_rollback() {
+  _arguments -s -w : $_hg_global_opts $_hg_dryrun_opts \
+  '(--force -f)'{-f,--force}'[ignore safety measures]' \
+}
+
 _hg_cmd_serve() {
   _arguments -s -w : $_hg_global_opts \
   '(--accesslog -A)'{-A+,--accesslog}'[name of access log file]:log file:_files' \
   '(--daemon -d)'{-d,--daemon}'[run server in background]' \
   '(--port -p)'{-p+,--port}'[listen port]:listen port:' \
   '(--address -a)'{-a+,--address}'[interface address]:interface address:' \
+  '--prefix[prefix path to serve from]:directory:_files' \
   '(--name -n)'{-n+,--name}'[name to show in web pages]:repository name:' \
+  '--web-conf[name of the hgweb config file]:webconf_file:_files' \
+  '--pid-file[name of file to write process ID to]:pid_file:_files' \
+  '--cmdserver[cmdserver mode]:mode:' \
   '(--templates -t)'{-t,--templates}'[web template directory]:template dir:_files -/' \
   '--style[web template style]:style' \
   '--stdio[for remote clients]' \
+  '--certificate[certificate file]:cert_file:_files' \
   '(--ipv6 -6)'{-6,--ipv6}'[use IPv6 in addition to IPv4]'
 }
 
 }
 
 _hg_cmd_status() {
-  _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_subrepos_opts \
   '(--all -A)'{-A,--all}'[show status of all files]' \
   '(--modified -m)'{-m,--modified}'[show only modified files]' \
   '(--added -a)'{-a,--added}'[show only added files]' \
   '(--copies -C)'{-C,--copies}'[show source of copied files]' \
   '(--print0 -0)'{-0,--print0}'[end filenames with NUL, for use with xargs]' \
   '--rev[show difference from revision]:revision:_hg_labels' \
+  '--change[list the changed files of a revision]:revision:_hg_labels' \
   '*:files:_files'
 }
 
   '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \
   '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \
   '(--rev -r)'{-r+,--rev}'[revision to tag]:revision:_hg_labels' \
+  '(--force -f)'{-f,--force}'[force tag]' \
+  '--remove[remove a tag]' \
+  '(--edit -e)'{-e,--edit}'[edit commit message]' \
   ':tag name:'
 }
 
 _hg_cmd_tip() {
-  _arguments -s -w : $_hg_global_opts $_hg_style_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_gitlike_opts $_hg_style_opts \
   '(--patch -p)'{-p,--patch}'[show patch]'
 }
 
   _arguments -s -w : $_hg_global_opts \
   '(--clean -C)'{-C,--clean}'[overwrite locally modified files]' \
   '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_labels' \
+  '(--check -c)'{-c,--check}'[update across branches if no uncommitted changes]' \
+  '(--date -d)'{-d+,--date}'[tipmost revision matching date]' \
   ':revision:_hg_labels'
 }
 
   '(--summary -s)'{-s,--summary}'[print first line of patch header]')
 
 _hg_cmd_qapplied() {
-  _arguments -s -w : $_hg_global_opts $_hg_qseries_opts
+  _arguments -s -w : $_hg_global_opts $_hg_qseries_opts \
+  '(--last -1)'{-1,--last}'[show only the preceding applied patch]' \
+  '*:patch:_hg_qapplied'
+}
+
+_hg_cmd_qclone() {
+  _arguments -s -w : $_hg_global_opts $_hg_remote_opts $_hg_clone_opts \
+  '(--patches -p)'{-p+,--patches}'[location of source patch repository]' \
+  ':source repository:_hg_remote' \
+  ':destination:_hg_clone_dest'
 }
 
 _hg_cmd_qdelete() {
 }
 
 _hg_cmd_qdiff() {
-  _arguments -s -w : $_hg_global_opts $_hg_pat_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_diff_opts \
+                     $_hg_ignore_space_opts \
   '*:pattern:_hg_files'
 }
 
 _hg_cmd_qfold() {
   _arguments -s -w : $_hg_global_opts $_h_commit_opts \
   '(--keep,-k)'{-k,--keep}'[keep folded patch files]' \
+  '(--force -f)'{-f,--force}'[overwrite any local changes]' \
+  '--no-backup[do not save backup copies of files]' \
   '*:unapplied patch:_hg_qunapplied'
 }
 
 _hg_cmd_qgoto() {
   _arguments -s -w : $_hg_global_opts \
   '(--force -f)'{-f,--force}'[overwrite any local changes]' \
+  '--keep-changes[tolerate non-conflicting local changes]' \
   ':patch:_hg_qseries'
 }
 
 }
 
 _hg_cmd_qimport() {
-  _arguments -s -w : $_hg_global_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_gitlike_opts \
   '(--existing -e)'{-e,--existing}'[import file in patch dir]' \
   '(--name -n 2)'{-n+,--name}'[patch file name]:name:' \
   '(--force -f)'{-f,--force}'[overwrite existing files]' \
   '*'{-r+,--rev}'[place existing revisions under mq control]:revision:_hg_revrange' \
+  '(--push -P)'{-P,--push}'[qpush after importing]' \
   '*:patch:_files'
 }
 
 _hg_cmd_qnew() {
-  _arguments -s -w : $_hg_global_opts $_hg_commit_opts \
-  '(--force -f)'{-f,--force}'[import uncommitted changes into patch]' \
+  _arguments -s -w : $_hg_global_opts $_hg_commit_opts $_hg_date_user_opts $_hg_gitlike_opts \
   ':patch:'
 }
 
 _hg_cmd_qpop() {
   _arguments -s -w : $_hg_global_opts \
   '(--all -a :)'{-a,--all}'[pop all patches]' \
-  '(--name -n)'{-n+,--name}'[queue name to pop]:' \
   '(--force -f)'{-f,--force}'[forget any local changes]' \
+  '--keep-changes[tolerate non-conflicting local changes]' \
+  '--no-backup[do not save backup copies of files]' \
   ':patch:_hg_qapplied'
 }
 
   _arguments -s -w : $_hg_global_opts \
   '(--all -a :)'{-a,--all}'[apply all patches]' \
   '(--list -l)'{-l,--list}'[list patch name in commit text]' \
-  '(--merge -m)'{-m+,--merge}'[merge from another queue]:' \
-  '(--name -n)'{-n+,--name}'[merge queue name]:' \
   '(--force -f)'{-f,--force}'[apply if the patch has rejects]' \
   '(--exact -e)'{-e,--exact}'[apply the target patch to its recorded parent]' \
   '--move[reorder patch series and apply only the patch]' \
+  '--keep-changes[tolerate non-conflicting local changes]' \
+  '--no-backup[do not save backup copies of files]' \
   ':patch:_hg_qunapplied'
 }
 
 _hg_cmd_qrefresh() {
-  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_commit_opts \
-  '(--git -g)'{-g,--git}'[use git extended diff format]' \
+  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_commit_opts $_hg_gitlike_opts \
   '(--short -s)'{-s,--short}'[short refresh]' \
   '*:files:_hg_files'
 }
 
 _hg_cmd_qrename() {
   _arguments -s -w : $_hg_global_opts \
-  ':patch:_hg_qseries' \
+  ':patch:_hg_qunapplied' \
   ':destination:'
 }
 
 }
 
 _hg_cmd_qunapplied() {
-  _arguments -s -w : $_hg_global_opts $_hg_qseries_opts
+  _arguments -s -w : $_hg_global_opts $_hg_qseries_opts \
+  '(--first -1)'{-1,--first}'[show only the first patch]'
 }
 
 _hg_cmd_qtop() {
 
 _hg_cmd_strip() {
   _arguments -s -w : $_hg_global_opts \
-  '(--force -f)'{-f,--force}'[force multi-head removal]' \
-  '(--backup -b)'{-b,--backup}'[bundle unrelated changesets]' \
-  '(--nobackup -n)'{-n,--nobackup}'[no backups]' \
+  '(--force -f)'{-f,--force}'[force removal, discard uncommitted changes, no backup]' \
+  '(--no-backup -n)'{-n,--no-backup}'[no backups]' \
+  '(--keep -k)'{-k,--keep}'[do not modify working copy during strip]' \
+  '(--bookmark -B)'{-B+,--bookmark}'[remove revs only reachable from given bookmark]:bookmark:_hg_bookmarks' \
+  '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_labels' \
   ':revision:_hg_labels'
 }
 
 # Patchbomb
 _hg_cmd_email() {
-  _arguments -s -w : $_hg_global_opts $_hg_remote_opts \
-  '(--git -g)'{-g,--git}'[use git extended diff format]' \
+  _arguments -s -w : $_hg_global_opts $_hg_remote_opts $_hg_gitlike_opts \
   '--plain[omit hg patch header]' \
   '--body[send patches as inline message text (default)]' \
   '(--outgoing -o)'{-o,--outgoing}'[send changes not found in the target repository]' \
 
 # Rebase
 _hg_cmd_rebase() {
-  _arguments -s -w : $_hg_global_opts \
+  _arguments -s -w : $_hg_global_opts $_hg_commit_opts $_hg_mergetool_opts \
   '*'{-r,--rev}'[rebase these revisions]:revision:_hg_revrange' \
-  '(--source -s)'{-s,--source}'[rebase from the specified changeset]:revision:_hg_labels' \
-  '(--base -b)'{-b,--base}'[rebase from the base of the specified changeset]:revision:_hg_labels' \
-  '(--dest -d)'{-d,--dest}'[rebase onto the specified changeset]' \
+  '(--source -s)'{-s+,--source}'[rebase from the specified changeset]:revision:_hg_labels' \
+  '(--base -b)'{-b+,--base}'[rebase from the base of the specified changeset]:revision:_hg_labels' \
+  '(--dest -d)'{-d+,--dest}'[rebase onto the specified changeset]:revision:_hg_labels' \
   '--collapse[collapse the rebased changeset]' \
-  '(--message -m)'{-m+,--message}'[use <text> as collapse commit message]:text:' \
-  '(--edit -e)'{-e,--edit}'[invoke editor on commit messages]' \
-  '(--logfile -l)'{-l+,--logfile}'[read collapse commit message from <file>]:log file:_files -g \*.txt' \
   '--keep[keep original changeset]' \
   '--keepbranches[keep original branch name]' \
-  '(--tool -t)'{-t,--tool}'[specify merge tool]' \
   '(--continue -c)'{-c,--continue}'[continue an interrupted rebase]' \
   '(--abort -a)'{-a,--abort}'[abort an interrupted rebase]' \
 }
 
+# Record
+_hg_cmd_record() {
+  _arguments -s -w : $_hg_global_opts $_hg_commit_opts $_hg_pat_opts \
+                     $_hg_ignore_space_opts $_hg_subrepos_opts \
+  '(--addremove -A)'{-A,--addremove}'[mark new/missing files as added/removed before committing]' \
+  '--close-branch[mark a branch as closed, hiding it from the branch list]' \
+  '--amend[amend the parent of the working dir]' \
+  '(--date -d)'{-d+,--date}'[record the specified date as commit date]:date:' \
+  '(--user -u)'{-u+,--user}'[record the specified user as committer]:user:'
+}
+
+_hg_cmd_qrecord() {
+  _arguments -s -w : $_hg_global_opts $_hg_commit_opts $_hg_date_user_opts $_hg_gitlike_opts \
+                     $_hg_pat_opts $_hg_ignore_space_opts $_hg_subrepos_opts
+}
+
+# Convert
+_hg_cmd_convert() {
+_arguments -s -w : $_hg_global_opts \
+  '(--source-type -s)'{-s,--source-type}'[source repository type]' \
+  '(--dest-type -d)'{-d,--dest-type}'[destination repository type]' \
+  '(--rev -r)'{-r+,--rev}'[import up to target revision]:revision:' \
+  '(--authormap -A)'{-A+,--authormap}'[remap usernames using this file]:file:_files' \
+  '--filemap[remap file names using contents of file]:file:_files' \
+  '--splicemap[splice synthesized history into place]:file:_files' \
+  '--branchmap[change branch names while converting]:file:_files' \
+  '--branchsort[try to sort changesets by branches]' \
+  '--datesort[try to sort changesets by date]' \
+  '--sourcesort[preserve source changesets order]'
+}
+
+# Graphlog
+_hg_cmd_glog() {
+  _hg_cmd_log $@
+}
+
+# Purge
+_hg_cmd_purge() {
+  _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_subrepos_opts \
+  '(--abort-on-err -a)'{-a,--abort-on-err}'[abort if an error occurs]' \
+  '--all[purge ignored files too]' \
+  '(--print -p)'{-p,--print}'[print filenames instead of deleting them]' \
+  '(--print0 -0)'{-0,--print0}'[end filenames with NUL, for use with xargs (implies -p/--print)]'
+}
+
 _hg "$@"

File doc/check-seclevel.py

+#!/usr/bin/env python
+#
+# checkseclevel - checking section title levels in each online help documents
+
+import sys, os
+import optparse
+
+# 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.commands import table
+from mercurial.help import helptable
+from mercurial import extensions
+from mercurial import minirst
+from mercurial import util
+
+_verbose = False
+
+def verbose(msg):
+    if _verbose:
+        print msg
+
+def error(msg):
+    sys.stderr.write('%s\n' % msg)
+
+level2mark = ['"', '=', '-', '.', '#']
+reservedmarks = ['"']
+
+mark2level = {}
+for m, l in zip(level2mark, xrange(len(level2mark))):
+    if m not in reservedmarks:
+        mark2level[m] = l
+
+initlevel_topic = 0
+initlevel_cmd = 1
+initlevel_ext = 1
+initlevel_ext_cmd = 3
+
+def showavailables(initlevel):
+    error('    available marks and order of them in this help: %s' %
+          (', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1:]])))
+
+def checkseclevel(doc, name, initlevel):
+    verbose('checking "%s"' % name)
+    blocks, pruned = minirst.parse(doc, 0, ['verbose'])
+    errorcnt = 0
+    curlevel = initlevel
+    for block in blocks:
+        if block['type'] != 'section':
+            continue
+        mark = block['underline']
+        title = block['lines'][0]
+        if (mark not in mark2level) or (mark2level[mark] <= initlevel):
+            error('invalid section mark %r for "%s" of %s' %
+                  (mark * 4, title, name))
+            showavailables(initlevel)
+            errorcnt += 1
+            continue
+        nextlevel = mark2level[mark]
+        if curlevel < nextlevel and curlevel + 1 != nextlevel:
+            error('gap of section level at "%s" of %s' %
+                  (title, name))
+            showavailables(initlevel)
+            errorcnt += 1
+            continue
+        verbose('appropriate section level for "%s %s"' %
+                (mark * (nextlevel * 2), title))
+        curlevel = nextlevel
+
+    return errorcnt
+
+def checkcmdtable(cmdtable, namefmt, initlevel):
+    errorcnt = 0
+    for k, entry in cmdtable.items():
+        name = k.split("|")[0].lstrip("^")
+        if not entry[0].__doc__:
+            verbose('skip checking %s: no help document' %
+                    (namefmt % name))
+            continue
+        errorcnt += checkseclevel(entry[0].__doc__,
+                                  namefmt % name,
+                                  initlevel)
+    return errorcnt
+
+def checkhghelps():
+    errorcnt = 0
+    for names, sec, doc in helptable:
+        if util.safehasattr(doc, '__call__'):
+            doc = doc()
+        errorcnt += checkseclevel(doc,
+                                  '%s help topic' % names[0],
+                                  initlevel_topic)
+
+    errorcnt += checkcmdtable(table, '%s command', initlevel_cmd)
+
+    for name in sorted(extensions.enabled().keys() +
+                       extensions.disabled().keys()):
+        mod = extensions.load(None, name, None)
+        if not mod.__doc__:
+            verbose('skip checking %s extension: no help document' % name)
+            continue
+        errorcnt += checkseclevel(mod.__doc__,
+                                  '%s extension' % name,
+                                  initlevel_ext)
+
+        cmdtable = getattr(mod, 'cmdtable', None)
+        if cmdtable:
+            errorcnt += checkcmdtable(cmdtable,
+                                      '%s command of ' + name + ' extension',
+                                      initlevel_ext_cmd)
+    return errorcnt
+
+def checkfile(filename, initlevel):
+    if filename == '-':
+        filename = 'stdin'
+        doc = sys.stdin.read()
+    else:
+        fp = open(filename)
+        try:
+            doc = fp.read()
+        finally:
+            fp.close()
+
+    verbose('checking input from %s with initlevel %d' %
+            (filename, initlevel))
+    return checkseclevel(doc, 'input from %s' % filename, initlevel)
+
+if __name__ == "__main__":
+    optparser = optparse.OptionParser("""%prog [options]
+
+This checks all help documents of Mercurial (topics, commands,
+extensions and commands of them), if no file is specified by --file
+option.
+""")
+    optparser.add_option("-v", "--verbose",
+                         help="enable additional output",
+                         action="store_true")
+    optparser.add_option("-f", "--file",
+                         help="filename to read in (or '-' for stdin)",
+                         action="store", default="")
+
+    optparser.add_option("-t", "--topic",
+                         help="parse file as help topic",
+                         action="store_const", dest="initlevel", const=0)
+    optparser.add_option("-c", "--command",
+                         help="parse file as help of core command",
+                         action="store_const", dest="initlevel", const=1)
+    optparser.add_option("-e", "--extension",
+                         help="parse file as help of extension",
+                         action="store_const", dest="initlevel", const=1)
+    optparser.add_option("-C", "--extension-command",
+                         help="parse file as help of extension command",
+                         action="store_const", dest="initlevel", const=3)
+
+    optparser.add_option("-l", "--initlevel",
+                         help="set initial section level manually",
+                         action="store", type="int", default=0)
+
+    (options, args) = optparser.parse_args()
+
+    _verbose = options.verbose
+
+    if options.file:
+        if checkfile(options.file, options.initlevel):
+            sys.exit(1)
+    else:
+        if checkhghelps():
+            sys.exit(1)

File doc/hgmanpage.py

     """"""
 
     words_and_spaces = re.compile(r'\S+| +|\n')
-    document_start = """Man page generated from reStructeredText."""
+    document_start = """Man page generated from reStructuredText."""
 
     def __init__(self, document):
         nodes.NodeVisitor.__init__(self, document)
         # ``.PP`` : Start standard indented paragraph.
         # ``.LP`` : Start block paragraph, all except the first.
         # ``.P [type]``  : Start paragraph type.
-        # NOTE dont use paragraph starts because they reset indentation.
+        # NOTE don't use paragraph starts because they reset indentation.
         # ``.sp`` is only vertical space
         self.ensure_eol()
         self.body.append('.sp\n')

File hgext/acl.py

File contents unchanged.

File hgext/bugzilla.py

 email to the Bugzilla email interface to submit comments to bugs.
 The From: address in the email is set to the email address of the Mercurial
 user, so the comment appears to come from the Mercurial user. In the event
-that the Mercurial user email is not recognised by Bugzilla as a Bugzilla
+that the Mercurial user email is not recognized by Bugzilla as a Bugzilla
 user, the email associated with the Bugzilla username used to log into
 Bugzilla is used instead as the source of the comment. Marking bugs fixed
 works on all supported Bugzilla versions.
 Configuration items common to all access modes:
 
 bugzilla.version
-  This access type to use. Values recognised are:
+  The access type to use. Values recognized are:
 
   :``xmlrpc``:       Bugzilla XMLRPC interface.
   :``xmlrpc+email``: Bugzilla XMLRPC and email interfaces.
     # Methods to be implemented by access classes.
     #
     # 'bugs' is a dict keyed on bug id, where values are a dict holding
-    # updates to bug state. Recognised dict keys are:
+    # updates to bug state. Recognized dict keys are:
     #
     # 'hours': Value, float containing work hours to be updated.
     # 'fix':   If key present, bug is to be marked fixed. Value ignored.
             raise util.Abort(_('unknown database schema'))
         return ids[0][0]
 
-# Buzgilla via XMLRPC interface.
+# Bugzilla via XMLRPC interface.
 
 class cookietransportrequest(object):
     """A Transport request method that retains cookies over its lifetime.

File hgext/children.py

 "children(REV)"` instead.
 '''
 
-from mercurial import cmdutil
+from mercurial import cmdutil, commands
 from mercurial.commands import templateopts
 from mercurial.i18n import _
 
          ] + templateopts,
          _('hg children [-r REV] [FILE]')),
 }
+
+commands.inferrepo += " children"

File hgext/churn.py

           ] + commands.walkopts,
          _("hg churn [-d DATE] [-r REV] [--aliases FILE] [FILE]")),
 }
+
+commands.inferrepo += " churn"

File hgext/color.py

     _terminfo_params = False
 
 _styles = {'grep.match': 'red bold',
+           'grep.linenumber': 'green',
+           'grep.rev': 'green',
+           'grep.change': 'green',
+           'grep.sep': 'cyan',
+           'grep.filename': 'magenta',
+           'grep.user': 'magenta',
+           'grep.date': 'magenta',
            'bookmarks.current': 'green',
            'branches.active': 'none',
            'branches.closed': 'black bold',
                 orig(m.group(2), **opts)
                 m = re.match(ansire, m.group(3))
         finally:
-            # Explicity reset original attributes
+            # Explicitly reset original attributes
             _kernel32.SetConsoleTextAttribute(stdout, origattr)

File hgext/convert/__init__.py

 
     The authormap is a simple text file that maps each source commit
     author to a destination commit author. It is handy for source SCMs
-    that use unix logins to identify authors (eg: CVS). One line per
+    that use unix logins to identify authors (e.g.: CVS). One line per
     author mapping and the line format is::
 
       source author = destination author

File hgext/convert/bzr.py

                         # register the change as move
                         renames[topath] = frompath
 
-                # no futher changes, go to the next change
+                # no further changes, go to the next change
                 continue
 
             # we got unicode paths, need to convert them

File hgext/convert/convcmd.py

 
     def toposort(self, parents, sortmode):
         '''Return an ordering such that every uncommitted changeset is
-        preceeded by all its uncommitted ancestors.'''
+        preceded by all its uncommitted ancestors.'''
 
         def mapchildren(parents):
             """Return a (children, roots) tuple where 'children' maps parent

File hgext/convert/cvs.py

     def getfile(self, name, rev):
 
         def chunkedread(fp, count):
-            # file-objects returned by socked.makefile() do not handle
+            # file-objects returned by socket.makefile() do not handle
             # large read() requests very well.
             chunksize = 65536
             output = StringIO()

File hgext/convert/cvsps.py

         # The cvsps cache pickle needs a uniquified name, based on the
         # repository location. The address may have all sort of nasties
         # in it, slashes, colons and such. So here we take just the
-        # alphanumerics, concatenated in a way that does not mix up the
-        # various components, so that
+        # alphanumeric characters, concatenated in a way that does not
+        # mix up the various components, so that
         #    :pserver:user@server:/path
         # and
         #    /pserver/user/server/path
 
         # Check if log entry belongs to the current changeset or not.
 
-        # Since CVS is file centric, two different file revisions with
+        # Since CVS is file-centric, two different file revisions with
         # different branchpoints should be treated as belonging to two
         # different changesets (and the ordering is important and not
         # honoured by cvsps at this point).

File hgext/convert/filemap.py

 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+import posixpath
 import shlex
 from mercurial.i18n import _
 from mercurial import util
         e = name.rfind('/', 0, e)
     yield '.', name
 
+def normalize(path):
+    ''' We use posixpath.normpath to support cross-platform path format.
+    However, it doesn't handle None input. So we wrap it up. '''
+    if path is None:
+        return None
+    return posixpath.normpath(path)
+
 class filemapper(object):
     '''Map and filter filenames when importing.
     A name can be mapped to itself, a new name, or None (omit from new
         cmd = lex.get_token()
         while cmd:
             if cmd == 'include':
-                name = lex.get_token()
+                name = normalize(lex.get_token())
                 errs += check(name, self.exclude, 'exclude')
                 self.include[name] = name
             elif cmd == 'exclude':
-                name = lex.get_token()
+                name = normalize(lex.get_token())
                 errs += check(name, self.include, 'include')
                 errs += check(name, self.rename, 'rename')
                 self.exclude[name] = name
             elif cmd == 'rename':
-                src = lex.get_token()
-                dest = lex.get_token()
+                src = normalize(lex.get_token())
+                dest = normalize(lex.get_token())
                 errs += check(src, self.exclude, 'exclude')
                 self.rename[src] = dest
             elif cmd == 'source':
-                errs += self.parse(lex.get_token())
+                errs += self.parse(normalize(lex.get_token()))
             else:
                 self.ui.warn(_('%s:%d: unknown directive %r\n') %
                              (lex.infile, lex.lineno, cmd))
         return errs
 
     def lookup(self, name, mapping):
+        name = normalize(name)
         for pre, suf in rpairs(name):
             try:
                 return mapping[pre], pre, suf

File hgext/convert/gnuarch.py

 
             # Get the complete list of revisions for that tree version
             output, status = self.runlines('revisions', '-r', '-f', treeversion)
-            self.checkexit(status, 'failed retrieveing revisions for %s'
+            self.checkexit(status, 'failed retrieving revisions for %s'
                            % treeversion)
 
             # No new iteration unless a revision has a continuation-of header

File hgext/convert/monotone.py

             return [self.rev]
 
     def getchanges(self, rev):
-        #revision = self.mtncmd("get_revision %s" % rev).split("\n\n")
         revision = self.mtnrun("get_revision", rev).split("\n\n")
         files = {}
         ignoremove = {}