changeset 18742:a07be8953733

merge with crew
author Matt Mackall <mpm@selenic.com>
date Thu, 28 Feb 2013 21:58:37 -0600
parents af9ddea2cb99 (diff) b376e8f91c16 (current diff)
children 70e2a22fd66e
files mercurial/httppeer.py
diffstat 43 files changed, 724 insertions(+), 303 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/check-code.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/contrib/check-code.py	Thu Feb 28 21:58:37 2013 -0600
@@ -105,7 +105,10 @@
      "use (glob) to match Windows paths too"),
   ],
   # warnings
-  []
+  [
+    (r'^  [^*?/\n]* \(glob\)$',
+     "warning: glob match with no glob character (?*/)"),
+  ]
 ]
 
 for i in [0, 1]:
--- a/contrib/mergetools.hgrc	Sun Feb 17 14:41:31 2013 -0600
+++ b/contrib/mergetools.hgrc	Thu Feb 28 21:58:37 2013 -0600
@@ -15,7 +15,7 @@
 gvimdiff.regname=path
 gvimdiff.priority=-9
 
-vimdiff.args=$local $other $base
+vimdiff.args=$local $other $base -c 'redraw | echomsg "hg merge conflict, type \":cq\" to abort vimdiff"'
 vimdiff.check=changed
 vimdiff.priority=-10
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/blackbox.py	Thu Feb 28 21:58:37 2013 -0600
@@ -0,0 +1,106 @@
+# blackbox.py - log repository events to a file for post-mortem debugging
+#
+# Copyright 2010 Nicolas Dumazet
+# Copyright 2013 Facebook, Inc.
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+"""log repository events to a blackbox for debugging
+
+Logs event information to .hg/blackbox.log to help debug and diagnose problems.
+The events that get logged can be configured via the blackbox.track config key.
+Examples:
+
+  [blackbox]
+  track = *
+
+  [blackbox]
+  track = command, commandfinish, commandexception, exthook, pythonhook
+
+  [blackbox]
+  track = incoming
+
+"""
+
+from mercurial import util, cmdutil
+from mercurial.i18n import _
+import os, getpass, re
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+testedwith = 'internal'
+lastblackbox = None
+
+def wrapui(ui):
+    class blackboxui(ui.__class__):
+        @util.propertycache
+        def track(self):
+            return ui.configlist('blackbox', 'track', ['*'])
+
+        def log(self, event, *msg, **opts):
+            global lastblackbox
+            super(blackboxui, self).log(event, *msg, **opts)
+
+            if not '*' in self.track and not event in self.track:
+                return
+
+            if util.safehasattr(self, '_blackbox'):
+                blackbox = self._blackbox
+            else:
+                # certain ui instances exist outside the context of
+                # a repo, so just default to the last blackbox that
+                # was seen.
+                blackbox = lastblackbox
+
+            if blackbox:
+                date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
+                user = getpass.getuser()
+                formattedmsg = msg[0] % msg[1:]
+                blackbox.write('%s %s> %s' % (date, user, formattedmsg))
+                lastblackbox = blackbox
+
+        def setrepo(self, repo):
+            self._blackbox = repo.opener('blackbox.log', 'a')
+
+    ui.__class__ = blackboxui
+
+def uisetup(ui):
+    wrapui(ui)
+
+def reposetup(ui, repo):
+    # During 'hg pull' a httppeer repo is created to represent the remote repo.
+    # It doesn't have a .hg directory to put a blackbox in, so we don't do
+    # the blackbox setup for it.
+    if not repo.local():
+        return
+
+    ui.setrepo(repo)
+
+@command('^blackbox',
+    [('l', 'limit', 10, _('the number of events to show')),
+    ],
+    _('hg blackbox [OPTION]...'))
+def blackbox(ui, repo, *revs, **opts):
+    '''view the recent repository events
+    '''
+
+    if not os.path.exists(repo.join('blackbox.log')):
+        return
+
+    limit = opts.get('limit')
+    blackbox = repo.opener('blackbox.log', 'r')
+    lines = blackbox.read().split('\n')
+
+    count = 0
+    output = []
+    for line in reversed(lines):
+        if count >= limit:
+            break
+
+        # count the commands by matching lines like: 2013/01/23 19:13:36 root>
+        if re.match('^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
+            count += 1
+        output.append(line)
+
+    ui.status('\n'.join(reversed(output)))
--- a/hgext/convert/cvsps.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/hgext/convert/cvsps.py	Thu Feb 28 21:58:37 2013 -0600
@@ -508,9 +508,15 @@
 
     ui.status(_('creating changesets\n'))
 
+    # try to order commitids by date
+    mindate = {}
+    for e in log:
+        if e.commitid:
+            mindate[e.commitid] = min(e.date, mindate.get(e.commitid))
+
     # Merge changesets
-    log.sort(key=lambda x: (x.commitid, x.comment, x.author, x.branch, x.date,
-                            x.branchpoints))
+    log.sort(key=lambda x: (mindate.get(x.commitid), x.commitid, x.comment,
+                            x.author, x.branch, x.date, x.branchpoints))
 
     changesets = []
     files = set()
--- a/hgext/largefiles/__init__.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/hgext/largefiles/__init__.py	Thu Feb 28 21:58:37 2013 -0600
@@ -41,13 +41,17 @@
 enabled for this to work.
 
 When you pull a changeset that affects largefiles from a remote
-repository, the largefiles for the changeset usually won't be
-pulled down until you update to the revision (there is one exception
-to this case).  However, when you update to such a revision, any
-largefiles needed by that revision are downloaded and cached (if
-they have never been downloaded before).  This means that network
-access may be required to update to changesets you have no
-previously updated to.
+repository, the largefiles for the changeset won't be pulled down.
+Instead, when you later update to such a revision, any largefiles
+needed by that revision are downloaded and cached (if they have
+never been downloaded before).  This means that network access may
+be required to update to changesets you have previously updated to.
+
+If you know you are pulling from a non-default location and want to
+ensure that you will have the largefiles needed to merge or rebase
+with new heads that you are pulling, then you can pull with the
+--cache-largefiles flag to pre-emptively download any largefiles
+that are new in the heads you are pulling.
 
 The one exception to the "largefiles won't be pulled until you update
 to a revision that changes them" rule is when you pull new heads.
--- a/hgext/largefiles/basestore.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/hgext/largefiles/basestore.py	Thu Feb 28 21:58:37 2013 -0600
@@ -60,6 +60,8 @@
         missing = []
         ui = self.ui
 
+        util.makedirs(lfutil.storepath(self.repo, ''))
+
         at = 0
         for filename, hash in files:
             ui.progress(_('getting largefiles'), at, unit='lfile',
--- a/hgext/largefiles/lfcommands.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/hgext/largefiles/lfcommands.py	Thu Feb 28 21:58:37 2013 -0600
@@ -8,7 +8,7 @@
 
 '''High-level command function for lfconvert, plus the cmdtable.'''
 
-import os
+import os, errno
 import shutil
 
 from mercurial import util, match as match_, hg, node, context, error, \
@@ -403,22 +403,13 @@
     toget = []
 
     for lfile in lfiles:
-        # If we are mid-merge, then we have to trust the standin that is in the
-        # working copy to have the correct hashvalue.  This is because the
-        # original hg.merge() already updated the standin as part of the normal
-        # merge process -- we just have to update the largefile to match.
-        if (getattr(repo, "_ismerging", False) and
-             os.path.exists(repo.wjoin(lfutil.standin(lfile)))):
-            expectedhash = lfutil.readstandin(repo, lfile)
-        else:
+        try:
             expectedhash = repo[node][lfutil.standin(lfile)].data().strip()
-
-        # if it exists and its hash matches, it might have been locally
-        # modified before updating and the user chose 'local'.  in this case,
-        # it will not be in any store, so don't look for it.
-        if ((not os.path.exists(repo.wjoin(lfile)) or
-             expectedhash != lfutil.hashfile(repo.wjoin(lfile))) and
-            not lfutil.findfile(repo, expectedhash)):
+        except IOError, err:
+            if err.errno == errno.ENOENT:
+                continue # node must be None and standin wasn't found in wctx
+            raise
+        if not lfutil.findfile(repo, expectedhash):
             toget.append((lfile, expectedhash))
 
     if toget:
@@ -435,11 +426,12 @@
         pass
     totalsuccess = 0
     totalmissing = 0
-    for ctx in cmdutil.walkchangerevs(repo, matchfn, {'rev' : rev},
-                                      prepare):
-        success, missing = cachelfiles(ui, repo, ctx.node())
-        totalsuccess += len(success)
-        totalmissing += len(missing)
+    if rev != []: # walkchangerevs on empty list would return all revs
+        for ctx in cmdutil.walkchangerevs(repo, matchfn, {'rev' : rev},
+                                          prepare):
+            success, missing = cachelfiles(ui, repo, ctx.node())
+            totalsuccess += len(success)
+            totalmissing += len(missing)
     ui.status(_("%d additional largefiles cached\n") % totalsuccess)
     if totalmissing > 0:
         ui.status(_("%d largefiles failed to download\n") % totalmissing)
@@ -458,7 +450,7 @@
         if printmessage and lfiles:
             ui.status(_('getting changed largefiles\n'))
             printed = True
-            cachelfiles(ui, repo, '.', lfiles)
+            cachelfiles(ui, repo, None, lfiles)
 
         updated, removed = 0, 0
         for f in lfiles:
@@ -500,6 +492,8 @@
                 # use normallookup() to allocate entry in largefiles dirstate,
                 # because lack of it misleads lfilesrepo.status() into
                 # recognition that such cache missing files are REMOVED.
+                if lfile not in repo[None]: # not switched to normal file
+                    util.unlinkpath(abslfile, ignoremissing=True)
                 lfdirstate.normallookup(lfile)
                 return None # don't try to set the mode
             else:
--- a/hgext/largefiles/lfutil.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/hgext/largefiles/lfutil.py	Thu Feb 28 21:58:37 2013 -0600
@@ -225,13 +225,9 @@
     standindir = repo.wjoin(shortname)
     if pats:
         pats = [os.path.join(standindir, pat) for pat in pats]
-    elif os.path.isdir(standindir):
+    else:
         # no patterns: relative to repo root
         pats = [standindir]
-    else:
-        # no patterns and no standin dir: return matcher that matches nothing
-        return match_.match(repo.root, None, [], exact=True)
-
     # no warnings about missing files or directories
     match = scmutil.match(repo[None], pats, opts)
     match.bad = lambda f, msg: None
--- a/hgext/largefiles/overrides.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/hgext/largefiles/overrides.py	Thu Feb 28 21:58:37 2013 -0600
@@ -686,15 +686,8 @@
     return result
 
 def hgmerge(orig, repo, node, force=None, remind=True):
-    # Mark the repo as being in the middle of a merge, so that
-    # updatelfiles() will know that it needs to trust the standins in
-    # the working copy, not in the standins in the current node
-    repo._ismerging = True
-    try:
-        result = orig(repo, node, force, remind)
-        lfcommands.updatelfiles(repo.ui, repo)
-    finally:
-        repo._ismerging = False
+    result = orig(repo, node, force, remind)
+    lfcommands.updatelfiles(repo.ui, repo)
     return result
 
 # When we rebase a repository with remotely changed largefiles, we need to
@@ -733,23 +726,25 @@
         repo.lfpullsource = source
         oldheads = lfutil.getcurrentheads(repo)
         result = orig(ui, repo, source, **opts)
-        # If we do not have the new largefiles for any new heads we pulled, we
-        # will run into a problem later if we try to merge or rebase with one of
-        # these heads, so cache the largefiles now directly into the system
-        # cache.
-        numcached = 0
-        heads = lfutil.getcurrentheads(repo)
-        newheads = set(heads).difference(set(oldheads))
-        if len(newheads) > 0:
-            ui.status(_("caching largefiles for %s heads\n") % len(newheads))
-        for head in newheads:
-            (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
-            numcached += len(cached)
-        ui.status(_("%d largefiles cached\n") % numcached)
+        if opts.get('cache_largefiles'):
+            # If you are pulling from a remote location that is not your
+            # default location, you may want to cache largefiles for new heads
+            # that have been pulled, so you can easily merge or rebase with
+            # them later
+            numcached = 0
+            heads = lfutil.getcurrentheads(repo)
+            newheads = set(heads).difference(set(oldheads))
+            if len(newheads) > 0:
+                ui.status(_("caching largefiles for %s heads\n") %
+                          len(newheads))
+            for head in newheads:
+                (cached, missing) = lfcommands.cachelfiles(ui, repo, head)
+                numcached += len(cached)
+            ui.status(_("%d largefiles cached\n") % numcached)
     if opts.get('all_largefiles'):
         revspostpull = len(repo)
         revs = []
-        for rev in xrange(revsprepull + 1, revspostpull):
+        for rev in xrange(revsprepull, revspostpull):
             revs.append(repo[rev].rev())
         lfcommands.downloadlfiles(ui, repo, revs)
     return result
@@ -772,17 +767,6 @@
         sourcerepo, destrepo = result
         repo = destrepo.local()
 
-        # The .hglf directory must exist for the standin matcher to match
-        # anything (which listlfiles uses for each rev), and .hg/largefiles is
-        # assumed to exist by the code that caches the downloaded file.  These
-        # directories exist if clone updated to any rev.  (If the repo does not
-        # have largefiles, download never gets to the point of needing
-        # .hg/largefiles, and the standin matcher won't match anything anyway.)
-        if 'largefiles' in repo.requirements:
-            if opts.get('noupdate'):
-                util.makedirs(repo.wjoin(lfutil.shortname))
-                util.makedirs(repo.join(lfutil.longname))
-
         # Caching is implicitly limited to 'rev' option, since the dest repo was
         # truncated at that point.  The user may expect a download count with
         # this option, so attempt whether or not this is a largefile repo.
--- a/hgext/largefiles/reposetup.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/hgext/largefiles/reposetup.py	Thu Feb 28 21:58:37 2013 -0600
@@ -299,9 +299,9 @@
                     lfdirstate = lfutil.openlfdirstate(ui, self)
                     dirtymatch = match_.always(self.root, self.getcwd())
                     s = lfdirstate.status(dirtymatch, [], False, False, False)
-                    modifiedfiles = []
-                    for i in s:
-                        modifiedfiles.extend(i)
+                    (unsure, modified, added, removed, _missing, _unknown,
+                            _ignored, _clean) = s
+                    modifiedfiles = unsure + modified + added + removed
                     lfiles = lfutil.listlfiles(self)
                     # this only loops through largefiles that exist (not
                     # removed/renamed)
--- a/hgext/largefiles/uisetup.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/hgext/largefiles/uisetup.py	Thu Feb 28 21:58:37 2013 -0600
@@ -79,7 +79,9 @@
     entry = extensions.wrapcommand(commands.table, 'pull',
                                    overrides.overridepull)
     pullopt = [('', 'all-largefiles', None,
-                 _('download all pulled versions of largefiles'))]
+                 _('download all pulled versions of largefiles')),
+               ('', 'cache-largefiles', None,
+                 _('caches new largefiles in all pulled heads'))]
     entry[1].extend(pullopt)
     entry = extensions.wrapcommand(commands.table, 'clone',
                                    overrides.overrideclone)
--- a/hgext/pager.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/hgext/pager.py	Thu Feb 28 21:58:37 2013 -0600
@@ -94,6 +94,8 @@
 
     @atexit.register
     def killpager():
+        if util.safehasattr(signal, "SIGINT"):
+            signal.signal(signal.SIGINT, signal.SIG_IGN)
         pager.stdin.close()
         os.dup2(stdout, sys.stdout.fileno())
         os.dup2(stderr, sys.stderr.fileno())
--- a/mercurial/cmdutil.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/cmdutil.py	Thu Feb 28 21:58:37 2013 -0600
@@ -1210,6 +1210,13 @@
             if ff.match(x):
                 wanted.discard(x)
 
+    # Choose a small initial window if we will probably only visit a
+    # few commits.
+    limit = loglimit(opts)
+    windowsize = 8
+    if limit:
+        windowsize = min(limit, windowsize)
+
     # Now that wanted is correctly initialized, we can iterate over the
     # revision range, yielding only revisions in wanted.
     def iterate():
@@ -1221,7 +1228,7 @@
             def want(rev):
                 return rev in wanted
 
-        for i, window in increasingwindows(0, len(revs)):
+        for i, window in increasingwindows(0, len(revs), windowsize):
             nrevs = [rev for rev in revs[i:i + window] if want(rev)]
             for rev in sorted(nrevs):
                 fns = fncache.get(rev)
@@ -1821,6 +1828,52 @@
 
     return text
 
+def commitstatus(repo, node, branch, bheads=None, opts={}):
+    ctx = repo[node]
+    parents = ctx.parents()
+
+    if (not opts.get('amend') and bheads and node not in bheads and not
+        [x for x in parents if x.node() in bheads and x.branch() == branch]):
+        repo.ui.status(_('created new head\n'))
+        # The message is not printed for initial roots. For the other
+        # changesets, it is printed in the following situations:
+        #
+        # Par column: for the 2 parents with ...
+        #   N: null or no parent
+        #   B: parent is on another named branch
+        #   C: parent is a regular non head changeset
+        #   H: parent was a branch head of the current branch
+        # Msg column: whether we print "created new head" message
+        # In the following, it is assumed that there already exists some
+        # initial branch heads of the current branch, otherwise nothing is
+        # printed anyway.
+        #
+        # Par Msg Comment
+        # N N  y  additional topo root
+        #
+        # B N  y  additional branch root
+        # C N  y  additional topo head
+        # H N  n  usual case
+        #
+        # B B  y  weird additional branch root
+        # C B  y  branch merge
+        # H B  n  merge with named branch
+        #
+        # C C  y  additional head from merge
+        # C H  n  merge with a head
+        #
+        # H H  n  head merge: head count decreases
+
+    if not opts.get('close_branch'):
+        for r in parents:
+            if r.closesbranch() and r.branch() == branch:
+                repo.ui.status(_('reopening closed branch head %d\n') % r)
+
+    if repo.ui.debugflag:
+        repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
+    elif repo.ui.verbose:
+        repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
+
 def revert(ui, repo, ctx, parents, *pats, **opts):
     parent, p2 = parents
     node = ctx.node()
--- a/mercurial/commands.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/commands.py	Thu Feb 28 21:58:37 2013 -0600
@@ -456,14 +456,11 @@
     wlock = repo.wlock()
     try:
         branch = repo.dirstate.branch()
+        bheads = repo.branchheads(branch)
         hg.clean(repo, node, show_stats=False)
         repo.dirstate.setbranch(branch)
-        revert_opts = opts.copy()
-        revert_opts['date'] = None
-        revert_opts['all'] = True
-        revert_opts['rev'] = hex(parent)
-        revert_opts['no_backup'] = None
-        revert(ui, repo, **revert_opts)
+        rctx = scmutil.revsingle(repo, hex(parent))
+        cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
         if not opts.get('merge') and op1 != node:
             try:
                 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
@@ -471,13 +468,18 @@
             finally:
                 ui.setconfig('ui', 'forcemerge', '')
 
-        commit_opts = opts.copy()
-        commit_opts['addremove'] = False
-        if not commit_opts['message'] and not commit_opts['logfile']:
+        e = cmdutil.commiteditor
+        if not opts['message'] and not opts['logfile']:
             # we don't translate commit messages
-            commit_opts['message'] = "Backed out changeset %s" % short(node)
-            commit_opts['force_editor'] = True
-        commit(ui, repo, **commit_opts)
+            opts['message'] = "Backed out changeset %s" % short(node)
+            e = cmdutil.commitforceeditor
+
+        def commitfunc(ui, repo, message, match, opts):
+            return repo.commit(message, opts.get('user'), opts.get('date'),
+                               match, editor=e)
+        newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
+        cmdutil.commitstatus(repo, newnode, branch, bheads)
+
         def nice(node):
             return '%d:%s' % (repo.changelog.rev(node), short(node))
         ui.status(_('changeset %s backs out changeset %s\n') %
@@ -1066,7 +1068,7 @@
         dest = ui.expandpath(dest or 'default-push', dest or 'default')
         dest, branches = hg.parseurl(dest, opts.get('branch'))
         other = hg.peer(repo, opts, dest)
-        revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
+        revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
         heads = revs and map(repo.lookup, revs) or revs
         outgoing = discovery.findcommonoutgoing(repo, other,
                                                 onlyheads=heads,
@@ -1361,50 +1363,7 @@
                 ui.status(_("nothing changed\n"))
             return 1
 
-    ctx = repo[node]
-    parents = ctx.parents()
-
-    if (not opts.get('amend') and bheads and node not in bheads and not
-        [x for x in parents if x.node() in bheads and x.branch() == branch]):
-        ui.status(_('created new head\n'))
-        # The message is not printed for initial roots. For the other
-        # changesets, it is printed in the following situations:
-        #
-        # Par column: for the 2 parents with ...
-        #   N: null or no parent
-        #   B: parent is on another named branch
-        #   C: parent is a regular non head changeset
-        #   H: parent was a branch head of the current branch
-        # Msg column: whether we print "created new head" message
-        # In the following, it is assumed that there already exists some
-        # initial branch heads of the current branch, otherwise nothing is
-        # printed anyway.
-        #
-        # Par Msg Comment
-        # N N  y  additional topo root
-        #
-        # B N  y  additional branch root
-        # C N  y  additional topo head
-        # H N  n  usual case
-        #
-        # B B  y  weird additional branch root
-        # C B  y  branch merge
-        # H B  n  merge with named branch
-        #
-        # C C  y  additional head from merge
-        # C H  n  merge with a head
-        #
-        # H H  n  head merge: head count decreases
-
-    if not opts.get('close_branch'):
-        for r in parents:
-            if r.closesbranch() and r.branch() == branch:
-                ui.status(_('reopening closed branch head %d\n') % r)
-
-    if ui.debugflag:
-        ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
-    elif ui.verbose:
-        ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
+    cmdutil.commitstatus(repo, node, branch, bheads, opts)
 
 @command('copy|cp',
     [('A', 'after', None, _('record a copy that has already occurred')),
@@ -4256,10 +4215,10 @@
         displayer.show(ctx, copies=copies, matchfn=revmatchfn)
 
     for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
+        if displayer.flush(ctx.rev()):
+            count += 1
         if count == limit:
             break
-        if displayer.flush(ctx.rev()):
-            count += 1
     displayer.close()
 
 @command('manifest',
--- a/mercurial/dispatch.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/dispatch.py	Thu Feb 28 21:58:37 2013 -0600
@@ -247,6 +247,7 @@
                     (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
                     (_("** Extensions loaded: %s\n") %
                      ", ".join([x[0] for x in extensions.extensions()])))
+        ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
         ui.warn(warning)
         raise
 
@@ -333,7 +334,7 @@
         self.cmdname = cmd = args.pop(0)
         args = map(util.expandpath, args)
 
-        for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
+        for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
             if _earlygetopt([invalidarg], args):
                 def fn(ui, *args):
                     ui.warn(_("error in definition for alias '%s': %s may only "
@@ -738,10 +739,16 @@
     msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
     ui.log("command", msg + "\n")
     d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
+    starttime = time.time()
+    ret = None
     try:
-        return runcommand(lui, repo, cmd, fullargs, ui, options, d,
-                          cmdpats, cmdoptions)
+        ret = runcommand(lui, repo, cmd, fullargs, ui, options, d,
+                         cmdpats, cmdoptions)
+        return ret
     finally:
+        duration = time.time() - starttime
+        ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
+               cmd, ret, duration)
         if repo and repo != req.repo:
             repo.close()
 
--- a/mercurial/extensions.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/extensions.py	Thu Feb 28 21:58:37 2013 -0600
@@ -50,7 +50,6 @@
             raise
 
 def load(ui, name, path):
-    # unused ui argument kept for backwards compatibility
     if name.startswith('hgext.') or name.startswith('hgext/'):
         shortname = name[6:]
     else:
--- a/mercurial/help/config.txt	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/help/config.txt	Thu Feb 28 21:58:37 2013 -0600
@@ -745,7 +745,7 @@
 For example::
 
     [hostfingerprints]
-    hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc
+    hg.intevation.org = 44:ed:af:1f:97:11:b6:01:7a:48:45:fc:10:3c:b7:f9:d4:89:2a:9d
 
 This feature is only supported when using Python 2.6 or later.
 
--- a/mercurial/hook.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/hook.py	Thu Feb 28 21:58:37 2013 -0600
@@ -6,7 +6,7 @@
 # GNU General Public License version 2 or any later version.
 
 from i18n import _
-import os, sys
+import os, sys, time, types
 import extensions, util, demandimport
 
 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
@@ -20,6 +20,8 @@
     be run as hooks without wrappers to convert return values.'''
 
     ui.note(_("calling hook %s: %s\n") % (hname, funcname))
+    starttime = time.time()
+
     obj = funcname
     if not util.safehasattr(obj, '__call__'):
         d = funcname.rfind('.')
@@ -92,6 +94,12 @@
             return True
     finally:
         sys.stdout, sys.stderr, sys.stdin = old
+        duration = time.time() - starttime
+        readablefunc = funcname
+        if isinstance(funcname, types.FunctionType):
+            readablefunc = funcname.__module__ + "." + funcname.__name__
+        ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
+               name, readablefunc, duration)
     if r:
         if throw:
             raise util.Abort(_('%s hook failed') % hname)
@@ -101,6 +109,7 @@
 def _exthook(ui, repo, name, cmd, args, throw):
     ui.note(_("running hook %s: %s\n") % (name, cmd))
 
+    starttime = time.time()
     env = {}
     for k, v in args.iteritems():
         if util.safehasattr(v, '__call__'):
@@ -121,6 +130,10 @@
         r = util.system(cmd, environ=env, cwd=cwd, out=ui)
     else:
         r = util.system(cmd, environ=env, cwd=cwd, out=ui.fout)
+
+    duration = time.time() - starttime
+    ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
+           name, cmd, duration)
     if r:
         desc, r = util.explainexit(r)
         if throw:
--- a/mercurial/localrepo.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/localrepo.py	Thu Feb 28 21:58:37 2013 -0600
@@ -1532,12 +1532,12 @@
 
             modified, added, clean = [], [], []
             withflags = mf1.withflags() | mf2.withflags()
-            for fn in mf2:
+            for fn, mf2node in mf2.iteritems():
                 if fn in mf1:
                     if (fn not in deleted and
                         ((fn in withflags and mf1.flags(fn) != mf2.flags(fn)) or
-                         (mf1[fn] != mf2[fn] and
-                          (mf2[fn] or ctx1[fn].cmp(ctx2[fn]))))):
+                         (mf1[fn] != mf2node and
+                          (mf2node or ctx1[fn].cmp(ctx2[fn]))))):
                         modified.append(fn)
                     elif listclean:
                         clean.append(fn)
@@ -2399,6 +2399,12 @@
                     for n in added:
                         self.hook("incoming", node=hex(n), source=srctype,
                                   url=url)
+
+                    newheads = [h for h in self.heads() if h not in oldheads]
+                    self.ui.log("incoming",
+                                "%s incoming changes - new heads: %s\n",
+                                len(added),
+                                ', '.join([hex(c[:6]) for c in newheads]))
                 self._afterlock(runhooks)
 
         finally:
--- a/mercurial/match.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/match.py	Thu Feb 28 21:58:37 2013 -0600
@@ -62,6 +62,7 @@
         self._files = []
         self._anypats = bool(include or exclude)
         self._ctx = ctx
+        self._always = False
 
         if include:
             pats = _normalize(include, 'glob', root, cwd, auditor)
@@ -103,6 +104,7 @@
                     m = lambda f: not em(f)
                 else:
                     m = lambda f: True
+                    self._always = True
 
         self.matchfn = m
         self._fmap = set(self._files)
@@ -130,7 +132,7 @@
     def anypats(self):
         return self._anypats
     def always(self):
-        return False
+        return self._always
 
 class exact(match):
     def __init__(self, root, cwd, files):
@@ -139,8 +141,7 @@
 class always(match):
     def __init__(self, root, cwd):
         match.__init__(self, root, cwd, [])
-    def always(self):
-        return True
+        self._always = True
 
 class narrowmatcher(match):
     """Adapt a matcher to work on a subdirectory only.
@@ -175,6 +176,7 @@
         self._cwd = matcher._cwd
         self._path = path
         self._matcher = matcher
+        self._always = matcher._always
 
         self._files = [f[len(path) + 1:] for f in matcher._files
                        if f.startswith(path + "/")]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/scmposix.py	Thu Feb 28 21:58:37 2013 -0600
@@ -0,0 +1,32 @@
+import sys, os
+import osutil
+
+def _rcfiles(path):
+    rcs = [os.path.join(path, 'hgrc')]
+    rcdir = os.path.join(path, 'hgrc.d')
+    try:
+        rcs.extend([os.path.join(rcdir, f)
+                    for f, kind in osutil.listdir(rcdir)
+                    if f.endswith(".rc")])
+    except OSError:
+        pass
+    return rcs
+
+def systemrcpath():
+    path = []
+    if sys.platform == 'plan9':
+        root = 'lib/mercurial'
+    else:
+        root = 'etc/mercurial'
+    # old mod_python does not set sys.argv
+    if len(getattr(sys, 'argv', [])) > 0:
+        p = os.path.dirname(os.path.dirname(sys.argv[0]))
+        path.extend(_rcfiles(os.path.join(p, root)))
+    path.extend(_rcfiles('/' + root))
+    return path
+
+def userrcpath():
+    if sys.platform == 'plan9':
+        return [os.environ['home'] + '/lib/hgrc']
+    else:
+        return [os.path.expanduser('~/.hgrc')]
--- a/mercurial/scmutil.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/scmutil.py	Thu Feb 28 21:58:37 2013 -0600
@@ -9,7 +9,15 @@
 from mercurial.node import nullrev
 import util, error, osutil, revset, similar, encoding, phases
 import match as matchmod
-import os, errno, re, stat, sys, glob
+import os, errno, re, stat, glob
+
+if os.name == 'nt':
+    import scmwindows as scmplatform
+else:
+    import scmposix as scmplatform
+
+systemrcpath = scmplatform.systemrcpath
+userrcpath = scmplatform.userrcpath
 
 def nochangesfound(ui, repo, excluded=None):
     '''Report no changes for push/pull, excluded is None or a list of
@@ -306,8 +314,7 @@
             # to a directory. Let the posixfile() call below raise IOError.
             if basename:
                 if atomictemp:
-                    if not os.path.isdir(dirname):
-                        util.makedirs(dirname, self.createmode)
+                    util.ensuredirs(dirname, self.createmode)
                     return util.atomictempfile(f, mode, self.createmode)
                 try:
                     if 'w' in mode:
@@ -325,8 +332,7 @@
                     if e.errno != errno.ENOENT:
                         raise
                     nlink = 0
-                    if not os.path.isdir(dirname):
-                        util.makedirs(dirname, self.createmode)
+                    util.ensuredirs(dirname, self.createmode)
                 if nlink > 0:
                     if self._trustnlink is None:
                         self._trustnlink = nlink > 1 or util.checknlink(f)
@@ -345,9 +351,7 @@
         except OSError:
             pass
 
-        dirname = os.path.dirname(linkname)
-        if not os.path.exists(dirname):
-            util.makedirs(dirname, self.createmode)
+        util.ensuredirs(os.path.dirname(linkname), self.createmode)
 
         if self._cansymlink:
             try:
@@ -535,84 +539,6 @@
             _rcpath = osrcpath()
     return _rcpath
 
-if os.name != 'nt':
-
-    def rcfiles(path):
-        rcs = [os.path.join(path, 'hgrc')]
-        rcdir = os.path.join(path, 'hgrc.d')
-        try:
-            rcs.extend([os.path.join(rcdir, f)
-                        for f, kind in osutil.listdir(rcdir)
-                        if f.endswith(".rc")])
-        except OSError:
-            pass
-        return rcs
-
-    def systemrcpath():
-        path = []
-        if sys.platform == 'plan9':
-            root = 'lib/mercurial'
-        else:
-            root = 'etc/mercurial'
-        # old mod_python does not set sys.argv
-        if len(getattr(sys, 'argv', [])) > 0:
-            p = os.path.dirname(os.path.dirname(sys.argv[0]))
-            path.extend(rcfiles(os.path.join(p, root)))
-        path.extend(rcfiles('/' + root))
-        return path
-
-    def userrcpath():
-        if sys.platform == 'plan9':
-            return [os.environ['home'] + '/lib/hgrc']
-        else:
-            return [os.path.expanduser('~/.hgrc')]
-
-else:
-
-    import _winreg
-
-    def systemrcpath():
-        '''return default os-specific hgrc search path'''
-        rcpath = []
-        filename = util.executablepath()
-        # Use mercurial.ini found in directory with hg.exe
-        progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
-        if os.path.isfile(progrc):
-            rcpath.append(progrc)
-            return rcpath
-        # Use hgrc.d found in directory with hg.exe
-        progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
-        if os.path.isdir(progrcd):
-            for f, kind in osutil.listdir(progrcd):
-                if f.endswith('.rc'):
-                    rcpath.append(os.path.join(progrcd, f))
-            return rcpath
-        # else look for a system rcpath in the registry
-        value = util.lookupreg('SOFTWARE\\Mercurial', None,
-                               _winreg.HKEY_LOCAL_MACHINE)
-        if not isinstance(value, str) or not value:
-            return rcpath
-        value = util.localpath(value)
-        for p in value.split(os.pathsep):
-            if p.lower().endswith('mercurial.ini'):
-                rcpath.append(p)
-            elif os.path.isdir(p):
-                for f, kind in osutil.listdir(p):
-                    if f.endswith('.rc'):
-                        rcpath.append(os.path.join(p, f))
-        return rcpath
-
-    def userrcpath():
-        '''return os-specific hgrc search path to the user dir'''
-        home = os.path.expanduser('~')
-        path = [os.path.join(home, 'mercurial.ini'),
-                os.path.join(home, '.hgrc')]
-        userprofile = os.environ.get('USERPROFILE')
-        if userprofile:
-            path.append(os.path.join(userprofile, 'mercurial.ini'))
-            path.append(os.path.join(userprofile, '.hgrc'))
-        return path
-
 def revsingle(repo, revspec, default='.'):
     if not revspec:
         return repo[default]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/scmwindows.py	Thu Feb 28 21:58:37 2013 -0600
@@ -0,0 +1,46 @@
+import os
+import osutil
+import util
+import _winreg
+
+def systemrcpath():
+    '''return default os-specific hgrc search path'''
+    rcpath = []
+    filename = util.executablepath()
+    # Use mercurial.ini found in directory with hg.exe
+    progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
+    if os.path.isfile(progrc):
+        rcpath.append(progrc)
+        return rcpath
+    # Use hgrc.d found in directory with hg.exe
+    progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
+    if os.path.isdir(progrcd):
+        for f, kind in osutil.listdir(progrcd):
+            if f.endswith('.rc'):
+                rcpath.append(os.path.join(progrcd, f))
+        return rcpath
+    # else look for a system rcpath in the registry
+    value = util.lookupreg('SOFTWARE\\Mercurial', None,
+                           _winreg.HKEY_LOCAL_MACHINE)
+    if not isinstance(value, str) or not value:
+        return rcpath
+    value = util.localpath(value)
+    for p in value.split(os.pathsep):
+        if p.lower().endswith('mercurial.ini'):
+            rcpath.append(p)
+        elif os.path.isdir(p):
+            for f, kind in osutil.listdir(p):
+                if f.endswith('.rc'):
+                    rcpath.append(os.path.join(p, f))
+    return rcpath
+
+def userrcpath():
+    '''return os-specific hgrc search path to the user dir'''
+    home = os.path.expanduser('~')
+    path = [os.path.join(home, 'mercurial.ini'),
+            os.path.join(home, '.hgrc')]
+    userprofile = os.environ.get('USERPROFILE')
+    if userprofile:
+        path.append(os.path.join(userprofile, 'mercurial.ini'))
+        path.append(os.path.join(userprofile, '.hgrc'))
+    return path
--- a/mercurial/templatefilters.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/templatefilters.py	Thu Feb 28 21:58:37 2013 -0600
@@ -5,6 +5,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from i18n import _
 import cgi, re, os, time, urllib
 import encoding, node, util, error
 import hbisect
--- a/mercurial/templatekw.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/templatekw.py	Thu Feb 28 21:58:37 2013 -0600
@@ -244,8 +244,8 @@
                 copies.append((fn, rename[0]))
 
     c = [{'name': x[0], 'source': x[1]} for x in copies]
-    return showlist('file_copy', c, plural='file_copies',
-                    element='file', **args)
+    f = _showlist('file_copy', c, plural='file_copies', **args)
+    return _hybrid(f, c)
 
 # showfilecopiesswitch() displays file copies only if copy records are
 # provided before calling the templater, usually with a --copies
@@ -256,8 +256,8 @@
     """
     copies = args['revcache'].get('copies') or []
     c = [{'name': x[0], 'source': x[1]} for x in copies]
-    return showlist('file_copy', c, plural='file_copies',
-                    element='file', **args)
+    f = _showlist('file_copy', c, plural='file_copies', **args)
+    return _hybrid(f, c)
 
 def showfiledels(**args):
     """:file_dels: List of strings. Files removed by this changeset."""
--- a/mercurial/ui.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/ui.py	Thu Feb 28 21:58:37 2013 -0600
@@ -739,7 +739,7 @@
         else:
             self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
 
-    def log(self, service, message):
+    def log(self, service, *msg, **opts):
         '''hook for logging facility extensions
 
         service should be a readily-identifiable subsystem, which will
--- a/mercurial/util.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/util.py	Thu Feb 28 21:58:37 2013 -0600
@@ -880,6 +880,23 @@
     if mode is not None:
         os.chmod(name, mode)
 
+def ensuredirs(name, mode=None):
+    """race-safe recursive directory creation"""
+    if os.path.isdir(name):
+        return
+    parent = os.path.dirname(os.path.abspath(name))
+    if parent != name:
+        ensuredirs(parent, mode)
+    try:
+        os.mkdir(name)
+    except OSError, err:
+        if err.errno == errno.EEXIST and os.path.isdir(name):
+            # someone else seems to have won a directory creation race
+            return
+        raise
+    if mode is not None:
+        os.chmod(name, mode)
+
 def readfile(path):
     fp = open(path, 'rb')
     try:
@@ -1251,7 +1268,18 @@
     except (UnicodeDecodeError, UnicodeEncodeError):
         return _ellipsis(text, maxlength)[0]
 
-_byteunits = (
+def unitcountfn(*unittable):
+    '''return a function that renders a readable count of some quantity'''
+
+    def go(count):
+        for multiplier, divisor, format in unittable:
+            if count >= divisor * multiplier:
+                return format % (count / float(divisor))
+        return unittable[-1][2] % count
+
+    return go
+
+bytecount = unitcountfn(
     (100, 1 << 30, _('%.0f GB')),
     (10, 1 << 30, _('%.1f GB')),
     (1, 1 << 30, _('%.2f GB')),
@@ -1264,14 +1292,6 @@
     (1, 1, _('%.0f bytes')),
     )
 
-def bytecount(nbytes):
-    '''return byte count formatted as readable string, with units'''
-
-    for multiplier, divisor, format in _byteunits:
-        if nbytes >= divisor * multiplier:
-            return format % (nbytes / float(divisor))
-    return _byteunits[-1][2] % nbytes
-
 def uirepr(s):
     # Avoid double backslash in Windows path repr()
     return repr(s).replace('\\\\', '\\')
@@ -1852,3 +1872,46 @@
         return fd.isatty()
     except AttributeError:
         return False
+
+timecount = unitcountfn(
+    (1, 1e3, _('%.0f s')),
+    (100, 1, _('%.1f s')),
+    (10, 1, _('%.2f s')),
+    (1, 1, _('%.3f s')),
+    (100, 0.001, _('%.1f ms')),
+    (10, 0.001, _('%.2f ms')),
+    (1, 0.001, _('%.3f ms')),
+    (100, 0.000001, _('%.1f us')),
+    (10, 0.000001, _('%.2f us')),
+    (1, 0.000001, _('%.3f us')),
+    (100, 0.000000001, _('%.1f ns')),
+    (10, 0.000000001, _('%.2f ns')),
+    (1, 0.000000001, _('%.3f ns')),
+    )
+
+_timenesting = [0]
+
+def timed(func):
+    '''Report the execution time of a function call to stderr.
+
+    During development, use as a decorator when you need to measure
+    the cost of a function, e.g. as follows:
+
+    @util.timed
+    def foo(a, b, c):
+        pass
+    '''
+
+    def wrapper(*args, **kwargs):
+        start = time.time()
+        indent = 2
+        _timenesting[0] += indent
+        try:
+            return func(*args, **kwargs)
+        finally:
+            elapsed = time.time() - start
+            _timenesting[0] -= indent
+            sys.stderr.write('%s%s: %s\n' %
+                             (' ' * _timenesting[0], func.__name__,
+                              timecount(elapsed)))
+    return wrapper
--- a/mercurial/worker.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/mercurial/worker.py	Thu Feb 28 21:58:37 2013 -0600
@@ -6,7 +6,7 @@
 # GNU General Public License version 2 or any later version.
 
 from i18n import _
-import os, signal, sys, util
+import os, signal, sys, threading, util
 
 def countcpus():
     '''try to count the number of CPUs on the system'''
@@ -75,9 +75,13 @@
 def _posixworker(ui, func, staticargs, args):
     rfd, wfd = os.pipe()
     workers = _numworkers(ui)
+    oldhandler = signal.getsignal(signal.SIGINT)
+    signal.signal(signal.SIGINT, signal.SIG_IGN)
+    pids, problem = [], [0]
     for pargs in partition(args, workers):
         pid = os.fork()
         if pid == 0:
+            signal.signal(signal.SIGINT, oldhandler)
             try:
                 os.close(rfd)
                 for i, item in func(*(staticargs + (pargs,))):
@@ -85,29 +89,57 @@
                 os._exit(0)
             except KeyboardInterrupt:
                 os._exit(255)
+        pids.append(pid)
+    pids.reverse()
     os.close(wfd)
     fp = os.fdopen(rfd, 'rb', 0)
-    oldhandler = signal.getsignal(signal.SIGINT)
-    signal.signal(signal.SIGINT, signal.SIG_IGN)
+    def killworkers():
+        # if one worker bails, there's no good reason to wait for the rest
+        for p in pids:
+            try:
+                os.kill(p, signal.SIGTERM)
+            except OSError, err:
+                if err.errno != errno.ESRCH:
+                    raise
+    def waitforworkers():
+        for _ in pids:
+            st = _exitstatus(os.wait()[1])
+            if st and not problem:
+                problem[0] = st
+                killworkers()
+    t = threading.Thread(target=waitforworkers)
+    t.start()
     def cleanup():
-        # python 2.4 is too dumb for try/yield/finally
         signal.signal(signal.SIGINT, oldhandler)
-        problems = 0
-        for i in xrange(workers):
-            problems |= os.wait()[1]
-        if problems:
-            sys.exit(1)
+        t.join()
+        status = problem[0]
+        if status:
+            if status < 0:
+                os.kill(os.getpid(), -status)
+            sys.exit(status)
     try:
         for line in fp:
             l = line.split(' ', 1)
             yield int(l[0]), l[1][:-1]
     except: # re-raises
+        killworkers()
         cleanup()
         raise
     cleanup()
 
+def _posixexitstatus(code):
+    '''convert a posix exit status into the same form returned by
+    os.spawnv
+
+    returns None if the process was stopped instead of exiting'''
+    if os.WIFEXITED(code):
+        return os.WEXITSTATUS(code)
+    elif os.WIFSIGNALED(code):
+        return -os.WTERMSIG(code)
+
 if os.name != 'nt':
     _platformworker = _posixworker
+    _exitstatus = _posixexitstatus
 
 def partition(lst, nslices):
     '''partition a list into N slices of equal size'''
--- a/tests/run-tests.py	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/run-tests.py	Thu Feb 28 21:58:37 2013 -0600
@@ -541,6 +541,13 @@
 def globmatch(el, l):
     # The only supported special characters are * and ? plus / which also
     # matches \ on windows. Escaping of these caracters is supported.
+    if el + '\n' == l:
+        if os.name == 'nt':
+            # matching on "/" is not needed for this line
+            iolock.acquire()
+            print "\nInfo, unnecessary glob: %s (glob)" % el
+            iolock.release()
+        return True
     i, n = 0, len(el)
     res = ''
     while i < n:
--- a/tests/test-alias.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-alias.t	Thu Feb 28 21:58:37 2013 -0600
@@ -17,6 +17,7 @@
   > no-R = status -R elsewhere
   > no--repo = status --repo elsewhere
   > no--repository = status --repository elsewhere
+  > no--config = status --config a.config=1
   > mylog = log
   > lognull = log -r null
   > shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
@@ -106,6 +107,8 @@
   error in definition for alias 'no--repository': --repository may only be given on the command line
   $ hg help no--repository
   error in definition for alias 'no--repository': --repository may only be given on the command line
+  $ hg no--config
+  error in definition for alias 'no--config': --config may only be given on the command line
 
 optional repository
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-blackbox.t	Thu Feb 28 21:58:37 2013 -0600
@@ -0,0 +1,79 @@
+setup
+  $ cat > mock.py <<EOF
+  > from mercurial import util
+  > import getpass
+  > 
+  > def makedate():
+  >     return 0, 0
+  > def getuser():
+  >     return 'bob'
+  > # mock the date and user apis so the output is always the same
+  > def uisetup(ui):
+  >     util.makedate = makedate
+  >     getpass.getuser = getuser
+  > EOF
+  $ cat >> $HGRCPATH <<EOF
+  > [extensions]
+  > blackbox=
+  > mock=`pwd`/mock.py
+  > EOF
+  $ hg init blackboxtest
+  $ cd blackboxtest
+
+command, exit codes, and duration
+
+  $ echo a > a
+  $ hg add a
+  $ hg blackbox
+  1970/01/01 00:00:00 bob> add a
+  1970/01/01 00:00:00 bob> add exited 0 after * seconds (glob)
+
+incoming change tracking
+
+create two heads to verify that we only see one change in the log later
+  $ hg commit -ma
+  $ hg up null
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo b > b
+  $ hg commit -Amb
+  adding b
+  created new head
+
+clone, commit, pull
+  $ hg clone . ../blackboxtest2
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo c > c
+  $ hg commit -Amc
+  adding c
+  $ cd ../blackboxtest2
+  $ hg pull
+  pulling from $TESTTMP/blackboxtest (glob)
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  (run 'hg update' to get a working copy)
+  $ hg blackbox -l 3
+  1970/01/01 00:00:00 bob> pull
+  1970/01/01 00:00:00 bob> 1 incoming changes - new heads: d02f48003e62
+  1970/01/01 00:00:00 bob> pull exited None after * seconds (glob)
+
+extension and python hooks - use the eol extension for a pythonhook
+
+  $ echo '[extensions]' >> .hg/hgrc
+  $ echo 'eol=' >> .hg/hgrc
+  $ echo '[hooks]' >> .hg/hgrc
+  $ echo 'update = echo hooked' >> .hg/hgrc
+  $ hg update
+  hooked
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg blackbox -l 4
+  1970/01/01 00:00:00 bob> update
+  1970/01/01 00:00:00 bob> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
+  1970/01/01 00:00:00 bob> exthook-update: echo hooked finished in * seconds (glob)
+  1970/01/01 00:00:00 bob> update exited False after * seconds (glob)
+
+cleanup
+  $ cd ..
--- a/tests/test-bundle.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-bundle.t	Thu Feb 28 21:58:37 2013 -0600
@@ -522,6 +522,21 @@
   [255]
   $ cd ..
 
+test to bundle revisions on the newly created branch (issue3828):
+
+  $ hg -q clone -U test test-clone
+  $ cd test
+
+  $ hg -q branch foo
+  $ hg commit -m "create foo branch"
+  $ hg -q outgoing ../test-clone
+  9:b4f5acb1ee27
+  $ hg -q bundle --branch foo foo.hg ../test-clone
+  $ hg -R foo.hg -q log -r "bundle()"
+  9:b4f5acb1ee27
+
+  $ cd ..
+
 test for http://mercurial.selenic.com/bts/issue1144
 
 test that verify bundle does not traceback
--- a/tests/test-command-template.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-command-template.t	Thu Feb 28 21:58:37 2013 -0600
@@ -43,6 +43,9 @@
   $ hg mv second fourth
   $ hg commit -m third -d "2020-01-01 10:01"
 
+  $ hg log --template '{file_copies % "{source} -> {name}\n"}' -r .
+  second -> fourth
+
 Quoting for ui.logtemplate
 
   $ hg tip --config "ui.logtemplate={rev}\n"
--- a/tests/test-diff-color.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-diff-color.t	Thu Feb 28 21:58:37 2013 -0600
@@ -152,7 +152,7 @@
    c
    c
   \x1b[0;32m+aa\x1b[0m (esc)
-  \x1b[0;1mdiff --git a/sub/b b/sub/b\x1b[0m (glob) (esc)
+  \x1b[0;1mdiff --git a/sub/b b/sub/b\x1b[0m (esc)
   \x1b[0;31;1m--- a/sub/b\x1b[0m (esc)
   \x1b[0;32;1m+++ b/sub/b\x1b[0m (esc)
   \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
--- a/tests/test-https.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-https.t	Thu Feb 28 21:58:37 2013 -0600
@@ -106,7 +106,7 @@
 
 #if windows
   $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
-  abort: cannot start server at ':$HGPORT': (glob)
+  abort: cannot start server at ':$HGPORT':
   [255]
 #else
   $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
--- a/tests/test-issue3084.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-issue3084.t	Thu Feb 28 21:58:37 2013 -0600
@@ -31,6 +31,8 @@
   foo has been turned into a largefile
   use (l)argefile or keep as (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   (branch merge, don't forget to commit)
+  getting changed largefiles
+  0 largefiles updated, 0 removed
 
   $ hg status
   $ cat foo
--- a/tests/test-largefiles-cache.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-largefiles-cache.t	Thu Feb 28 21:58:37 2013 -0600
@@ -16,6 +16,9 @@
   $ echo large > large
   $ hg add --large large
   $ hg commit -m 'add largefile'
+  $ hg rm large
+  $ hg commit -m 'branchhead without largefile'
+  $ hg up -qr 0
   $ cd ..
 
 Discard all cached largefiles in USERCACHE
@@ -35,16 +38,14 @@
   adding changesets
   adding manifests
   adding file changes
-  added 1 changesets with 1 changes to 1 files
+  added 2 changesets with 1 changes to 1 files
   (run 'hg update' to get a working copy)
-  caching largefiles for 1 heads
-  0 largefiles cached
 
 Update working directory to "tip", which requires largefile("large"),
 but there is no cache file for it.  So, hg must treat it as
 "missing"(!) file.
 
-  $ hg update
+  $ hg update -r0
   getting changed largefiles
   error getting id 7f7097b041ccf68cc5561e9600da4655d21c6d18 from url file:$TESTTMP/mirror for file large: can't get file locally (glob)
   0 largefiles updated, 0 removed
@@ -61,7 +62,7 @@
 
 Update working directory to tip, again.
 
-  $ hg update
+  $ hg update -r0
   getting changed largefiles
   error getting id 7f7097b041ccf68cc5561e9600da4655d21c6d18 from url file:$TESTTMP/mirror for file large: can't get file locally (glob)
   0 largefiles updated, 0 removed
@@ -70,6 +71,17 @@
   ! large
   $ cd ..
 
+Verify that largefiles from pulled branchheads are fetched, also to an empty repo
+
+  $ hg init mirror2
+  $ hg -R mirror2 pull src -r0
+  pulling from src
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  (run 'hg update' to get a working copy)
+
 #if unix-permissions
 
 Portable way to print file permissions:
@@ -90,6 +102,7 @@
   $ chmod 660 large
   $ echo change >> large
   $ hg commit -m change
+  created new head
   $ ../ls-l.py .hg/largefiles/e151b474069de4ca6898f67ce2f2a7263adf8fea
   640
 
--- a/tests/test-largefiles.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-largefiles.t	Thu Feb 28 21:58:37 2013 -0600
@@ -883,9 +883,7 @@
   adding file changes
   added 6 changesets with 16 changes to 8 files
   (run 'hg update' to get a working copy)
-  caching largefiles for 1 heads
-  3 largefiles cached
-  3 additional largefiles cached
+  6 additional largefiles cached
   $ cd ..
 
 Rebasing between two repositories does not revert largefiles to old
@@ -919,8 +917,12 @@
   $ cd d
 
 More rebase testing, but also test that the largefiles are downloaded from
-'default' instead of 'default-push' when no source is specified (issue3584).
-The error messages go away if repo 'b' is created with --all-largefiles.
+'default-push' when no source is specified (issue3584). (The largefile from the
+pulled revision is however not downloaded but found in the local cache.)
+Largefiles are fetched for the new pulled revision, not for existing revisions,
+rebased or not.
+
+  $ [ ! -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
   $ hg pull --rebase --all-largefiles --config paths.default-push=bogus/path --config paths.default=../b
   pulling from $TESTTMP/b (glob)
   searching for changes
@@ -932,18 +934,9 @@
   M sub/normal4
   M sub2/large6
   saved backup bundle to $TESTTMP/d/.hg/strip-backup/f574fb32bb45-backup.hg (glob)
-  error getting id eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from url file:$TESTTMP/b for file large3: can't get file locally (glob)
-  error getting id eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from url file:$TESTTMP/b for file sub/large4: can't get file locally (glob)
-  error getting id eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from url file:$TESTTMP/b for file large1: can't get file locally (glob)
-  error getting id eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from url file:$TESTTMP/b for file sub/large2: can't get file locally (glob)
-  error getting id eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from url file:$TESTTMP/b for file sub/large2: can't get file locally (glob)
-  error getting id 5f78770c0e77ba4287ad6ef3071c9bf9c379742f from url file:$TESTTMP/b for file large1: can't get file locally (glob)
-  error getting id eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 from url file:$TESTTMP/b for file sub/large2: can't get file locally (glob)
-  error getting id 4669e532d5b2c093a78eca010077e708a071bb64 from url file:$TESTTMP/b for file large1: can't get file locally (glob)
-  error getting id 1deebade43c8c498a3c8daddac0244dc55d1331d from url file:$TESTTMP/b for file sub/large2: can't get file locally (glob)
   0 additional largefiles cached
-  9 largefiles failed to download
   nothing to rebase
+  $ [ -f .hg/largefiles/e166e74c7303192238d60af5a9c4ce9bef0b7928 ]
   $ hg log --template '{rev}:{node|short}  {desc|firstline}\n'
   9:598410d3eb9a  modify normal file largefile in repo d
   8:a381d2c8c80e  modify normal file and largefile in repo b
@@ -974,8 +967,6 @@
   adding file changes
   added 1 changesets with 2 changes to 2 files (+1 heads)
   (run 'hg heads' to see heads, 'hg merge' to merge)
-  caching largefiles for 1 heads
-  0 largefiles cached
   $ hg rebase
   Invoking status precommit hook
   M sub/normal4
@@ -1233,10 +1224,76 @@
   changeset 3:9e8fbc4bce62: large1 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
   changeset 4:74c02385b94c: large3 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
   changeset 4:74c02385b94c: sub/large4 references corrupted $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4 (glob)
+  changeset 5:9d5af5072dbd: large3 references missing $TESTTMP/d/.hg/largefiles/baaf12afde9d8d67f25dab6dced0d2bf77dba47c
+  changeset 5:9d5af5072dbd: sub/large4 references missing $TESTTMP/d/.hg/largefiles/aeb2210d19f02886dde00dac279729a48471e2f9
+  changeset 6:4355d653f84f: large3 references missing $TESTTMP/d/.hg/largefiles/7838695e10da2bb75ac1156565f40a2595fa2fa0
   [1]
 
 - cleanup
   $ rm $TESTTMP/d/.hg/largefiles/eb7338044dc27f9bc59b8dd5a246b065ead7a9c4
+  $ rm -f .hglf/sub/*.orig
+
+Update to revision with missing largefile - and make sure it really is missing
+
+  $ rm ${USERCACHE}/7838695e10da2bb75ac1156565f40a2595fa2fa0
+  $ hg up -r 6
+  getting changed largefiles
+  error getting id 7838695e10da2bb75ac1156565f40a2595fa2fa0 from url file:$TESTTMP/d for file large3: can't get file locally (glob)
+  1 largefiles updated, 2 removed
+  4 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ rm normal3
+  $ echo >> sub/normal4
+  $ hg ci -m 'commit with missing files'
+  Invoking status precommit hook
+  M sub/normal4
+  ! large3
+  ! normal3
+  created new head
+  $ hg st
+  ! large3
+  ! normal3
+  $ hg up -r.
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg st
+  ! large3
+  ! normal3
+  $ hg up -Cr.
+  getting changed largefiles
+  error getting id 7838695e10da2bb75ac1156565f40a2595fa2fa0 from url file:$TESTTMP/d for file large3: can't get file locally (glob)
+  0 largefiles updated, 0 removed
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg st
+  ! large3
+  $ hg rollback
+  repository tip rolled back to revision 9 (undo commit)
+  working directory now based on revision 6
+
+Merge with revision with missing largefile - and make sure it tries to fetch it.
+
+  $ hg up -Cqr null
+  $ echo f > f
+  $ hg ci -Am branch
+  adding f
+  Invoking status precommit hook
+  A f
+  created new head
+  $ hg merge -r 6
+  4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  getting changed largefiles
+  error getting id 7838695e10da2bb75ac1156565f40a2595fa2fa0 from url file:$TESTTMP/d for file large3: can't get file locally (glob)
+  1 largefiles updated, 0 removed
+
+  $ hg rollback -q
+  $ hg up -Cq
+
+Pulling 0 revisions with --all-largefiles should not fetch for all revisions
+
+  $ hg pull --all-largefiles
+  pulling from $TESTTMP/d (glob)
+  searching for changes
+  no changes found
+  0 additional largefiles cached
 
 Merging does not revert to old versions of largefiles and also check
 that merging after having pulled from a non-default remote works
@@ -1265,7 +1322,8 @@
   $ hg commit -m "Modify large4 to test merge"
   Invoking status precommit hook
   M sub/large4
-  $ hg pull ../e
+# Test --cache-largefiles flag
+  $ hg pull --cache-largefiles ../e
   pulling from ../e
   searching for changes
   adding changesets
--- a/tests/test-mq.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-mq.t	Thu Feb 28 21:58:37 2013 -0600
@@ -1567,12 +1567,13 @@
   > wsgicgi.launch(app)
   > HGWEB
   $ . "$TESTDIR/cgienv"
+#if msys
+  $ PATH_INFO=//tags; export PATH_INFO
+#else
   $ PATH_INFO=/tags; export PATH_INFO
+#endif
   $ QUERY_STRING='style=raw'
-  $ python hgweb.cgi | grep -v ETag:
-  Status: 200 Script output follows\r (esc)
-  Content-Type: text/plain; charset=ascii\r (esc)
-  \r (esc)
+  $ python hgweb.cgi | grep '^tip'
   tip	[0-9a-f]{40} (re)
 
   $ cd ..
--- a/tests/test-obsolete.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-obsolete.t	Thu Feb 28 21:58:37 2013 -0600
@@ -816,7 +816,7 @@
      summary:     A
   
   $ hg incoming
-  comparing with $TESTTMP/tmpe/repo-issue3805
+  comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
   searching for changes
   changeset:   2:3816541e5485
   tag:         tip
@@ -826,7 +826,7 @@
   summary:     A
   
   $ hg incoming --bundle ../issue3805.hg
-  comparing with $TESTTMP/tmpe/repo-issue3805
+  comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
   searching for changes
   changeset:   2:3816541e5485
   tag:         tip
@@ -836,7 +836,7 @@
   summary:     A
   
   $ hg outgoing
-  comparing with $TESTTMP/tmpe/repo-issue3805
+  comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
   searching for changes
   no changes found
   [1]
--- a/tests/test-progress.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-progress.t	Thu Feb 28 21:58:37 2013 -0600
@@ -167,6 +167,7 @@
 
   $ hg -y loop 8
   \r (no-eol) (esc)
+  loop [====>                                     ] 1/8 1m18s\r (no-eol) (esc)
   loop [=========>                                ] 2/8 1m07s\r (no-eol) (esc)
   loop [===============>                            ] 3/8 56s\r (no-eol) (esc)
   loop [=====================>                      ] 4/8 45s\r (no-eol) (esc)
@@ -203,6 +204,7 @@
 Time estimates should not fail when there's no end point:
   $ hg -y loop -- -4
   \r (no-eol) (esc)
-  loop [ <=>                                              ] 2\r (no-eol) (esc)
-  loop [  <=>                                             ] 3\r (no-eol) (esc)
+  loop [ <=>                                              ] 1\r (no-eol) (esc)
+  loop [  <=>                                             ] 2\r (no-eol) (esc)
+  loop [   <=>                                            ] 3\r (no-eol) (esc)
                                                               \r (no-eol) (esc)
--- a/tests/test-subrepo.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-subrepo.t	Thu Feb 28 21:58:37 2013 -0600
@@ -269,9 +269,9 @@
   $ cd ..
   $ hg clone t tc
   updating to branch default
-  cloning subrepo s from $TESTTMP/t/s (glob)
+  cloning subrepo s from $TESTTMP/t/s
   cloning subrepo s/ss from $TESTTMP/t/s/ss (glob)
-  cloning subrepo t from $TESTTMP/t/t (glob)
+  cloning subrepo t from $TESTTMP/t/t
   3 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd tc
   $ hg debugsub
@@ -292,10 +292,10 @@
   pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
   searching for changes
   no changes found
-  pushing subrepo s to $TESTTMP/t/s (glob)
+  pushing subrepo s to $TESTTMP/t/s
   searching for changes
   no changes found
-  pushing subrepo t to $TESTTMP/t/t (glob)
+  pushing subrepo t to $TESTTMP/t/t
   searching for changes
   adding changesets
   adding manifests
@@ -317,7 +317,7 @@
   pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
   searching for changes
   no changes found
-  pushing subrepo s to $TESTTMP/t/s (glob)
+  pushing subrepo s to $TESTTMP/t/s
   searching for changes
   abort: push creates new remote head 12a213df6fa9! (in subrepo s)
   (did you forget to merge? use push -f to force)
@@ -327,13 +327,13 @@
   pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
   searching for changes
   no changes found
-  pushing subrepo s to $TESTTMP/t/s (glob)
+  pushing subrepo s to $TESTTMP/t/s
   searching for changes
   adding changesets
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
-  pushing subrepo t to $TESTTMP/t/t (glob)
+  pushing subrepo t to $TESTTMP/t/t
   searching for changes
   no changes found
   searching for changes
@@ -366,7 +366,7 @@
 should pull t
 
   $ hg up
-  pulling subrepo t from $TESTTMP/t/t (glob)
+  pulling subrepo t from $TESTTMP/t/t
   searching for changes
   adding changesets
   adding manifests
@@ -572,7 +572,7 @@
   adding .hgsub
   $ hg clone repo repo2
   updating to branch default
-  cloning subrepo s from $TESTTMP/repo/s (glob)
+  cloning subrepo s from $TESTTMP/repo/s
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg -q -R repo2 pull -u
   $ echo 1 > repo2/s/a
--- a/tests/test-walk.t	Sun Feb 17 14:41:31 2013 -0600
+++ b/tests/test-walk.t	Thu Feb 28 21:58:37 2013 -0600
@@ -155,7 +155,7 @@
   abort: path 'mammals/.hg' is inside nested repo 'mammals' (glob)
   [255]
   $ hg debugwalk ../.hg
-  abort: path contains illegal component: .hg (glob)
+  abort: path contains illegal component: .hg
   [255]
   $ cd ..
 
@@ -187,10 +187,10 @@
   abort: beans/../.. not under root '$TESTTMP/t' (glob)
   [255]
   $ hg debugwalk .hg
-  abort: path contains illegal component: .hg (glob)
+  abort: path contains illegal component: .hg
   [255]
   $ hg debugwalk beans/../.hg
-  abort: path contains illegal component: .hg (glob)
+  abort: path contains illegal component: .hg
   [255]
   $ hg debugwalk beans/../.hg/data
   abort: path contains illegal component: .hg/data (glob)