changeset 26368:0224d22ef5d8

merge with stable
author Matt Mackall <mpm@selenic.com>
date Fri, 25 Sep 2015 23:10:47 -0500
parents a672cc61ab1d (diff) f31ddc9bfa5f (current diff)
children 4799b5c4aaf4
files mercurial/commands.py
diffstat 235 files changed, 5865 insertions(+), 2763 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Fri Sep 25 13:30:49 2015 -0700
+++ b/Makefile	Fri Sep 25 23:10:47 2015 -0500
@@ -157,14 +157,12 @@
 	N=`cd dist && echo mercurial-*.mpkg | sed 's,\.mpkg$$,,'` && hdiutil create -srcfolder dist/$$N.mpkg/ -scrub -volname "$$N" -ov packages/osx/$$N.dmg
 	rm -rf dist/mercurial-*.mpkg
 
-debian-jessie:
-	mkdir -p packages/debian-jessie
-	contrib/builddeb
-	mv debbuild/*.deb packages/debian-jessie
-	rm -rf debbuild
+deb:
+	mkdir -p packages/debian-unknown
+	contrib/builddeb --release unknown
 
 docker-debian-jessie:
-	mkdir -p packages/debian/jessie
+	mkdir -p packages/debian-jessie
 	contrib/dockerdeb jessie
 
 fedora20:
--- a/contrib/builddeb	Fri Sep 25 13:30:49 2015 -0700
+++ b/contrib/builddeb	Fri Sep 25 23:10:47 2015 -0500
@@ -7,13 +7,23 @@
 . $(dirname $0)/packagelib.sh
 
 BUILD=1
-DEBBUILDDIR="$PWD/debbuild"
+CLEANUP=1
+DEBVERSION=jessie
 while [ "$1" ]; do
     case "$1" in
-    --prepare )
+    --release )
+        shift
+        DEBVERSION="$1"
+        shift
+        ;;
+    --cleanup )
         shift
         BUILD=
         ;;
+    --build )
+        shift
+        CLEANUP=
+        ;;
     --debbuilddir )
         shift
         DEBBUILDDIR="$1"
@@ -26,10 +36,9 @@
     esac
 done
 
-set -u
+trap "if [ '$CLEANUP' ] ; then rm -r '$PWD/debian' ; fi" EXIT
 
-rm -rf $DEBBUILDDIR
-mkdir -p $DEBBUILDDIR
+set -u
 
 if [ ! -d .hg ]; then
     echo 'You are not inside a Mercurial repository!' 1>&2
@@ -38,25 +47,38 @@
 
 gethgversion
 
-cp -r $PWD/contrib/debian $DEBBUILDDIR/DEBIAN
-chmod -R 0755 $DEBBUILDDIR/DEBIAN
-
-control=$DEBBUILDDIR/DEBIAN/control
-
-# This looks like sed -i, but sed -i behaves just differently enough
-# between BSD and GNU sed that I gave up and did the dumb thing.
-sed "s/__VERSION__/$version/" < $control > $control.tmp
-mv $control.tmp $control
+control=debian/control
+changelog=debian/changelog
 
 if [ "$BUILD" ]; then
-    dpkg-deb --build $DEBBUILDDIR
-    mv $DEBBUILDDIR.deb $DEBBUILDDIR/mercurial-$version-$release.deb
-    if [ $? = 0 ]; then
-        echo
-        echo "Built packages for $version-$release:"
-        find $DEBBUILDDIR/ -type f -newer $control
+    if [ -d debian ] ; then
+        echo "Error! debian control directory already exists!"
+        exit 1
     fi
-else
-    echo "Prepared sources for $version-$release $control are in $DEBBUILDDIR - use like:"
-    echo "dpkg-deb --build $DEBBUILDDIR"
+
+    cp -r $PWD/contrib/debian debian
+    chmod -R 0755 debian
+
+    # This looks like sed -i, but sed -i behaves just differently enough
+    # between BSD and GNU sed that I gave up and did the dumb thing.
+    sed "s/__VERSION__/$version/" < $changelog > $changelog.tmp
+    date=$(date --rfc-2822)
+    sed "s/__DATE__/$date/" < $changelog.tmp > $changelog
+    rm $changelog.tmp
+
+    debuild -us -uc -b
+    if [ $? != 0 ]; then
+        echo 'debuild failed!'
+        exit 1
+    fi
+
 fi
+if [ "$CLEANUP" ] ; then
+    echo
+    OUTPUTDIR=${OUTPUTDIR:=packages/debian-$DEBVERSION}
+    find ../mercurial*.deb ../mercurial_*.build ../mercurial_*.changes \
+          -type f -newer $control -print0 | \
+      xargs -Inarf -0 mv narf "$OUTPUTDIR"
+    echo "Built packages for $version-$release:"
+    find "$OUTPUTDIR" -type f -newer $control -name '*.deb'
+fi
--- a/contrib/buildrpm	Fri Sep 25 13:30:49 2015 -0700
+++ b/contrib/buildrpm	Fri Sep 25 23:10:47 2015 -0500
@@ -56,6 +56,7 @@
     RPMPYTHONVER=%{nil}
 fi
 
+mkdir -p $RPMBUILDDIR/SOURCES
 $HG archive -t tgz $RPMBUILDDIR/SOURCES/mercurial-$version-$release.tar.gz
 if [ "$PYTHONVER" ]; then
 (
@@ -79,6 +80,7 @@
 )
 fi
 
+mkdir -p $RPMBUILDDIR/SPECS
 rpmspec=$RPMBUILDDIR/SPECS/mercurial.spec
 
 sed -e "s,^Version:.*,Version: $version," \
--- a/contrib/check-code.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/contrib/check-code.py	Fri Sep 25 23:10:47 2015 -0500
@@ -291,6 +291,8 @@
     (r'os\.path\.join\(.*, *(""|\'\')\)',
      "use pathutil.normasprefix(path) instead of os.path.join(path, '')"),
     (r'\s0[0-7]+\b', 'legacy octal syntax; use "0o" prefix instead of "0"'),
+    # XXX only catch mutable arguments on the first line of the definition
+    (r'def.*[( ]\w+=\{\}', "don't use mutable default arguments"),
   ],
   # warnings
   [
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/debian/cacerts.rc	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,5 @@
+# This config file points Mercurial at the system-wide certificate
+# store from the ca-certificates package.
+
+[web]
+cacerts = /etc/ssl/certs/ca-certificates.crt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/debian/changelog	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,5 @@
+mercurial (__VERSION__) unstable; urgency=medium
+
+  * Automated build performed by upstream.
+
+ -- Mercurial Devel <mercurial-devel@selenic.com>  __DATE__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/debian/compat	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,1 @@
+9
--- a/contrib/debian/control	Fri Sep 25 13:30:49 2015 -0700
+++ b/contrib/debian/control	Fri Sep 25 23:10:47 2015 -0500
@@ -1,9 +1,47 @@
-Package: mercurial
-Version: __VERSION__
+Source: mercurial
 Section: vcs
 Priority: optional
+Maintainer: Mercurial Developers <mercurial-devel@selenic.com>
+Build-Depends:
+ debhelper (>= 7),
+ dh-python,
+ python-all
+Standards-Version: 3.9.4
+X-Python-Version: >= 2.6
+
+Package: mercurial
+Depends:
+ python,
+ ${shlibs:Depends},
+ ${misc:Depends},
+ ${python:Depends},
+ mercurial-common (= ${source:Version})
+Architecture: any
+Description: fast, easy to use, distributed revision control tool.
+ Mercurial is a fast, lightweight Source Control Management system designed
+ for efficient handling of very large distributed projects.
+ .
+ Its features include:
+  * O(1) delta-compressed file storage and retrieval scheme
+  * Complete cross-indexing of files and changesets for efficient exploration
+    of project history
+  * Robust SHA1-based integrity checking and append-only storage model
+  * Decentralized development model with arbitrary merging between trees
+  * Easy-to-use command-line interface
+  * Integrated stand-alone web interface
+  * Small Python codebase
+
+Package: mercurial-common
 Architecture: all
-Depends: python
-Conflicts: mercurial-common
-Maintainer: Mercurial Developers <mercurial-devel@selenic.com>
-Description: Mercurial (probably nightly) package built by upstream.
+Depends:
+ ${misc:Depends},
+ ${python:Depends},
+Recommends: mercurial (= ${source:Version}), ca-certificates
+Breaks: mercurial (<< ${source:Version})
+Replaces: mercurial (<< 2.6.3)
+Description: easy-to-use, scalable distributed version control system (common files)
+ Mercurial is a fast, lightweight Source Control Management system designed
+ for efficient handling of very large distributed projects.
+ .
+ This package contains the architecture independent components of Mercurial,
+ and is generally useless without the mercurial package.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/debian/copyright	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,27 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: mercurial
+Source: http://www.selenic.com/mercurial/
+
+Files: *
+Copyright: 2005-2015, Matt Mackall <mpm@selenic.com> and others.
+License: GPL-2+
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ .
+ This program is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.  See the GNU General Public License for more
+ details.
+ .
+ You should have received a copy of the GNU General Public
+ License along with this package; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2'.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/debian/hgkpath.rc	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,2 @@
+[hgk]
+path = /usr/share/mercurial/hgk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/debian/rules	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,36 @@
+#!/usr/bin/make -f
+# Uncomment this to turn on verbose mode.
+# export DH_VERBOSE=1
+
+CPUS=$(shell cat /proc/cpuinfo | grep -E ^processor | wc -l)
+
+%:
+	dh $@ --with python2
+
+override_dh_auto_test:
+	http_proxy='' dh_auto_test -- TESTFLAGS="-j$(CPUS)"
+
+override_dh_python2:
+	dh_python2
+	find debian/mercurial/usr/share -type d -empty -delete
+
+override_dh_install:
+	python$(PYVERS) setup.py install --root $(CURDIR)/debian/mercurial --install-layout=deb
+	# remove arch-independent python stuff
+	find $(CURDIR)/debian/mercurial/usr/lib \
+		! -name '*.so' ! -type d -delete , \
+		-type d -empty -delete
+	python$(PYVERS) setup.py install --root $(CURDIR)/debian/mercurial-common --install-layout=deb
+	make install-doc PREFIX=$(CURDIR)/debian/mercurial-common/usr
+	# remove arch-dependent python stuff
+	find $(CURDIR)/debian/mercurial-common/usr/lib \
+		-name '*.so' ! -type d -delete , \
+		-type d -empty -delete
+	cp contrib/hg-ssh $(CURDIR)/debian/mercurial-common/usr/bin
+	mkdir -p $(CURDIR)/debian/mercurial-common/usr/share/mercurial
+	cp contrib/hgk $(CURDIR)/debian/mercurial-common/usr/share/mercurial
+	mkdir -p $(CURDIR)/debian/mercurial-common/etc/mercurial/hgrc.d/
+	cp contrib/debian/*.rc $(CURDIR)/debian/mercurial-common/etc/mercurial/hgrc.d/
+	mkdir -p $(CURDIR)/debian/mercurial-common/usr/share/bash-completion/completions
+	cp contrib/bash_completion $(CURDIR)/debian/mercurial-common/usr/share/bash-completion/completions/mercurial
+	rm $(CURDIR)/debian/mercurial-common/usr/bin/hg
--- a/contrib/dockerdeb	Fri Sep 25 13:30:49 2015 -0700
+++ b/contrib/dockerdeb	Fri Sep 25 23:10:47 2015 -0500
@@ -8,32 +8,27 @@
 
 checkdocker
 
+DEBPLATFORM="$1"
 PLATFORM="debian-$1"
 shift # extra params are passed to build process
 
+OUTPUTDIR=${OUTPUTDIR:=$ROOTDIR/packages/$PLATFORM}
+
 initcontainer $PLATFORM
 
-DEBBUILDDIR=$ROOTDIR/packages/$PLATFORM
-contrib/builddeb --debbuilddir $DEBBUILDDIR/staged --prepare
+# debuild only appears to be able to save built debs etc to .., so we
+# have to share the .. of the current directory with the docker
+# container and hope it's writable. Whee.
+dn=$(basename $PWD)
 
-DSHARED=/mnt/shared/
 if [ $(uname) = "Darwin" ] ; then
-    $DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED -v $PWD:/mnt/hg $CONTAINER \
-            sh -c "cd /mnt/hg && make clean && make local"
+    $DOCKER run -u $DBUILDUSER --rm -v $PWD/..:/mnt $CONTAINER \
+            sh -c "cd /mnt/$dn && make clean && make local"
 fi
-$DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED -v $PWD:/mnt/hg $CONTAINER \
-  sh -c "cd /mnt/hg && make PREFIX=$DSHARED/staged/usr install"
-$DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED $CONTAINER \
-  dpkg-deb --build $DSHARED/staged
+$DOCKER run -u $DBUILDUSER --rm -v $PWD/..:/mnt $CONTAINER \
+  sh -c "cd /mnt/$dn && DEB_BUILD_OPTIONS='${DEB_BUILD_OPTIONS:=}' contrib/builddeb --build --release $DEBPLATFORM"
+contrib/builddeb --cleanup --release $DEBPLATFORM
 if [ $(uname) = "Darwin" ] ; then
-    $DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED -v $PWD:/mnt/hg $CONTAINER \
-            sh -c "cd /mnt/hg && make clean"
+    $DOCKER run -u $DBUILDUSER --rm -v $PWD/..:/mnt $CONTAINER \
+            sh -c "cd /mnt/$dn && make clean"
 fi
-
-gethgversion
-
-rm -r $DEBBUILDDIR/staged
-mv $DEBBUILDDIR/staged.deb $DEBBUILDDIR/mercurial-$version-$release.deb
-
-echo
-echo "Build complete - results can be found in $DEBBUILDDIR"
--- a/contrib/import-checker.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/contrib/import-checker.py	Fri Sep 25 23:10:47 2015 -0500
@@ -164,7 +164,7 @@
     for m in ['msvcrt', '_winreg']:
         yield m
     # These get missed too
-    for m in 'ctypes', 'email':
+    for m in 'ctypes', 'email', 'multiprocessing':
         yield m
     yield 'builtins' # python3 only
     for m in 'fcntl', 'grp', 'pwd', 'termios':  # Unix only
@@ -200,8 +200,7 @@
             for name in files:
                 if name == '__init__.py':
                     continue
-                if not (name.endswith('.py') or name.endswith('.so')
-                        or name.endswith('.pyd')):
+                if not name.endswith(('.py', '.so', '.pyc', '.pyo', '.pyd')):
                     continue
                 full_path = os.path.join(top, name)
                 rel_path = full_path[len(libpath) + 1:]
--- a/contrib/revsetbenchmarks.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/contrib/revsetbenchmarks.py	Fri Sep 25 23:10:47 2015 -0500
@@ -33,6 +33,8 @@
     """update the repo to a revision"""
     try:
         check_call(['hg', 'update', '--quiet', '--check', str(rev)])
+        check_output(['make', 'local'],
+                     stderr=None)  # suppress output except for error/warning
     except CalledProcessError as exc:
         print >> sys.stderr, 'update to revision %s failed, aborting' % rev
         sys.exit(exc.returncode)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/showstack.py	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,17 @@
+# showstack.py - extension to dump a Python stack trace on signal
+#
+# binds to both SIGQUIT (Ctrl-\) and SIGINFO (Ctrl-T on BSDs)
+
+import sys, signal, traceback
+
+def sigshow(*args):
+    sys.stderr.write("\n")
+    traceback.print_stack(args[1], limit=10, file=sys.stderr)
+    sys.stderr.write("----\n")
+
+def extsetup(ui):
+    signal.signal(signal.SIGQUIT, sigshow)
+    try:
+        signal.signal(signal.SIGINFO, sigshow)
+    except AttributeError:
+        pass
--- a/contrib/vagrant/Vagrantfile	Fri Sep 25 13:30:49 2015 -0700
+++ b/contrib/vagrant/Vagrantfile	Fri Sep 25 23:10:47 2015 -0500
@@ -1,9 +1,8 @@
 # -*- mode: ruby -*-
 
 Vagrant.configure('2') do |config|
-  # Debian 7.4 32-bit i386 without configuration management software
-  config.vm.box = "puppetlabs/debian-7.4-32-nocm"
-  #config.vm.box = "pnd/debian-wheezy32-basebox"
+  # Debian 8.1 x86_64 without configuration management software
+  config.vm.box = "debian/jessie64"
   config.vm.hostname = "tests"
 
   config.vm.define "tests" do |conf|
--- a/contrib/vim/patchreview.txt	Fri Sep 25 13:30:49 2015 -0700
+++ b/contrib/vim/patchreview.txt	Fri Sep 25 23:10:47 2015 -0500
@@ -30,7 +30,7 @@
 software development projects. This plugin provides that missing
 functionality.
 
-It also improves on |:diffpatch|'s behaviour of creating the patched files in
+It also improves on |:diffpatch|'s behavior of creating the patched files in
 the same directory as original file which can lead to project workspace
 pollution.
 
--- a/doc/check-seclevel.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/doc/check-seclevel.py	Fri Sep 25 23:10:47 2015 -0500
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# checkseclevel - checking section title levels in each online help documents
+# checkseclevel - checking section title levels in each online help document
 
 import sys, os
 import optparse
--- a/doc/hgmanpage.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/doc/hgmanpage.py	Fri Sep 25 23:10:47 2015 -0500
@@ -18,11 +18,11 @@
  7 miscellaneous
  8 system administration
 
-Man pages are written *troff*, a text file formatting system.
+Man pages are written in *troff*, a text file formatting system.
 
 See http://www.tldp.org/HOWTO/Man-Page for a start.
 
-Man pages have no subsection only parts.
+Man pages have no subsections only parts.
 Standard parts
 
   NAME ,
@@ -317,7 +317,7 @@
                     self._cnt = 0
                 self._indent = 2
                 if style == 'arabic':
-                    # indentation depends on number of childrens
+                    # indentation depends on number of children
                     # and start value.
                     self._indent = len(str(len(node.children)))
                     self._indent += len(str(self._cnt)) + 1
--- a/hgext/blackbox.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/blackbox.py	Fri Sep 25 23:10:47 2015 -0500
@@ -107,9 +107,11 @@
             if blackbox:
                 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
                 user = util.getuser()
+                pid = str(os.getpid())
                 formattedmsg = msg[0] % msg[1:]
                 try:
-                    blackbox.write('%s %s> %s' % (date, user, formattedmsg))
+                    blackbox.write('%s %s (%s)> %s' %
+                                   (date, user, pid, formattedmsg))
                 except IOError as err:
                     self.debug('warning: cannot write to blackbox.log: %s\n' %
                                err.strerror)
--- a/hgext/convert/__init__.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/convert/__init__.py	Fri Sep 25 23:10:47 2015 -0500
@@ -316,6 +316,9 @@
         ``convert.git.remoteprefix`` as a prefix followed by a /. The default
         is 'remote'.
 
+    :convert.git.skipsubmodules: does not convert root level .gitmodules files
+        or files with 160000 mode indicating a submodule. Default is False.
+
     Perforce Source
     ###############
 
--- a/hgext/convert/common.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/convert/common.py	Fri Sep 25 23:10:47 2015 -0500
@@ -82,6 +82,13 @@
     def after(self):
         pass
 
+    def targetfilebelongstosource(self, targetfilename):
+        """Returns true if the given targetfile belongs to the source repo. This
+        is useful when only a subdirectory of the target belongs to the source
+        repo."""
+        # For normal full repo converts, this is always True.
+        return True
+
     def setrevmap(self, revmap):
         """set the map of already-converted revisions"""
         pass
--- a/hgext/convert/convcmd.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/convert/convcmd.py	Fri Sep 25 23:10:47 2015 -0500
@@ -120,6 +120,9 @@
                          item=file, total=self.filecount)
         return self.source.getfile(file, rev)
 
+    def targetfilebelongstosource(self, targetfilename):
+        return self.source.targetfilebelongstosource(targetfilename)
+
     def lookuprev(self, rev):
         return self.source.lookuprev(rev)
 
--- a/hgext/convert/filemap.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/convert/filemap.py	Fri Sep 25 23:10:47 2015 -0500
@@ -42,6 +42,7 @@
         self.include = {}
         self.exclude = {}
         self.rename = {}
+        self.targetprefixes = None
         if path:
             if self.parse(path):
                 raise util.Abort(_('errors in filemap'))
@@ -100,6 +101,30 @@
                 pass
         return '', name, ''
 
+    def istargetfile(self, filename):
+        """Return true if the given target filename is covered as a destination
+        of the filemap. This is useful for identifying what parts of the target
+        repo belong to the source repo and what parts don't."""
+        if self.targetprefixes is None:
+            self.targetprefixes = set()
+            for before, after in self.rename.iteritems():
+                self.targetprefixes.add(after)
+
+        # If "." is a target, then all target files are considered from the
+        # source.
+        if not self.targetprefixes or '.' in self.targetprefixes:
+            return True
+
+        filename = normalize(filename)
+        for pre, suf in rpairs(filename):
+            # This check is imperfect since it doesn't account for the
+            # include/exclude list, but it should work in filemaps that don't
+            # apply include/exclude to the same source directories they are
+            # renaming.
+            if pre in self.targetprefixes:
+                return True
+        return False
+
     def __call__(self, name):
         if self.include:
             inc = self.lookup(name, self.include)[0]
@@ -410,6 +435,9 @@
 
         return files, ncopies, ncleanp2
 
+    def targetfilebelongstosource(self, targetfilename):
+        return self.filemapper.istargetfile(targetfilename)
+
     def getfile(self, name, rev):
         realname, realrev = rev
         return self.base.getfile(realname, realrev)
--- a/hgext/convert/git.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/convert/git.py	Fri Sep 25 23:10:47 2015 -0500
@@ -224,6 +224,8 @@
         lcount = len(difftree)
         i = 0
 
+        skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules',
+                                            False)
         def add(entry, f, isdest):
             seen.add(f)
             h = entry[3]
@@ -232,6 +234,9 @@
             renamesource = (not isdest and entry[4][0] == 'R')
 
             if f == '.gitmodules':
+                if skipsubmodules:
+                    return
+
                 subexists[0] = True
                 if entry[4] == 'D' or renamesource:
                     subdeleted[0] = True
@@ -239,7 +244,8 @@
                 else:
                     changes.append(('.hgsub', ''))
             elif entry[1] == '160000' or entry[0] == ':160000':
-                subexists[0] = True
+                if not skipsubmodules:
+                    subexists[0] = True
             else:
                 if renamesource:
                     h = hex(nullid)
@@ -377,28 +383,31 @@
     def getbookmarks(self):
         bookmarks = {}
 
-        # Interesting references in git are prefixed
-        prefix = 'refs/heads/'
-        prefixlen = len(prefix)
+        # Handle local and remote branches
+        remoteprefix = self.ui.config('convert', 'git.remoteprefix', 'remote')
+        reftypes = [
+            # (git prefix, hg prefix)
+            ('refs/remotes/origin/', remoteprefix + '/'),
+            ('refs/heads/', '')
+        ]
 
-        # factor two commands
-        remoteprefix = self.ui.config('convert', 'git.remoteprefix', 'remote')
-        gitcmd = { remoteprefix + '/': 'git ls-remote --heads origin',
-                                   '': 'git show-ref'}
+        exclude = set([
+            'refs/remotes/origin/HEAD',
+        ])
 
-        # Origin heads
-        for reftype in gitcmd:
-            try:
-                fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
-                for line in fh:
-                    line = line.strip()
-                    rev, name = line.split(None, 1)
-                    if not name.startswith(prefix):
+        try:
+            fh = self.gitopen('git show-ref', err=subprocess.PIPE)
+            for line in fh:
+                line = line.strip()
+                rev, name = line.split(None, 1)
+                # Process each type of branch
+                for gitprefix, hgprefix in reftypes:
+                    if not name.startswith(gitprefix) or name in exclude:
                         continue
-                    name = '%s%s' % (reftype, name[prefixlen:])
+                    name = '%s%s' % (hgprefix, name[len(gitprefix):])
                     bookmarks[name] = rev
-            except Exception:
-                pass
+        except Exception:
+            pass
 
         return bookmarks
 
--- a/hgext/convert/hg.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/convert/hg.py	Fri Sep 25 23:10:47 2015 -0500
@@ -23,6 +23,7 @@
 from mercurial.node import bin, hex, nullid
 from mercurial import hg, util, context, bookmarks, error, scmutil, exchange
 from mercurial import phases
+from mercurial import merge as mergemod
 
 from common import NoRepo, commit, converter_source, converter_sink, mapfile
 
@@ -176,14 +177,58 @@
 
         return fp.getvalue()
 
+    def _calculatemergedfiles(self, source, p1ctx, p2ctx):
+        """Calculates the files from p2 that we need to pull in when merging p1
+        and p2, given that the merge is coming from the given source.
+
+        This prevents us from losing files that only exist in the target p2 and
+        that don't come from the source repo (like if you're merging multiple
+        repositories together).
+        """
+        anc = [p1ctx.ancestor(p2ctx)]
+        # Calculate what files are coming from p2
+        actions, diverge, rename = mergemod.calculateupdates(
+            self.repo, p1ctx, p2ctx, anc,
+            True,  # branchmerge
+            True,  # force
+            False, # partial
+            False, # acceptremote
+            False, # followcopies
+        )
+
+        for file, (action, info, msg) in actions.iteritems():
+            if source.targetfilebelongstosource(file):
+                # If the file belongs to the source repo, ignore the p2
+                # since it will be covered by the existing fileset.
+                continue
+
+            # If the file requires actual merging, abort. We don't have enough
+            # context to resolve merges correctly.
+            if action in ['m', 'dm', 'cd', 'dc']:
+                raise util.Abort(_("unable to convert merge commit "
+                    "since target parents do not merge cleanly (file "
+                    "%s, parents %s and %s)") % (file, p1ctx,
+                                                 p2ctx))
+            elif action == 'k':
+                # 'keep' means nothing changed from p1
+                continue
+            else:
+                # Any other change means we want to take the p2 version
+                yield file
+
     def putcommit(self, files, copies, parents, commit, source, revmap, full,
                   cleanp2):
         files = dict(files)
 
         def getfilectx(repo, memctx, f):
-            if p2ctx and f in cleanp2 and f not in copies:
+            if p2ctx and f in p2files and f not in copies:
                 self.ui.debug('reusing %s from p2\n' % f)
-                return p2ctx[f]
+                try:
+                    return p2ctx[f]
+                except error.ManifestLookupError:
+                    # If the file doesn't exist in p2, then we're syncing a
+                    # delete, so just return None.
+                    return None
             try:
                 v = files[f]
             except KeyError:
@@ -255,6 +300,7 @@
         while parents:
             p1 = p2
             p2 = parents.pop(0)
+            p1ctx = self.repo[p1]
             p2ctx = None
             if p2 != nullid:
                 p2ctx = self.repo[p2]
@@ -262,6 +308,13 @@
             if full:
                 fileset.update(self.repo[p1])
                 fileset.update(self.repo[p2])
+
+            if p2ctx:
+                p2files = set(cleanp2)
+                for file in self._calculatemergedfiles(source, p1ctx, p2ctx):
+                    p2files.add(file)
+                    fileset.add(file)
+
             ctx = context.memctx(self.repo, (p1, p2), text, fileset,
                                  getfilectx, commit.author, commit.date, extra)
 
@@ -378,9 +431,6 @@
 class mercurial_source(converter_source):
     def __init__(self, ui, path, revs=None):
         converter_source.__init__(self, ui, path, revs)
-        if revs and len(revs) > 1:
-            raise util.Abort(_("mercurial source does not support specifying "
-                               "multiple revisions"))
         self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
         self.ignored = set()
         self.saverev = ui.configbool('convert', 'hg.saverev', False)
@@ -415,7 +465,7 @@
             else:
                 self.keep = util.always
             if revs:
-                self._heads = [self.repo[revs[0]].node()]
+                self._heads = [self.repo[r].node() for r in revs]
             else:
                 self._heads = self.repo.heads()
         else:
--- a/hgext/eol.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/eol.py	Fri Sep 25 23:10:47 2015 -0500
@@ -23,7 +23,7 @@
 ``native`` is an alias for checking out in the platform's default line
 ending: ``LF`` on Unix (including Mac OS X) and ``CRLF`` on
 Windows. Note that ``BIN`` (do nothing to line endings) is Mercurial's
-default behaviour; it is only needed if you need to override a later,
+default behavior; it is only needed if you need to override a later,
 more general pattern.
 
 The optional ``[repository]`` section specifies the line endings to
--- a/hgext/extdiff.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/extdiff.py	Fri Sep 25 23:10:47 2015 -0500
@@ -146,72 +146,94 @@
     subrepos=opts.get('subrepos')
 
     matcher = scmutil.match(repo[node2], pats, opts)
-    mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher,
-                                               listsubrepos=subrepos)[:3])
-    if do3way:
-        mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher,
-                                                   listsubrepos=subrepos)[:3])
+
+    if opts.get('patch'):
+        if subrepos:
+            raise util.Abort(_('--patch cannot be used with --subrepos'))
+        if node2 is None:
+            raise util.Abort(_('--patch requires two revisions'))
     else:
-        mod_b, add_b, rem_b = set(), set(), set()
-    modadd = mod_a | add_a | mod_b | add_b
-    common = modadd | rem_a | rem_b
-    if not common:
-        return 0
+        mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher,
+                                                   listsubrepos=subrepos)[:3])
+        if do3way:
+            mod_b, add_b, rem_b = map(set,
+                                      repo.status(node1b, node2, matcher,
+                                                  listsubrepos=subrepos)[:3])
+        else:
+            mod_b, add_b, rem_b = set(), set(), set()
+        modadd = mod_a | add_a | mod_b | add_b
+        common = modadd | rem_a | rem_b
+        if not common:
+            return 0
 
     tmproot = tempfile.mkdtemp(prefix='extdiff.')
     try:
-        # Always make a copy of node1a (and node1b, if applicable)
-        dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
-        dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[0]
-        rev1a = '@%d' % repo[node1a].rev()
-        if do3way:
-            dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
-            dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot,
+        if not opts.get('patch'):
+            # Always make a copy of node1a (and node1b, if applicable)
+            dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
+            dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot,
                              subrepos)[0]
-            rev1b = '@%d' % repo[node1b].rev()
-        else:
-            dir1b = None
-            rev1b = ''
+            rev1a = '@%d' % repo[node1a].rev()
+            if do3way:
+                dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
+                dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot,
+                                 subrepos)[0]
+                rev1b = '@%d' % repo[node1b].rev()
+            else:
+                dir1b = None
+                rev1b = ''
 
-        fns_and_mtime = []
+            fns_and_mtime = []
 
-        # If node2 in not the wc or there is >1 change, copy it
-        dir2root = ''
-        rev2 = ''
-        if node2:
-            dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0]
-            rev2 = '@%d' % repo[node2].rev()
-        elif len(common) > 1:
-            #we only actually need to get the files to copy back to
-            #the working dir in this case (because the other cases
-            #are: diffing 2 revisions or single file -- in which case
-            #the file is already directly passed to the diff tool).
-            dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot,
-                                           subrepos)
-        else:
-            # This lets the diff tool open the changed file directly
-            dir2 = ''
-            dir2root = repo.root
+            # If node2 in not the wc or there is >1 change, copy it
+            dir2root = ''
+            rev2 = ''
+            if node2:
+                dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0]
+                rev2 = '@%d' % repo[node2].rev()
+            elif len(common) > 1:
+                #we only actually need to get the files to copy back to
+                #the working dir in this case (because the other cases
+                #are: diffing 2 revisions or single file -- in which case
+                #the file is already directly passed to the diff tool).
+                dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot,
+                                               subrepos)
+            else:
+                # This lets the diff tool open the changed file directly
+                dir2 = ''
+                dir2root = repo.root
+
+            label1a = rev1a
+            label1b = rev1b
+            label2 = rev2
 
-        label1a = rev1a
-        label1b = rev1b
-        label2 = rev2
-
-        # If only one change, diff the files instead of the directories
-        # Handle bogus modifies correctly by checking if the files exist
-        if len(common) == 1:
-            common_file = util.localpath(common.pop())
-            dir1a = os.path.join(tmproot, dir1a, common_file)
-            label1a = common_file + rev1a
-            if not os.path.isfile(dir1a):
-                dir1a = os.devnull
-            if do3way:
-                dir1b = os.path.join(tmproot, dir1b, common_file)
-                label1b = common_file + rev1b
-                if not os.path.isfile(dir1b):
-                    dir1b = os.devnull
-            dir2 = os.path.join(dir2root, dir2, common_file)
-            label2 = common_file + rev2
+            # If only one change, diff the files instead of the directories
+            # Handle bogus modifies correctly by checking if the files exist
+            if len(common) == 1:
+                common_file = util.localpath(common.pop())
+                dir1a = os.path.join(tmproot, dir1a, common_file)
+                label1a = common_file + rev1a
+                if not os.path.isfile(dir1a):
+                    dir1a = os.devnull
+                if do3way:
+                    dir1b = os.path.join(tmproot, dir1b, common_file)
+                    label1b = common_file + rev1b
+                    if not os.path.isfile(dir1b):
+                        dir1b = os.devnull
+                dir2 = os.path.join(dir2root, dir2, common_file)
+                label2 = common_file + rev2
+        else:
+            template = 'hg-%h.patch'
+            cmdutil.export(repo, [repo[node1a].rev(), repo[node2].rev()],
+                           template=repo.vfs.reljoin(tmproot, template),
+                           match=matcher)
+            label1a = cmdutil.makefilename(repo, template, node1a)
+            label2 = cmdutil.makefilename(repo, template, node2)
+            dir1a = repo.vfs.reljoin(tmproot, label1a)
+            dir2 = repo.vfs.reljoin(tmproot, label2)
+            dir1b = None
+            label1b = None
+            fns_and_mtime = []
 
         # Function to quote file/dir names in the argument string.
         # When not operating in 3-way mode, an empty string is
@@ -255,6 +277,7 @@
      _('pass option to comparison program'), _('OPT')),
     ('r', 'rev', [], _('revision'), _('REV')),
     ('c', 'change', '', _('change made by revision'), _('REV')),
+    ('', 'patch', None, _('compare patches for two revisions'))
     ] + commands.walkopts + commands.subrepoopts,
     _('hg extdiff [OPT]... [FILE]...'),
     inferrepo=True)
--- a/hgext/highlight/__init__.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/highlight/__init__.py	Fri Sep 25 23:10:47 2015 -0500
@@ -13,23 +13,28 @@
 It depends on the Pygments syntax highlighting library:
 http://pygments.org/
 
-There is a single configuration option::
+There are two configuration options::
 
   [web]
-  pygments_style = <style>
-
-The default is 'colorful'.
+  pygments_style = <style> (default: colorful)
+  highlightfiles = <fileset> (default: size('<5M'))
 """
 
 import highlight
 from mercurial.hgweb import webcommands, webutil, common
-from mercurial import extensions, encoding
+from mercurial import extensions, encoding, fileset
 # Note for extension authors: ONLY specify testedwith = 'internal' for
 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
 # be specifying the version(s) of Mercurial they are tested with, or
 # leave the attribute unspecified.
 testedwith = 'internal'
 
+def checkfctx(fctx, expr):
+    ctx = fctx.changectx()
+    tree = fileset.parse(expr)
+    mctx = fileset.matchctx(ctx, subset=[fctx.path()], status=None)
+    return fctx.path() in fileset.getset(mctx, tree)
+
 def filerevision_highlight(orig, web, req, tmpl, fctx):
     mt = ''.join(tmpl('mimetype', encoding=encoding.encoding))
     # only pygmentize for mimetype containing 'html' so we both match
@@ -41,7 +46,9 @@
     # pygmentize a html file
     if 'html' in mt:
         style = web.config('web', 'pygments_style', 'colorful')
-        highlight.pygmentize('fileline', fctx, style, tmpl)
+        expr = web.config('web', 'highlightfiles', "size('<5M')")
+        if checkfctx(fctx, expr):
+            highlight.pygmentize('fileline', fctx, style, tmpl)
     return orig(web, req, tmpl, fctx)
 
 def annotate_highlight(orig, web, req, tmpl):
@@ -49,7 +56,9 @@
     if 'html' in mt:
         fctx = webutil.filectx(web.repo, req)
         style = web.config('web', 'pygments_style', 'colorful')
-        highlight.pygmentize('annotateline', fctx, style, tmpl)
+        expr = web.config('web', 'highlightfiles', "size('<5M')")
+        if checkfctx(fctx, expr):
+            highlight.pygmentize('annotateline', fctx, style, tmpl)
     return orig(web, req, tmpl)
 
 def generate_css(web, req, tmpl):
--- a/hgext/highlight/highlight.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/highlight/highlight.py	Fri Sep 25 23:10:47 2015 -0500
@@ -49,7 +49,12 @@
         try:
             lexer = guess_lexer(text[:1024], stripnl=False)
         except (ClassNotFound, ValueError):
-            lexer = TextLexer(stripnl=False)
+            # Don't highlight unknown files
+            return
+
+    # Don't highlight text files
+    if isinstance(lexer, TextLexer):
+        return
 
     formatter = HtmlFormatter(nowrap=True, style=style)
 
--- a/hgext/histedit.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/histedit.py	Fri Sep 25 23:10:47 2015 -0500
@@ -38,7 +38,7 @@
  #  f, fold = use commit, but combine it with the one above
  #  r, roll = like fold, but discard this commit's description
  #  d, drop = remove commit from history
- #  m, mess = edit message without changing commit content
+ #  m, mess = edit commit message without changing commit content
  #
 
 In this file, lines beginning with ``#`` are ignored. You must specify a rule
@@ -60,7 +60,7 @@
  #  f, fold = use commit, but combine it with the one above
  #  r, roll = like fold, but discard this commit's description
  #  d, drop = remove commit from history
- #  m, mess = edit message without changing commit content
+ #  m, mess = edit commit message without changing commit content
  #
 
 At which point you close the editor and ``histedit`` starts working. When you
@@ -144,7 +144,7 @@
 repo, you can add a ``--force`` option.
 
 Histedit rule lines are truncated to 80 characters by default. You
-can customise this behaviour by setting a different length in your
+can customize this behavior by setting a different length in your
 configuration file::
 
   [histedit]
@@ -198,7 +198,7 @@
 #  f, fold = use commit, but combine it with the one above
 #  r, roll = like fold, but discard this commit's description
 #  d, drop = remove commit from history
-#  m, mess = edit message without changing commit content
+#  m, mess = edit commit message without changing commit content
 #
 """)
 
@@ -406,7 +406,7 @@
     """Merge changeset from ctx (only) in the current working directory"""
     wcpar = repo.dirstate.parents()[0]
     if ctx.p1().node() == wcpar:
-        # edition ar "in place" we do not need to make any merge,
+        # edits are "in place" we do not need to make any merge,
         # just applies changes on parent for edition
         cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
         stats = None
@@ -557,8 +557,21 @@
                                middlecommits)
 
     def skipprompt(self):
+        """Returns true if the rule should skip the message editor.
+
+        For example, 'fold' wants to show an editor, but 'rollup'
+        doesn't want to.
+        """
         return False
 
+    def mergedescs(self):
+        """Returns true if the rule should merge messages of multiple changes.
+
+        This exists mainly so that 'rollup' rules can be a subclass of
+        'fold'.
+        """
+        return True
+
     def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges):
         parent = ctx.parents()[0].node()
         hg.update(repo, parent)
@@ -566,7 +579,7 @@
         commitopts = {}
         commitopts['user'] = ctx.user()
         # commit message
-        if self.skipprompt():
+        if not self.mergedescs():
             newmessage = ctx.description()
         else:
             newmessage = '\n***\n'.join(
@@ -601,7 +614,22 @@
             replacements.append((ich, (n,)))
         return repo[n], replacements
 
+class _multifold(fold):
+    """fold subclass used for when multiple folds happen in a row
+
+    We only want to fire the editor for the folded message once when
+    (say) four changes are folded down into a single change. This is
+    similar to rollup, but we should preserve both messages so that
+    when the last fold operation runs we can show the user all the
+    commit messages in their editor.
+    """
+    def skipprompt(self):
+        return True
+
 class rollup(fold):
+    def mergedescs(self):
+        return False
+
     def skipprompt(self):
         return True
 
@@ -614,10 +642,12 @@
     def commiteditor(self):
         return cmdutil.getcommiteditor(edit=True, editform='histedit.mess')
 
-def findoutgoing(ui, repo, remote=None, force=False, opts={}):
+def findoutgoing(ui, repo, remote=None, force=False, opts=None):
     """utility function to find the first outgoing changeset
 
-    Used by initialisation code"""
+    Used by initialization code"""
+    if opts is None:
+        opts = {}
     dest = ui.expandpath(remote or 'default-push', remote or 'default')
     dest, revs = hg.parseurl(dest, None)[:2]
     ui.status(_('comparing with %s\n') % util.hidepassword(dest))
@@ -644,6 +674,7 @@
                'edit': edit,
                'f': fold,
                'fold': fold,
+               '_multifold': _multifold,
                'r': rollup,
                'roll': rollup,
                'd': drop,
@@ -675,9 +706,9 @@
     destination repository. If URL of the destination is omitted, the
     'default-push' (or 'default') path will be used.
 
-    For safety, this command is aborted, also if there are ambiguous
-    outgoing revisions which may confuse users: for example, there are
-    multiple branches containing outgoing revisions.
+    For safety, this command is also aborted if there are ambiguous
+    outgoing revisions which may confuse users: for example, if there
+    are multiple branches containing outgoing revisions.
 
     Use "min(outgoing() and ::.)" or similar revset specification
     instead of --outgoing to specify edit target revision exactly in
@@ -778,7 +809,7 @@
         return
     elif goal == 'abort':
         state.read()
-        mapping, tmpnodes, leafs, _ntm = processreplacement(state)
+        tmpnodes, leafs = newnodestoabort(state)
         ui.debug('restore wc to old parent %s\n' % node.short(state.topmost))
 
         # Recover our old commits if necessary
@@ -791,13 +822,9 @@
             os.remove(backupfile)
 
         # check whether we should update away
-        parentnodes = [c.node() for c in repo[None].parents()]
-        for n in leafs | set([state.parentctxnode]):
-            if n in parentnodes:
-                hg.clean(repo, state.topmost)
-                break
-        else:
-            pass
+        if repo.unfiltered().revs('parents() and (%n  or %ln::)',
+                                  state.parentctxnode, leafs | tmpnodes):
+            hg.clean(repo, state.topmost)
         cleanupnode(ui, repo, 'created', tmpnodes)
         cleanupnode(ui, repo, 'temp', leafs)
         state.clear()
@@ -854,6 +881,14 @@
                                         'histedit')
         state.backupfile = backupfile
 
+    # preprocess rules so that we can hide inner folds from the user
+    # and only show one editor
+    rules = state.rules[:]
+    for idx, ((action, ha), (nextact, unused)) in enumerate(
+            zip(rules, rules[1:] + [(None, None)])):
+        if action == 'fold' and nextact == 'fold':
+            state.rules[idx] = '_multifold', ha
+
     while state.rules:
         state.write()
         action, ha = state.rules.pop(0)
@@ -999,7 +1034,7 @@
             raise util.Abort(_('duplicated command for changeset %s') %
                     ha[:12])
         seen.add(ha)
-        if action not in actiontable:
+        if action not in actiontable or action.startswith('_'):
             raise util.Abort(_('unknown action "%s"') % action)
         parsed.append([action, ha])
     missing = sorted(expected - seen)  # sort to stabilize output
@@ -1009,6 +1044,25 @@
                 hint=_('do you want to use the drop action?'))
     return parsed
 
+def newnodestoabort(state):
+    """process the list of replacements to return
+
+    1) the list of final node
+    2) the list of temporary node
+
+    This meant to be used on abort as less data are required in this case.
+    """
+    replacements = state.replacements
+    allsuccs = set()
+    replaced = set()
+    for rep in replacements:
+        allsuccs.update(rep[1])
+        replaced.add(rep[0])
+    newnodes = allsuccs - replaced
+    tmpnodes = allsuccs & replaced
+    return newnodes, tmpnodes
+
+
 def processreplacement(state):
     """process the list of replacements to return
 
@@ -1019,15 +1073,15 @@
     allsuccs = set()
     replaced = set()
     fullmapping = {}
-    # initialise basic set
-    # fullmapping record all operation recorded in replacement
+    # initialize basic set
+    # fullmapping records all operations recorded in replacement
     for rep in replacements:
         allsuccs.update(rep[1])
         replaced.add(rep[0])
         fullmapping.setdefault(rep[0], set()).update(rep[1])
     new = allsuccs - replaced
     tmpnodes = allsuccs & replaced
-    # Reduce content fullmapping  into direct relation between original nodes
+    # Reduce content fullmapping into direct relation between original nodes
     # and final node created during history edition
     # Dropped changeset are replaced by an empty list
     toproceed = set(fullmapping)
@@ -1113,8 +1167,12 @@
     lock = None
     try:
         lock = repo.lock()
-        # Find all node that need to be stripped
-        # (we hg %lr instead of %ln to silently ignore unknown item
+        # do not let filtering get in the way of the cleanse
+        # we should probably get rid of obsolescence marker created during the
+        # histedit, but we currently do not have such information.
+        repo = repo.unfiltered()
+        # Find all nodes that need to be stripped
+        # (we use %lr instead of %ln to silently ignore unknown items)
         nm = repo.changelog.nodemap
         nodes = sorted(n for n in nodes if n in nm)
         roots = [c.node() for c in repo.set("roots(%ln)", nodes)]
--- a/hgext/largefiles/overrides.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/largefiles/overrides.py	Fri Sep 25 23:10:47 2015 -0500
@@ -50,8 +50,10 @@
 
 def installnormalfilesmatchfn(manifest):
     '''installmatchfn with a matchfn that ignores all largefiles'''
-    def overridematch(ctx, pats=[], opts={}, globbed=False,
+    def overridematch(ctx, pats=(), opts=None, globbed=False,
             default='relpath', badfn=None):
+        if opts is None:
+            opts = {}
         match = oldmatch(ctx, pats, opts, globbed, default, badfn=badfn)
         return composenormalfilematcher(match, manifest)
     oldmatch = installmatchfn(overridematch)
@@ -287,13 +289,15 @@
         repo._repo.lfstatus = False
 
 def overridelog(orig, ui, repo, *pats, **opts):
-    def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
+    def overridematchandpats(ctx, pats=(), opts=None, globbed=False,
             default='relpath', badfn=None):
         """Matcher that merges root directory with .hglf, suitable for log.
         It is still possible to match .hglf directly.
         For any listed files run log on the standin too.
         matchfn tries both the given filename and with .hglf stripped.
         """
+        if opts is None:
+            opts = {}
         matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default,
                                        badfn=badfn)
         m, p = copy.copy(matchandpats)
@@ -613,8 +617,10 @@
         wlock = repo.wlock()
 
         manifest = repo[None].manifest()
-        def overridematch(ctx, pats=[], opts={}, globbed=False,
+        def overridematch(ctx, pats=(), opts=None, globbed=False,
                 default='relpath', badfn=None):
+            if opts is None:
+                opts = {}
             newpats = []
             # The patterns were previously mangled to add the standin
             # directory; we need to remove that now
@@ -722,8 +728,10 @@
 
         oldstandins = lfutil.getstandinsstate(repo)
 
-        def overridematch(mctx, pats=[], opts={}, globbed=False,
+        def overridematch(mctx, pats=(), opts=None, globbed=False,
                 default='relpath', badfn=None):
+            if opts is None:
+                opts = {}
             match = oldmatch(mctx, pats, opts, globbed, default, badfn=badfn)
             m = copy.copy(match)
 
@@ -1164,8 +1172,10 @@
     finally:
         repo.lfstatus = False
 
-def scmutiladdremove(orig, repo, matcher, prefix, opts={}, dry_run=None,
+def scmutiladdremove(orig, repo, matcher, prefix, opts=None, dry_run=None,
                      similarity=None):
+    if opts is None:
+        opts = {}
     if not lfutil.islfilesrepo(repo):
         return orig(repo, matcher, prefix, opts, dry_run, similarity)
     # Get the list of missing largefiles so we can remove them
--- a/hgext/mq.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/mq.py	Fri Sep 25 23:10:47 2015 -0500
@@ -28,7 +28,7 @@
 
 By default, mq will automatically use git patches when required to
 avoid losing file mode changes, copy records, binary files or empty
-files creations or deletions. This behaviour can be configured with::
+files creations or deletions. This behavior can be configured with::
 
   [mq]
   git = auto/keep/yes/no
@@ -483,7 +483,7 @@
         self.guardsdirty = False
         self.activeguards = None
 
-    def diffopts(self, opts={}, patchfn=None):
+    def diffopts(self, opts=None, patchfn=None):
         diffopts = patchmod.diffopts(self.ui, opts)
         if self.gitmode == 'auto':
             diffopts.upgrade = True
--- a/hgext/progress.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/progress.py	Fri Sep 25 23:10:47 2015 -0500
@@ -10,3 +10,8 @@
 This extension has been merged into core, you can remove it from your config.
 See hg help config.progress for configuration options.
 """
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
+testedwith = 'internal'
--- a/hgext/rebase.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/rebase.py	Fri Sep 25 23:10:47 2015 -0500
@@ -16,7 +16,7 @@
 
 from mercurial import hg, util, repair, merge, cmdutil, commands, bookmarks
 from mercurial import extensions, patch, scmutil, phases, obsolete, error
-from mercurial import copies, repoview
+from mercurial import copies, repoview, revset
 from mercurial.commands import templateopts
 from mercurial.node import nullrev, nullid, hex, short
 from mercurial.lock import release
@@ -26,6 +26,7 @@
 revtodo = -1
 nullmerge = -2
 revignored = -3
+revprecursor = -4
 
 cmdtable = {}
 command = cmdutil.command(cmdtable)
@@ -54,6 +55,21 @@
             c(ctx, extra)
     return extrafn
 
+def _rebasedefaultdest(repo, subset, x):
+    # ``_rebasedefaultdest()``
+
+    # default destination for rebase.
+    # # XXX: Currently private because I expect the signature to change.
+    # # XXX: - taking rev as arguments,
+    # # XXX: - bailing out in case of ambiguity vs returning all data.
+    # # XXX: - probably merging with the merge destination.
+    # i18n: "_rebasedefaultdest" is a keyword
+    revset.getargs(x, 0, 0, _("_rebasedefaultdest takes no arguments"))
+    # Destination defaults to the latest revision in the
+    # current branch
+    branch = repo[None].branch()
+    return subset & revset.baseset([repo[branch].rev()])
+
 @command('rebase',
     [('s', 'source', '',
      _('rebase the specified changeset and descendants'), _('REV')),
@@ -218,7 +234,7 @@
             if srcf or basef or destf:
                 raise util.Abort(
                     _('abort and continue do not allow specifying revisions'))
-            if opts.get('tool', False):
+            if abortf and opts.get('tool', False):
                 ui.warn(_('tool option will be ignored\n'))
 
             try:
@@ -252,12 +268,8 @@
             cmdutil.bailifchanged(repo)
 
             if not destf:
-                # Destination defaults to the latest revision in the
-                # current branch
-                branch = repo[None].branch()
-                dest = repo[branch]
-            else:
-                dest = scmutil.revsingle(repo, destf)
+                destf = '_rebasedefaultdest()'
+            dest = scmutil.revsingle(repo, destf)
 
             if revf:
                 rebaseset = scmutil.revrange(repo, revf)
@@ -322,7 +334,20 @@
                       " unrebased descendants"),
                     hint=_('use --keep to keep original changesets'))
 
-            result = buildstate(repo, dest, rebaseset, collapsef)
+            obsoletenotrebased = {}
+            if ui.configbool('experimental', 'rebaseskipobsolete'):
+                rebasesetrevs = set(rebaseset)
+                obsoletenotrebased = _computeobsoletenotrebased(repo,
+                                                                rebasesetrevs,
+                                                                dest)
+
+                # - plain prune (no successor) changesets are rebased
+                # - split changesets are not rebased if at least one of the
+                # changeset resulting from the split is an ancestor of dest
+                rebaseset = rebasesetrevs - set(obsoletenotrebased)
+            result = buildstate(repo, dest, rebaseset, collapsef,
+                                obsoletenotrebased)
+
             if not result:
                 # Empty state built, nothing to rebase
                 ui.status(_('nothing to rebase\n'))
@@ -406,7 +431,8 @@
                     editform = cmdutil.mergeeditform(merging, 'rebase')
                     editor = cmdutil.getcommiteditor(editform=editform, **opts)
                     newnode = concludenode(repo, rev, p1, p2, extrafn=extrafn,
-                                           editor=editor)
+                                           editor=editor,
+                                           keepbranches=keepbranchesf)
                 else:
                     # Skip commit if we are collapsing
                     repo.dirstate.beginparentchange()
@@ -428,6 +454,12 @@
                 ui.debug('ignoring null merge rebase of %s\n' % rev)
             elif state[rev] == revignored:
                 ui.status(_('not rebasing ignored %s\n') % desc)
+            elif state[rev] == revprecursor:
+                targetctx = repo[obsoletenotrebased[rev]]
+                desctarget = '%d:%s "%s"' % (targetctx.rev(), targetctx,
+                             targetctx.description().split('\n', 1)[0])
+                msg = _('note: not rebasing %s, already in destination as %s\n')
+                ui.status(msg % (desc, desctarget))
             else:
                 ui.status(_('already rebased %s as %s\n') %
                           (desc, repo[state[rev]]))
@@ -450,7 +482,8 @@
                 editopt = True
             editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
             newnode = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
-                                   extrafn=extrafn, editor=editor)
+                                   extrafn=extrafn, editor=editor,
+                                   keepbranches=keepbranchesf)
             if newnode is None:
                 newrev = target
             else:
@@ -530,7 +563,8 @@
                      (max(targetancestors),
                       ', '.join(str(p) for p in sorted(parents))))
 
-def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None):
+def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None,
+                 keepbranches=False):
     '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
     but also store useful information in extra.
     Return node of committed revision.'''
@@ -540,6 +574,7 @@
         ctx = repo[rev]
         if commitmsg is None:
             commitmsg = ctx.description()
+        keepbranch = keepbranches and repo[p1].branch() != ctx.branch()
         extra = {'rebase_source': ctx.hex()}
         if extrafn:
             extrafn(ctx, extra)
@@ -548,6 +583,8 @@
         try:
             targetphase = max(ctx.phase(), phases.draft)
             repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
+            if keepbranch:
+                repo.ui.setconfig('ui', 'allowemptycommit', True)
             # Commit might fail if unresolved files exist
             newnode = repo.commit(text=commitmsg, user=ctx.user(),
                                   date=ctx.date(), extra=extra, editor=editor)
@@ -609,7 +646,7 @@
     elif p1n in state:
         if state[p1n] == nullmerge:
             p1 = target
-        elif state[p1n] == revignored:
+        elif state[p1n] in (revignored, revprecursor):
             p1 = nearestrebased(repo, p1n, state)
             if p1 is None:
                 p1 = target
@@ -625,7 +662,7 @@
         if p2n in state:
             if p1 == target: # p1n in targetancestors or external
                 p1 = state[p2n]
-            elif state[p2n] == revignored:
+            elif state[p2n] in (revignored, revprecursor):
                 p2 = nearestrebased(repo, p2n, state)
                 if p2 is None:
                     # no ancestors rebased yet, detach
@@ -813,7 +850,8 @@
                 activebookmark = l
             else:
                 oldrev, newrev = l.split(':')
-                if newrev in (str(nullmerge), str(revignored)):
+                if newrev in (str(nullmerge), str(revignored),
+                              str(revprecursor)):
                     state[repo[oldrev].rev()] = int(newrev)
                 elif newrev == nullid:
                     state[repo[oldrev].rev()] = revtodo
@@ -901,7 +939,7 @@
     repo.ui.warn(_('rebase aborted\n'))
     return 0
 
-def buildstate(repo, dest, rebaseset, collapse):
+def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased):
     '''Define which revisions are going to be rebased and where
 
     repo: repo
@@ -988,6 +1026,8 @@
         rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
         for ignored in set(rebasedomain) - set(rebaseset):
             state[ignored] = revignored
+    for r in obsoletenotrebased:
+        state[r] = revprecursor
     return repo['.'].rev(), dest.rev(), state
 
 def clearrebased(ui, repo, state, skipped, collapsedas=None):
@@ -1096,6 +1136,32 @@
     blockers.update(getattr(repo, '_rebaseset', ()))
     return blockers
 
+def _computeobsoletenotrebased(repo, rebasesetrevs, dest):
+    """return a mapping obsolete => successor for all obsolete nodes to be
+    rebased that have a successors in the destination"""
+    obsoletenotrebased = {}
+
+    # Build a mapping succesor => obsolete nodes for the obsolete
+    # nodes to be rebased
+    allsuccessors = {}
+    for r in rebasesetrevs:
+        n = repo[r]
+        if n.obsolete():
+            node = repo.changelog.node(r)
+            for s in obsolete.allsuccessors(repo.obsstore, [node]):
+                allsuccessors[repo.changelog.rev(s)] = repo.changelog.rev(node)
+
+    if allsuccessors:
+        # Look for successors of obsolete nodes to be rebased among
+        # the ancestors of dest
+        ancs = repo.changelog.ancestors([repo[dest].rev()],
+                                        stoprev=min(allsuccessors),
+                                        inclusive=True)
+        for s in allsuccessors:
+            if s in ancs:
+                obsoletenotrebased[allsuccessors[s]] = s
+    return obsoletenotrebased
+
 def summaryhook(ui, repo):
     if not os.path.exists(repo.join('rebasestate')):
         return
@@ -1126,3 +1192,4 @@
          _("use 'hg rebase --continue' or 'hg rebase --abort'")])
     # ensure rebased rev are not hidden
     extensions.wrapfunction(repoview, '_getdynamicblockers', _rebasedvisible)
+    revset.symbols['_rebasedefaultdest'] = _rebasedefaultdest
--- a/hgext/transplant.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/hgext/transplant.py	Fri Sep 25 23:10:47 2015 -0500
@@ -117,8 +117,10 @@
                 return True
         return False
 
-    def apply(self, repo, source, revmap, merges, opts={}):
+    def apply(self, repo, source, revmap, merges, opts=None):
         '''apply the revisions in revmap one by one in revision order'''
+        if opts is None:
+            opts = {}
         revs = sorted(revmap)
         p1, p2 = repo.dirstate.parents()
         pulls = []
--- a/i18n/check-translation.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/i18n/check-translation.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,8 +5,15 @@
 import polib
 import re
 
+scanners = []
 checkers = []
 
+def scanner():
+    def decorator(func):
+        scanners.append(func)
+        return func
+    return decorator
+
 def levelchecker(level, msgidpat):
     def decorator(func):
         if msgidpat:
@@ -61,6 +68,46 @@
     if [c for c, i in indices if len(c) == i + 1]:
         yield "msgstr has invalid '&' followed by none"
 
+deprecatedpe = None
+@scanner()
+def deprecatedsetup(pofile):
+    pes = [p for p in pofile if p.msgid == 'DEPRECATED']
+    if len(pes):
+        global deprecatedpe
+        deprecatedpe = pes[0]
+
+@fatalchecker('(DEPRECATED)')
+def deprecated(pe):
+    """Check for DEPRECATED
+    >>> ped = polib.POEntry(
+    ...     msgid = 'DEPRECATED',
+    ...     msgstr= 'DETACERPED')
+    >>> deprecatedsetup([ped])
+    >>> pe = polib.POEntry(
+    ...     msgid = 'Something (DEPRECATED)',
+    ...     msgstr= 'something (DEPRECATED)')
+    >>> match(deprecated, pe)
+    True
+    >>> for e in deprecated(pe): print e
+    >>> pe = polib.POEntry(
+    ...     msgid = 'Something (DEPRECATED)',
+    ...     msgstr= 'something (DETACERPED)')
+    >>> match(deprecated, pe)
+    True
+    >>> for e in deprecated(pe): print e
+    >>> pe = polib.POEntry(
+    ...     msgid = 'Something (DEPRECATED)',
+    ...     msgstr= 'something')
+    >>> match(deprecated, pe)
+    True
+    >>> for e in deprecated(pe): print e
+    msgstr inconsistently translated (DEPRECATED)
+    """
+    if not ('(DEPRECATED)' in pe.msgstr or
+            (deprecatedpe and deprecatedpe.msgstr and
+             deprecatedpe.msgstr in pe.msgstr)):
+        yield "msgstr inconsistently translated (DEPRECATED)"
+
 ####################
 
 def warningchecker(msgidpat=None):
@@ -117,6 +164,8 @@
         return []
 
     detected = []
+    for checker in scanners:
+        checker(pofile)
     for pe in pofile.translated_entries():
         errors = []
         for checker, level in targetcheckers:
--- a/i18n/da.po	Fri Sep 25 13:30:49 2015 -0700
+++ b/i18n/da.po	Fri Sep 25 23:10:47 2015 -0500
@@ -9367,7 +9367,7 @@
 msgstr ""
 
 msgid "DEPRECATED"
-msgstr ""
+msgstr "FORÆLDET"
 
 msgid ""
 "\n"
--- a/i18n/fr.po	Fri Sep 25 13:30:49 2015 -0700
+++ b/i18n/fr.po	Fri Sep 25 23:10:47 2015 -0500
@@ -4014,7 +4014,7 @@
 msgstr "garder le fichier du patch"
 
 msgid "stop managing a revision (DEPRECATED)"
-msgstr "arrêter de gérer une révision"
+msgstr ""
 
 msgid "hg qdelete [-k] [-r REV]... [PATCH]..."
 msgstr "hg qdelete [-k] [-r REV]... [PATCH]..."
--- a/i18n/it.po	Fri Sep 25 13:30:49 2015 -0700
+++ b/i18n/it.po	Fri Sep 25 23:10:47 2015 -0500
@@ -7506,7 +7506,7 @@
 msgstr ""
 
 msgid "DEPRECATED"
-msgstr ""
+msgstr "DEPRECATO"
 
 msgid ""
 "\n"
--- a/i18n/pt_BR.po	Fri Sep 25 13:30:49 2015 -0700
+++ b/i18n/pt_BR.po	Fri Sep 25 23:10:47 2015 -0500
@@ -3821,7 +3821,7 @@
 msgstr "factotum não está respondendo"
 
 msgid "pull, update and merge in one command (DEPRECATED)"
-msgstr "pull, update e merge em um comando (OBSOLETA)"
+msgstr "pull, update e merge em um comando (OBSOLETO)"
 
 msgid "a specific revision you would like to pull"
 msgstr "uma revisão específica que você gostaria de trazer"
@@ -4082,7 +4082,7 @@
 msgstr "revisões de autoria do usuário"
 
 msgid "show only changesets within the given named branch (DEPRECATED)"
-msgstr "mostra apenas revisões dentro do ramo nomeado especificado (OBSOLETA)"
+msgstr "mostra apenas revisões dentro do ramo nomeado especificado (OBSOLETO)"
 
 msgid "BRANCH"
 msgstr "RAMO"
@@ -8342,7 +8342,7 @@
 msgstr "escrevendo"
 
 msgid "show progress bars for some actions (DEPRECATED)"
-msgstr "mostra barras de progresso para algumas ações (OBSOLETA)"
+msgstr "mostra barras de progresso para algumas ações (OBSOLETO)"
 
 msgid ""
 "This extension has been merged into core, you can remove it from your config.\n"
@@ -8505,7 +8505,7 @@
 msgstr "mantém nomes de ramos originais"
 
 msgid "(DEPRECATED)"
-msgstr "(OBSOLETA)"
+msgstr "(OBSOLETO)"
 
 msgid "specify merge tool"
 msgstr "especifica o utilitário de mesclagem"
@@ -11140,7 +11140,7 @@
 msgstr "faz um annotate da revisão especificada"
 
 msgid "follow copies/renames and list the filename (DEPRECATED)"
-msgstr "segue cópias e renomeações e lista o nome de arquivo (OBSOLETA)"
+msgstr "segue cópias e renomeações e lista o nome de arquivo (OBSOLETO)"
 
 msgid "don't follow copies and renames"
 msgstr "não segue cópias e renomeações"
@@ -12862,7 +12862,7 @@
 msgid "backwards compatibility with old bash completion scripts (DEPRECATED)"
 msgstr ""
 "compatibilidade retroativa com antigos scripts bash de completação "
-"(OBSOLETA)"
+"(OBSOLETO)"
 
 msgid "NAME..."
 msgstr "NOME..."
@@ -13783,7 +13783,7 @@
 msgstr "mostra apenas cabeças topológicas"
 
 msgid "show active branchheads only (DEPRECATED)"
-msgstr "mostra apenas cabeças de ramo ativas (OBSOLETA)"
+msgstr "mostra apenas cabeças de ramo ativas (OBSOLETO)"
 
 msgid "show normal and closed branch heads"
 msgstr "mostra cabeças de ramo normais e fechadas"
@@ -15606,7 +15606,7 @@
 msgstr "nome do arquivo de configuração do hgweb (veja \"hg help hgweb\")"
 
 msgid "name of the hgweb config file (DEPRECATED)"
-msgstr "nome do arquivo de configuração do hgweb (OBSOLETA)"
+msgstr "nome do arquivo de configuração do hgweb (OBSOLETO)"
 
 msgid "name of file to write process ID to"
 msgstr "nome do arquivo no qual escrever o ID do processo"
@@ -21142,7 +21142,7 @@
 "    Default is False."
 msgstr ""
 "``allowbz2``\n"
-"    (OBSOLETA) Determina se revisões estarão disponíveis para download\n"
+"    (OBSOLETO) Determina se revisões estarão disponíveis para download\n"
 "    em formato .tar.bz2.\n"
 "    O padrão é False."
 
@@ -21153,7 +21153,7 @@
 "    Default is False."
 msgstr ""
 "``allowgz``\n"
-"    (OBSOLETA) Determina se revisões estarão disponíveis para download\n"
+"    (OBSOLETO) Determina se revisões estarão disponíveis para download\n"
 "    em formato .tar.gz.\n"
 "    O padrão é False."
 
@@ -21214,7 +21214,7 @@
 "    revisions. Default is False. This feature creates temporary files."
 msgstr ""
 "``allowzip``\n"
-"    (OBSOLETA) Determina se revisões estarão disponíveis para download\n"
+"    (OBSOLETO) Determina se revisões estarão disponíveis para download\n"
 "    em formato .zip.\n"
 "    O padrão é False."
 
--- a/i18n/ro.po	Fri Sep 25 13:30:49 2015 -0700
+++ b/i18n/ro.po	Fri Sep 25 23:10:47 2015 -0500
@@ -8063,7 +8063,7 @@
 msgstr "afișează doar capetele topologice"
 
 msgid "show active branchheads only (DEPRECATED)"
-msgstr "afișează doar capetele de ramură active [ÎNVECHIT]"
+msgstr "afișează doar capetele de ramură active (ÎNVECHIT)"
 
 msgid "show normal and closed branch heads"
 msgstr "afișează capetele de ramură normale și închise"
@@ -8259,7 +8259,7 @@
 msgstr "VALOARE"
 
 msgid "DEPRECATED"
-msgstr ""
+msgstr "ÎNVECHIT"
 
 msgid ""
 "\n"
--- a/i18n/sv.po	Fri Sep 25 13:30:49 2015 -0700
+++ b/i18n/sv.po	Fri Sep 25 23:10:47 2015 -0500
@@ -826,7 +826,7 @@
 msgstr "Bugzilla-fel: %s"
 
 msgid "command to display child changesets (DEPRECATED)"
-msgstr "kommando för att visa barnändringar (FÖRLEGAD)"
+msgstr "kommando för att visa barnändringar (FÖRÅLDRAD)"
 
 msgid ""
 "This extension is deprecated. You should use :hg:`log -r\n"
@@ -2741,7 +2741,7 @@
 "följ ändringshistorik, eller filhistorik över kopieringar och namnbyten"
 
 msgid "only follow the first parent of merge changesets (DEPRECATED)"
-msgstr "följ bara den första föräldern vid sammanfogningar (FÖRLEGAD)"
+msgstr "följ bara den första föräldern vid sammanfogningar (FÖRÅLDRAD)"
 
 msgid "show revisions matching date spec"
 msgstr "visa revisioner som matchar datumspecen"
@@ -2759,7 +2759,7 @@
 msgstr "inkludera revisioner där filer togs bort"
 
 msgid "show only merges (DEPRECATED)"
-msgstr "visa bara sammanfogningar (FÖRLEGAD)"
+msgstr "visa bara sammanfogningar (FÖRÅLDRAD)"
 
 msgid "USER"
 msgstr "ANVÄNDARE"
@@ -2768,7 +2768,7 @@
 msgstr "revisioner arkiverade av användare"
 
 msgid "show only changesets within the given named branch (DEPRECATED)"
-msgstr "visa bara ändringar i den namngivna grenen (FÖRLEGAD)"
+msgstr "visa bara ändringar i den namngivna grenen (FÖRÅLDRAD)"
 
 msgid "BRANCH"
 msgstr "GREN"
@@ -2780,7 +2780,7 @@
 msgstr "visa inte revision eller någon av dess föräldrar"
 
 msgid "show hidden changesets (DEPRECATED)"
-msgstr "visa dolda ändringar (FÖRLEGAD)"
+msgstr "visa dolda ändringar (FÖRÅLDRAD)"
 
 msgid "[OPTION]... [FILE]"
 msgstr "[FLAGGA]... [FIL]"
@@ -5011,7 +5011,7 @@
 msgstr "skriv ut namnet på föregående applicerade patch"
 
 msgid "import uncommitted changes (DEPRECATED)"
-msgstr "importera icke arkiverade ändringar (FÖRLEGAD)"
+msgstr "importera icke arkiverade ändringar (FÖRÅLDRAD)"
 
 msgid "add \"From: <current user>\" to patch"
 msgstr "lägg till \"From: <denna användare>\" i patch"
@@ -5306,7 +5306,7 @@
 msgstr "poppa alla patchar"
 
 msgid "queue name to pop (DEPRECATED)"
-msgstr "könamn att poppa (FÖRLEGAD)"
+msgstr "könamn att poppa (FÖRÅLDRAD)"
 
 msgid "forget any local changes to patched files"
 msgstr ""
@@ -5404,7 +5404,7 @@
 "not descendants of REV (DEPRECATED)"
 msgstr ""
 "bunta bara ändringar med lokala revisionsnummer större än REV som inte är "
-"ättling till REV (FÖRLEGAD)"
+"ättling till REV (FÖRÅLDRAD)"
 
 msgid "no backups"
 msgstr "inga säkerhetskopior"
@@ -6537,7 +6537,7 @@
 msgstr ""
 
 msgid "(DEPRECATED)"
-msgstr "(FÖRLEGAD)"
+msgstr "(FÖRÅLDRAD)"
 
 msgid "specify merge tool"
 msgstr "ange sammanfogningsverktyg"
@@ -8088,7 +8088,7 @@
 msgstr "annotera den angivna revisionen"
 
 msgid "follow copies/renames and list the filename (DEPRECATED)"
-msgstr "följ kopieringar/namnbyten och visa filnamnet (FÖRLEGAD)"
+msgstr "följ kopieringar/namnbyten och visa filnamnet (FÖRÅLDRAD)"
 
 msgid "don't follow copies and renames"
 msgstr "följ inte kopieringar och namnbyten"
@@ -8247,7 +8247,7 @@
 msgstr "sammanfoga med gamla dirstate-föräldern efter återkallning"
 
 msgid "parent to choose when backing out merge (DEPRECATED)"
-msgstr "förälder att välja när en sammanfogning återkallas (FÖRLEGAD)"
+msgstr "förälder att välja när en sammanfogning återkallas (FÖRÅLDRAD)"
 
 msgid "revision to backout"
 msgstr "revision att återkalla"
@@ -10105,7 +10105,7 @@
 msgstr "visa bara topologiska huvuden"
 
 msgid "show active branchheads only (DEPRECATED)"
-msgstr "visa bara aktiva grenhuvuden (FÖRLEGAD)"
+msgstr "visa bara aktiva grenhuvuden (FÖRÅLDRAD)"
 
 msgid "show normal and closed branch heads"
 msgstr "visa normala och stängda grenhuvuden"
@@ -11764,7 +11764,7 @@
 msgstr "namn på webdir-konfigurationsfil (se \"hg help hgweb\")"
 
 msgid "name of the hgweb config file (DEPRECATED)"
-msgstr "namn på webdir-konfigurationsfil (FÖRLEGAD)"
+msgstr "namn på webdir-konfigurationsfil (FÖRÅLDRAD)"
 
 msgid "for remote clients"
 msgstr "för fjärrklienter"
@@ -13116,7 +13116,7 @@
 msgstr "VÄRDE"
 
 msgid "DEPRECATED"
-msgstr "FÖRLEGAD"
+msgstr "FÖRÅLDRAD"
 
 msgid ""
 "\n"
--- a/i18n/zh_CN.po	Fri Sep 25 13:30:49 2015 -0700
+++ b/i18n/zh_CN.po	Fri Sep 25 23:10:47 2015 -0500
@@ -10443,3 +10443,6 @@
 
 msgid "user name not available - set USERNAME environment variable"
 msgstr ""
+
+msgid "DEPRECATED"
+msgstr "不赞成"
--- a/mercurial/ancestor.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/ancestor.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,12 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import collections
 import heapq
-from node import nullrev
+
+from .node import nullrev
 
 def commonancestorsheads(pfunc, *nodes):
     """Returns a set with the heads of all common ancestors of all nodes,
--- a/mercurial/archival.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/archival.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,14 +5,27 @@
 # 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 match as matchmod
-import cmdutil
-import scmutil, util, encoding
-import cStringIO, os, tarfile, time, zipfile
-import zlib, gzip
+from __future__ import absolute_import
+
+import cStringIO
+import gzip
+import os
 import struct
-import error
+import tarfile
+import time
+import zipfile
+import zlib
+
+from .i18n import _
+
+from . import (
+    cmdutil,
+    encoding,
+    error,
+    match as matchmod,
+    scmutil,
+    util,
+)
 
 # from unzip source code:
 _UNX_IFREG = 0x8000
@@ -111,11 +124,7 @@
         def _write_gzip_header(self):
             self.fileobj.write('\037\213')             # magic header
             self.fileobj.write('\010')                 # compression method
-            # Python 2.6 introduced self.name and deprecated self.filename
-            try:
-                fname = self.name
-            except AttributeError:
-                fname = self.filename
+            fname = self.name
             if fname and fname.endswith('.gz'):
                 fname = fname[:-3]
             flags = 0
--- a/mercurial/base85.c	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/base85.c	Fri Sep 25 23:10:47 2015 -0500
@@ -21,7 +21,7 @@
 static void
 b85prep(void)
 {
-	int i;
+	unsigned i;
 
 	memset(b85dec, 0, sizeof(b85dec));
 	for (i = 0; i < sizeof(b85chars); i++)
--- a/mercurial/bookmarks.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/bookmarks.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,11 +5,22 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
+import errno
 import os
-from mercurial.i18n import _
-from mercurial.node import hex, bin
-from mercurial import encoding, util, obsolete, lock as lockmod
-import errno
+
+from .i18n import _
+from .node import (
+    bin,
+    hex,
+)
+from . import (
+    encoding,
+    lock as lockmod,
+    obsolete,
+    util,
+)
 
 class bmstore(dict):
     """Storage for bookmarks.
@@ -79,6 +90,11 @@
         can be copied back on rollback.
         '''
         repo = self._repo
+        if (repo.ui.configbool('devel', 'all-warnings')
+                or repo.ui.configbool('devel', 'check-locks')):
+            l = repo._wlockref and repo._wlockref()
+            if l is None or not l.held:
+                repo.ui.develwarn('bookmarks write with no wlock')
         self._writerepo(repo)
         repo.invalidatevolatilesets()
 
--- a/mercurial/branchmap.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/branchmap.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,13 +5,28 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from node import bin, hex, nullid, nullrev
-import encoding
-import scmutil
-import util
+from __future__ import absolute_import
+
+import array
+import struct
 import time
-from array import array
-from struct import calcsize, pack, unpack
+
+from .node import (
+    bin,
+    hex,
+    nullid,
+    nullrev,
+)
+from . import (
+    encoding,
+    scmutil,
+    util,
+)
+
+array = array.array
+calcsize = struct.calcsize
+pack = struct.pack
+unpack = struct.unpack
 
 def _filename(repo):
     """name of a branchcache file for a given repo or repoview"""
--- a/mercurial/bundle2.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/bundle2.py	Fri Sep 25 23:10:47 2015 -0500
@@ -145,19 +145,25 @@
 preserve.
 """
 
+from __future__ import absolute_import
+
 import errno
-import sys
-import util
-import struct
-import urllib
+import re
 import string
-import obsolete
-import pushkey
-import url
-import re
+import struct
+import sys
+import urllib
 
-import changegroup, error, tags
-from i18n import _
+from .i18n import _
+from . import (
+    changegroup,
+    error,
+    obsolete,
+    pushkey,
+    tags,
+    url,
+    util,
+)
 
 _pack = struct.pack
 _unpack = struct.unpack
@@ -841,6 +847,12 @@
                 outdebug(ui, 'payload chunk size: %i' % len(chunk))
                 yield _pack(_fpayloadsize, len(chunk))
                 yield chunk
+        except GeneratorExit:
+            # GeneratorExit means that nobody is listening for our
+            # results anyway, so just bail quickly rather than trying
+            # to produce an error part.
+            ui.debug('bundle2-generatorexit\n')
+            raise
         except BaseException as exc:
             # backup exception data for later
             ui.debug('bundle2-input-stream-interrupt: encoding exception %s'
@@ -1162,7 +1174,7 @@
     unpackerversion = inpart.params.get('version', '01')
     # We should raise an appropriate exception here
     unpacker = changegroup.packermap[unpackerversion][1]
-    cg = unpacker(inpart, 'UN')
+    cg = unpacker(inpart, None)
     # the source and url passed here are overwritten by the one contained in
     # the transaction.hookargs argument. So 'bundle2' is a placeholder
     nbchangesets = None
@@ -1233,7 +1245,7 @@
     # we need to make sure we trigger the creation of a transaction object used
     # for the whole processing scope.
     op.gettransaction()
-    import exchange
+    from . import exchange
     cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
     if not isinstance(cg, changegroup.cg1unpacker):
         raise util.Abort(_('%s: not a bundle version 1.0') %
--- a/mercurial/bundlerepo.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/bundlerepo.py	Fri Sep 25 23:10:47 2015 -0500
@@ -11,12 +11,33 @@
 were part of the actual repository.
 """
 
-from node import nullid
-from i18n import _
-import os, tempfile, shutil
-import changegroup, util, mdiff, discovery, cmdutil, scmutil, exchange
-import localrepo, changelog, manifest, filelog, revlog, error, phases, bundle2
-import pathutil
+from __future__ import absolute_import
+
+import os
+import shutil
+import tempfile
+
+from .i18n import _
+from .node import nullid
+
+from . import (
+    bundle2,
+    changegroup,
+    changelog,
+    cmdutil,
+    discovery,
+    error,
+    exchange,
+    filelog,
+    localrepo,
+    manifest,
+    mdiff,
+    pathutil,
+    phases,
+    revlog,
+    scmutil,
+    util,
+)
 
 class bundlerevlog(revlog.revlog):
     def __init__(self, opener, indexfile, bundle, linkmapper):
--- a/mercurial/changegroup.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/changegroup.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,12 +5,30 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
+import os
+import struct
+import tempfile
 import weakref
-from i18n import _
-from node import nullrev, nullid, hex, short
-import mdiff, util, dagutil
-import struct, os, bz2, zlib, tempfile
-import discovery, error, phases, branchmap
+
+from .i18n import _
+from .node import (
+    hex,
+    nullid,
+    nullrev,
+    short,
+)
+
+from . import (
+    branchmap,
+    dagutil,
+    discovery,
+    error,
+    mdiff,
+    phases,
+    util,
+)
 
 _CHANGEGROUPV1_DELTA_HEADER = "20s20s20s20s"
 _CHANGEGROUPV2_DELTA_HEADER = "20s20s20s20s20s"
@@ -61,20 +79,14 @@
         result = -1 + changedheads
     return result
 
-class nocompress(object):
-    def compress(self, x):
-        return x
-    def flush(self):
-        return ""
-
 bundletypes = {
-    "": ("", nocompress), # only when using unbundle on ssh and old http servers
+    "": ("", None),       # only when using unbundle on ssh and old http servers
                           # since the unification ssh accepts a header but there
                           # is no capability signaling it.
     "HG20": (), # special-cased below
-    "HG10UN": ("HG10UN", nocompress),
-    "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()),
-    "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
+    "HG10UN": ("HG10UN", None),
+    "HG10BZ": ("HG10", 'BZ'),
+    "HG10GZ": ("HG10GZ", 'GZ'),
 }
 
 # hgweb uses this list to communicate its preferred type
@@ -103,19 +115,22 @@
         cleanup = filename
 
         if bundletype == "HG20":
-            import bundle2
+            from . import bundle2
             bundle = bundle2.bundle20(ui)
             part = bundle.newpart('changegroup', data=cg.getchunks())
             part.addparam('version', cg.version)
-            z = nocompress()
+            z = util.compressors[None]()
             chunkiter = bundle.getchunks()
         else:
             if cg.version != '01':
                 raise util.Abort(_('old bundle types only supports v1 '
                                    'changegroups'))
-            header, compressor = bundletypes[bundletype]
+            header, comp = bundletypes[bundletype]
             fh.write(header)
-            z = compressor()
+            if comp not in util.compressors:
+                raise util.Abort(_('unknown stream compression type: %s')
+                                 % comp)
+            z = util.compressors[comp]()
             chunkiter = cg.getchunks()
 
         # parse the changegroup data, otherwise we will block
@@ -138,34 +153,21 @@
             else:
                 os.unlink(cleanup)
 
-def decompressor(fh, alg):
-    if alg == 'UN':
-        return fh
-    elif alg == 'GZ':
-        def generator(f):
-            zd = zlib.decompressobj()
-            for chunk in util.filechunkiter(f):
-                yield zd.decompress(chunk)
-    elif alg == 'BZ':
-        def generator(f):
-            zd = bz2.BZ2Decompressor()
-            zd.decompress("BZ")
-            for chunk in util.filechunkiter(f, 4096):
-                yield zd.decompress(chunk)
-    else:
-        raise util.Abort("unknown bundle compression '%s'" % alg)
-    return util.chunkbuffer(generator(fh))
-
 class cg1unpacker(object):
     deltaheader = _CHANGEGROUPV1_DELTA_HEADER
     deltaheadersize = struct.calcsize(deltaheader)
     version = '01'
     def __init__(self, fh, alg):
-        self._stream = decompressor(fh, alg)
+        if alg == 'UN':
+            alg = None # get more modern without breaking too much
+        if not alg in util.decompressors:
+            raise util.Abort(_('unknown stream compression type: %s')
+                             % alg)
+        self._stream = util.decompressors[alg](fh)
         self._type = alg
         self.callback = None
     def compressed(self):
-        return self._type != 'UN'
+        return self._type is not None
     def read(self, l):
         return self._stream.read(l)
     def seek(self, pos):
@@ -568,7 +570,7 @@
 
 def getsubset(repo, outgoing, bundler, source, fastpath=False, version='01'):
     gengroup = getsubsetraw(repo, outgoing, bundler, source, fastpath)
-    return packermap[version][1](util.chunkbuffer(gengroup), 'UN')
+    return packermap[version][1](util.chunkbuffer(gengroup), None)
 
 def changegroupsubset(repo, roots, heads, source, version='01'):
     """Compute a changegroup consisting of all the nodes that are
--- a/mercurial/changelog.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/changelog.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,21 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from node import bin, hex, nullid
-from i18n import _
-import util, error, revlog, encoding
+from __future__ import absolute_import
+
+from .i18n import _
+from .node import (
+    bin,
+    hex,
+    nullid,
+)
+
+from . import (
+    encoding,
+    error,
+    revlog,
+    util,
+)
 
 _defaultextra = {'branch': 'default'}
 
@@ -172,6 +184,9 @@
         self.rev(self.node(0))
         return self._nodecache
 
+    def reachableroots(self, minroot, heads, roots, includepath=False):
+        return self.index.reachableroots2(minroot, heads, roots, includepath)
+
     def headrevs(self):
         if self.filteredrevs:
             try:
--- a/mercurial/cmdutil.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/cmdutil.py	Fri Sep 25 23:10:47 2015 -0500
@@ -10,7 +10,7 @@
 import os, sys, errno, re, tempfile, cStringIO, shutil
 import util, scmutil, templater, patch, error, templatekw, revlog, copies
 import match as matchmod
-import context, repair, graphmod, revset, phases, obsolete, pathutil
+import repair, graphmod, revset, phases, obsolete, pathutil
 import changelog
 import bookmarks
 import encoding
@@ -848,6 +848,8 @@
     :updatefunc: a function that update a repo to a given node
                  updatefunc(<repo>, <node>)
     """
+    # avoid cycle context -> subrepo -> cmdutil
+    import context
     tmpname, message, user, date, branch, nodeid, p1, p2 = \
         patch.extract(ui, hunk)
 
@@ -990,7 +992,7 @@
         os.unlink(tmpname)
 
 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
-           opts=None):
+           opts=None, match=None):
     '''export changesets as hg patches.'''
 
     total = len(revs)
@@ -1041,7 +1043,7 @@
         write(ctx.description().rstrip())
         write("\n\n")
 
-        for chunk, label in patch.diffui(repo, prev, node, opts=opts):
+        for chunk, label in patch.diffui(repo, prev, node, match, opts=opts):
             write(chunk, label=label)
 
         if shouldclose:
@@ -1412,15 +1414,43 @@
 
         self.cache = {}
 
+        # find correct templates for current mode
+        tmplmodes = [
+            (True, None),
+            (self.ui.verbose, 'verbose'),
+            (self.ui.quiet, 'quiet'),
+            (self.ui.debugflag, 'debug'),
+        ]
+
+        self._parts = {'header': '', 'footer': '', 'changeset': 'changeset',
+                       'docheader': '', 'docfooter': ''}
+        for mode, postfix in tmplmodes:
+            for t in self._parts:
+                cur = t
+                if postfix:
+                    cur += "_" + postfix
+                if mode and cur in self.t:
+                    self._parts[t] = cur
+
+        if self._parts['docheader']:
+            self.ui.write(templater.stringify(self.t(self._parts['docheader'])))
+
+    def close(self):
+        if self._parts['docfooter']:
+            if not self.footer:
+                self.footer = ""
+            self.footer += templater.stringify(self.t(self._parts['docfooter']))
+        return super(changeset_templater, self).close()
+
     def _show(self, ctx, copies, matchfn, props):
         '''show a single changeset or file revision'''
 
         showlist = templatekw.showlist
 
-        # showparents() behaviour depends on ui trace level which
-        # causes unexpected behaviours at templating level and makes
+        # showparents() behavior depends on ui trace level which
+        # causes unexpected behaviors at templating level and makes
         # it harder to extract it in a standalone function. Its
-        # behaviour cannot be changed so leave it here for now.
+        # behavior cannot be changed so leave it here for now.
         def showparents(**args):
             ctx = args['ctx']
             parents = [[('rev', p.rev()),
@@ -1438,27 +1468,10 @@
         props['revcache'] = {'copies': copies}
         props['cache'] = self.cache
 
-        # find correct templates for current mode
-
-        tmplmodes = [
-            (True, None),
-            (self.ui.verbose, 'verbose'),
-            (self.ui.quiet, 'quiet'),
-            (self.ui.debugflag, 'debug'),
-        ]
-
-        types = {'header': '', 'footer':'', 'changeset': 'changeset'}
-        for mode, postfix  in tmplmodes:
-            for type in types:
-                cur = postfix and ('%s_%s' % (type, postfix)) or type
-                if mode and cur in self.t:
-                    types[type] = cur
-
         try:
-
             # write header
-            if types['header']:
-                h = templater.stringify(self.t(types['header'], **props))
+            if self._parts['header']:
+                h = templater.stringify(self.t(self._parts['header'], **props))
                 if self.buffered:
                     self.header[ctx.rev()] = h
                 else:
@@ -1467,15 +1480,14 @@
                         self.ui.write(h)
 
             # write changeset metadata, then patch if requested
-            key = types['changeset']
+            key = self._parts['changeset']
             self.ui.write(templater.stringify(self.t(key, **props)))
             self.showpatch(ctx.node(), matchfn)
 
-            if types['footer']:
+            if self._parts['footer']:
                 if not self.footer:
-                    self.footer = templater.stringify(self.t(types['footer'],
-                                                      **props))
-
+                    self.footer = templater.stringify(
+                        self.t(self._parts['footer'], **props))
         except KeyError as inst:
             msg = _("%s: no key named '%s'")
             raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
@@ -1928,7 +1940,7 @@
         followfirst = 1
     else:
         followfirst = 0
-    # --follow with FILE behaviour depends on revs...
+    # --follow with FILE behavior depends on revs...
     it = iter(revs)
     startrev = it.next()
     followdescendants = startrev < next(it, startrev)
@@ -2049,7 +2061,7 @@
     return expr, filematcher
 
 def _logrevs(repo, opts):
-    # Default --rev value depends on --follow but --follow behaviour
+    # Default --rev value depends on --follow but --follow behavior
     # depends on revisions resolved from --rev...
     follow = opts.get('follow') or opts.get('follow_first')
     if opts.get('rev'):
@@ -2207,7 +2219,12 @@
     if abort or warn:
         cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
 
-    for f in wctx.walk(matchmod.badmatch(match, badfn)):
+    badmatch = matchmod.badmatch(match, badfn)
+    dirstate = repo.dirstate
+    # We don't want to just call wctx.walk here, since it would return a lot of
+    # clean files, which we aren't interested in and takes time.
+    for f in sorted(dirstate.walk(badmatch, sorted(wctx.substate),
+                                  True, False, full=False)):
         exact = match.exact(f)
         if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
             if cca:
@@ -2464,6 +2481,9 @@
     return commitfunc(ui, repo, message, matcher, opts)
 
 def amend(ui, repo, commitfunc, old, extra, pats, opts):
+    # avoid cycle context -> subrepo -> cmdutil
+    import context
+
     # amend will reuse the existing user if not specified, but the obsolete
     # marker creation requires that the current user's name is specified.
     if obsolete.isenabled(repo, obsolete.createmarkersopt):
@@ -2743,7 +2763,9 @@
 
     return "\n".join(edittext)
 
-def commitstatus(repo, node, branch, bheads=None, opts={}):
+def commitstatus(repo, node, branch, bheads=None, opts=None):
+    if opts is None:
+        opts = {}
     ctx = repo[node]
     parents = ctx.parents()
 
--- a/mercurial/commands.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/commands.py	Fri Sep 25 23:10:47 2015 -0500
@@ -13,13 +13,13 @@
 import hg, scmutil, util, revlog, copies, error, bookmarks
 import patch, help, encoding, templatekw, discovery
 import archival, changegroup, cmdutil, hbisect
-import sshserver, hgweb, commandserver
+import sshserver, hgweb
 import extensions
 from hgweb import server as hgweb_server
 import merge as mergemod
 import minirst, revset, fileset
 import dagparser, context, simplemerge, graphmod, copies
-import random
+import random, operator
 import setdiscovery, treediscovery, dagutil, pvec, localrepo
 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
 import ui as uimod
@@ -875,7 +875,7 @@
     [('f', 'force', False, _('force')),
     ('r', 'rev', '', _('revision'), _('REV')),
     ('d', 'delete', False, _('delete a given bookmark')),
-    ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
+    ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
     ('i', 'inactive', False, _('mark a bookmark inactive')),
     ] + formatteropts,
     _('hg bookmarks [OPTIONS]... [NAME]...'))
@@ -916,6 +916,10 @@
 
           hg book -r .^ tested
 
+      - rename bookmark turkey to dinner::
+
+          hg book -m turkey dinner
+
       - move the '@' bookmark from another branch::
 
           hg book -f @
@@ -2167,6 +2171,45 @@
         localrevs = opts.get('local_head')
         doit(localrevs, remoterevs)
 
+@command('debugextensions', formatteropts, [], norepo=True)
+def debugextensions(ui, **opts):
+    '''show information about active extensions'''
+    exts = extensions.extensions(ui)
+    fm = ui.formatter('debugextensions', opts)
+    for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
+        extsource = extmod.__file__
+        exttestedwith = getattr(extmod, 'testedwith', None)
+        if exttestedwith is not None:
+            exttestedwith = exttestedwith.split()
+        extbuglink = getattr(extmod, 'buglink', None)
+
+        fm.startitem()
+
+        if ui.quiet or ui.verbose:
+            fm.write('name', '%s\n', extname)
+        else:
+            fm.write('name', '%s', extname)
+            if not exttestedwith:
+                fm.plain(_(' (untested!)\n'))
+            else:
+                if exttestedwith == ['internal'] or \
+                                util.version() in exttestedwith:
+                    fm.plain('\n')
+                else:
+                    lasttestedversion = exttestedwith[-1]
+                    fm.plain(' (%s!)\n' % lasttestedversion)
+
+        fm.condwrite(ui.verbose and extsource, 'source',
+                 _('  location: %s\n'), extsource or "")
+
+        fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
+                 _('  tested with: %s\n'), ' '.join(exttestedwith or []))
+
+        fm.condwrite(ui.verbose and extbuglink, 'buglink',
+                 _('  bug reporting: %s\n'), extbuglink or "")
+
+    fm.end()
+
 @command('debugfileset',
     [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
     _('[-r REV] FILESPEC'))
@@ -2700,9 +2743,12 @@
               pa.distance(pb), rel))
 
 @command('debugrebuilddirstate|debugrebuildstate',
-    [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
+    [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
+     ('', 'minimal', None, _('only rebuild files that are inconsistent with '
+                             'the working copy parent')),
+    ],
     _('[-r REV]'))
-def debugrebuilddirstate(ui, repo, rev):
+def debugrebuilddirstate(ui, repo, rev, **opts):
     """rebuild the dirstate as it would look like for the given revision
 
     If no revision is specified the first current parent will be used.
@@ -2711,13 +2757,33 @@
     The actual working directory content or existing dirstate
     information such as adds or removes is not considered.
 
+    ``minimal`` will only rebuild the dirstate status for files that claim to be
+    tracked but are not in the parent manifest, or that exist in the parent
+    manifest but are not in the dirstate. It will not change adds, removes, or
+    modified files that are in the working copy parent.
+
     One use of this command is to make the next :hg:`status` invocation
     check the actual file content.
     """
     ctx = scmutil.revsingle(repo, rev)
     wlock = repo.wlock()
     try:
-        repo.dirstate.rebuild(ctx.node(), ctx.manifest())
+        dirstate = repo.dirstate
+
+        # See command doc for what minimal does.
+        if opts.get('minimal'):
+            dirstatefiles = set(dirstate)
+            ctxfiles = set(ctx.manifest().keys())
+            for file in (dirstatefiles | ctxfiles):
+                indirstate = file in dirstatefiles
+                inctx = file in ctxfiles
+
+                if indirstate and not inctx and dirstate[file] != 'a':
+                    dirstate.drop(file)
+                elif inctx and not indirstate:
+                    dirstate.normallookup(file)
+        else:
+            dirstate.rebuild(ctx.node(), ctx.manifest())
     finally:
         wlock.release()
 
@@ -2933,7 +2999,7 @@
     expansion.
     """
     if ui.verbose:
-        tree = revset.parse(expr)
+        tree = revset.parse(expr, lookup=repo.__contains__)
         ui.note(revset.prettyformat(tree), "\n")
         newtree = revset.findaliases(ui, tree)
         if newtree != tree:
@@ -2945,7 +3011,7 @@
         if opts["optimize"]:
             weight, optimizedtree = revset.optimize(newtree, True)
             ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
-    func = revset.match(ui, expr)
+    func = revset.match(ui, expr, repo)
     revs = func(repo)
     if ui.verbose:
         ui.note("* set:\n", revset.prettyformatset(revs), "\n")
@@ -3915,9 +3981,9 @@
 @command('help',
     [('e', 'extension', None, _('show only help for extensions')),
      ('c', 'command', None, _('show only help for commands')),
-     ('k', 'keyword', '', _('show topics matching keyword')),
+     ('k', 'keyword', None, _('show topics matching keyword')),
      ],
-    _('[-ec] [TOPIC]'),
+    _('[-eck] [TOPIC]'),
     norepo=True)
 def help_(ui, name=None, **opts):
     """show help for a given topic or a help overview
@@ -3948,12 +4014,17 @@
     section = None
     if name and '.' in name:
         name, section = name.split('.', 1)
+        section = section.lower()
 
     text = help.help_(ui, name, **opts)
 
     formatted, pruned = minirst.format(text, textwidth, keep=keep,
                                        section=section)
-    if section and not formatted:
+
+    # We could have been given a weird ".foo" section without a name
+    # to look for, or we could have simply failed to found "foo.bar"
+    # because bar isn't a section of foo
+    if section and not (formatted and name):
         raise util.Abort(_("help section not found"))
 
     if 'verbose' in pruned:
@@ -4740,58 +4811,8 @@
     if node:
         node = scmutil.revsingle(repo, node).node()
 
-    if not node and repo._activebookmark:
-        bmheads = repo.bookmarkheads(repo._activebookmark)
-        curhead = repo[repo._activebookmark].node()
-        if len(bmheads) == 2:
-            if curhead == bmheads[0]:
-                node = bmheads[1]
-            else:
-                node = bmheads[0]
-        elif len(bmheads) > 2:
-            raise util.Abort(_("multiple matching bookmarks to merge - "
-                "please merge with an explicit rev or bookmark"),
-                hint=_("run 'hg heads' to see all heads"))
-        elif len(bmheads) <= 1:
-            raise util.Abort(_("no matching bookmark to merge - "
-                "please merge with an explicit rev or bookmark"),
-                hint=_("run 'hg heads' to see all heads"))
-
-    if not node and not repo._activebookmark:
-        branch = repo[None].branch()
-        bheads = repo.branchheads(branch)
-        nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
-
-        if len(nbhs) > 2:
-            raise util.Abort(_("branch '%s' has %d heads - "
-                               "please merge with an explicit rev")
-                             % (branch, len(bheads)),
-                             hint=_("run 'hg heads .' to see heads"))
-
-        parent = repo.dirstate.p1()
-        if len(nbhs) <= 1:
-            if len(bheads) > 1:
-                raise util.Abort(_("heads are bookmarked - "
-                                   "please merge with an explicit rev"),
-                                 hint=_("run 'hg heads' to see all heads"))
-            if len(repo.heads()) > 1:
-                raise util.Abort(_("branch '%s' has one head - "
-                                   "please merge with an explicit rev")
-                                 % branch,
-                                 hint=_("run 'hg heads' to see all heads"))
-            msg, hint = _('nothing to merge'), None
-            if parent != repo.lookup(branch):
-                hint = _("use 'hg update' instead")
-            raise util.Abort(msg, hint=hint)
-
-        if parent not in bheads:
-            raise util.Abort(_('working directory not at a head revision'),
-                             hint=_("use 'hg update' or merge with an "
-                                    "explicit revision"))
-        if parent == nbhs[0]:
-            node = nbhs[-1]
-        else:
-            node = nbhs[0]
+    if not node:
+        node = scmutil.revsingle(repo, '_mergedefaultdest()').node()
 
     if opts.get('preview'):
         # find nodes that are ancestors of p2 but not of p1
@@ -5004,8 +5025,7 @@
 
         public < draft < secret
 
-    Returns 0 on success, 1 if no phases were changed or some could not
-    be changed.
+    Returns 0 on success, 1 if some phases could not be changed.
 
     (For more information about the phases concept, see :hg:`help phases`.)
     """
@@ -5074,7 +5094,6 @@
                 ui.note(msg)
         else:
             ui.warn(_('no phases changed\n'))
-            ret = 1
     return ret
 
 def postincoming(ui, repo, modheads, optupdate, checkout):
@@ -5251,18 +5270,14 @@
                 # this lets simultaneous -r, -b options continue working
                 opts.setdefault('rev', []).append("null")
 
-    dest = ui.expandpath(dest or 'default-push', dest or 'default')
-    dest, branches = hg.parseurl(dest, opts.get('branch'))
+    path = ui.paths.getpath(dest, default='default')
+    if not path:
+        raise util.Abort(_('default repository not configured!'),
+                         hint=_('see the "path" section in "hg help config"'))
+    dest, branches = path.pushloc, (path.branch, opts.get('branch') or [])
     ui.status(_('pushing to %s\n') % util.hidepassword(dest))
     revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
-    try:
-        other = hg.peer(repo, opts, dest)
-    except error.RepoError:
-        if dest == "default-push":
-            raise util.Abort(_("default repository not configured!"),
-                    hint=_('see the "path" section in "hg help config"'))
-        else:
-            raise
+    other = hg.peer(repo, opts, dest)
 
     if revs:
         revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
@@ -5446,7 +5461,7 @@
         raise util.Abort(_("can't specify --all and patterns"))
     if not (all or pats or show or mark or unmark):
         raise util.Abort(_('no files or directories specified'),
-                         hint=('use --all to remerge all files'))
+                         hint=('use --all to re-merge all unresolved files'))
 
     if show:
         fm = ui.formatter('resolve', opts)
@@ -5713,6 +5728,7 @@
         s.serve_forever()
 
     if opts["cmdserver"]:
+        import commandserver
         service = commandserver.createservice(ui, repo, opts)
         return cmdutil.service(opts, initfn=service.init, runfn=service.run)
 
@@ -6248,7 +6264,7 @@
                         raise util.Abort(_("tag '%s' is not a global tag") % n)
                     else:
                         raise util.Abort(_("tag '%s' is not a local tag") % n)
-            rev_ = nullid
+            rev_ = 'null'
             if not message:
                 # we don't translate commit messages
                 message = 'Removed tag %s' % ', '.join(names)
@@ -6461,6 +6477,11 @@
     try:
         cmdutil.clearunfinished(repo)
 
+        if date:
+            if rev is not None:
+                raise util.Abort(_("you can't specify a revision and a date"))
+            rev = cmdutil.finddate(ui, repo, date)
+
         # with no argument, we also move the active bookmark, if any
         rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
 
@@ -6471,11 +6492,6 @@
         if check and clean:
             raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
 
-        if date:
-            if rev is not None:
-                raise util.Abort(_("you can't specify a revision and a date"))
-            rev = cmdutil.finddate(ui, repo, date)
-
         if check:
             cmdutil.bailifchanged(repo, merge=False)
             if rev is None:
--- a/mercurial/config.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/config.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,16 @@
 # 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 error, util
-import os, errno
+from __future__ import absolute_import
+
+import errno
+import os
+
+from .i18n import _
+from . import (
+    error,
+    util,
+)
 
 class config(object):
     def __init__(self, data=None, includepaths=[]):
--- a/mercurial/copies.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/copies.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,15 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import util, pathutil
+from __future__ import absolute_import
+
 import heapq
 
+from . import (
+    pathutil,
+    util,
+)
+
 def _findlimit(repo, a, b):
     """
     Find the last revision that needs to be checked to ensure that a full
@@ -185,6 +191,9 @@
     return cm
 
 def _backwardrenames(a, b):
+    if a._repo.ui.configbool('experimental', 'disablecopytrace'):
+        return {}
+
     # Even though we're not taking copies into account, 1:n rename situations
     # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
     # arbitrarily pick one of the renames.
@@ -258,17 +267,25 @@
     if c2.node() is None and c1.node() == repo.dirstate.p1():
         return repo.dirstate.copies(), {}, {}, {}
 
+    # Copy trace disabling is explicitly below the node == p1 logic above
+    # because the logic above is required for a simple copy to be kept across a
+    # rebase.
+    if repo.ui.configbool('experimental', 'disablecopytrace'):
+        return {}, {}, {}, {}
+
     limit = _findlimit(repo, c1.rev(), c2.rev())
     if limit is None:
         # no common ancestor, no copies
         return {}, {}, {}, {}
+    repo.ui.debug("  searching for copies back to rev %d\n" % limit)
+
     m1 = c1.manifest()
     m2 = c2.manifest()
     ma = ca.manifest()
 
 
     def setupctx(ctx):
-        """return a 'makectx' function suitable for checkcopies usage from ctx
+        """return a 'getfctx' function suitable for checkcopies usage
 
         We have to re-setup the function building 'filectx' for each
         'checkcopies' to ensure the linkrev adjustement is properly setup for
@@ -301,28 +318,30 @@
             return fctx
         return util.lrucachefunc(makectx)
 
-    copy = {}
-    movewithdir = {}
-    fullcopy = {}
+    copy1, copy2, = {}, {}
+    movewithdir1, movewithdir2 = {}, {}
+    fullcopy1, fullcopy2 = {}, {}
     diverge = {}
 
-    repo.ui.debug("  searching for copies back to rev %d\n" % limit)
-
     addedinm1 = m1.filesnotin(ma)
     addedinm2 = m2.filesnotin(ma)
     u1, u2 = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
 
     for f in u1:
-        ctx = setupctx(c1)
-        checkcopies(ctx, f, m1, m2, ca, limit, diverge, copy, fullcopy)
+        getfctx = setupctx(c1)
+        checkcopies(getfctx, f, m1, m2, ca, limit, diverge, copy1, fullcopy1)
 
     for f in u2:
-        ctx = setupctx(c2)
-        checkcopies(ctx, f, m2, m1, ca, limit, diverge, copy, fullcopy)
+        getfctx = setupctx(c2)
+        checkcopies(getfctx, f, m2, m1, ca, limit, diverge, copy2, fullcopy2)
+
+    copy = dict(copy1.items() + copy2.items())
+    movewithdir = dict(movewithdir1.items() + movewithdir2.items())
+    fullcopy = dict(fullcopy1.items() + fullcopy2.items())
 
     renamedelete = {}
     renamedelete2 = set()
-    diverge2 = set()
+    divergeset = set()
     for of, fl in diverge.items():
         if len(fl) == 1 or of in c1 or of in c2:
             del diverge[of] # not actually divergent, or not a rename
@@ -332,7 +351,7 @@
                 renamedelete[of] = [f for f in fl if f in c1 or f in c2]
                 renamedelete2.update(fl) # reverse map for below
         else:
-            diverge2.update(fl) # reverse map for below
+            divergeset.update(fl) # reverse map for below
 
     bothnew = sorted(addedinm1 & addedinm2)
     if bothnew:
@@ -340,10 +359,12 @@
                       % "\n   ".join(bothnew))
     bothdiverge, _copy, _fullcopy = {}, {}, {}
     for f in bothnew:
-        ctx = setupctx(c1)
-        checkcopies(ctx, f, m1, m2, ca, limit, bothdiverge, _copy, _fullcopy)
-        ctx = setupctx(c2)
-        checkcopies(ctx, f, m2, m1, ca, limit, bothdiverge, _copy, _fullcopy)
+        getfctx = setupctx(c1)
+        checkcopies(getfctx, f, m1, m2, ca, limit, bothdiverge,
+                    _copy, _fullcopy)
+        getfctx = setupctx(c2)
+        checkcopies(getfctx, f, m2, m1, ca, limit, bothdiverge,
+                    _copy, _fullcopy)
     for of, fl in bothdiverge.items():
         if len(fl) == 2 and fl[0] == fl[1]:
             copy[fl[0]] = of # not actually divergent, just matching renames
@@ -355,13 +376,13 @@
             note = ""
             if f in copy:
                 note += "*"
-            if f in diverge2:
+            if f in divergeset:
                 note += "!"
             if f in renamedelete2:
                 note += "%"
             repo.ui.debug("   src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
                                                               note))
-    del diverge2
+    del divergeset
 
     if not fullcopy:
         return copy, movewithdir, diverge, renamedelete
@@ -423,11 +444,11 @@
 
     return copy, movewithdir, diverge, renamedelete
 
-def checkcopies(ctx, f, m1, m2, ca, limit, diverge, copy, fullcopy):
+def checkcopies(getfctx, f, m1, m2, ca, limit, diverge, copy, fullcopy):
     """
     check possible copies of f from m1 to m2
 
-    ctx = function accepting (filename, node) that returns a filectx.
+    getfctx = function accepting (filename, node) that returns a filectx.
     f = the filename to check
     m1 = the source manifest
     m2 = the destination manifest
@@ -473,7 +494,7 @@
 
     of = None
     seen = set([f])
-    for oc in ctx(f, m1[f]).ancestors():
+    for oc in getfctx(f, m1[f]).ancestors():
         ocr = oc.linkrev()
         of = oc.path()
         if of in seen:
@@ -488,7 +509,7 @@
             continue # no match, keep looking
         if m2[of] == ma.get(of):
             break # no merge needed, quit early
-        c2 = ctx(of, m2[of])
+        c2 = getfctx(of, m2[of])
         cr = _related(oc, c2, ca.rev())
         if cr and (of == f or of == c2.path()): # non-divergent
             copy[f] = of
@@ -507,7 +528,12 @@
     copies between fromrev and rev.
     '''
     exclude = {}
-    if skiprev is not None:
+    if (skiprev is not None and
+        not repo.ui.configbool('experimental', 'disablecopytrace')):
+        # disablecopytrace skips this line, but not the entire function because
+        # the line below is O(size of the repo) during a rebase, while the rest
+        # of the function is much faster (and is required for carrying copy
+        # metadata across the rebase anyway).
         exclude = pathcopies(repo[fromrev], repo[skiprev])
     for dst, src in pathcopies(repo[fromrev], repo[rev]).iteritems():
         # copies.pathcopies returns backward renames, so dst might not
--- a/mercurial/crecord.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/crecord.py	Fri Sep 25 23:10:47 2015 -0500
@@ -8,11 +8,23 @@
 # This code is based on the Mark Edgington's crecord extension.
 # (Itself based on Bryan O'Sullivan's record extension.)
 
-from i18n import _
-import patch as patchmod
-import util, encoding
+from __future__ import absolute_import
 
-import os, re, sys, struct, signal, tempfile, locale, cStringIO
+import cStringIO
+import locale
+import os
+import re
+import signal
+import struct
+import sys
+import tempfile
+
+from .i18n import _
+from . import (
+    encoding,
+    patch as patchmod,
+    util,
+)
 
 # This is required for ncurses to display non-ASCII characters in default user
 # locale encoding correctly.  --immerrr
@@ -21,7 +33,8 @@
 # os.name is one of: 'posix', 'nt', 'dos', 'os2', 'mac', or 'ce'
 if os.name == 'posix':
     import curses
-    import fcntl, termios
+    import fcntl
+    import termios
 else:
     # I have no idea if wcurses works with crecord...
     try:
--- a/mercurial/dagparser.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/dagparser.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,13 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import re, string
-import util
-from i18n import _
+from __future__ import absolute_import
+
+import re
+import string
+
+from .i18n import _
+from . import util
 
 def parsedag(desc):
     '''parses a DAG from a concise textual description; generates events
--- a/mercurial/dagutil.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/dagutil.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,9 +6,10 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from node import nullrev
-from i18n import _
+from __future__ import absolute_import
 
+from .i18n import _
+from .node import nullrev
 
 class basedag(object):
     '''generic interface for DAGs
--- a/mercurial/demandimport.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/demandimport.py	Fri Sep 25 23:10:47 2015 -0500
@@ -24,8 +24,11 @@
   b = __import__(a)
 '''
 
-import os, sys
-from contextlib import contextmanager
+from __future__ import absolute_import
+
+import contextlib
+import os
+import sys
 
 # __builtin__ in Python 2, builtins in Python 3.
 try:
@@ -33,26 +36,21 @@
 except ImportError:
     import builtins
 
+contextmanager = contextlib.contextmanager
+
 _origimport = __import__
 
 nothing = object()
 
-try:
-    # Python 3 doesn't have relative imports nor level -1.
-    level = -1
-    if sys.version_info[0] >= 3:
-        level = 0
-    _origimport(builtins.__name__, {}, {}, None, level)
-except TypeError: # no level argument
-    def _import(name, globals, locals, fromlist, level):
-        "call _origimport with no level argument"
-        return _origimport(name, globals, locals, fromlist)
-else:
-    _import = _origimport
+# Python 3 doesn't have relative imports nor level -1.
+level = -1
+if sys.version_info[0] >= 3:
+    level = 0
+_import = _origimport
 
-def _hgextimport(importfunc, name, globals, *args):
+def _hgextimport(importfunc, name, globals, *args, **kwargs):
     try:
-        return importfunc(name, globals, *args)
+        return importfunc(name, globals, *args, **kwargs)
     except ImportError:
         if not globals:
             raise
@@ -63,7 +61,7 @@
         if nameroot != contextroot:
             raise
         # retry to import with "hgext_" prefix
-        return importfunc(hgextname, globals, *args)
+        return importfunc(hgextname, globals, *args, **kwargs)
 
 class _demandmod(object):
     """module demand-loader and proxy"""
@@ -135,15 +133,44 @@
                 return locals[base]
         return _demandmod(name, globals, locals, level)
     else:
-        if level != -1:
-            # from . import b,c,d or from .a import b,c,d
-            return _origimport(name, globals, locals, fromlist, level)
+        # There is a fromlist.
         # from a import b,c,d
+        # from . import b,c,d
+        # from .a import b,c,d
+
+        # level == -1: relative and absolute attempted (Python 2 only).
+        # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
+        # The modern Mercurial convention is to use absolute_import everywhere,
+        # so modern Mercurial code will have level >= 0.
+
+        if level >= 0:
+            # Mercurial's enforced import style does not use
+            # "from a import b,c,d" or "from .a import b,c,d" syntax. In
+            # addition, this appears to be giving errors with some modules
+            # for unknown reasons. Since we shouldn't be using this syntax
+            # much, work around the problems.
+            if name:
+                return _hgextimport(_origimport, name, globals, locals,
+                                    fromlist, level)
+
+            mod = _hgextimport(_origimport, name, globals, locals, level=level)
+            for x in fromlist:
+                # Missing symbols mean they weren't defined in the module
+                # itself which means they are sub-modules.
+                if getattr(mod, x, nothing) is nothing:
+                    setattr(mod, x,
+                            _demandmod(x, mod.__dict__, locals, level=level))
+
+            return mod
+
+        # But, we still need to support lazy loading of standard library and 3rd
+        # party modules. So handle level == -1.
         mod = _hgextimport(_origimport, name, globals, locals)
         # recurse down the module chain
         for comp in name.split('.')[1:]:
             if getattr(mod, comp, nothing) is nothing:
-                setattr(mod, comp, _demandmod(comp, mod.__dict__, mod.__dict__))
+                setattr(mod, comp,
+                        _demandmod(comp, mod.__dict__, mod.__dict__))
             mod = getattr(mod, comp)
         for x in fromlist:
             # set requested submodules for demand load
@@ -152,6 +179,7 @@
         return mod
 
 ignore = [
+    '__future__',
     '_hashlib',
     '_xmlplus',
     'fcntl',
--- a/mercurial/dirstate.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/dirstate.py	Fri Sep 25 23:10:47 2015 -0500
@@ -42,6 +42,10 @@
         # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is
         # UNC path pointing to root share (issue4557)
         self._rootdir = pathutil.normasprefix(root)
+        # internal config: ui.forcecwd
+        forcecwd = ui.config('ui', 'forcecwd')
+        if forcecwd:
+            self._cwd = forcecwd
         self._dirty = False
         self._dirtypl = False
         self._lastnormaltime = 0
@@ -220,6 +224,12 @@
         return os.getcwd()
 
     def getcwd(self):
+        '''Return the path from which a canonical path is calculated.
+
+        This path should be used to resolve file patterns or to convert
+        canonical paths back to file paths for display. It shouldn't be
+        used to get real file paths. Use vfs functions instead.
+        '''
         cwd = self._cwd
         if cwd == self._root:
             return ''
--- a/mercurial/discovery.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/discovery.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,10 +5,23 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from node import nullid, short
-from i18n import _
-import util, setdiscovery, treediscovery, phases, obsolete, bookmarks
-import branchmap
+from __future__ import absolute_import
+
+from .i18n import _
+from .node import (
+    nullid,
+    short,
+)
+
+from . import (
+    bookmarks,
+    branchmap,
+    obsolete,
+    phases,
+    setdiscovery,
+    treediscovery,
+    util,
+)
 
 def findcommonincoming(repo, remote, heads=None, force=False):
     """Return a tuple (common, anyincoming, heads) used to identify the common
--- a/mercurial/dispatch.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/dispatch.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,13 +5,37 @@
 # 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 os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
+from __future__ import absolute_import
+
+import atexit
 import difflib
-import util, commands, hg, fancyopts, extensions, hook, error
-import cmdutil, encoding
-import ui as uimod
-import demandimport
+import errno
+import os
+import pdb
+import re
+import shlex
+import signal
+import socket
+import sys
+import time
+import traceback
+
+
+from .i18n import _
+
+from . import (
+    cmdutil,
+    commands,
+    demandimport,
+    encoding,
+    error,
+    extensions,
+    fancyopts,
+    hg,
+    hook,
+    ui as uimod,
+    util,
+)
 
 class request(object):
     def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
@@ -157,8 +181,8 @@
                     debugtrace[debugger] == debugtrace['pdb']):
                     ui.warn(_("%s debugger specified "
                               "but its module was not found\n") % debugger)
-
-                debugtrace[debugger]()
+                with demandimport.deactivated():
+                    debugtrace[debugger]()
             try:
                 return _dispatch(req)
             finally:
@@ -229,7 +253,7 @@
             # check if the command is in a disabled extension
             # (but don't check for extensions themselves)
             commands.help_(ui, inst.args[0], unknowncmd=True)
-        except error.UnknownCommand:
+        except (error.UnknownCommand, util.Abort):
             suggested = False
             if len(inst.args) == 2:
                 sim = _getsimilar(inst.args[1], inst.args[0])
@@ -268,8 +292,7 @@
             ui.warn(_("abort: error: %s\n") % reason)
         elif (util.safehasattr(inst, "args")
               and inst.args and inst.args[0] == errno.EPIPE):
-            if ui.debugflag:
-                ui.warn(_("broken pipe\n"))
+            pass
         elif getattr(inst, "strerror", None):
             if getattr(inst, "filename", None):
                 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
@@ -286,10 +309,7 @@
         try:
             ui.warn(_("interrupted!\n"))
         except IOError as inst:
-            if inst.errno == errno.EPIPE:
-                if ui.debugflag:
-                    ui.warn(_("\nbroken pipe\n"))
-            else:
+            if inst.errno != errno.EPIPE:
                 raise
     except MemoryError:
         ui.warn(_("abort: out of memory\n"))
@@ -311,26 +331,27 @@
         compare = myver.split('+')[0]
         ct = tuplever(compare)
         worst = None, ct, ''
-        for name, mod in extensions.extensions():
-            testedwith = getattr(mod, 'testedwith', '')
-            report = getattr(mod, 'buglink', _('the extension author.'))
-            if not testedwith.strip():
-                # We found an untested extension. It's likely the culprit.
-                worst = name, 'unknown', report
-                break
+        if ui.config('ui', 'supportcontact', None) is None:
+            for name, mod in extensions.extensions():
+                testedwith = getattr(mod, 'testedwith', '')
+                report = getattr(mod, 'buglink', _('the extension author.'))
+                if not testedwith.strip():
+                    # We found an untested extension. It's likely the culprit.
+                    worst = name, 'unknown', report
+                    break
 
-            # Never blame on extensions bundled with Mercurial.
-            if testedwith == 'internal':
-                continue
+                # Never blame on extensions bundled with Mercurial.
+                if testedwith == 'internal':
+                    continue
 
-            tested = [tuplever(t) for t in testedwith.split()]
-            if ct in tested:
-                continue
+                tested = [tuplever(t) for t in testedwith.split()]
+                if ct in tested:
+                    continue
 
-            lower = [t for t in tested if t < ct]
-            nearest = max(lower or tested)
-            if worst[0] is None or nearest < worst[1]:
-                worst = name, nearest, report
+                lower = [t for t in tested if t < ct]
+                nearest = max(lower or tested)
+                if worst[0] is None or nearest < worst[1]:
+                    worst = name, nearest, report
         if worst[0] is not None:
             name, testedwith, report = worst
             if not isinstance(testedwith, str):
@@ -342,9 +363,11 @@
                          '** If that fixes the bug please report it to %s\n')
                        % (name, testedwith, name, report))
         else:
+            bugtracker = ui.config('ui', 'supportcontact', None)
+            if bugtracker is None:
+                bugtracker = _("http://mercurial.selenic.com/wiki/BugTracker")
             warning = (_("** unknown exception encountered, "
-                         "please report by visiting\n") +
-                       _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
+                         "please report by visiting\n** ") + bugtracker + '\n')
         warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
                     (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
                     (_("** Extensions loaded: %s\n") %
@@ -866,6 +889,8 @@
             except error.RequirementError:
                 raise
             except error.RepoError:
+                if rpath and rpath[-1]: # invalid -R path
+                    raise
                 if cmd not in commands.optionalrepo.split():
                     if (cmd in commands.inferrepo.split() and
                         args and not path): # try to infer -R from command args
@@ -909,7 +934,7 @@
         format = 'text'
 
     try:
-        from mercurial import lsprof
+        from . import lsprof
     except ImportError:
         raise util.Abort(_(
             'lsprof not available - install from '
@@ -922,7 +947,7 @@
         p.disable()
 
         if format == 'kcachegrind':
-            import lsprofcalltree
+            from . import lsprofcalltree
             calltree = lsprofcalltree.KCacheGrind(p)
             calltree.output(fp)
         else:
@@ -977,13 +1002,17 @@
         statprof.display(fp)
 
 def _runcommand(ui, options, cmd, cmdfunc):
+    """Enables the profiler if applicable.
+
+    ``profiling.enabled`` - boolean config that enables or disables profiling
+    """
     def checkargs():
         try:
             return cmdfunc()
         except error.SignatureError:
             raise error.CommandError(cmd, _("invalid arguments"))
 
-    if options['profile']:
+    if options['profile'] or ui.configbool('profiling', 'enabled'):
         profiler = os.getenv('HGPROF')
         if profiler is None:
             profiler = ui.config('profiling', 'type', default='ls')
@@ -993,7 +1022,10 @@
 
         output = ui.config('profiling', 'output')
 
-        if output:
+        if output == 'blackbox':
+            import StringIO
+            fp = StringIO.StringIO()
+        elif output:
             path = ui.expandpath(output)
             fp = open(path, 'wb')
         else:
@@ -1008,6 +1040,12 @@
                 return statprofile(ui, checkargs, fp)
         finally:
             if output:
+                if output == 'blackbox':
+                    val = "Profile:\n%s" % fp.getvalue()
+                    # ui.log treats the input as a format string,
+                    # so we need to escape any % signs.
+                    val = val.replace('%', '%%')
+                    ui.log('profile', val)
                 fp.close()
     else:
         return checkargs()
--- a/mercurial/error.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/error.py	Fri Sep 25 23:10:47 2015 -0500
@@ -11,6 +11,8 @@
 imports.
 """
 
+from __future__ import absolute_import
+
 # Do not import anything here, please
 
 class HintException(Exception):
@@ -32,7 +34,7 @@
         # Python 2.6+ complain about the 'message' property being deprecated
         self.lookupmessage = message
         if isinstance(name, str) and len(name) == 20:
-            from node import short
+            from .node import short
             name = short(name)
         RevlogError.__init__(self, '%s@%s: %s' % (index, name, message))
 
@@ -78,7 +80,7 @@
     """Exception raised when a {rev,file}set references an unknown identifier"""
 
     def __init__(self, function, symbols):
-        from i18n import _
+        from .i18n import _
         ParseError.__init__(self, _("unknown identifier: %s") % function)
         self.function = function
         self.symbols = symbols
@@ -112,6 +114,10 @@
 class LockUnavailable(LockError):
     pass
 
+# LockError is for errors while acquiring the lock -- this is unrelated
+class LockInheritanceContractViolation(AssertionError):
+    pass
+
 class ResponseError(Exception):
     """Raised to print an error with part of output and exit."""
 
@@ -173,7 +179,7 @@
     """
 
     def __init__(self, filename, node, tombstone):
-        from node import short
+        from .node import short
         RevlogError.__init__(self, '%s:%s' % (filename, short(node)))
         self.tombstone = tombstone
 
--- a/mercurial/exchange.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/exchange.py	Fri Sep 25 23:10:47 2015 -0500
@@ -147,7 +147,7 @@
         #
         # We can pick:
         # * missingheads part of common (::commonheads)
-        common = set(self.outgoing.common)
+        common = self.outgoing.common
         nm = self.repo.changelog.nodemap
         cheads = [node for node in self.revs if nm[node] in common]
         # and
@@ -571,7 +571,7 @@
 
 @b2partsgenerator('bookmarks')
 def _pushb2bookmarks(pushop, bundler):
-    """handle phase push through bundle2"""
+    """handle bookmark push through bundle2"""
     if 'bookmarks' in pushop.stepsdone:
         return
     b2caps = bundle2.bundle2caps(pushop.remote)
@@ -1419,7 +1419,7 @@
                 op = bundle2.bundleoperation(repo, lambda: tr,
                                              captureoutput=captureoutput)
                 try:
-                    r = bundle2.processbundle(repo, cg, op=op)
+                    op = bundle2.processbundle(repo, cg, op=op)
                 finally:
                     r = op.reply
                     if captureoutput and r is not None:
--- a/mercurial/extensions.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/extensions.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,21 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import imp, os
-import util, cmdutil, error
-from i18n import _, gettext
+from __future__ import absolute_import
+
+import imp
+import os
+
+from .i18n import (
+    _,
+    gettext,
+)
+
+from . import (
+    cmdutil,
+    error,
+    util,
+)
 
 _extensions = {}
 _aftercallbacks = {}
--- a/mercurial/fancyopts.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/fancyopts.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,12 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import getopt
-import util
-from i18n import _
+
+from .i18n import _
+from . import util
 
 def gnugetopt(args, options, longoptions):
     """Parse options mostly like getopt.gnu_getopt.
--- a/mercurial/filelog.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/filelog.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,8 +5,16 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import error, mdiff, revlog
-import re, struct
+from __future__ import absolute_import
+
+import re
+import struct
+
+from . import (
+    error,
+    mdiff,
+    revlog,
+)
 
 _mdre = re.compile('\1\n')
 def parsemeta(text):
--- a/mercurial/filemerge.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/filemerge.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,11 +5,25 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from node import short
-from i18n import _
-import util, simplemerge, match, error, templater, templatekw
-import os, tempfile, re, filecmp
-import tagmerge
+from __future__ import absolute_import
+
+import filecmp
+import os
+import re
+import tempfile
+
+from .i18n import _
+from .node import short
+
+from . import (
+    error,
+    match,
+    simplemerge,
+    tagmerge,
+    templatekw,
+    templater,
+    util,
+)
 
 def _toolstr(ui, tool, part, default=""):
     return ui.config("merge-tools", tool + "." + part, default)
@@ -213,15 +227,12 @@
             util.copyfile(back, a) # restore from backup and try again
     return 1 # continue merging
 
-@internaltool('merge', True,
-              _("merging %s incomplete! "
-                "(edit conflicts, then use 'hg resolve --mark')\n"))
-def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
+def _merge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels, mode):
     """
     Uses the internal non-interactive simple merge algorithm for merging
     files. It will fail if there are any conflicts and leave markers in
     the partially merged file. Markers will have two sections, one for each side
-    of merge."""
+    of merge, unless mode equals 'union' which suppresses the markers."""
     tool, toolpath, binary, symlink = toolconf
     if symlink:
         repo.ui.warn(_('warning: internal :merge cannot merge symlinks '
@@ -233,10 +244,33 @@
 
         ui = repo.ui
 
-        r = simplemerge.simplemerge(ui, a, b, c, label=labels)
+        r = simplemerge.simplemerge(ui, a, b, c, label=labels, mode=mode)
         return True, r
     return False, 0
 
+@internaltool('union', True,
+              _("merging %s incomplete! "
+                "(edit conflicts, then use 'hg resolve --mark')\n"))
+def _iunion(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
+    """
+    Uses the internal non-interactive simple merge algorithm for merging
+    files. It will use both left and right sides for conflict regions.
+    No markers are inserted."""
+    return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
+                  files, labels, 'union')
+
+@internaltool('merge', True,
+              _("merging %s incomplete! "
+                "(edit conflicts, then use 'hg resolve --mark')\n"))
+def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
+    """
+    Uses the internal non-interactive simple merge algorithm for merging
+    files. It will fail if there are any conflicts and leave markers in
+    the partially merged file. Markers will have two sections, one for each side
+    of merge."""
+    return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
+                  files, labels, 'merge')
+
 @internaltool('merge3', True,
               _("merging %s incomplete! "
                 "(edit conflicts, then use 'hg resolve --mark')\n"))
@@ -252,6 +286,38 @@
         labels.append('base')
     return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
 
+def _imergeauto(repo, mynode, orig, fcd, fco, fca, toolconf, files,
+                labels=None, localorother=None):
+    """
+    Generic driver for _imergelocal and _imergeother
+    """
+    assert localorother is not None
+    tool, toolpath, binary, symlink = toolconf
+    if symlink:
+        repo.ui.warn(_('warning: :merge-%s cannot merge symlinks '
+                       'for %s\n') % (localorother, fcd.path()))
+        return False, 1
+    a, b, c, back = files
+    r = simplemerge.simplemerge(repo.ui, a, b, c, label=labels,
+                                localorother=localorother)
+    return True, r
+
+@internaltool('merge-local', True)
+def _imergelocal(*args, **kwargs):
+    """
+    Like :merge, but resolve all conflicts non-interactively in favor
+    of the local changes."""
+    success, status = _imergeauto(localorother='local', *args, **kwargs)
+    return success, status
+
+@internaltool('merge-other', True)
+def _imergeother(*args, **kwargs):
+    """
+    Like :merge, but resolve all conflicts non-interactively in favor
+    of the other changes."""
+    success, status = _imergeauto(localorother='other', *args, **kwargs)
+    return success, status
+
 @internaltool('tagmerge', True,
               _("automatic tag merging of %s failed! "
                 "(use 'hg resolve --tool :merge' or another merge "
--- a/mercurial/fileset.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/fileset.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,17 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import re
-import parser, error, util, merge
-from i18n import _
+
+from .i18n import _
+from . import (
+    error,
+    merge,
+    parser,
+    util,
+)
 
 elements = {
     # token-type: binding-strength, primary, prefix, infix, suffix
@@ -46,7 +54,7 @@
                 c = program[pos]
                 decode = lambda x: x
             else:
-                decode = lambda x: x.decode('string-escape')
+                decode = parser.unescapestr
             pos += 1
             s = pos
             while pos < l: # find closing quote
@@ -124,7 +132,7 @@
 
 def modified(mctx, x):
     """``modified()``
-    File that is modified according to status.
+    File that is modified according to :hg:`status`.
     """
     # i18n: "modified" is a keyword
     getargs(x, 0, 0, _("modified takes no arguments"))
@@ -133,7 +141,7 @@
 
 def added(mctx, x):
     """``added()``
-    File that is added according to status.
+    File that is added according to :hg:`status`.
     """
     # i18n: "added" is a keyword
     getargs(x, 0, 0, _("added takes no arguments"))
@@ -142,7 +150,7 @@
 
 def removed(mctx, x):
     """``removed()``
-    File that is removed according to status.
+    File that is removed according to :hg:`status`.
     """
     # i18n: "removed" is a keyword
     getargs(x, 0, 0, _("removed takes no arguments"))
@@ -151,7 +159,7 @@
 
 def deleted(mctx, x):
     """``deleted()``
-    File that is deleted according to status.
+    File that is deleted according to :hg:`status`.
     """
     # i18n: "deleted" is a keyword
     getargs(x, 0, 0, _("deleted takes no arguments"))
@@ -160,7 +168,7 @@
 
 def unknown(mctx, x):
     """``unknown()``
-    File that is unknown according to status. These files will only be
+    File that is unknown according to :hg:`status`. These files will only be
     considered if this predicate is used.
     """
     # i18n: "unknown" is a keyword
@@ -170,7 +178,7 @@
 
 def ignored(mctx, x):
     """``ignored()``
-    File that is ignored according to status. These files will only be
+    File that is ignored according to :hg:`status`. These files will only be
     considered if this predicate is used.
     """
     # i18n: "ignored" is a keyword
@@ -180,7 +188,7 @@
 
 def clean(mctx, x):
     """``clean()``
-    File that is clean according to status.
+    File that is clean according to :hg:`status`.
     """
     # i18n: "clean" is a keyword
     getargs(x, 0, 0, _("clean takes no arguments"))
@@ -235,7 +243,7 @@
 
 def resolved(mctx, x):
     """``resolved()``
-    File that is marked resolved according to the resolve state.
+    File that is marked resolved according to :hg:`resolve -l`.
     """
     # i18n: "resolved" is a keyword
     getargs(x, 0, 0, _("resolved takes no arguments"))
@@ -246,7 +254,7 @@
 
 def unresolved(mctx, x):
     """``unresolved()``
-    File that is marked unresolved according to the resolve state.
+    File that is marked unresolved according to :hg:`resolve -l`.
     """
     # i18n: "unresolved" is a keyword
     getargs(x, 0, 0, _("unresolved takes no arguments"))
@@ -410,7 +418,7 @@
         # i18n: "subrepo" is a keyword
         pat = getstring(x, _("subrepo requires a pattern or no arguments"))
 
-        import match as matchmod # avoid circular import issues
+        from . import match as matchmod # avoid circular import issues
         fast = not matchmod.patkind(pat)
         if fast:
             def m(s):
--- a/mercurial/formatter.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/formatter.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,13 +5,23 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import cPickle
-from node import hex, short
-from i18n import _
-import encoding, util
-import templater
 import os
 
+from .i18n import _
+from .node import (
+    hex,
+    short,
+)
+
+from . import (
+    encoding,
+    templater,
+    util,
+)
+
 class baseformatter(object):
     def __init__(self, ui, topic, opts):
         self._ui = ui
--- a/mercurial/graphmod.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/graphmod.py	Fri Sep 25 23:10:47 2015 -0500
@@ -17,11 +17,16 @@
 Data depends on type.
 """
 
-from mercurial.node import nullrev
-import util
+from __future__ import absolute_import
 
 import heapq
 
+from .node import nullrev
+from . import (
+    revset,
+    util,
+)
+
 CHANGESET = 'C'
 
 def groupbranchiter(revs, parentsfunc, firstbranch=()):
@@ -233,8 +238,6 @@
     if not revs:
         return
 
-    cl = repo.changelog
-    lowestrev = revs.min()
     gpcache = {}
 
     if repo.ui.configbool('experimental', 'graph-group-branches', False):
@@ -244,7 +247,8 @@
         if firstbranchrevset:
             firstbranch = repo.revs(firstbranchrevset)
         parentrevs = repo.changelog.parentrevs
-        revs = list(groupbranchiter(revs, parentrevs, firstbranch))
+        revs = groupbranchiter(revs, parentrevs, firstbranch)
+        revs = revset.baseset(revs)
 
     for rev in revs:
         ctx = repo[rev]
@@ -256,7 +260,11 @@
         for mpar in mpars:
             gp = gpcache.get(mpar)
             if gp is None:
-                gp = gpcache[mpar] = grandparent(cl, lowestrev, revs, mpar)
+                # precompute slow query as we know reachableroots() goes
+                # through all revs (issue4782)
+                if not isinstance(revs, revset.baseset):
+                    revs = revset.baseset(revs)
+                gp = gpcache[mpar] = revset.reachableroots(repo, revs, [mpar])
             if not gp:
                 parents.append(mpar)
             else:
@@ -354,24 +362,6 @@
         yield (cur, type, data, (col, color), edges)
         seen = next
 
-def grandparent(cl, lowestrev, roots, head):
-    """Return all ancestors of head in roots which revision is
-    greater or equal to lowestrev.
-    """
-    pending = set([head])
-    seen = set()
-    kept = set()
-    llowestrev = max(nullrev, lowestrev)
-    while pending:
-        r = pending.pop()
-        if r >= llowestrev and r not in seen:
-            if r in roots:
-                kept.add(r)
-            else:
-                pending.update([p for p in cl.parentrevs(r)])
-            seen.add(r)
-    return sorted(kept)
-
 def asciiedges(type, char, lines, seen, rev, parents):
     """adds edge info to changelog DAG walk suitable for ascii()"""
     if rev not in seen:
--- a/mercurial/hbisect.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hbisect.py	Fri Sep 25 23:10:47 2015 -0500
@@ -8,12 +8,20 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import collections
 import os
-import error
-from i18n import _
-from node import short, hex
-import util
+
+from .i18n import _
+from .node import (
+    hex,
+    short,
+)
+from . import (
+    error,
+    util,
+)
 
 def bisect(changelog, state):
     """find the next node (if any) for testing during a bisect search.
--- a/mercurial/help.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/help.py	Fri Sep 25 23:10:47 2015 -0500
@@ -179,7 +179,7 @@
 
 def makeitemsdoc(topic, doc, marker, items, dedent=False):
     """Extract docstring from the items key to function mapping, build a
-    .single documentation block and use it to overwrite the marker in doc
+    single documentation block and use it to overwrite the marker in doc.
     """
     entries = []
     for name in sorted(items):
@@ -475,11 +475,18 @@
     rst = []
     kw = opts.get('keyword')
     if kw:
-        matches = topicmatch(kw)
-        for t, title in (('topics', _('Topics')),
+        matches = topicmatch(name)
+        helpareas = []
+        if opts.get('extension'):
+            helpareas += [('extensions', _('Extensions'))]
+        if opts.get('command'):
+            helpareas += [('commands', _('Commands'))]
+        if not helpareas:
+            helpareas = [('topics', _('Topics')),
                          ('commands', _('Commands')),
                          ('extensions', _('Extensions')),
-                         ('extensioncommands', _('Extension Commands'))):
+                         ('extensioncommands', _('Extension Commands'))]
+        for t, title in helpareas:
             if matches[t]:
                 rst.append('%s:\n\n' % title)
                 rst.extend(minirst.maketable(sorted(matches[t]), 1))
@@ -489,13 +496,14 @@
             hint = _('try "hg help" for a list of topics')
             raise util.Abort(msg, hint=hint)
     elif name and name != 'shortlist':
+        queries = []
         if unknowncmd:
-            queries = (helpextcmd,)
-        elif opts.get('extension'):
-            queries = (helpext,)
-        elif opts.get('command'):
-            queries = (helpcmd,)
-        else:
+            queries += [helpextcmd]
+        if opts.get('extension'):
+            queries += [helpext]
+        if opts.get('command'):
+            queries += [helpcmd]
+        if not queries:
             queries = (helptopic, helpcmd, helpext, helpextcmd)
         for f in queries:
             try:
--- a/mercurial/help/config.txt	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/help/config.txt	Fri Sep 25 23:10:47 2015 -0500
@@ -1,6 +1,19 @@
 The Mercurial system uses a set of configuration files to control
 aspects of its behavior.
 
+Troubleshooting
+===============
+
+If you're having problems with your configuration,
+:hg:`config --debug` can help you understand what is introducing
+a setting into your environment.
+
+See :hg:`help config.syntax` and :hg:`help config.files`
+for information about how and where to override things.
+
+Format
+======
+
 The configuration files use a simple ini-file format. A configuration
 file consists of sections, led by a ``[section]`` header and followed
 by ``name = value`` entries::
@@ -10,7 +23,7 @@
   verbose = True
 
 The above entries will be referred to as ``ui.username`` and
-``ui.verbose``, respectively. See the Syntax section below.
+``ui.verbose``, respectively. See :hg:`help config.syntax`.
 
 Files
 =====
@@ -76,8 +89,8 @@
 will not get transferred during a "clone" operation. Options in
 this file override options in all other configuration files. On
 Plan 9 and Unix, most of this file will be ignored if it doesn't
-belong to a trusted user or to a trusted group. See the documentation
-for the ``[trusted]`` section below for more details.
+belong to a trusted user or to a trusted group. See
+:hg:`help config.trusted` for more details.
 
 Per-user configuration file(s) are for the user running Mercurial. On
 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
@@ -208,9 +221,10 @@
 ---------
 
 Defines command aliases.
+
 Aliases allow you to define your own commands in terms of other
 commands (or aliases), optionally including arguments. Positional
-arguments in the form of ``$1``, ``$2``, etc in the alias definition
+arguments in the form of ``$1``, ``$2``, etc. in the alias definition
 are expanded by Mercurial before execution. Positional arguments not
 already used by ``$N`` in the definition are put at the end of the
 command to be executed.
@@ -273,8 +287,8 @@
 ------------
 
 Settings used when displaying file annotations. All values are
-Booleans and default to False. See ``diff`` section for related
-options for the diff command.
+Booleans and default to False. See :hg:`help config.diff` for
+related options for the diff command.
 
 ``ignorews``
     Ignore white space when comparing lines.
@@ -291,7 +305,7 @@
 
 Authentication credentials for HTTP authentication. This section
 allows you to store usernames and passwords for use when logging
-*into* HTTP servers. See the ``[web]`` configuration section if
+*into* HTTP servers. See :hg:`help config.web` if
 you want to configure *who* can login to your HTTP server.
 
 Each line has the following format::
@@ -347,7 +361,7 @@
     authentication entry with. Only used if the prefix doesn't include
     a scheme. Supported schemes are http and https. They will match
     static-http and static-https respectively, as well.
-    Default: https.
+    (default: https)
 
 If no suitable authentication entry is found, the user is prompted
 for credentials as usual if required by the remote.
@@ -356,8 +370,9 @@
 ``committemplate``
 ------------------
 
-``changeset`` configuration in this section is used as the template to
-customize the text shown in the editor when committing.
+``changeset``
+    String: configuration in this section is used as the template to
+    customize the text shown in the editor when committing.
 
 In addition to pre-defined template keywords, commit log specific one
 below can be used for customization:
@@ -390,10 +405,10 @@
    detail), this customization should be configured carefully, to
    avoid showing broken characters.
 
-   For example, if multibyte character ending with backslash (0x5c) is
-   followed by ASCII character 'n' in the customized template,
-   sequence of backslash and 'n' is treated as line-feed unexpectedly
-   (and multibyte character is broken, too).
+   For example, if a multibyte character ending with backslash (0x5c) is
+   followed by the ASCII character 'n' in the customized template,
+   the sequence of backslash and 'n' is treated as line-feed unexpectedly
+   (and the multibyte character is broken, too).
 
 Customized template is used for commands below (``--edit`` may be
 required):
@@ -447,9 +462,10 @@
 only for :hg:`tag --remove`, but ``changeset.tag`` customizes the
 commit message for :hg:`tag` regardless of ``--remove`` option.
 
-At the external editor invocation for committing, corresponding
-dot-separated list of names without ``changeset.`` prefix
-(e.g. ``commit.normal.normal``) is in ``HGEDITFORM`` environment variable.
+When the external editor is invoked for a commit, the corresponding
+dot-separated list of names without the ``changeset.`` prefix
+(e.g. ``commit.normal.normal``) is in the ``HGEDITFORM`` environment
+variable.
 
 In this section, items other than ``changeset`` can be referred from
 others. For example, the configuration to list committed files up
@@ -514,7 +530,7 @@
 ``defaults``
 ------------
 
-(defaults are deprecated. Don't use them. Use aliases instead)
+(defaults are deprecated. Don't use them. Use aliases instead.)
 
 Use the ``[defaults]`` section to define command defaults, i.e. the
 default options/arguments to pass to the specified commands.
@@ -535,8 +551,8 @@
 --------
 
 Settings used when displaying diffs. Everything except for ``unified``
-is a Boolean and defaults to False. See ``annotate`` section for
-related options for the annotate command.
+is a Boolean and defaults to False. See :hg:`help config.annotate`
+for related options for the annotate command.
 
 ``git``
     Use git extended diff format.
@@ -599,8 +615,8 @@
     containing patches of outgoing messages will be encoded in the
     first character set to which conversion from local encoding
     (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
-    conversion fails, the text in question is sent as is. Defaults to
-    empty (explicit) list.
+    conversion fails, the text in question is sent as is.
+    (default: '')
 
     Order of outgoing email character sets:
 
@@ -711,8 +727,7 @@
 action. Overriding a site-wide hook can be done by changing its
 value or setting it to an empty string.  Hooks can be prioritized
 by adding a prefix of ``priority`` to the hook name on a new line
-and setting the priority.  The default priority is 0 if
-not specified.
+and setting the priority. The default priority is 0.
 
 Example ``.hg/hgrc``::
 
@@ -748,7 +763,7 @@
 ``outgoing``
   Run after sending changes from local repository to another. ID of
   first changeset sent is in ``$HG_NODE``. Source of operation is in
-  ``$HG_SOURCE``; see "preoutgoing" hook for description.
+  ``$HG_SOURCE``; Also see :hg:`help config.preoutgoing` hook.
 
 ``post-<command>``
   Run after successful invocations of the associated command. The
@@ -830,12 +845,12 @@
 ``txnclose``
   Run after any repository transaction has been committed. At this
   point, the transaction can no longer be rolled back. The hook will run
-  after the lock is released. See ``pretxnclose`` docs for details about
-  available variables.
+  after the lock is released. See :hg:`help config.pretxnclose` docs for
+  details about available variables.
 
 ``txnabort``
-  Run when a transaction is aborted. See ``pretxnclose`` docs for details about
-  available variables.
+  Run when a transaction is aborted. See :hg:`help config.pretxnclose`
+  docs for details about available variables.
 
 ``pretxnchangegroup``
   Run after a changegroup has been added via push, pull or unbundle,
@@ -954,7 +969,7 @@
 
 ``always``
     Optional. Always use the proxy, even for localhost and any entries
-    in ``http_proxy.no``. True or False. Default: False.
+    in ``http_proxy.no``. (default: False)
 
 ``merge-patterns``
 ------------------
@@ -1000,12 +1015,12 @@
 
 ``priority``
   The priority in which to evaluate this tool.
-  Default: 0.
+  (default: 0)
 
 ``executable``
   Either just the name of the executable or its pathname.  On Windows,
   the path can use environment variables with ${ProgramFiles} syntax.
-  Default: the tool name.
+  (default: the tool name)
 
 ``args``
   The arguments to pass to the tool executable. You can refer to the
@@ -1017,7 +1032,7 @@
   to or the commit you are merging with. During a rebase ``$local``
   represents the destination of the rebase, and ``$other`` represents the
   commit being rebased.
-  Default: ``$local $base $other``
+  (default: ``$local $base $other``)
 
 ``premerge``
   Attempt to run internal non-interactive 3-way merge tool before
@@ -1026,15 +1041,14 @@
   premerge fails. The ``keep-merge3`` will do the same but include information
   about the base of the merge in the marker (see internal :merge3 in
   :hg:`help merge-tools`).
-  Default: True
+  (default: True)
 
 ``binary``
-  This tool can merge binary files. Defaults to False, unless tool
-  was selected by file pattern match.
+  This tool can merge binary files. (default: False, unless tool
+  was selected by file pattern match)
 
 ``symlink``
-  This tool can merge symlinks. Defaults to False, even if tool was
-  selected by file pattern match.
+  This tool can merge symlinks. (default: False)
 
 ``check``
   A list of merge success-checking options:
@@ -1048,32 +1062,32 @@
 
 ``fixeol``
   Attempt to fix up EOL changes caused by the merge tool.
-  Default: False
+  (default: False)
 
 ``gui``
-  This tool requires a graphical interface to run. Default: False
+  This tool requires a graphical interface to run. (default: False)
 
 ``regkey``
   Windows registry key which describes install location of this
   tool. Mercurial will search for this key first under
   ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
-  Default: None
+  (default: None)
 
 ``regkeyalt``
   An alternate Windows registry key to try if the first key is not
   found.  The alternate key uses the same ``regname`` and ``regappend``
   semantics of the primary key.  The most common use for this key
   is to search for 32bit applications on 64bit operating systems.
-  Default: None
+  (default: None)
 
 ``regname``
-  Name of value to read from specified registry key. Defaults to the
-  unnamed (default) value.
+  Name of value to read from specified registry key.
+  (default: the unnamed (default) value)
 
 ``regappend``
   String to append to the value read from the registry, typically
   the executable name of the tool.
-  Default: None
+  (default: None)
 
 
 ``patch``
@@ -1091,13 +1105,13 @@
     endings in patched files are normalized to their original setting
     on a per-file basis. If target file does not exist or has no end
     of line, patch line endings are preserved.
-    Default: strict.
+    (default: strict)
 
 ``fuzz``
     The number of lines of 'fuzz' to allow when applying patches. This
     controls how much context the patcher is allowed to ignore when
     trying to apply a patch.
-    Default: 2
+    (default: 2)
 
 ``paths``
 ---------
@@ -1109,8 +1123,7 @@
 
 ``default``
     Directory or URL to use when pulling if no source is specified.
-    Default is set to repository from which the current repository was
-    cloned.
+    (default: repository from which the current repository was cloned)
 
 ``default-push``
     Optional. Directory or URL to use when pushing if no destination
@@ -1137,11 +1150,11 @@
     Controls draft phase behavior when working as a server. When true,
     pushed changesets are set to public in both client and server and
     pulled or cloned changesets are set to public in the client.
-    Default: True
+    (default: True)
 
 ``new-commit``
     Phase of newly-created commits.
-    Default: draft
+    (default: draft)
 
 ``checksubrepos``
     Check the phase of the current revision of each subrepository. Allowed
@@ -1152,7 +1165,7 @@
     "secret" phase while the parent repo is in "draft" phase), the commit is
     either aborted (if checksubrepos is set to "abort") or the higher phase is
     used for the parent repository commit (if set to "follow").
-    Default: "follow"
+    (default: follow)
 
 
 ``profiling``
@@ -1169,7 +1182,7 @@
 
 ``type``
     The type of profiler to use.
-    Default: ls.
+    (default: ls)
 
     ``ls``
       Use Python's built-in instrumenting profiler. This profiler
@@ -1183,7 +1196,7 @@
 
 ``format``
     Profiling format.  Specific to the ``ls`` instrumenting profiler.
-    Default: text.
+    (default: text)
 
     ``text``
       Generate a profiling report. When saving to a file, it should be
@@ -1196,28 +1209,28 @@
 
 ``frequency``
     Sampling frequency.  Specific to the ``stat`` sampling profiler.
-    Default: 1000.
+    (default: 1000)
 
 ``output``
     File path where profiling data or report should be saved. If the
-    file exists, it is replaced. Default: None, data is printed on
-    stderr
+    file exists, it is replaced. (default: None, data is printed on
+    stderr)
 
 ``sort``
     Sort field.  Specific to the ``ls`` instrumenting profiler.
     One of ``callcount``, ``reccallcount``, ``totaltime`` and
     ``inlinetime``.
-    Default: inlinetime.
+    (default: inlinetime)
 
 ``limit``
     Number of lines to show. Specific to the ``ls`` instrumenting profiler.
-    Default: 30.
+    (default: 30)
 
 ``nested``
     Show at most this number of lines of drill-down info after each main entry.
     This can help explain the difference between Total and Inline.
     Specific to the ``ls`` instrumenting profiler.
-    Default: 5.
+    (default: 5)
 
 ``progress``
 ------------
@@ -1249,16 +1262,16 @@
 
 ``width``
     If set, the maximum width of the progress information (that is, min(width,
-    term width) will be used)
+    term width) will be used).
 
 ``clear-complete``
-    clear the progress bar after it's done (default to True)
+    Clear the progress bar after it's done. (default: True)
 
 ``disable``
-    If true, don't show a progress bar
+    If true, don't show a progress bar.
 
 ``assume-tty``
-    If true, ALWAYS show a progress bar, unless disable is given
+    If true, ALWAYS show a progress bar, unless disable is given.
 
 ``revsetalias``
 ---------------
@@ -1280,20 +1293,20 @@
     about 6 Mbps), uncompressed streaming is slower, because of the
     extra data transfer overhead. This mode will also temporarily hold
     the write lock while determining what data to transfer.
-    Default is True.
+    (default: True)
 
 ``preferuncompressed``
     When set, clients will try to use the uncompressed streaming
-    protocol. Default is False.
+    protocol. (default: False)
 
 ``validate``
     Whether to validate the completeness of pushed changesets by
     checking that all new file revisions specified in manifests are
-    present. Default is False.
+    present. (default: False)
 
 ``maxhttpheaderlen``
     Instruct HTTP clients not to send request headers longer than this
-    many bytes. Default is 1024.
+    many bytes. (default: 1024)
 
 ``smtp``
 --------
@@ -1304,12 +1317,12 @@
     Host name of mail server, e.g. "mail.example.com".
 
 ``port``
-    Optional. Port to connect to on mail server. Default: 465 (if
-    ``tls`` is smtps) or 25 (otherwise).
+    Optional. Port to connect to on mail server. (default: 465 if
+    ``tls`` is smtps; 25 otherwise)
 
 ``tls``
     Optional. Method to enable TLS when connecting to mail server: starttls,
-    smtps or none. Default: none.
+    smtps or none. (default: none)
 
 ``verifycert``
     Optional. Verification for the certificate of mail server, when
@@ -1319,19 +1332,19 @@
     ``[web] cacerts`` also). For "strict", sending email is also
     aborted, if there is no configuration for mail server in
     ``[hostfingerprints]`` and ``[web] cacerts``.  --insecure for
-    :hg:`email` overwrites this as "loose". Default: "strict".
+    :hg:`email` overwrites this as "loose". (default: strict)
 
 ``username``
     Optional. User name for authenticating with the SMTP server.
-    Default: none.
+    (default: None)
 
 ``password``
     Optional. Password for authenticating with the SMTP server. If not
     specified, interactive sessions will prompt the user for a
-    password; non-interactive sessions will fail. Default: none.
+    password; non-interactive sessions will fail. (default: None)
 
 ``local_hostname``
-    Optional. It's the hostname that the sender can use to identify
+    Optional. The hostname that the sender can use to identify
     itself to the MTA.
 
 
@@ -1390,30 +1403,30 @@
     Whether to include the .hg_archival.txt file containing meta data
     (hashes for the repository base and for tip) in archives created
     by the :hg:`archive` command or downloaded via hgweb.
-    Default is True.
+    (default: True)
 
 ``askusername``
     Whether to prompt for a username when committing. If True, and
     neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
     be prompted to enter a username. If no username is entered, the
     default ``USER@HOST`` is used instead.
-    Default is False.
+    (default: False)
 
 ``commitsubrepos``
     Whether to commit modified subrepositories when committing the
     parent repository. If False and one subrepository has uncommitted
     changes, abort the commit.
-    Default is False.
+    (default: False)
 
 ``debug``
-    Print debugging information. True or False. Default is False.
+    Print debugging information. (default: False)
 
 ``editor``
-    The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
+    The editor to use during a commit. (default: ``$EDITOR`` or ``vi``)
 
 ``fallbackencoding``
     Encoding to try if it's not possible to decode the changelog using
-    UTF-8. Default is ISO-8859-1.
+    UTF-8. (default: ISO-8859-1)
 
 ``ignore``
     A file to read per-user ignore patterns from. This file should be
@@ -1424,7 +1437,7 @@
     of the ignore file format, see the ``hgignore(5)`` man page.
 
 ``interactive``
-    Allow to prompt the user. True or False. Default is True.
+    Allow to prompt the user. (default: True)
 
 ``logtemplate``
     Template string for commands that print changesets.
@@ -1439,14 +1452,16 @@
     style uses the ``mergemarkertemplate`` setting to style the labels.
     The ``basic`` style just uses 'local' and 'other' as the marker label.
     One of ``basic`` or ``detailed``.
-    Default is ``basic``.
+    (default: ``basic``)
 
 ``mergemarkertemplate``
     The template used to print the commit description next to each conflict
     marker during merge conflicts. See :hg:`help templates` for the template
     format.
+
     Defaults to showing the hash, tags, branches, bookmarks, author, and
     the first line of the commit description.
+
     If you use non-ASCII characters in names for tags, branches, bookmarks,
     authors, and/or commit descriptions, you must pay attention to encodings of
     managed files. At template expansion, non-ASCII characters use the encoding
@@ -1470,7 +1485,7 @@
 
 ``portablefilenames``
     Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
-    Default is ``warn``.
+    (default: ``warn``)
     If set to ``warn`` (or ``true``), a warning message is printed on POSIX
     platforms, if a file with a non-portable filename is added (e.g. a file
     with a name that can't be created on Windows because it contains reserved
@@ -1481,56 +1496,63 @@
     On Windows, this configuration option is ignored and the command aborted.
 
 ``quiet``
-    Reduce the amount of output printed. True or False. Default is False.
+    Reduce the amount of output printed. (default: False)
 
 ``remotecmd``
-    remote command to use for clone/push/pull operations. Default is ``hg``.
+    Remote command to use for clone/push/pull operations. (default: ``hg``)
 
 ``report_untrusted``
     Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
-    trusted user or group. True or False. Default is True.
+    trusted user or group. (default: True)
 
 ``slash``
     Display paths using a slash (``/``) as the path separator. This
     only makes a difference on systems where the default path
     separator is not the slash character (e.g. Windows uses the
     backslash character (``\``)).
-    Default is False.
+    (default: False)
 
 ``statuscopies``
     Display copies in the status command.
 
 ``ssh``
-    command to use for SSH connections. Default is ``ssh``.
+    Command to use for SSH connections. (default: ``ssh``)
 
 ``strict``
     Require exact command names, instead of allowing unambiguous
-    abbreviations. True or False. Default is False.
+    abbreviations. (default: False)
 
 ``style``
     Name of style to use for command output.
 
+``supportcontact``
+    A URL where users should report a Mercurial traceback. Use this if you are a
+    large organisation with its own Mercurial deployment process and crash
+    reports should be addressed to your internal support.
+
 ``timeout``
     The timeout used when a lock is held (in seconds), a negative value
-    means no timeout. Default is 600.
+    means no timeout. (default: 600)
 
 ``traceback``
     Mercurial always prints a traceback when an unknown exception
     occurs. Setting this to True will make Mercurial print a traceback
     on all exceptions, even those recognized by Mercurial (such as
-    IOError or MemoryError). Default is False.
+    IOError or MemoryError). (default: False)
 
 ``username``
     The committer of a changeset created when running "commit".
     Typically a person's name and email address, e.g. ``Fred Widget
-    <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
-    the username in hgrc is empty, it has to be specified manually or
-    in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
-    ``username =``  in the system hgrc). Environment variables in the
+    <fred@example.com>``. Environment variables in the
     username are expanded.
 
+    (default: ``$EMAIL`` or ``username@hostname``. If the username in
+    hgrc is empty, e.g. if the system admin set ``username =``  in the
+    system hgrc, it has to be specified manually or in a different
+    hgrc file)
+
 ``verbose``
-    Increase the amount of output printed. True or False. Default is False.
+    Increase the amount of output printed. (default: False)
 
 
 ``web``
@@ -1560,35 +1582,35 @@
 The full set of options is:
 
 ``accesslog``
-    Where to output the access log. Default is stdout.
+    Where to output the access log. (default: stdout)
 
 ``address``
-    Interface address to bind to. Default is all.
+    Interface address to bind to. (default: all)
 
 ``allow_archive``
     List of archive format (bz2, gz, zip) allowed for downloading.
-    Default is empty.
+    (default: empty)
 
 ``allowbz2``
     (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
     revisions.
-    Default is False.
+    (default: False)
 
 ``allowgz``
     (DEPRECATED) Whether to allow .tar.gz downloading of repository
     revisions.
-    Default is False.
+    (default: False)
 
 ``allowpull``
-    Whether to allow pulling from the repository. Default is True.
+    Whether to allow pulling from the repository. (default: True)
 
 ``allow_push``
     Whether to allow pushing to the repository. If empty or not set,
-    push is not allowed. If the special value ``*``, any remote user can
-    push, including unauthenticated users. Otherwise, the remote user
-    must have been authenticated, and the authenticated user name must
-    be present in this list. The contents of the allow_push list are
-    examined after the deny_push list.
+    pushing is not allowed. If the special value ``*``, any remote
+    user can push, including unauthenticated users. Otherwise, the
+    remote user must have been authenticated, and the authenticated
+    user name must be present in this list. The contents of the
+    allow_push list are examined after the deny_push list.
 
 ``allow_read``
     If the user has not already been denied repository access due to
@@ -1603,11 +1625,12 @@
 
 ``allowzip``
     (DEPRECATED) Whether to allow .zip downloading of repository
-    revisions. Default is False. This feature creates temporary files.
+    revisions. This feature creates temporary files.
+    (default: False)
 
 ``archivesubrepos``
-    Whether to recurse into subrepositories when archiving. Default is
-    False.
+    Whether to recurse into subrepositories when archiving.
+    (default: False)
 
 ``baseurl``
     Base URL to use when publishing URLs in other locations, so
@@ -1642,7 +1665,7 @@
         -----END CERTIFICATE-----
 
 ``cache``
-    Whether to support caching in hgweb. Defaults to True.
+    Whether to support caching in hgweb. (default: True)
 
 ``certificate``
     Certificate to use when running :hg:`serve`.
@@ -1654,17 +1677,18 @@
     the current path are grouped behind navigable directory entries that
     lead to the locations of these repositories. In effect, this setting
     collapses each collection of repositories found within a subdirectory
-    into a single entry for that subdirectory. Default is False.
+    into a single entry for that subdirectory. (default: False)
 
 ``comparisoncontext``
     Number of lines of context to show in side-by-side file comparison. If
-    negative or the value ``full``, whole files are shown. Default is 5.
+    negative or the value ``full``, whole files are shown. (default: 5)
+
     This setting can be overridden by a ``context`` request parameter to the
     ``comparison`` command, taking the same values.
 
 ``contact``
     Name or email address of the person in charge of the repository.
-    Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
+    (default: ui.username or ``$EMAIL`` or "unknown" if unset or empty)
 
 ``deny_push``
     Whether to deny pushing to the repository. If empty or not set,
@@ -1695,28 +1719,28 @@
 
 ``description``
     Textual description of the repository's purpose or contents.
-    Default is "unknown".
+    (default: "unknown")
 
 ``encoding``
-    Character encoding name. Default is the current locale charset.
-    Example: "UTF-8"
+    Character encoding name. (default: the current locale charset)
+    Example: "UTF-8".
 
 ``errorlog``
-    Where to output the error log. Default is stderr.
+    Where to output the error log. (default: stderr)
 
 ``guessmime``
     Control MIME types for raw download of file content.
     Set to True to let hgweb guess the content type from the file
     extension. This will serve HTML files as ``text/html`` and might
     allow cross-site scripting attacks when serving untrusted
-    repositories. Default is False.
+    repositories. (default: False)
 
 ``hidden``
     Whether to hide the repository in the hgwebdir index.
-    Default is False.
+    (default: False)
 
 ``ipv6``
-    Whether to use IPv6. Default is False.
+    Whether to use IPv6. (default: False)
 
 ``logoimg``
     File name of the logo image that some templates display on each page.
@@ -1729,28 +1753,37 @@
     will be used.
 
 ``maxchanges``
-    Maximum number of changes to list on the changelog. Default is 10.
+    Maximum number of changes to list on the changelog. (default: 10)
 
 ``maxfiles``
-    Maximum number of files to list per changeset. Default is 10.
+    Maximum number of files to list per changeset. (default: 10)
 
 ``maxshortchanges``
     Maximum number of changes to list on the shortlog, graph or filelog
-    pages. Default is 60.
+    pages. (default: 60)
 
 ``name``
-    Repository name to use in the web interface. Default is current
-    working directory.
+    Repository name to use in the web interface.
+    (default: current working directory)
 
 ``port``
-    Port to listen on. Default is 8000.
+    Port to listen on. (default: 8000)
 
 ``prefix``
-    Prefix path to serve from. Default is '' (server root).
+    Prefix path to serve from. (default: '' (server root))
 
 ``push_ssl``
     Whether to require that inbound pushes be transported over SSL to
-    prevent password sniffing. Default is True.
+    prevent password sniffing. (default: True)
+
+``refreshinterval``
+    How frequently directory listings re-scan the filesystem for new
+    repositories, in seconds. This is relevant when wildcards are used
+    to define paths. Depending on how much filesystem traversal is
+    required, refreshing may negatively impact performance.
+
+    Values less than or equal to 0 always refresh.
+    (default: 20)
 
 ``staticurl``
     Base URL to use for static files. If unset, static files (e.g. the
@@ -1760,12 +1793,12 @@
 
 ``stripes``
     How many lines a "zebra stripe" should span in multi-line output.
-    Default is 1; set to 0 to disable.
+    Set to 0 to disable. (default: 1)
 
 ``style``
     Which template map style to use. The available options are the names of
-    subdirectories in the HTML templates path. Default is ``paper``.
-    Example: ``monoblue``
+    subdirectories in the HTML templates path. (default: ``paper``)
+    Example: ``monoblue``.
 
 ``templates``
     Where to find the HTML templates. The default path to the HTML templates
@@ -1812,6 +1845,6 @@
 helps performance.
 
 ``numcpus``
-    Number of CPUs to use for parallel operations. Default is 4 or the
-    number of CPUs on the system, whichever is larger. A zero or
+    Number of CPUs to use for parallel operations. A zero or
     negative value is treated as ``use the default``.
+    (default: 4 or the number of CPUs on the system, whichever is larger)
--- a/mercurial/help/glossary.txt	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/help/glossary.txt	Fri Sep 25 23:10:47 2015 -0500
@@ -32,12 +32,12 @@
     explicitly with a named branch, but it can also be done locally,
     using bookmarks or clones and anonymous branches.
 
-    Example: "The experimental branch".
+    Example: "The experimental branch."
 
     (Verb) The action of creating a child changeset which results in
     its parent having more than one child.
 
-    Example: "I'm going to branch at X".
+    Example: "I'm going to branch at X."
 
 Branch, anonymous
     Every time a new child changeset is created from a parent that is not
@@ -135,7 +135,7 @@
     See 'Changeset, child'.
 
 Close changeset
-    See 'Head, closed branch'
+    See 'Head, closed branch'.
 
 Closed branch
     See 'Branch, closed'.
@@ -144,11 +144,11 @@
     (Noun) An entire or partial copy of a repository. The partial
     clone must be in the form of a revision and its ancestors.
 
-    Example: "Is your clone up to date?".
+    Example: "Is your clone up to date?"
 
     (Verb) The process of creating a clone, using :hg:`clone`.
 
-    Example: "I'm going to clone the repository".
+    Example: "I'm going to clone the repository."
 
 Closed branch head
     See 'Head, closed branch'.
@@ -398,13 +398,13 @@
 Update
     (Noun) Another synonym of changeset.
 
-    Example: "I've pushed an update".
+    Example: "I've pushed an update."
 
     (Verb) This term is usually used to describe updating the state of
     the working directory to that of a specific changeset. See
     :hg:`help update`.
 
-    Example: "You should update".
+    Example: "You should update."
 
 Working directory
     See 'Directory, working'.
--- a/mercurial/help/scripting.txt	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/help/scripting.txt	Fri Sep 25 23:10:47 2015 -0500
@@ -50,15 +50,15 @@
     invoking ``hg`` processes.
 
 HGENCODING
-   If not set, the locale used by Mercurial will be detected from the
-   environment. If the determined locale does not support display of
-   certain characters, Mercurial may render these character sequences
-   incorrectly (often by using "?" as a placeholder for invalid
-   characters in the current locale).
+    If not set, the locale used by Mercurial will be detected from the
+    environment. If the determined locale does not support display of
+    certain characters, Mercurial may render these character sequences
+    incorrectly (often by using "?" as a placeholder for invalid
+    characters in the current locale).
 
-   Explicitly setting this environment variable is a good practice to
-   guarantee consistent results. "utf-8" is a good choice on UNIX-like
-   environments.
+    Explicitly setting this environment variable is a good practice to
+    guarantee consistent results. "utf-8" is a good choice on UNIX-like
+    environments.
 
 HGRCPATH
     If not set, Mercurial will inherit config options from config files
--- a/mercurial/help/templates.txt	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/help/templates.txt	Fri Sep 25 23:10:47 2015 -0500
@@ -69,6 +69,10 @@
 
    $ hg log -r 0 --template "{date(date, '%Y')}\n"
 
+- Display date in UTC::
+
+   $ hg log -r 0 --template "{localdate(date, 'UTC')|date}\n"
+
 - Output the description set to a fill-width of 30::
 
    $ hg log -r 0 --template "{fill(desc, 30)}"
@@ -102,6 +106,10 @@
 
    $ hg log --template "{ifcontains(rev, revset('.'), '@')}\n"
 
+- Show details of parent revisions::
+
+   $ hg log --template "{revset('parents(%d)', rev) % '{desc|firstline}\n'}"
+
 - Show only commit descriptions that start with "template"::
 
    $ hg log --template "{startswith('template', firstline(desc))}\n"
--- a/mercurial/hg.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hg.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,17 +6,41 @@
 # 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 _
-from lock import release
-from node import nullid
+from __future__ import absolute_import
+
+import errno
+import os
+import shutil
+
+from .i18n import _
+from .node import nullid
 
-import localrepo, bundlerepo, unionrepo, httppeer, sshpeer, statichttprepo
-import bookmarks, lock, util, extensions, error, node, scmutil, phases, url
-import cmdutil, discovery, repoview, exchange
-import ui as uimod
-import merge as mergemod
-import verify as verifymod
-import errno, os, shutil
+from . import (
+    bookmarks,
+    bundlerepo,
+    cmdutil,
+    discovery,
+    error,
+    exchange,
+    extensions,
+    httppeer,
+    localrepo,
+    lock,
+    merge as mergemod,
+    node,
+    phases,
+    repoview,
+    scmutil,
+    sshpeer,
+    statichttprepo,
+    ui as uimod,
+    unionrepo,
+    url,
+    util,
+    verify as verifymod,
+)
+
+release = lock.release
 
 def _local(path):
     path = util.expandpath(util.urllocalpath(path))
@@ -558,7 +582,11 @@
                     try:
                         uprev = destrepo.lookup(checkout)
                     except error.RepoLookupError:
-                        pass
+                        if update is not True:
+                            try:
+                                uprev = destrepo.lookup(update)
+                            except error.RepoLookupError:
+                                pass
                 if uprev is None:
                     try:
                         uprev = destrepo._bookmarks['@']
@@ -568,7 +596,7 @@
                             status = _("updating to bookmark @\n")
                         else:
                             status = (_("updating to bookmark @ on branch %s\n")
-                                       % bn)
+                                      % bn)
                     except KeyError:
                         try:
                             uprev = destrepo.branchtip('default')
@@ -796,3 +824,77 @@
         dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
 
     return dst
+
+# Files of interest
+# Used to check if the repository has changed looking at mtime and size of
+# theses files.
+foi = [('spath', '00changelog.i'),
+       ('spath', 'phaseroots'), # ! phase can change content at the same size
+       ('spath', 'obsstore'),
+       ('path', 'bookmarks'), # ! bookmark can change content at the same size
+      ]
+
+class cachedlocalrepo(object):
+    """Holds a localrepository that can be cached and reused."""
+
+    def __init__(self, repo):
+        """Create a new cached repo from an existing repo.
+
+        We assume the passed in repo was recently created. If the
+        repo has changed between when it was created and when it was
+        turned into a cache, it may not refresh properly.
+        """
+        assert isinstance(repo, localrepo.localrepository)
+        self._repo = repo
+        self._state, self.mtime = self._repostate()
+
+    def fetch(self):
+        """Refresh (if necessary) and return a repository.
+
+        If the cached instance is out of date, it will be recreated
+        automatically and returned.
+
+        Returns a tuple of the repo and a boolean indicating whether a new
+        repo instance was created.
+        """
+        # We compare the mtimes and sizes of some well-known files to
+        # determine if the repo changed. This is not precise, as mtimes
+        # are susceptible to clock skew and imprecise filesystems and
+        # file content can change while maintaining the same size.
+
+        state, mtime = self._repostate()
+        if state == self._state:
+            return self._repo, False
+
+        self._repo = repository(self._repo.baseui, self._repo.url())
+        self._state = state
+        self.mtime = mtime
+
+        return self._repo, True
+
+    def _repostate(self):
+        state = []
+        maxmtime = -1
+        for attr, fname in foi:
+            prefix = getattr(self._repo, attr)
+            p = os.path.join(prefix, fname)
+            try:
+                st = os.stat(p)
+            except OSError:
+                st = os.stat(prefix)
+            state.append((st.st_mtime, st.st_size))
+            maxmtime = max(maxmtime, st.st_mtime)
+
+        return tuple(state), maxmtime
+
+    def copy(self):
+        """Obtain a copy of this class instance.
+
+        A new localrepository instance is obtained. The new instance should be
+        completely independent of the original.
+        """
+        repo = repository(self._repo.baseui, self._repo.origroot)
+        c = cachedlocalrepo(repo)
+        c._state = self._state
+        c.mtime = self.mtime
+        return c
--- a/mercurial/hgweb/common.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hgweb/common.py	Fri Sep 25 23:10:47 2015 -0500
@@ -80,12 +80,9 @@
     def __init__(self, code, message=None, headers=[]):
         if message is None:
             message = _statusmessage(code)
-        Exception.__init__(self)
+        Exception.__init__(self, message)
         self.code = code
-        self.message = message
         self.headers = headers
-    def __str__(self):
-        return self.message
 
 class continuereader(object):
     def __init__(self, f, write):
--- a/mercurial/hgweb/hgweb_mod.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hgweb/hgweb_mod.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,11 +6,11 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import os, re
+import contextlib
+import os
 from mercurial import ui, hg, hook, error, encoding, templater, util, repoview
 from mercurial.templatefilters import websub
-from mercurial.i18n import _
-from common import get_stat, ErrorResponse, permhooks, caching
+from common import ErrorResponse, permhooks, caching
 from common import HTTP_OK, HTTP_NOT_MODIFIED, HTTP_BAD_REQUEST
 from common import HTTP_NOT_FOUND, HTTP_SERVER_ERROR
 from request import wsgirequest
@@ -26,15 +26,6 @@
     'pushkey': 'push',
 }
 
-## Files of interest
-# Used to check if the repository has changed looking at mtime and size of
-# theses files. This should probably be relocated a bit higher in core.
-foi = [('spath', '00changelog.i'),
-       ('spath', 'phaseroots'), # ! phase can change content at the same size
-       ('spath', 'obsstore'),
-       ('path', 'bookmarks'), # ! bookmark can change content at the same size
-      ]
-
 def makebreadcrumb(url, prefix=''):
     '''Return a 'URL breadcrumb' list
 
@@ -60,8 +51,145 @@
         urlel = os.path.dirname(urlel)
     return reversed(breadcrumb)
 
+class requestcontext(object):
+    """Holds state/context for an individual request.
+
+    Servers can be multi-threaded. Holding state on the WSGI application
+    is prone to race conditions. Instances of this class exist to hold
+    mutable and race-free state for requests.
+    """
+    def __init__(self, app, repo):
+        self.repo = repo
+        self.reponame = app.reponame
+
+        self.archives = ('zip', 'gz', 'bz2')
+
+        self.maxchanges = self.configint('web', 'maxchanges', 10)
+        self.stripecount = self.configint('web', 'stripes', 1)
+        self.maxshortchanges = self.configint('web', 'maxshortchanges', 60)
+        self.maxfiles = self.configint('web', 'maxfiles', 10)
+        self.allowpull = self.configbool('web', 'allowpull', True)
+
+        # we use untrusted=False to prevent a repo owner from using
+        # web.templates in .hg/hgrc to get access to any file readable
+        # by the user running the CGI script
+        self.templatepath = self.config('web', 'templates', untrusted=False)
+
+        # This object is more expensive to build than simple config values.
+        # It is shared across requests. The app will replace the object
+        # if it is updated. Since this is a reference and nothing should
+        # modify the underlying object, it should be constant for the lifetime
+        # of the request.
+        self.websubtable = app.websubtable
+
+    # Trust the settings from the .hg/hgrc files by default.
+    def config(self, section, name, default=None, untrusted=True):
+        return self.repo.ui.config(section, name, default,
+                                   untrusted=untrusted)
+
+    def configbool(self, section, name, default=False, untrusted=True):
+        return self.repo.ui.configbool(section, name, default,
+                                       untrusted=untrusted)
+
+    def configint(self, section, name, default=None, untrusted=True):
+        return self.repo.ui.configint(section, name, default,
+                                      untrusted=untrusted)
+
+    def configlist(self, section, name, default=None, untrusted=True):
+        return self.repo.ui.configlist(section, name, default,
+                                       untrusted=untrusted)
+
+    archivespecs = {
+        'bz2': ('application/x-bzip2', 'tbz2', '.tar.bz2', None),
+        'gz': ('application/x-gzip', 'tgz', '.tar.gz', None),
+        'zip': ('application/zip', 'zip', '.zip', None),
+    }
+
+    def archivelist(self, nodeid):
+        allowed = self.configlist('web', 'allow_archive')
+        for typ, spec in self.archivespecs.iteritems():
+            if typ in allowed or self.configbool('web', 'allow%s' % typ):
+                yield {'type': typ, 'extension': spec[2], 'node': nodeid}
+
+    def templater(self, req):
+        # determine scheme, port and server name
+        # this is needed to create absolute urls
+
+        proto = req.env.get('wsgi.url_scheme')
+        if proto == 'https':
+            proto = 'https'
+            default_port = '443'
+        else:
+            proto = 'http'
+            default_port = '80'
+
+        port = req.env['SERVER_PORT']
+        port = port != default_port and (':' + port) or ''
+        urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port)
+        logourl = self.config('web', 'logourl', 'http://mercurial.selenic.com/')
+        logoimg = self.config('web', 'logoimg', 'hglogo.png')
+        staticurl = self.config('web', 'staticurl') or req.url + 'static/'
+        if not staticurl.endswith('/'):
+            staticurl += '/'
+
+        # some functions for the templater
+
+        def motd(**map):
+            yield self.config('web', 'motd', '')
+
+        # figure out which style to use
+
+        vars = {}
+        styles = (
+            req.form.get('style', [None])[0],
+            self.config('web', 'style'),
+            'paper',
+        )
+        style, mapfile = templater.stylemap(styles, self.templatepath)
+        if style == styles[0]:
+            vars['style'] = style
+
+        start = req.url[-1] == '?' and '&' or '?'
+        sessionvars = webutil.sessionvars(vars, start)
+
+        if not self.reponame:
+            self.reponame = (self.config('web', 'name')
+                             or req.env.get('REPO_NAME')
+                             or req.url.strip('/') or self.repo.root)
+
+        def websubfilter(text):
+            return websub(text, self.websubtable)
+
+        # create the templater
+
+        tmpl = templater.templater(mapfile,
+                                   filters={'websub': websubfilter},
+                                   defaults={'url': req.url,
+                                             'logourl': logourl,
+                                             'logoimg': logoimg,
+                                             'staticurl': staticurl,
+                                             'urlbase': urlbase,
+                                             'repo': self.reponame,
+                                             'encoding': encoding.encoding,
+                                             'motd': motd,
+                                             'sessionvars': sessionvars,
+                                             'pathdef': makebreadcrumb(req.url),
+                                             'style': style,
+                                            })
+        return tmpl
+
 
 class hgweb(object):
+    """HTTP server for individual repositories.
+
+    Instances of this class serve HTTP responses for a particular
+    repository.
+
+    Instances are typically used as WSGI applications.
+
+    Some servers are multi-threaded. On these servers, there may
+    be multiple active threads inside __call__.
+    """
     def __init__(self, repo, name=None, baseui=None):
         if isinstance(repo, str):
             if baseui:
@@ -73,93 +201,62 @@
             # we trust caller to give us a private copy
             r = repo
 
-        r = self._getview(r)
         r.ui.setconfig('ui', 'report_untrusted', 'off', 'hgweb')
         r.baseui.setconfig('ui', 'report_untrusted', 'off', 'hgweb')
         r.ui.setconfig('ui', 'nontty', 'true', 'hgweb')
         r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb')
+        # resolve file patterns relative to repo root
+        r.ui.setconfig('ui', 'forcecwd', r.root, 'hgweb')
+        r.baseui.setconfig('ui', 'forcecwd', r.root, 'hgweb')
         # displaying bundling progress bar while serving feel wrong and may
         # break some wsgi implementation.
         r.ui.setconfig('progress', 'disable', 'true', 'hgweb')
         r.baseui.setconfig('progress', 'disable', 'true', 'hgweb')
-        self.repo = r
+        self._repos = [hg.cachedlocalrepo(self._webifyrepo(r))]
+        self._lastrepo = self._repos[0]
         hook.redirect(True)
-        self.repostate = ((-1, -1), (-1, -1))
-        self.mtime = -1
         self.reponame = name
-        self.archives = 'zip', 'gz', 'bz2'
-        self.stripecount = 1
-        # we use untrusted=False to prevent a repo owner from using
-        # web.templates in .hg/hgrc to get access to any file readable
-        # by the user running the CGI script
-        self.templatepath = self.config('web', 'templates', untrusted=False)
-        self.websubtable = self.loadwebsub()
 
-    # The CGI scripts are often run by a user different from the repo owner.
-    # Trust the settings from the .hg/hgrc files by default.
-    def config(self, section, name, default=None, untrusted=True):
-        return self.repo.ui.config(section, name, default,
-                                   untrusted=untrusted)
-
-    def configbool(self, section, name, default=False, untrusted=True):
-        return self.repo.ui.configbool(section, name, default,
-                                       untrusted=untrusted)
+    def _webifyrepo(self, repo):
+        repo = getwebview(repo)
+        self.websubtable = webutil.getwebsubs(repo)
+        return repo
 
-    def configlist(self, section, name, default=None, untrusted=True):
-        return self.repo.ui.configlist(section, name, default,
-                                       untrusted=untrusted)
+    @contextlib.contextmanager
+    def _obtainrepo(self):
+        """Obtain a repo unique to the caller.
 
-    def _getview(self, repo):
-        """The 'web.view' config controls changeset filter to hgweb. Possible
-        values are ``served``, ``visible`` and ``all``. Default is ``served``.
-        The ``served`` filter only shows changesets that can be pulled from the
-        hgweb instance.  The``visible`` filter includes secret changesets but
-        still excludes "hidden" one.
-
-        See the repoview module for details.
+        Internally we maintain a stack of cachedlocalrepo instances
+        to be handed out. If one is available, we pop it and return it,
+        ensuring it is up to date in the process. If one is not available,
+        we clone the most recently used repo instance and return it.
 
-        The option has been around undocumented since Mercurial 2.5, but no
-        user ever asked about it. So we better keep it undocumented for now."""
-        viewconfig = repo.ui.config('web', 'view', 'served',
-                                    untrusted=True)
-        if viewconfig == 'all':
-            return repo.unfiltered()
-        elif viewconfig in repoview.filtertable:
-            return repo.filtered(viewconfig)
+        It is currently possible for the stack to grow without bounds
+        if the server allows infinite threads. However, servers should
+        have a thread limit, thus establishing our limit.
+        """
+        if self._repos:
+            cached = self._repos.pop()
+            r, created = cached.fetch()
         else:
-            return repo.filtered('served')
+            cached = self._lastrepo.copy()
+            r, created = cached.fetch()
+        if created:
+            r = self._webifyrepo(r)
 
-    def refresh(self, request=None):
-        repostate = []
-        mtime = 0
-        # file of interrests mtime and size
-        for meth, fname in foi:
-            prefix = getattr(self.repo, meth)
-            st = get_stat(prefix, fname)
-            repostate.append((st.st_mtime, st.st_size))
-            mtime = max(mtime, st.st_mtime)
-        repostate = tuple(repostate)
-        # we need to compare file size in addition to mtime to catch
-        # changes made less than a second ago
-        if repostate != self.repostate:
-            r = hg.repository(self.repo.baseui, self.repo.url())
-            self.repo = self._getview(r)
-            self.maxchanges = int(self.config("web", "maxchanges", 10))
-            self.stripecount = int(self.config("web", "stripes", 1))
-            self.maxshortchanges = int(self.config("web", "maxshortchanges",
-                                                   60))
-            self.maxfiles = int(self.config("web", "maxfiles", 10))
-            self.allowpull = self.configbool("web", "allowpull", True)
-            encoding.encoding = self.config("web", "encoding",
-                                            encoding.encoding)
-            # update these last to avoid threads seeing empty settings
-            self.repostate = repostate
-            # mtime is needed for ETag
-            self.mtime = mtime
-        if request:
-            self.repo.ui.environ = request.env
+        self._lastrepo = cached
+        self.mtime = cached.mtime
+        try:
+            yield r
+        finally:
+            self._repos.append(cached)
 
     def run(self):
+        """Start a server from CGI environment.
+
+        Modern servers should be using WSGI and should avoid this
+        method, if possible.
+        """
         if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
             raise RuntimeError("This function is only intended to be "
                                "called while running as a CGI script.")
@@ -167,12 +264,29 @@
         wsgicgi.launch(self)
 
     def __call__(self, env, respond):
+        """Run the WSGI application.
+
+        This may be called by multiple threads.
+        """
         req = wsgirequest(env, respond)
         return self.run_wsgi(req)
 
     def run_wsgi(self, req):
+        """Internal method to run the WSGI application.
 
-        self.refresh(req)
+        This is typically only called by Mercurial. External consumers
+        should be using instances of this class as the WSGI application.
+        """
+        with self._obtainrepo() as repo:
+            for r in self._runwsgi(req, repo):
+                yield r
+
+    def _runwsgi(self, req, repo):
+        rctx = requestcontext(self, repo)
+
+        # This state is global across all threads.
+        encoding.encoding = rctx.config('web', 'encoding', encoding.encoding)
+        rctx.repo.ui.environ = req.env
 
         # work with CGI variables to create coherent structure
         # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
@@ -203,8 +317,8 @@
                 if query:
                     raise ErrorResponse(HTTP_NOT_FOUND)
                 if cmd in perms:
-                    self.check_perm(req, perms[cmd])
-                return protocol.call(self.repo, req, cmd)
+                    self.check_perm(rctx, req, perms[cmd])
+                return protocol.call(rctx.repo, req, cmd)
             except ErrorResponse as inst:
                 # A client that sends unbundle without 100-continue will
                 # break if we respond early.
@@ -216,7 +330,7 @@
                 else:
                     req.headers.append(('Connection', 'Close'))
                 req.respond(inst, protocol.HGTYPE,
-                            body='0\n%s\n' % inst.message)
+                            body='0\n%s\n' % inst)
                 return ''
 
         # translate user-visible url structure to internal structure
@@ -249,7 +363,7 @@
 
             if cmd == 'archive':
                 fn = req.form['node'][0]
-                for type_, spec in self.archive_specs.iteritems():
+                for type_, spec in rctx.archivespecs.iteritems():
                     ext = spec[2]
                     if fn.endswith(ext):
                         req.form['node'] = [fn[:-len(ext)]]
@@ -258,28 +372,28 @@
         # process the web interface request
 
         try:
-            tmpl = self.templater(req)
+            tmpl = rctx.templater(req)
             ctype = tmpl('mimetype', encoding=encoding.encoding)
             ctype = templater.stringify(ctype)
 
             # check read permissions non-static content
             if cmd != 'static':
-                self.check_perm(req, None)
+                self.check_perm(rctx, req, None)
 
             if cmd == '':
                 req.form['cmd'] = [tmpl.cache['default']]
                 cmd = req.form['cmd'][0]
 
-            if self.configbool('web', 'cache', True):
+            if rctx.configbool('web', 'cache', True):
                 caching(self, req) # sets ETag header or raises NOT_MODIFIED
             if cmd not in webcommands.__all__:
                 msg = 'no such method: %s' % cmd
                 raise ErrorResponse(HTTP_BAD_REQUEST, msg)
             elif cmd == 'file' and 'raw' in req.form.get('style', []):
-                self.ctype = ctype
-                content = webcommands.rawfile(self, req, tmpl)
+                rctx.ctype = ctype
+                content = webcommands.rawfile(rctx, req, tmpl)
             else:
-                content = getattr(webcommands, cmd)(self, req, tmpl)
+                content = getattr(webcommands, cmd)(rctx, req, tmpl)
                 req.respond(HTTP_OK, ctype)
 
             return content
@@ -299,129 +413,29 @@
             if inst.code == HTTP_NOT_MODIFIED:
                 # Not allowed to return a body on a 304
                 return ['']
-            return tmpl('error', error=inst.message)
-
-    def loadwebsub(self):
-        websubtable = []
-        websubdefs = self.repo.ui.configitems('websub')
-        # we must maintain interhg backwards compatibility
-        websubdefs += self.repo.ui.configitems('interhg')
-        for key, pattern in websubdefs:
-            # grab the delimiter from the character after the "s"
-            unesc = pattern[1]
-            delim = re.escape(unesc)
+            return tmpl('error', error=str(inst))
 
-            # identify portions of the pattern, taking care to avoid escaped
-            # delimiters. the replace format and flags are optional, but
-            # delimiters are required.
-            match = re.match(
-                r'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
-                % (delim, delim, delim), pattern)
-            if not match:
-                self.repo.ui.warn(_("websub: invalid pattern for %s: %s\n")
-                                  % (key, pattern))
-                continue
-
-            # we need to unescape the delimiter for regexp and format
-            delim_re = re.compile(r'(?<!\\)\\%s' % delim)
-            regexp = delim_re.sub(unesc, match.group(1))
-            format = delim_re.sub(unesc, match.group(2))
+    def check_perm(self, rctx, req, op):
+        for permhook in permhooks:
+            permhook(rctx, req, op)
 
-            # the pattern allows for 6 regexp flags, so set them if necessary
-            flagin = match.group(3)
-            flags = 0
-            if flagin:
-                for flag in flagin.upper():
-                    flags |= re.__dict__[flag]
-
-            try:
-                regexp = re.compile(regexp, flags)
-                websubtable.append((regexp, format))
-            except re.error:
-                self.repo.ui.warn(_("websub: invalid regexp for %s: %s\n")
-                                  % (key, regexp))
-        return websubtable
-
-    def templater(self, req):
-
-        # determine scheme, port and server name
-        # this is needed to create absolute urls
-
-        proto = req.env.get('wsgi.url_scheme')
-        if proto == 'https':
-            proto = 'https'
-            default_port = "443"
-        else:
-            proto = 'http'
-            default_port = "80"
+def getwebview(repo):
+    """The 'web.view' config controls changeset filter to hgweb. Possible
+    values are ``served``, ``visible`` and ``all``. Default is ``served``.
+    The ``served`` filter only shows changesets that can be pulled from the
+    hgweb instance.  The``visible`` filter includes secret changesets but
+    still excludes "hidden" one.
 
-        port = req.env["SERVER_PORT"]
-        port = port != default_port and (":" + port) or ""
-        urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port)
-        logourl = self.config("web", "logourl", "http://mercurial.selenic.com/")
-        logoimg = self.config("web", "logoimg", "hglogo.png")
-        staticurl = self.config("web", "staticurl") or req.url + 'static/'
-        if not staticurl.endswith('/'):
-            staticurl += '/'
-
-        # some functions for the templater
-
-        def motd(**map):
-            yield self.config("web", "motd", "")
-
-        # figure out which style to use
-
-        vars = {}
-        styles = (
-            req.form.get('style', [None])[0],
-            self.config('web', 'style'),
-            'paper',
-        )
-        style, mapfile = templater.stylemap(styles, self.templatepath)
-        if style == styles[0]:
-            vars['style'] = style
-
-        start = req.url[-1] == '?' and '&' or '?'
-        sessionvars = webutil.sessionvars(vars, start)
-
-        if not self.reponame:
-            self.reponame = (self.config("web", "name")
-                             or req.env.get('REPO_NAME')
-                             or req.url.strip('/') or self.repo.root)
+    See the repoview module for details.
 
-        def websubfilter(text):
-            return websub(text, self.websubtable)
-
-        # create the templater
+    The option has been around undocumented since Mercurial 2.5, but no
+    user ever asked about it. So we better keep it undocumented for now."""
+    viewconfig = repo.ui.config('web', 'view', 'served',
+                                untrusted=True)
+    if viewconfig == 'all':
+        return repo.unfiltered()
+    elif viewconfig in repoview.filtertable:
+        return repo.filtered(viewconfig)
+    else:
+        return repo.filtered('served')
 
-        tmpl = templater.templater(mapfile,
-                                   filters={"websub": websubfilter},
-                                   defaults={"url": req.url,
-                                             "logourl": logourl,
-                                             "logoimg": logoimg,
-                                             "staticurl": staticurl,
-                                             "urlbase": urlbase,
-                                             "repo": self.reponame,
-                                             "encoding": encoding.encoding,
-                                             "motd": motd,
-                                             "sessionvars": sessionvars,
-                                             "pathdef": makebreadcrumb(req.url),
-                                             "style": style,
-                                            })
-        return tmpl
-
-    def archivelist(self, nodeid):
-        allowed = self.configlist("web", "allow_archive")
-        for i, spec in self.archive_specs.iteritems():
-            if i in allowed or self.configbool("web", "allow" + i):
-                yield {"type" : i, "extension" : spec[2], "node" : nodeid}
-
-    archive_specs = {
-        'bz2': ('application/x-bzip2', 'tbz2', '.tar.bz2', None),
-        'gz': ('application/x-gzip', 'tgz', '.tar.gz', None),
-        'zip': ('application/zip', 'zip', '.zip', None),
-        }
-
-    def check_perm(self, req, op):
-        for permhook in permhooks:
-            permhook(self, req, op)
--- a/mercurial/hgweb/hgwebdir_mod.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hgweb/hgwebdir_mod.py	Fri Sep 25 23:10:47 2015 -0500
@@ -79,17 +79,30 @@
     return name, str(port), path
 
 class hgwebdir(object):
-    refreshinterval = 20
+    """HTTP server for multiple repositories.
 
+    Given a configuration, different repositories will be served depending
+    on the request path.
+
+    Instances are typically used as WSGI applications.
+    """
     def __init__(self, conf, baseui=None):
         self.conf = conf
         self.baseui = baseui
+        self.ui = None
         self.lastrefresh = 0
         self.motd = None
         self.refresh()
 
     def refresh(self):
-        if self.lastrefresh + self.refreshinterval > time.time():
+        refreshinterval = 20
+        if self.ui:
+            refreshinterval = self.ui.configint('web', 'refreshinterval',
+                                                refreshinterval)
+
+        # refreshinterval <= 0 means to always refresh.
+        if (refreshinterval > 0 and
+            self.lastrefresh + refreshinterval > time.time()):
             return
 
         if self.baseui:
--- a/mercurial/hgweb/request.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hgweb/request.py	Fri Sep 25 23:10:47 2015 -0500
@@ -40,6 +40,12 @@
     return form
 
 class wsgirequest(object):
+    """Higher-level API for a WSGI request.
+
+    WSGI applications are invoked with 2 arguments. They are used to
+    instantiate instances of this class, which provides higher-level APIs
+    for obtaining request parameters, writing HTTP output, etc.
+    """
     def __init__(self, wsgienv, start_response):
         version = wsgienv['wsgi.version']
         if (version < (1, 0)) or (version >= (2, 0)):
@@ -94,7 +100,7 @@
                     self.headers = [(k, v) for (k, v) in self.headers if
                                     k in ('Date', 'ETag', 'Expires',
                                           'Cache-Control', 'Vary')]
-                status = statusmessage(status.code, status.message)
+                status = statusmessage(status.code, str(status))
             elif status == 200:
                 status = '200 Script output follows'
             elif isinstance(status, int):
--- a/mercurial/hgweb/server.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hgweb/server.py	Fri Sep 25 23:10:47 2015 -0500
@@ -239,7 +239,7 @@
             pass
 
 class _httprequesthandlerssl(_httprequesthandler):
-    """HTTPS handler based on Pythons ssl module (introduced in 2.6)"""
+    """HTTPS handler based on Python's ssl module"""
 
     url_scheme = 'https'
 
--- a/mercurial/hgweb/webcommands.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hgweb/webcommands.py	Fri Sep 25 23:10:47 2015 -0500
@@ -639,35 +639,10 @@
 
     The ``branches`` template is rendered.
     """
-    tips = []
-    heads = web.repo.heads()
-    parity = paritygen(web.stripecount)
-    sortkey = lambda item: (not item[1], item[0].rev())
-
-    def entries(limit, **map):
-        count = 0
-        if not tips:
-            for tag, hs, tip, closed in web.repo.branchmap().iterbranches():
-                tips.append((web.repo[tip], closed))
-        for ctx, closed in sorted(tips, key=sortkey, reverse=True):
-            if limit > 0 and count >= limit:
-                return
-            count += 1
-            if closed:
-                status = 'closed'
-            elif ctx.node() not in heads:
-                status = 'inactive'
-            else:
-                status = 'open'
-            yield {'parity': parity.next(),
-                   'branch': ctx.branch(),
-                   'status': status,
-                   'node': ctx.hex(),
-                   'date': ctx.date()}
-
+    entries = webutil.branchentries(web.repo, web.stripecount)
+    latestentry = webutil.branchentries(web.repo, web.stripecount, 1)
     return tmpl('branches', node=hex(web.repo.changelog.tip()),
-                entries=lambda **x: entries(0, **x),
-                latestentry=lambda **x: entries(1, **x))
+                entries=entries, latestentry=latestentry)
 
 @webcommand('summary')
 def summary(web, req, tmpl):
@@ -710,18 +685,6 @@
                    'date': web.repo[n].date(),
                    'node': hex(n)}
 
-    def branches(**map):
-        parity = paritygen(web.stripecount)
-
-        b = web.repo.branchmap()
-        l = [(-web.repo.changelog.rev(tip), tip, tag)
-             for tag, heads, tip, closed in b.iterbranches()]
-        for r, n, t in sorted(l):
-            yield {'parity': parity.next(),
-                   'branch': t,
-                   'node': hex(n),
-                   'date': web.repo[n].date()}
-
     def changelist(**map):
         parity = paritygen(web.stripecount, offset=start - end)
         l = [] # build a list in forward order for efficiency
@@ -761,7 +724,7 @@
                 lastchange=tip.date(),
                 tags=tagentries,
                 bookmarks=bookmarks,
-                branches=branches,
+                branches=webutil.branchentries(web.repo, web.stripecount, 10),
                 shortlog=changelist,
                 node=tip.hex(),
                 symrev='tip',
@@ -1115,7 +1078,7 @@
                 raise ErrorResponse(HTTP_NOT_FOUND,
                     'file(s) not found: %s' % file[0])
 
-    mimetype, artype, extension, encoding = web.archive_specs[type_]
+    mimetype, artype, extension, encoding = web.archivespecs[type_]
     headers = [
         ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
         ]
--- a/mercurial/hgweb/webutil.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hgweb/webutil.py	Fri Sep 25 23:10:47 2015 -0500
@@ -7,6 +7,7 @@
 # GNU General Public License version 2 or any later version.
 
 import os, copy
+import re
 from mercurial import match, patch, error, ui, util, pathutil, context
 from mercurial.i18n import _
 from mercurial.node import hex, nullid, short
@@ -199,11 +200,42 @@
     for t in repo.nodebookmarks(node):
         yield tmpl(t1, bookmark=t, **args)
 
+def branchentries(repo, stripecount, limit=0):
+    tips = []
+    heads = repo.heads()
+    parity = paritygen(stripecount)
+    sortkey = lambda item: (not item[1], item[0].rev())
+
+    def entries(**map):
+        count = 0
+        if not tips:
+            for tag, hs, tip, closed in repo.branchmap().iterbranches():
+                tips.append((repo[tip], closed))
+        for ctx, closed in sorted(tips, key=sortkey, reverse=True):
+            if limit > 0 and count >= limit:
+                return
+            count += 1
+            if closed:
+                status = 'closed'
+            elif ctx.node() not in heads:
+                status = 'inactive'
+            else:
+                status = 'open'
+            yield {
+                'parity': parity.next(),
+                'branch': ctx.branch(),
+                'status': status,
+                'node': ctx.hex(),
+                'date': ctx.date()
+            }
+
+    return entries
+
 def cleanpath(repo, path):
     path = path.lstrip('/')
     return pathutil.canonpath(repo.root, '', path)
 
-def changeidctx (repo, changeid):
+def changeidctx(repo, changeid):
     try:
         ctx = repo[changeid]
     except error.RepoError:
@@ -212,11 +244,11 @@
 
     return ctx
 
-def changectx (repo, req):
+def changectx(repo, req):
     changeid = "tip"
     if 'node' in req.form:
         changeid = req.form['node'][0]
-        ipos=changeid.find(':')
+        ipos = changeid.find(':')
         if ipos != -1:
             changeid = changeid[(ipos + 1):]
     elif 'manifest' in req.form:
@@ -227,7 +259,7 @@
 def basechangectx(repo, req):
     if 'node' in req.form:
         changeid = req.form['node'][0]
-        ipos=changeid.find(':')
+        ipos = changeid.find(':')
         if ipos != -1:
             changeid = changeid[:ipos]
             return changeidctx(repo, changeid)
@@ -509,3 +541,44 @@
     # default termwidth breaks under mod_wsgi
     def termwidth(self):
         return 80
+
+def getwebsubs(repo):
+    websubtable = []
+    websubdefs = repo.ui.configitems('websub')
+    # we must maintain interhg backwards compatibility
+    websubdefs += repo.ui.configitems('interhg')
+    for key, pattern in websubdefs:
+        # grab the delimiter from the character after the "s"
+        unesc = pattern[1]
+        delim = re.escape(unesc)
+
+        # identify portions of the pattern, taking care to avoid escaped
+        # delimiters. the replace format and flags are optional, but
+        # delimiters are required.
+        match = re.match(
+            r'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
+            % (delim, delim, delim), pattern)
+        if not match:
+            repo.ui.warn(_("websub: invalid pattern for %s: %s\n")
+                              % (key, pattern))
+            continue
+
+        # we need to unescape the delimiter for regexp and format
+        delim_re = re.compile(r'(?<!\\)\\%s' % delim)
+        regexp = delim_re.sub(unesc, match.group(1))
+        format = delim_re.sub(unesc, match.group(2))
+
+        # the pattern allows for 6 regexp flags, so set them if necessary
+        flagin = match.group(3)
+        flags = 0
+        if flagin:
+            for flag in flagin.upper():
+                flags |= re.__dict__[flag]
+
+        try:
+            regexp = re.compile(regexp, flags)
+            websubtable.append((regexp, format))
+        except re.error:
+            repo.ui.warn(_("websub: invalid regexp for %s: %s\n")
+                         % (key, regexp))
+    return websubtable
--- a/mercurial/hook.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/hook.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,19 @@
 # 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 os, sys, time
-import extensions, util, demandimport, error
+from __future__ import absolute_import
+
+import os
+import sys
+import time
+
+from .i18n import _
+from . import (
+    demandimport,
+    error,
+    extensions,
+    util,
+)
 
 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
     '''call python hook. hook is callable object, looked up as
--- a/mercurial/httpconnection.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/httpconnection.py	Fri Sep 25 23:10:47 2015 -0500
@@ -107,7 +107,9 @@
 
 class HTTPConnection(httpclient.HTTPConnection):
     response_class = HTTPResponse
-    def request(self, method, uri, body=None, headers={}):
+    def request(self, method, uri, body=None, headers=None):
+        if headers is None:
+            headers = {}
         if isinstance(body, httpsendfile):
             body.seek(0)
         httpclient.HTTPConnection.request(self, method, uri, body=body,
--- a/mercurial/httppeer.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/httppeer.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,12 +6,28 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from node import nullid
-from i18n import _
+from __future__ import absolute_import
+
+import errno
+import httplib
+import os
+import socket
 import tempfile
-import changegroup, statichttprepo, error, httpconnection, url, util, wireproto
-import os, urllib, urllib2, zlib, httplib
-import errno, socket
+import urllib
+import urllib2
+import zlib
+
+from .i18n import _
+from .node import nullid
+from . import (
+    changegroup,
+    error,
+    httpconnection,
+    statichttprepo,
+    url,
+    util,
+    wireproto,
+)
 
 def zgenerator(f):
     zd = zlib.decompressobj()
--- a/mercurial/i18n.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/i18n.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,8 +5,14 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import encoding
-import gettext as gettextmod, sys, os, locale
+from __future__ import absolute_import
+
+import gettext as gettextmod
+import locale
+import os
+import sys
+
+from . import encoding
 
 # modelled after templater.templatepath:
 if getattr(sys, 'frozen', None) is not None:
--- a/mercurial/localrepo.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/localrepo.py	Fri Sep 25 23:10:47 2015 -0500
@@ -300,6 +300,7 @@
         if create:
             self._writerequirements()
 
+        self._dirstatevalidatewarned = False
 
         self._branchcaches = {}
         self._revbranchcache = None
@@ -354,6 +355,10 @@
         manifestcachesize = self.ui.configint('format', 'manifestcachesize')
         if manifestcachesize is not None:
             self.svfs.options['manifestcachesize'] = manifestcachesize
+        # experimental config: format.aggressivemergedeltas
+        aggressivemergedeltas = self.ui.configbool('format',
+            'aggressivemergedeltas', False)
+        self.svfs.options['aggressivemergedeltas'] = aggressivemergedeltas
 
     def _writerequirements(self):
         scmutil.writerequires(self.vfs, self.requirements)
@@ -469,19 +474,19 @@
 
     @repofilecache('dirstate')
     def dirstate(self):
-        warned = [0]
-        def validate(node):
-            try:
-                self.changelog.rev(node)
-                return node
-            except error.LookupError:
-                if not warned[0]:
-                    warned[0] = True
-                    self.ui.warn(_("warning: ignoring unknown"
-                                   " working parent %s!\n") % short(node))
-                return nullid
+        return dirstate.dirstate(self.vfs, self.ui, self.root,
+                                 self._dirstatevalidate)
 
-        return dirstate.dirstate(self.vfs, self.ui, self.root, validate)
+    def _dirstatevalidate(self, node):
+        try:
+            self.changelog.rev(node)
+            return node
+        except error.LookupError:
+            if not self._dirstatevalidatewarned:
+                self._dirstatevalidatewarned = True
+                self.ui.warn(_("warning: ignoring unknown"
+                               " working parent %s!\n") % short(node))
+            return nullid
 
     def __getitem__(self, changeid):
         if changeid is None or changeid == wdirrev:
@@ -535,7 +540,7 @@
         return hook.hook(self.ui, self, name, throw, **args)
 
     @unfilteredmethod
-    def _tag(self, names, node, message, local, user, date, extra={},
+    def _tag(self, names, node, message, local, user, date, extra=None,
              editor=False):
         if isinstance(names, str):
             names = (names,)
@@ -1016,6 +1021,9 @@
             reporef().hook('txnabort', throw=False, txnname=desc,
                            **tr2.hookargs)
         tr.addabort('txnabort-hook', txnaborthook)
+        # avoid eager cache invalidation. in-memory data should be identical
+        # to stored data if transaction has no error.
+        tr.addpostclose('refresh-filecachestats', self._refreshfilecachestats)
         self._transref = weakref.ref(tr)
         return tr
 
@@ -1193,9 +1201,17 @@
         self.invalidate()
         self.invalidatedirstate()
 
+    def _refreshfilecachestats(self, tr):
+        """Reload stats of cached files so that they are flagged as valid"""
+        for k, ce in self._filecache.items():
+            if k == 'dirstate' or k not in self.__dict__:
+                continue
+            ce.refresh()
+
     def _lock(self, vfs, lockname, wait, releasefn, acquirefn, desc):
         try:
-            l = lockmod.lock(vfs, lockname, 0, releasefn, desc=desc)
+            l = lockmod.lock(vfs, lockname, 0, releasefn=releasefn,
+                             acquirefn=acquirefn, desc=desc)
         except error.LockHeld as inst:
             if not wait:
                 raise
@@ -1204,10 +1220,9 @@
             # default to 600 seconds timeout
             l = lockmod.lock(vfs, lockname,
                              int(self.ui.config("ui", "timeout", "600")),
-                             releasefn, desc=desc)
+                             releasefn=releasefn, acquirefn=acquirefn,
+                             desc=desc)
             self.ui.warn(_("got lock after %s seconds\n") % l.delay)
-        if acquirefn:
-            acquirefn()
         return l
 
     def _afterlock(self, callback):
@@ -1235,13 +1250,7 @@
             l.lock()
             return l
 
-        def unlock():
-            for k, ce in self._filecache.items():
-                if k == 'dirstate' or k not in self.__dict__:
-                    continue
-                ce.refresh()
-
-        l = self._lock(self.svfs, "lock", wait, unlock,
+        l = self._lock(self.svfs, "lock", wait, None,
                        self.invalidate, _('repository %s') % self.origroot)
         self._lockref = weakref.ref(l)
         return l
@@ -1369,13 +1378,15 @@
 
     @unfilteredmethod
     def commit(self, text="", user=None, date=None, match=None, force=False,
-               editor=False, extra={}):
+               editor=False, extra=None):
         """Add a new revision to current repository.
 
         Revision information is gathered from the working directory,
         match can be used to filter the committed files. If editor is
         supplied, it is called to get a commit message.
         """
+        if extra is None:
+            extra = {}
 
         def fail(f, msg):
             raise util.Abort('%s: %s' % (f, msg))
--- a/mercurial/lock.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/lock.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,10 +5,19 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import util, error
-import errno, os, socket, time
+from __future__ import absolute_import
+
+import errno
+import os
+import socket
+import time
 import warnings
 
+from . import (
+    error,
+    util,
+)
+
 class lock(object):
     '''An advisory lock held by one process to control access to a set
     of files.  Non-cooperating processes or incorrectly written scripts
@@ -29,16 +38,23 @@
 
     _host = None
 
-    def __init__(self, vfs, file, timeout=-1, releasefn=None, desc=None):
+    def __init__(self, vfs, file, timeout=-1, releasefn=None, acquirefn=None,
+                 desc=None, parentlock=None):
         self.vfs = vfs
         self.f = file
         self.held = 0
         self.timeout = timeout
         self.releasefn = releasefn
+        self.acquirefn = acquirefn
         self.desc = desc
+        self.parentlock = parentlock
+        self._parentheld = False
+        self._inherited = False
         self.postrelease  = []
         self.pid = os.getpid()
         self.delay = self.lock()
+        if self.acquirefn:
+            self.acquirefn()
 
     def __del__(self):
         if self.held:
@@ -56,7 +72,7 @@
         timeout = self.timeout
         while True:
             try:
-                self.trylock()
+                self._trylock()
                 return self.timeout - timeout
             except error.LockHeld as inst:
                 if timeout != 0:
@@ -67,14 +83,16 @@
                 raise error.LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
                                      inst.locker)
 
-    def trylock(self):
+    def _trylock(self):
         if self.held:
             self.held += 1
             return
         if lock._host is None:
             lock._host = socket.gethostname()
         lockname = '%s:%s' % (lock._host, self.pid)
-        while not self.held:
+        retry = 5
+        while not self.held and retry:
+            retry -= 1
             try:
                 self.vfs.makelock(lockname, self.f)
                 self.held = 1
@@ -89,23 +107,22 @@
                     raise error.LockUnavailable(why.errno, why.strerror,
                                                 why.filename, self.desc)
 
-    def testlock(self):
-        """return id of locker if lock is valid, else None.
+    def _readlock(self):
+        """read lock and return its value
 
-        If old-style lock, we cannot tell what machine locker is on.
-        with new-style lock, if locker is on this machine, we can
-        see if locker is alive.  If locker is on this machine but
-        not alive, we can safely break lock.
-
-        The lock file is only deleted when None is returned.
-
+        Returns None if no lock exists, pid for old-style locks, and host:pid
+        for new-style locks.
         """
         try:
-            locker = self.vfs.readlock(self.f)
+            return self.vfs.readlock(self.f)
         except (OSError, IOError) as why:
             if why.errno == errno.ENOENT:
                 return None
             raise
+
+    def _testlock(self, locker):
+        if locker is None:
+            return None
         try:
             host, pid = locker.split(":", 1)
         except ValueError:
@@ -127,6 +144,50 @@
         except error.LockError:
             return locker
 
+    def testlock(self):
+        """return id of locker if lock is valid, else None.
+
+        If old-style lock, we cannot tell what machine locker is on.
+        with new-style lock, if locker is on this machine, we can
+        see if locker is alive.  If locker is on this machine but
+        not alive, we can safely break lock.
+
+        The lock file is only deleted when None is returned.
+
+        """
+        locker = self._readlock()
+        return self._testlock(locker)
+
+    def prepinherit(self):
+        """prepare for the lock to be inherited by a Mercurial subprocess
+
+        Returns a string that will be recognized by the lock in the
+        subprocess. Communicating this string to the subprocess needs to be done
+        separately -- typically by an environment variable.
+        """
+        if not self.held:
+            raise error.LockInheritanceContractViolation(
+                'prepinherit can only be called while lock is held')
+        if self._inherited:
+            raise error.LockInheritanceContractViolation(
+                'prepinherit cannot be called while lock is already inherited')
+        if self.releasefn:
+            self.releasefn()
+        if self._parentheld:
+            lockname = self.parentlock
+        else:
+            lockname = '%s:%s' % (lock._host, self.pid)
+        self._inherited = True
+        return lockname
+
+    def reacquire(self):
+        if not self._inherited:
+            raise error.LockInheritanceContractViolation(
+                'reacquire can only be called after prepinherit')
+        if self.acquirefn:
+            self.acquirefn()
+        self._inherited = False
+
     def release(self):
         """release the lock and execute callback function if any
 
@@ -143,10 +204,11 @@
                 if self.releasefn:
                     self.releasefn()
             finally:
-                try:
-                    self.vfs.unlink(self.f)
-                except OSError:
-                    pass
+                if not self._parentheld:
+                    try:
+                        self.vfs.unlink(self.f)
+                    except OSError:
+                        pass
             for callback in self.postrelease:
                 callback()
 
--- a/mercurial/mail.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/mail.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,10 +5,22 @@
 # 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 util, encoding, sslutil
-import os, smtplib, socket, quopri, time, sys
+from __future__ import absolute_import
+
 import email
+import os
+import quopri
+import smtplib
+import socket
+import sys
+import time
+
+from .i18n import _
+from . import (
+    encoding,
+    sslutil,
+    util,
+)
 
 _oldheaderinit = email.Header.Header.__init__
 def _unifiedheaderinit(self, *args, **kw):
@@ -19,10 +31,10 @@
     constructor, and 2.7 removed this parameter.
 
     Default argument is continuation_ws=' ', which means that the
-    behaviour is different in <2.7 and 2.7
+    behavior is different in <2.7 and 2.7
 
-    We consider the 2.7 behaviour to be preferable, but need
-    to have an unified behaviour for versions 2.4 to 2.7
+    We consider the 2.7 behavior to be preferable, but need
+    to have an unified behavior for versions 2.4 to 2.7
     """
     # override continuation_ws
     kw['continuation_ws'] = ' '
--- a/mercurial/manifest.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/manifest.py	Fri Sep 25 23:10:47 2015 -0500
@@ -9,6 +9,7 @@
 import mdiff, parsers, error, revlog, util
 import array, struct
 import os
+import heapq
 
 propertycache = util.propertycache
 
@@ -970,12 +971,9 @@
             # revlog layer.
 
             _checkforbidden(added)
-            # combine the changed lists into one list for sorting
-            work = [(x, False) for x in added]
-            work.extend((x, True) for x in removed)
-            # this could use heapq.merge() (from Python 2.6+) or equivalent
-            # since the lists are already sorted
-            work.sort()
+            # combine the changed lists into one sorted iterator
+            work = heapq.merge([(x, False) for x in added],
+                               [(x, True) for x in removed])
 
             arraytext, deltatext = m.fastdelta(self._mancache[p1][1], work)
             cachedelta = self.rev(p1), deltatext
--- a/mercurial/match.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/match.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,17 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import copy, os, re
-import util, pathutil
-from i18n import _
+from __future__ import absolute_import
+
+import copy
+import os
+import re
+
+from .i18n import _
+from . import (
+    pathutil,
+    util,
+)
 
 propertycache = util.propertycache
 
--- a/mercurial/merge.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/merge.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,13 +5,28 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
+import errno
+import os
+import shutil
 import struct
 
-from node import nullid, nullrev, hex, bin
-from i18n import _
-from mercurial import obsolete
-import error as errormod, util, filemerge, copies, subrepo, worker
-import errno, os, shutil
+from .i18n import _
+from .node import (
+    bin,
+    hex,
+    nullid,
+    nullrev,
+)
+from . import (
+    copies,
+    filemerge,
+    obsolete,
+    subrepo,
+    util,
+    worker,
+)
 
 _pack = struct.pack
 _unpack = struct.unpack
@@ -27,7 +42,7 @@
 
     it is stored on disk when needed. Two file are used, one with an old
     format, one with a new format. Both contains similar data, but the new
-    format can store new kind of field.
+    format can store new kinds of field.
 
     Current new format is a list of arbitrary record of the form:
 
@@ -581,10 +596,14 @@
                 repo, wctx, mctx, ancestor, branchmerge, force, partial,
                 acceptremote, followcopies)
             _checkunknownfiles(repo, wctx, mctx, force, actions)
-            if diverge is None: # and renamedelete is None.
-                # Arbitrarily pick warnings from first iteration
+
+            # Track the shortest set of warning on the theory that bid
+            # merge will correctly incorporate more information
+            if diverge is None or len(diverge1) < len(diverge):
                 diverge = diverge1
+            if renamedelete is None or len(renamedelete) < len(renamedelete1):
                 renamedelete = renamedelete1
+
             for f, a in sorted(actions.iteritems()):
                 m, args, msg = a
                 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
@@ -779,25 +798,6 @@
         repo.ui.debug(" %s: %s -> k\n" % (f, msg))
         # no progress
 
-    # merge
-    for f, args, msg in actions['m']:
-        repo.ui.debug(" %s: %s -> m\n" % (f, msg))
-        z += 1
-        progress(_updating, z, item=f, total=numupdates, unit=_files)
-        if f == '.hgsubstate': # subrepo states need updating
-            subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
-                             overwrite)
-            continue
-        audit(f)
-        r = ms.resolve(f, wctx, labels=labels)
-        if r is not None and r > 0:
-            unresolved += 1
-        else:
-            if r is None:
-                updated += 1
-            else:
-                merged += 1
-
     # directory rename, move local
     for f, args, msg in actions['dm']:
         repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
@@ -830,6 +830,25 @@
         util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
         updated += 1
 
+    # merge
+    for f, args, msg in actions['m']:
+        repo.ui.debug(" %s: %s -> m\n" % (f, msg))
+        z += 1
+        progress(_updating, z, item=f, total=numupdates, unit=_files)
+        if f == '.hgsubstate': # subrepo states need updating
+            subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
+                             overwrite)
+            continue
+        audit(f)
+        r = ms.resolve(f, wctx, labels=labels)
+        if r is not None and r > 0:
+            unresolved += 1
+        else:
+            if r is None:
+                updated += 1
+            else:
+                merged += 1
+
     ms.commit()
     progress(_updating, None, total=numupdates, unit=_files)
 
@@ -969,42 +988,10 @@
             pas = [repo[ancestor]]
 
         if node is None:
-            # Here is where we should consider bookmarks, divergent bookmarks,
-            # foreground changesets (successors), and tip of current branch;
-            # but currently we are only checking the branch tips.
-            try:
-                node = repo.branchtip(wc.branch())
-            except errormod.RepoLookupError:
-                if wc.branch() == 'default': # no default branch!
-                    node = repo.lookup('tip') # update to tip
-                else:
-                    raise util.Abort(_("branch %s not found") % wc.branch())
-
-            if p1.obsolete() and not p1.children():
-                # allow updating to successors
-                successors = obsolete.successorssets(repo, p1.node())
-
-                # behavior of certain cases is as follows,
-                #
-                # divergent changesets: update to highest rev, similar to what
-                #     is currently done when there are more than one head
-                #     (i.e. 'tip')
-                #
-                # replaced changesets: same as divergent except we know there
-                # is no conflict
-                #
-                # pruned changeset: no update is done; though, we could
-                #     consider updating to the first non-obsolete parent,
-                #     similar to what is current done for 'hg prune'
-
-                if successors:
-                    # flatten the list here handles both divergent (len > 1)
-                    # and the usual case (len = 1)
-                    successors = [n for sub in successors for n in sub]
-
-                    # get the max revision for the given successors set,
-                    # i.e. the 'tip' of a set
-                    node = repo.revs('max(%ln)', successors).first()
+            nodes = list(repo.set('_updatedefaultdest()'))
+            if nodes:
+                node = nodes[0].node()
+                if p1.obsolete() and not p1.children():
                     pas = [p1]
 
         overwrite = force and not branchmerge
--- a/mercurial/minirst.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/minirst.py	Fri Sep 25 23:10:47 2015 -0500
@@ -18,11 +18,16 @@
 when adding support for new constructs.
 """
 
-import re
-import util, encoding
-from i18n import _
+from __future__ import absolute_import
 
 import cgi
+import re
+
+from .i18n import _
+from . import (
+    encoding,
+    util,
+)
 
 def section(s):
     return "%s\n%s\n\n" % (s, "\"" * encoding.colwidth(s))
@@ -651,13 +656,17 @@
 def format(text, width=80, indent=0, keep=None, style='plain', section=None):
     """Parse and format the text according to width."""
     blocks, pruned = parse(text, indent, keep or [])
+    parents = []
     if section:
         sections = getsections(blocks)
         blocks = []
         i = 0
         while i < len(sections):
             name, nest, b = sections[i]
+            del parents[nest:]
+            parents.append(name)
             if name == section:
+                b[0]['path'] = parents[3:]
                 blocks.extend(b)
 
                 ## Also show all subnested sections
@@ -669,6 +678,14 @@
     if style == 'html':
         text = formathtml(blocks)
     else:
+        if len([b for b in blocks if b['type'] == 'definition']) > 1:
+            i = 0
+            while i < len(blocks):
+                if blocks[i]['type'] == 'definition':
+                    if 'path' in blocks[i]:
+                        blocks[i]['lines'][0] = '"%s"' % '.'.join(
+                            blocks[i]['path'])
+                i += 1
         text = ''.join(formatblock(b, width) for b in blocks)
     if keep is None:
         return text
@@ -705,11 +722,43 @@
                 nest += i
             level = nest.index(i) + 1
             nest = nest[:level]
+            for i in range(1, len(secs) + 1):
+                sec = secs[-i]
+                if sec[1] < level:
+                    break
+                siblings = [a for a in sec[2] if a['type'] == 'definition']
+                if siblings:
+                    siblingindent = siblings[-1]['indent']
+                    indent = b['indent']
+                    if siblingindent < indent:
+                        level += 1
+                        break
+                    elif siblingindent == indent:
+                        level = sec[1]
+                        break
             secs.append((getname(b), level, [b]))
         else:
             if not secs:
                 # add an initial empty section
                 secs = [('', 0, [])]
+            if b['type'] != 'margin':
+                pointer = 1
+                bindent = b['indent']
+                while pointer < len(secs):
+                    section = secs[-pointer][2][0]
+                    if section['type'] != 'margin':
+                        sindent = section['indent']
+                        if len(section['lines']) > 1:
+                            sindent += len(section['lines'][1]) - \
+                              len(section['lines'][1].lstrip(' '))
+                        if bindent >= sindent:
+                            break
+                    pointer += 1
+                if pointer > 1:
+                    blevel = secs[-pointer][1]
+                    if section['type'] != b['type']:
+                        blevel += 1
+                    secs.append(('', blevel, []))
             secs[-1][2].append(b)
     return secs
 
--- a/mercurial/namespaces.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/namespaces.py	Fri Sep 25 23:10:47 2015 -0500
@@ -1,6 +1,10 @@
-from i18n import _
-from mercurial import util
-import templatekw
+from __future__ import absolute_import
+
+from .i18n import _
+from . import (
+    templatekw,
+    util,
+)
 
 def tolist(val):
     """
--- a/mercurial/node.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/node.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,6 +5,8 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import binascii
 
 nullrev = -1
--- a/mercurial/obsolete.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/obsolete.py	Fri Sep 25 23:10:47 2015 -0500
@@ -67,7 +67,7 @@
 comment associated with each format for details.
 
 """
-import struct
+import errno, struct
 import util, base85, node, parsers
 import phases
 from i18n import _
@@ -520,14 +520,9 @@
     def __init__(self, svfs, defaultformat=_fm1version, readonly=False):
         # caches for various obsolescence related cache
         self.caches = {}
-        self._all = []
         self.svfs = svfs
-        data = svfs.tryread('obsstore')
         self._version = defaultformat
         self._readonly = readonly
-        if data:
-            self._version, markers = _readmarkers(data)
-            self._addmarkers(markers)
 
     def __iter__(self):
         return iter(self._all)
@@ -536,6 +531,15 @@
         return len(self._all)
 
     def __nonzero__(self):
+        if not self._cached('_all'):
+            try:
+                return self.svfs.stat('obsstore').st_size > 1
+            except OSError as inst:
+                if inst.errno != errno.ENOENT:
+                    raise
+                # just build an empty _all list if no obsstore exists, which
+                # avoids further stat() syscalls
+                pass
         return bool(self._all)
 
     def create(self, transaction, prec, succs=(), flag=0, parents=None,
@@ -615,6 +619,16 @@
         return self.add(transaction, markers)
 
     @propertycache
+    def _all(self):
+        data = self.svfs.tryread('obsstore')
+        if not data:
+            return []
+        self._version, markers = _readmarkers(data)
+        markers = list(markers)
+        _checkinvalidmarkers(markers)
+        return markers
+
+    @propertycache
     def successors(self):
         successors = {}
         _addsuccessors(successors, self._all)
@@ -841,15 +855,15 @@
 
 
 def successorssets(repo, initialnode, cache=None):
-    """Return all set of successors of initial nodes
+    """Return set of all latest successors of initial nodes
 
-    The successors set of a changeset A are a group of revisions that succeed
+    The successors set of a changeset A are the group of revisions that succeed
     A. It succeeds A as a consistent whole, each revision being only a partial
     replacement. The successors set contains non-obsolete changesets only.
 
     This function returns the full list of successor sets which is why it
     returns a list of tuples and not just a single tuple. Each tuple is a valid
-    successors set. Not that (A,) may be a valid successors set for changeset A
+    successors set. Note that (A,) may be a valid successors set for changeset A
     (see below).
 
     In most cases, a changeset A will have a single element (e.g. the changeset
@@ -865,7 +879,7 @@
 
     If a changeset A is not obsolete, then it will conceptually have no
     successors set. To distinguish this from a pruned changeset, the successor
-    set will only contain itself, i.e. [(A,)].
+    set will contain itself only, i.e. [(A,)].
 
     Finally, successors unknown locally are considered to be pruned (obsoleted
     without any successors).
@@ -873,10 +887,9 @@
     The optional `cache` parameter is a dictionary that may contain precomputed
     successors sets. It is meant to reuse the computation of a previous call to
     `successorssets` when multiple calls are made at the same time. The cache
-    dictionary is updated in place. The caller is responsible for its live
-    spawn. Code that makes multiple calls to `successorssets` *must* use this
-    cache mechanism or suffer terrible performances.
-
+    dictionary is updated in place. The caller is responsible for its life
+    span. Code that makes multiple calls to `successorssets` *must* use this
+    cache mechanism or suffer terrible performance.
     """
 
     succmarkers = repo.obsstore.successors
@@ -1046,16 +1059,6 @@
                 cache[current] = final
     return cache[initialnode]
 
-def _knownrevs(repo, nodes):
-    """yield revision numbers of known nodes passed in parameters
-
-    Unknown revisions are silently ignored."""
-    torev = repo.changelog.nodemap.get
-    for n in nodes:
-        rev = torev(n)
-        if rev is not None:
-            yield rev
-
 # mapping of 'set-name' -> <function to compute this set>
 cachefuncs = {}
 def cachefor(name):
--- a/mercurial/parser.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/parser.py	Fri Sep 25 23:10:47 2015 -0500
@@ -16,8 +16,10 @@
 # an action is a tree node name, a tree label, and an optional match
 # __call__(program) parses program into a labeled tree
 
-import error
-from i18n import _
+from __future__ import absolute_import
+
+from .i18n import _
+from . import error
 
 class parser(object):
     def __init__(self, elements, methods=None):
@@ -120,6 +122,13 @@
         args[k] = x[2]
     return args
 
+def unescapestr(s):
+    try:
+        return s.decode("string_escape")
+    except ValueError as e:
+        # mangle Python's exception into our format
+        raise error.ParseError(str(e).lower())
+
 def _prettyformat(tree, leafnodes, level, lines):
     if not isinstance(tree, tuple) or tree[0] in leafnodes:
         lines.append((level, str(tree)))
--- a/mercurial/parsers.c	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/parsers.c	Fri Sep 25 23:10:47 2015 -0500
@@ -253,8 +253,11 @@
 
 			if (normed == NULL)
 				goto quit;
-			if (PyDict_SetItem(file_foldmap, normed, k) == -1)
+			if (PyDict_SetItem(file_foldmap, normed, k) == -1) {
+				Py_DECREF(normed);
 				goto quit;
+			}
+			Py_DECREF(normed);
 		}
 	}
 	return file_foldmap;
@@ -475,14 +478,14 @@
 			      &str, &readlen))
 		goto quit;
 
-	if (readlen < 0)
-		goto quit;
-
 	len = readlen;
 
 	/* read parents */
-	if (len < 40)
+	if (len < 40) {
+		PyErr_SetString(
+			PyExc_ValueError, "too little data for parents");
 		goto quit;
+	}
 
 	parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
 	if (!parents)
@@ -679,7 +682,7 @@
 } nodetree;
 
 /*
- * This class has two behaviours.
+ * This class has two behaviors.
  *
  * When used in a list-like way (with integer keys), we decode an
  * entry in a RevlogNG index file on demand. Our last entry is a
@@ -702,8 +705,8 @@
 	PyObject *headrevs;    /* cache, invalidated on changes */
 	PyObject *filteredrevs;/* filtered revs set */
 	nodetree *nt;          /* base-16 trie */
-	int ntlength;          /* # nodes in use */
-	int ntcapacity;        /* # nodes allocated */
+	unsigned ntlength;          /* # nodes in use */
+	unsigned ntcapacity;        /* # nodes allocated */
 	int ntdepth;           /* maximum depth of tree */
 	int ntsplits;          /* # splits performed */
 	int ntrev;             /* last rev scanned */
@@ -1043,13 +1046,12 @@
 	return newlist;
 }
 
-/* arg should be Py_ssize_t but Python 2.4 do not support the n format */
-static int check_filter(PyObject *filter, unsigned long arg) {
+static int check_filter(PyObject *filter, Py_ssize_t arg) {
 	if (filter) {
 		PyObject *arglist, *result;
 		int isfiltered;
 
-		arglist = Py_BuildValue("(k)", arg);
+		arglist = Py_BuildValue("(n)", arg);
 		if (!arglist) {
 			return -1;
 		}
@@ -1105,6 +1107,162 @@
 		phases[i] = phases[parent_2];
 }
 
+static PyObject *reachableroots2(indexObject *self, PyObject *args)
+{
+
+	/* Input */
+	long minroot;
+	PyObject *includepatharg = NULL;
+	int includepath = 0;
+	/* heads and roots are lists */
+	PyObject *heads = NULL;
+	PyObject *roots = NULL;
+	PyObject *reachable = NULL;
+
+	PyObject *val;
+	Py_ssize_t len = index_length(self) - 1;
+	long revnum;
+	Py_ssize_t k;
+	Py_ssize_t i;
+	Py_ssize_t l;
+	int r;
+	int parents[2];
+
+	/* Internal data structure:
+	 * tovisit: array of length len+1 (all revs + nullrev), filled upto lentovisit
+	 * revstates: array of length len+1 (all revs + nullrev) */
+	int *tovisit = NULL;
+	long lentovisit = 0;
+	enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
+	char *revstates = NULL;
+
+	/* Get arguments */
+	if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
+			      &PyList_Type, &roots,
+			      &PyBool_Type, &includepatharg))
+		goto bail;
+
+	if (includepatharg == Py_True)
+		includepath = 1;
+
+	/* Initialize return set */
+	reachable = PyList_New(0);
+	if (reachable == NULL)
+		goto bail;
+
+	/* Initialize internal datastructures */
+	tovisit = (int *)malloc((len + 1) * sizeof(int));
+	if (tovisit == NULL) {
+		PyErr_NoMemory();
+		goto bail;
+	}
+
+	revstates = (char *)calloc(len + 1, 1);
+	if (revstates == NULL) {
+		PyErr_NoMemory();
+		goto bail;
+	}
+
+	l = PyList_GET_SIZE(roots);
+	for (i = 0; i < l; i++) {
+		revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
+		if (revnum == -1 && PyErr_Occurred())
+			goto bail;
+		/* If root is out of range, e.g. wdir(), it must be unreachable
+		 * from heads. So we can just ignore it. */
+		if (revnum + 1 < 0 || revnum + 1 >= len + 1)
+			continue;
+		revstates[revnum + 1] |= RS_ROOT;
+	}
+
+	/* Populate tovisit with all the heads */
+	l = PyList_GET_SIZE(heads);
+	for (i = 0; i < l; i++) {
+		revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
+		if (revnum == -1 && PyErr_Occurred())
+			goto bail;
+		if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
+			PyErr_SetString(PyExc_IndexError, "head out of range");
+			goto bail;
+		}
+		if (!(revstates[revnum + 1] & RS_SEEN)) {
+			tovisit[lentovisit++] = (int)revnum;
+			revstates[revnum + 1] |= RS_SEEN;
+		}
+	}
+
+	/* Visit the tovisit list and find the reachable roots */
+	k = 0;
+	while (k < lentovisit) {
+		/* Add the node to reachable if it is a root*/
+		revnum = tovisit[k++];
+		if (revstates[revnum + 1] & RS_ROOT) {
+			revstates[revnum + 1] |= RS_REACHABLE;
+			val = PyInt_FromLong(revnum);
+			if (val == NULL)
+				goto bail;
+			r = PyList_Append(reachable, val);
+			Py_DECREF(val);
+			if (r < 0)
+				goto bail;
+			if (includepath == 0)
+				continue;
+		}
+
+		/* Add its parents to the list of nodes to visit */
+		if (revnum == -1)
+			continue;
+		r = index_get_parents(self, revnum, parents, (int)len - 1);
+		if (r < 0)
+			goto bail;
+		for (i = 0; i < 2; i++) {
+			if (!(revstates[parents[i] + 1] & RS_SEEN)
+			    && parents[i] >= minroot) {
+				tovisit[lentovisit++] = parents[i];
+				revstates[parents[i] + 1] |= RS_SEEN;
+			}
+		}
+	}
+
+	/* Find all the nodes in between the roots we found and the heads
+	 * and add them to the reachable set */
+	if (includepath == 1) {
+		long minidx = minroot;
+		if (minidx < 0)
+			minidx = 0;
+		for (i = minidx; i < len; i++) {
+			if (!(revstates[i + 1] & RS_SEEN))
+				continue;
+			r = index_get_parents(self, i, parents, (int)len - 1);
+			/* Corrupted index file, error is set from
+			 * index_get_parents */
+			if (r < 0)
+				goto bail;
+			if (((revstates[parents[0] + 1] |
+			      revstates[parents[1] + 1]) & RS_REACHABLE)
+			    && !(revstates[i + 1] & RS_REACHABLE)) {
+				revstates[i + 1] |= RS_REACHABLE;
+				val = PyInt_FromLong(i);
+				if (val == NULL)
+					goto bail;
+				r = PyList_Append(reachable, val);
+				Py_DECREF(val);
+				if (r < 0)
+					goto bail;
+			}
+		}
+	}
+
+	free(revstates);
+	free(tovisit);
+	return reachable;
+bail:
+	Py_XDECREF(reachable);
+	free(revstates);
+	free(tovisit);
+	return NULL;
+}
+
 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
 {
 	PyObject *roots = Py_None;
@@ -2011,16 +2169,18 @@
  */
 static PyObject *index_ancestors(indexObject *self, PyObject *args)
 {
+	PyObject *ret;
 	PyObject *gca = index_commonancestorsheads(self, args);
 	if (gca == NULL)
 		return NULL;
 
 	if (PyList_GET_SIZE(gca) <= 1) {
-		Py_INCREF(gca);
 		return gca;
 	}
 
-	return find_deepest(self, gca);
+	ret = find_deepest(self, gca);
+	Py_DECREF(gca);
+	return ret;
 }
 
 /*
@@ -2282,6 +2442,8 @@
 	 "get an index entry"},
 	{"computephasesmapsets", (PyCFunction)compute_phases_map_sets,
 			METH_VARARGS, "compute phases"},
+	{"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
+		"reachableroots"},
 	{"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
 	 "get head revisions"}, /* Can do filtering since 3.2 */
 	{"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
@@ -2402,7 +2564,7 @@
 			Py_DECREF(list);
 			return NULL;
 		}
-		PyTuple_SetItem(list, i, hash);
+		PyTuple_SET_ITEM(list, i, hash);
 		source += hashwidth;
 	}
 	return list;
@@ -2474,18 +2636,16 @@
 		metasize = (unsigned char)(*data++);
 		right = PyString_FromStringAndSize(meta, metasize);
 		meta += metasize;
-		if (!left || !right) {
+		tmp = PyTuple_New(2);
+		if (!left || !right || !tmp) {
 			Py_XDECREF(left);
 			Py_XDECREF(right);
+			Py_XDECREF(tmp);
 			goto bail;
 		}
-		tmp = PyTuple_Pack(2, left, right);
-		Py_DECREF(left);
-		Py_DECREF(right);
-		if (!tmp) {
-			goto bail;
-		}
-		PyTuple_SetItem(metadata, i, tmp);
+		PyTuple_SET_ITEM(tmp, 0, left);
+		PyTuple_SET_ITEM(tmp, 1, right);
+		PyTuple_SET_ITEM(metadata, i, tmp);
 	}
 	ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
 			    metadata, mtime, (int)tz * 60, parents);
@@ -2502,12 +2662,10 @@
 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
 	const char *data;
 	Py_ssize_t datalen;
-	/* only unsigned long because python 2.4, should be Py_ssize_t */
-	unsigned long offset, stop;
+	Py_ssize_t offset, stop;
 	PyObject *markers = NULL;
 
-	/* replace kk with nn when we drop Python 2.4 */
-	if (!PyArg_ParseTuple(args, "s#kk", &data, &datalen, &offset, &stop)) {
+	if (!PyArg_ParseTuple(args, "s#nn", &data, &datalen, &offset, &stop)) {
 		return NULL;
 	}
 	data += offset;
--- a/mercurial/pathencode.c	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/pathencode.c	Fri Sep 25 23:10:47 2015 -0500
@@ -684,6 +684,8 @@
 
 	hashobj = PyObject_CallMethod(shaobj, "digest", "");
 	Py_DECREF(shaobj);
+	if (hashobj == NULL)
+		return -1;
 
 	if (!PyString_Check(hashobj) || PyString_GET_SIZE(hashobj) != 20) {
 		PyErr_SetString(PyExc_TypeError,
--- a/mercurial/pathutil.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/pathutil.py	Fri Sep 25 23:10:47 2015 -0500
@@ -1,8 +1,15 @@
-import os, errno, stat, posixpath
+from __future__ import absolute_import
 
-import encoding
-import util
-from i18n import _
+import errno
+import os
+import posixpath
+import stat
+
+from .i18n import _
+from . import (
+    encoding,
+    util,
+)
 
 def _lowerclean(s):
     return encoding.hfsignoreclean(s.lower())
--- a/mercurial/peer.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/peer.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,11 +6,91 @@
 # 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 error
+from __future__ import absolute_import
+
+from .i18n import _
+from . import (
+    error,
+    util,
+)
+
+# abstract batching support
+
+class future(object):
+    '''placeholder for a value to be set later'''
+    def set(self, value):
+        if util.safehasattr(self, 'value'):
+            raise error.RepoError("future is already set")
+        self.value = value
+
+class batcher(object):
+    '''base class for batches of commands submittable in a single request
+
+    All methods invoked on instances of this class are simply queued and
+    return a a future for the result. Once you call submit(), all the queued
+    calls are performed and the results set in their respective futures.
+    '''
+    def __init__(self):
+        self.calls = []
+    def __getattr__(self, name):
+        def call(*args, **opts):
+            resref = future()
+            self.calls.append((name, args, opts, resref,))
+            return resref
+        return call
+    def submit(self):
+        pass
+
+class localbatch(batcher):
+    '''performs the queued calls directly'''
+    def __init__(self, local):
+        batcher.__init__(self)
+        self.local = local
+    def submit(self):
+        for name, args, opts, resref in self.calls:
+            resref.set(getattr(self.local, name)(*args, **opts))
+
+def batchable(f):
+    '''annotation for batchable methods
+
+    Such methods must implement a coroutine as follows:
+
+    @batchable
+    def sample(self, one, two=None):
+        # Handle locally computable results first:
+        if not one:
+            yield "a local result", None
+        # Build list of encoded arguments suitable for your wire protocol:
+        encargs = [('one', encode(one),), ('two', encode(two),)]
+        # Create future for injection of encoded result:
+        encresref = future()
+        # Return encoded arguments and future:
+        yield encargs, encresref
+        # Assuming the future to be filled with the result from the batched
+        # request now. Decode it:
+        yield decode(encresref.value)
+
+    The decorator returns a function which wraps this coroutine as a plain
+    method, but adds the original method as an attribute called "batchable",
+    which is used by remotebatch to split the call into separate encoding and
+    decoding phases.
+    '''
+    def plain(*args, **opts):
+        batchable = f(*args, **opts)
+        encargsorres, encresref = batchable.next()
+        if not encresref:
+            return encargsorres # a local result in this case
+        self = args[0]
+        encresref.set(self._submitone(f.func_name, encargsorres))
+        return batchable.next()
+    setattr(plain, 'batchable', f)
+    return plain
 
 class peerrepository(object):
 
+    def batch(self):
+        return localbatch(self)
+
     def capable(self, name):
         '''tell whether repo supports named capability.
         return False if not supported.
--- a/mercurial/phases.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/phases.py	Fri Sep 25 23:10:47 2015 -0500
@@ -100,11 +100,23 @@
 
 """
 
-import os
+from __future__ import absolute_import
+
 import errno
-from node import nullid, nullrev, bin, hex, short
-from i18n import _
-import util, error
+import os
+
+from .i18n import _
+from .node import (
+    bin,
+    hex,
+    nullid,
+    nullrev,
+    short,
+)
+from . import (
+    error,
+    util,
+)
 
 allphases = public, draft, secret = range(3)
 trackedphases = allphases[1:]
--- a/mercurial/posix.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/posix.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,11 +5,26 @@
 # 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 encoding
-import os, sys, errno, stat, getpass, pwd, grp, socket, tempfile, unicodedata
+from __future__ import absolute_import
+
+import errno
+import fcntl
+import getpass
+import grp
+import os
+import pwd
+import re
 import select
-import fcntl, re
+import socket
+import stat
+import sys
+import tempfile
+import unicodedata
+
+from .i18n import _
+from . import (
+    encoding,
+)
 
 posixfile = open
 normpath = os.path.normpath
@@ -335,7 +350,7 @@
         return '"%s"' % s
     global _needsshellquote
     if _needsshellquote is None:
-        _needsshellquote = re.compile(r'[^a-zA-Z0-9._/-]').search
+        _needsshellquote = re.compile(r'[^a-zA-Z0-9._/+-]').search
     if s and not _needsshellquote(s):
         # "s" shouldn't have to be quoted
         return s
@@ -459,7 +474,8 @@
 
 def termwidth():
     try:
-        import termios, array
+        import array
+        import termios
         for dev in (sys.stderr, sys.stdout, sys.stdin):
             try:
                 try:
--- a/mercurial/progress.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/progress.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,13 +5,14 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import sys
-import time
 import threading
-from mercurial import encoding
+import time
 
-from mercurial.i18n import _
-
+from .i18n import _
+from . import encoding
 
 def spacejoin(*args):
     return ' '.join(s for s in args if s)
--- a/mercurial/pushkey.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/pushkey.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,7 +5,14 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import bookmarks, phases, obsolete, encoding
+from __future__ import absolute_import
+
+from . import (
+    bookmarks,
+    encoding,
+    obsolete,
+    phases,
+)
 
 def _nslist(repo):
     n = {}
--- a/mercurial/repair.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/repair.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,11 +6,19 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from mercurial import changegroup, exchange, util, bundle2
-from mercurial.node import short
-from mercurial.i18n import _
+from __future__ import absolute_import
+
 import errno
 
+from .i18n import _
+from .node import short
+from . import (
+    bundle2,
+    changegroup,
+    exchange,
+    util,
+)
+
 def _bundle(repo, bases, heads, node, suffix, compress=True):
     """create a bundle with the specified revisions as a backup"""
     usebundle2 = (repo.ui.configbool('experimental', 'bundle2-exp', True) and
--- a/mercurial/repoview.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/repoview.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,15 +6,20 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import heapq
+from __future__ import absolute_import
+
 import copy
-import error
-import phases
-import util
-import obsolete
+import heapq
 import struct
-import tags as tagsmod
-from node import nullrev
+
+from .node import nullrev
+from . import (
+    error,
+    obsolete,
+    phases,
+    tags as tagsmod,
+    util,
+)
 
 def hideablerevs(repo):
     """Revisions candidates to be hidden
--- a/mercurial/revlog.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/revlog.py	Fri Sep 25 23:10:47 2015 -0500
@@ -100,11 +100,10 @@
 #  4 bytes: compressed length
 #  4 bytes: base rev
 #  4 bytes: link rev
-# 32 bytes: parent 1 nodeid
-# 32 bytes: parent 2 nodeid
-# 32 bytes: nodeid
+# 20 bytes: parent 1 nodeid
+# 20 bytes: parent 2 nodeid
+# 20 bytes: nodeid
 indexformatv0 = ">4l20s20s20s"
-v0shaoffset = 56
 
 class revlogoldio(object):
     def __init__(self):
@@ -150,7 +149,6 @@
 #  4 bytes: parent 2 rev
 # 32 bytes: nodeid
 indexformatng = ">Qiiiiii20s12x"
-ngshaoffset = 32
 versionformat = ">I"
 
 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
@@ -212,6 +210,7 @@
         self._chunkcache = (0, '')
         self._chunkcachesize = 65536
         self._maxchainlen = None
+        self._aggressivemergedeltas = False
         self.index = []
         self._pcache = {}
         self._nodecache = {nullid: nullrev}
@@ -229,6 +228,8 @@
                 self._chunkcachesize = opts['chunkcachesize']
             if 'maxchainlen' in opts:
                 self._maxchainlen = opts['maxchainlen']
+            if 'aggressivemergedeltas' in opts:
+                self._aggressivemergedeltas = opts['aggressivemergedeltas']
 
         if self._chunkcachesize <= 0:
             raise RevlogError(_('revlog chunk cache size %r is not greater '
@@ -237,14 +238,14 @@
             raise RevlogError(_('revlog chunk cache size %r is not a power '
                                 'of 2') % self._chunkcachesize)
 
-        i = ''
+        indexdata = ''
         self._initempty = True
         try:
             f = self.opener(self.indexfile)
-            i = f.read()
+            indexdata = f.read()
             f.close()
-            if len(i) > 0:
-                v = struct.unpack(versionformat, i[:4])[0]
+            if len(indexdata) > 0:
+                v = struct.unpack(versionformat, indexdata[:4])[0]
                 self._initempty = False
         except IOError as inst:
             if inst.errno != errno.ENOENT:
@@ -269,7 +270,7 @@
         if self.version == REVLOGV0:
             self._io = revlogoldio()
         try:
-            d = self._io.parseindex(i, self._inline)
+            d = self._io.parseindex(indexdata, self._inline)
         except (ValueError, IndexError):
             raise RevlogError(_("index %s is corrupted") % (self.indexfile))
         self.index, nodemap, self._chunkcache = d
@@ -1048,14 +1049,13 @@
             node = nodeorrev
             rev = None
 
-        _cache = self._cache # grab local copy of cache to avoid thread race
         cachedrev = None
         if node == nullid:
             return ""
-        if _cache:
-            if _cache[0] == node:
-                return _cache[2]
-            cachedrev = _cache[1]
+        if self._cache:
+            if self._cache[0] == node:
+                return self._cache[2]
+            cachedrev = self._cache[1]
 
         # look up what we need to read
         text = None
@@ -1083,7 +1083,7 @@
 
         if iterrev == cachedrev:
             # cache hit
-            text = _cache[2]
+            text = self._cache[2]
         else:
             chain.append(iterrev)
         chain.reverse()
@@ -1235,8 +1235,27 @@
             return ('u', text)
         return ("", bin)
 
+    def _isgooddelta(self, d, textlen):
+        """Returns True if the given delta is good. Good means that it is within
+        the disk span, disk size, and chain length bounds that we know to be
+        performant."""
+        if d is None:
+            return False
+
+        # - 'dist' is the distance from the base revision -- bounding it limits
+        #   the amount of I/O we need to do.
+        # - 'compresseddeltalen' is the sum of the total size of deltas we need
+        #   to apply -- bounding it limits the amount of CPU we consume.
+        dist, l, data, base, chainbase, chainlen, compresseddeltalen = d
+        if (dist > textlen * 4 or l > textlen or
+            compresseddeltalen > textlen * 2 or
+            (self._maxchainlen and chainlen > self._maxchainlen)):
+            return False
+
+        return True
+
     def _addrevision(self, node, text, transaction, link, p1, p2, flags,
-                     cachedelta, ifh, dfh):
+                     cachedelta, ifh, dfh, alwayscache=False):
         """internal function to add revisions to the log
 
         see addrevision for argument descriptions.
@@ -1315,19 +1334,6 @@
         basecache = self._basecache
         p1r, p2r = self.rev(p1), self.rev(p2)
 
-        # should we try to build a delta?
-        if prev != nullrev:
-            if self._generaldelta:
-                if p1r >= basecache[1]:
-                    d = builddelta(p1r)
-                elif p2r >= basecache[1]:
-                    d = builddelta(p2r)
-                else:
-                    d = builddelta(prev)
-            else:
-                d = builddelta(prev)
-            dist, l, data, base, chainbase, chainlen, compresseddeltalen = d
-
         # full versions are inserted when the needed deltas
         # become comparable to the uncompressed text
         if text is None:
@@ -1336,13 +1342,42 @@
         else:
             textlen = len(text)
 
-        # - 'dist' is the distance from the base revision -- bounding it limits
-        #   the amount of I/O we need to do.
-        # - 'compresseddeltalen' is the sum of the total size of deltas we need
-        #   to apply -- bounding it limits the amount of CPU we consume.
-        if (d is None or dist > textlen * 4 or l > textlen or
-            compresseddeltalen > textlen * 2 or
-            (self._maxchainlen and chainlen > self._maxchainlen)):
+        # should we try to build a delta?
+        if prev != nullrev:
+            if self._generaldelta:
+                if p2r != nullrev and self._aggressivemergedeltas:
+                    d = builddelta(p1r)
+                    d2 = builddelta(p2r)
+                    p1good = self._isgooddelta(d, textlen)
+                    p2good = self._isgooddelta(d2, textlen)
+                    if p1good and p2good:
+                        # If both are good deltas, choose the smallest
+                        if d2[1] < d[1]:
+                            d = d2
+                    elif p2good:
+                        # If only p2 is good, use it
+                        d = d2
+                    elif p1good:
+                        pass
+                    else:
+                        # Neither is good, try against prev to hopefully save us
+                        # a fulltext.
+                        d = builddelta(prev)
+                else:
+                    # Pick whichever parent is closer to us (to minimize the
+                    # chance of having to build a fulltext). Since
+                    # nullrev == -1, any non-merge commit will always pick p1r.
+                    drev = p2r if p2r > p1r else p1r
+                    d = builddelta(drev)
+                    # If the chosen delta will result in us making a full text,
+                    # give it one last try against prev.
+                    if drev != prev and not self._isgooddelta(d, textlen):
+                        d = builddelta(prev)
+            else:
+                d = builddelta(prev)
+            dist, l, data, base, chainbase, chainlen, compresseddeltalen = d
+
+        if not self._isgooddelta(d, textlen):
             text = buildtext()
             data = self.compress(text)
             l = len(data[1]) + len(data[0])
@@ -1356,6 +1391,9 @@
         entry = self._io.packentry(e, self.node, self.version, curr)
         self._writeentry(transaction, ifh, dfh, entry, data, link, offset)
 
+        if alwayscache and text is None:
+            text = buildtext()
+
         if type(text) == str: # only accept immutable objects
             self._cache = (node, curr, text)
         self._basecache = (curr, chainbase)
@@ -1459,15 +1497,16 @@
                 if self._peek_iscensored(baserev, delta, flush):
                     flags |= REVIDX_ISCENSORED
 
+                # We assume consumers of addrevisioncb will want to retrieve
+                # the added revision, which will require a call to
+                # revision(). revision() will fast path if there is a cache
+                # hit. So, we tell _addrevision() to always cache in this case.
                 chain = self._addrevision(node, None, transaction, link,
                                           p1, p2, flags, (baserev, delta),
-                                          ifh, dfh)
+                                          ifh, dfh,
+                                          alwayscache=bool(addrevisioncb))
 
                 if addrevisioncb:
-                    # Data for added revision can't be read unless flushed
-                    # because _loadchunk always opensa new file handle and
-                    # there is no guarantee data was actually written yet.
-                    flush()
                     addrevisioncb(self, chain)
 
                 if not dfh and not self._inline:
--- a/mercurial/revset.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/revset.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,16 +5,25 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import re
-import parser, util, error, hbisect, phases
-import node
+from __future__ import absolute_import
+
 import heapq
-import match as matchmod
-from i18n import _
-import encoding
-import obsolete as obsmod
-import pathutil
-import repoview
+import re
+
+from .i18n import _
+from . import (
+    encoding,
+    error,
+    hbisect,
+    match as matchmod,
+    node,
+    obsolete as obsmod,
+    parser,
+    pathutil,
+    phases,
+    repoview,
+    util,
+)
 
 def _revancestors(repo, revs, followfirst):
     """Like revlog.ancestors(), but supports followfirst."""
@@ -78,19 +87,17 @@
 
     return generatorset(iterate(), iterasc=True)
 
-def _revsbetween(repo, roots, heads):
-    """Return all paths between roots and heads, inclusive of both endpoint
-    sets."""
+def _reachablerootspure(repo, minroot, roots, heads, includepath):
+    """return (heads(::<roots> and ::<heads>))
+
+    If includepath is True, return (<roots>::<heads>)."""
     if not roots:
-        return baseset()
+        return []
     parentrevs = repo.changelog.parentrevs
+    roots = set(roots)
     visit = list(heads)
     reachable = set()
     seen = {}
-    # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
-    # (and if it is not, it should.)
-    minroot = min(roots)
-    roots = set(roots)
     # prefetch all the things! (because python is slow)
     reached = reachable.add
     dovisit = visit.append
@@ -101,6 +108,8 @@
         rev = nextvisit()
         if rev in roots:
             reached(rev)
+            if not includepath:
+                continue
         parents = parentrevs(rev)
         seen[rev] = parents
         for parent in parents:
@@ -108,11 +117,30 @@
                 dovisit(parent)
     if not reachable:
         return baseset()
+    if not includepath:
+        return reachable
     for rev in sorted(seen):
         for parent in seen[rev]:
             if parent in reachable:
                 reached(rev)
-    return baseset(sorted(reachable))
+    return reachable
+
+def reachableroots(repo, roots, heads, includepath=False):
+    """return (heads(::<roots> and ::<heads>))
+
+    If includepath is True, return (<roots>::<heads>)."""
+    if not roots:
+        return baseset()
+    minroot = roots.min()
+    roots = list(roots)
+    heads = list(heads)
+    try:
+        revs = repo.changelog.reachableroots(minroot, heads, roots, includepath)
+    except AttributeError:
+        revs = _reachablerootspure(repo, minroot, roots, heads, includepath)
+    revs = baseset(revs)
+    revs.sort()
+    return revs
 
 elements = {
     # token-type: binding-strength, primary, prefix, infix, suffix
@@ -178,6 +206,21 @@
     if symletters is None:
         symletters = _symletters
 
+    if program and lookup:
+        # attempt to parse old-style ranges first to deal with
+        # things like old-tag which contain query metacharacters
+        parts = program.split(':', 1)
+        if all(lookup(sym) for sym in parts if sym):
+            if parts[0]:
+                yield ('symbol', parts[0], 0)
+            if len(parts) > 1:
+                s = len(parts[0])
+                yield (':', None, s)
+                if parts[1]:
+                    yield ('symbol', parts[1], s + 1)
+            yield ('end', None, len(program))
+            return
+
     pos, l = 0, len(program)
     while pos < l:
         c = program[pos]
@@ -201,7 +244,7 @@
                 c = program[pos]
                 decode = lambda x: x
             else:
-                decode = lambda x: x.decode('string-escape')
+                decode = parser.unescapestr
             pos += 1
             s = pos
             while pos < l: # find closing quote
@@ -382,7 +425,8 @@
 
 def dagrange(repo, subset, x, y):
     r = fullreposet(repo)
-    xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
+    xs = reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
+                         includepath=True)
     # XXX We should combine with subset first: 'subset & baseset(...)'. This is
     # necessary to ensure we preserve the order in subset.
     return xs & subset
@@ -391,8 +435,13 @@
     return getset(repo, getset(repo, subset, x), y)
 
 def orset(repo, subset, *xs):
-    rs = [getset(repo, subset, x) for x in xs]
-    return _combinesets(rs)
+    assert xs
+    if len(xs) == 1:
+        return getset(repo, subset, xs[0])
+    p = len(xs) // 2
+    a = orset(repo, subset, *xs[:p])
+    b = orset(repo, subset, *xs[p:])
+    return a + b
 
 def notset(repo, subset, x):
     return subset - getset(repo, subset, x)
@@ -414,6 +463,116 @@
 
 # functions
 
+def _mergedefaultdest(repo, subset, x):
+    # ``_mergedefaultdest()``
+
+    # default destination for merge.
+    # # XXX: Currently private because I expect the signature to change.
+    # # XXX: - taking rev as arguments,
+    # # XXX: - bailing out in case of ambiguity vs returning all data.
+    getargs(x, 0, 0, _("_mergedefaultdest takes no arguments"))
+    if repo._activebookmark:
+        bmheads = repo.bookmarkheads(repo._activebookmark)
+        curhead = repo[repo._activebookmark].node()
+        if len(bmheads) == 2:
+            if curhead == bmheads[0]:
+                node = bmheads[1]
+            else:
+                node = bmheads[0]
+        elif len(bmheads) > 2:
+            raise util.Abort(_("multiple matching bookmarks to merge - "
+                "please merge with an explicit rev or bookmark"),
+                hint=_("run 'hg heads' to see all heads"))
+        elif len(bmheads) <= 1:
+            raise util.Abort(_("no matching bookmark to merge - "
+                "please merge with an explicit rev or bookmark"),
+                hint=_("run 'hg heads' to see all heads"))
+    else:
+        branch = repo[None].branch()
+        bheads = repo.branchheads(branch)
+        nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
+
+        if len(nbhs) > 2:
+            raise util.Abort(_("branch '%s' has %d heads - "
+                               "please merge with an explicit rev")
+                             % (branch, len(bheads)),
+                             hint=_("run 'hg heads .' to see heads"))
+
+        parent = repo.dirstate.p1()
+        if len(nbhs) <= 1:
+            if len(bheads) > 1:
+                raise util.Abort(_("heads are bookmarked - "
+                                   "please merge with an explicit rev"),
+                                 hint=_("run 'hg heads' to see all heads"))
+            if len(repo.heads()) > 1:
+                raise util.Abort(_("branch '%s' has one head - "
+                                   "please merge with an explicit rev")
+                                 % branch,
+                                 hint=_("run 'hg heads' to see all heads"))
+            msg, hint = _('nothing to merge'), None
+            if parent != repo.lookup(branch):
+                hint = _("use 'hg update' instead")
+            raise util.Abort(msg, hint=hint)
+
+        if parent not in bheads:
+            raise util.Abort(_('working directory not at a head revision'),
+                             hint=_("use 'hg update' or merge with an "
+                                    "explicit revision"))
+        if parent == nbhs[0]:
+            node = nbhs[-1]
+        else:
+            node = nbhs[0]
+    return subset & baseset([repo[node].rev()])
+
+def _updatedefaultdest(repo, subset, x):
+    # ``_updatedefaultdest()``
+
+    # default destination for update.
+    # # XXX: Currently private because I expect the signature to change.
+    # # XXX: - taking rev as arguments,
+    # # XXX: - bailing out in case of ambiguity vs returning all data.
+    getargs(x, 0, 0, _("_updatedefaultdest takes no arguments"))
+    # Here is where we should consider bookmarks, divergent bookmarks,
+    # foreground changesets (successors), and tip of current branch;
+    # but currently we are only checking the branch tips.
+    node = None
+    wc = repo[None]
+    p1 = wc.p1()
+    try:
+        node = repo.branchtip(wc.branch())
+    except error.RepoLookupError:
+        if wc.branch() == 'default': # no default branch!
+            node = repo.lookup('tip') # update to tip
+        else:
+            raise util.Abort(_("branch %s not found") % wc.branch())
+
+    if p1.obsolete() and not p1.children():
+        # allow updating to successors
+        successors = obsmod.successorssets(repo, p1.node())
+
+        # behavior of certain cases is as follows,
+        #
+        # divergent changesets: update to highest rev, similar to what
+        #     is currently done when there are more than one head
+        #     (i.e. 'tip')
+        #
+        # replaced changesets: same as divergent except we know there
+        # is no conflict
+        #
+        # pruned changeset: no update is done; though, we could
+        #     consider updating to the first non-obsolete parent,
+        #     similar to what is current done for 'hg prune'
+
+        if successors:
+            # flatten the list here handles both divergent (len > 1)
+            # and the usual case (len = 1)
+            successors = [n for sub in successors for n in sub]
+
+            # get the max revision for the given successors set,
+            # i.e. the 'tip' of a set
+            node = repo.revs('max(%ln)', successors).first()
+    return subset & baseset([repo[node].rev()])
+
 def adds(repo, subset, x):
     """``adds(pattern)``
     Changesets that add a file matching pattern.
@@ -990,34 +1149,37 @@
     return limit(repo, subset, x)
 
 def _follow(repo, subset, x, name, followfirst=False):
-    l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
+    l = getargs(x, 0, 1, _("%s takes no arguments or a pattern") % name)
     c = repo['.']
     if l:
-        x = getstring(l[0], _("%s expected a filename") % name)
-        if x in c:
-            cx = c[x]
-            s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
-            # include the revision responsible for the most recent version
-            s.add(cx.introrev())
-        else:
-            return baseset()
+        x = getstring(l[0], _("%s expected a pattern") % name)
+        matcher = matchmod.match(repo.root, repo.getcwd(), [x],
+                                 ctx=repo[None], default='path')
+
+        s = set()
+        for fname in c:
+            if matcher(fname):
+                fctx = c[fname]
+                s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
+                # include the revision responsible for the most recent version
+                s.add(fctx.introrev())
     else:
         s = _revancestors(repo, baseset([c.rev()]), followfirst)
 
     return subset & s
 
 def follow(repo, subset, x):
-    """``follow([file])``
+    """``follow([pattern])``
     An alias for ``::.`` (ancestors of the working directory's first parent).
-    If a filename is specified, the history of the given file is followed,
-    including copies.
+    If pattern is specified, the histories of files matching given
+    pattern is followed, including copies.
     """
     return _follow(repo, subset, x, 'follow')
 
 def _followfirst(repo, subset, x):
-    # ``followfirst([file])``
-    # Like ``follow([file])`` but follows only the first parent of
-    # every revision or file revision.
+    # ``followfirst([pattern])``
+    # Like ``follow([pattern])`` but follows only the first parent of
+    # every revisions or files revisions.
     return _follow(repo, subset, x, '_followfirst', followfirst=True)
 
 def getall(repo, subset, x):
@@ -1225,10 +1387,14 @@
     Changeset with highest revision number in set.
     """
     os = getset(repo, fullreposet(repo), x)
-    if os:
+    try:
         m = os.max()
         if m in subset:
             return baseset([m])
+    except ValueError:
+        # os.max() throws a ValueError when the collection is empty.
+        # Same as python's max().
+        pass
     return baseset()
 
 def merge(repo, subset, x):
@@ -1264,10 +1430,14 @@
     Changeset with lowest revision number in set.
     """
     os = getset(repo, fullreposet(repo), x)
-    if os:
+    try:
         m = os.min()
         if m in subset:
             return baseset([m])
+    except ValueError:
+        # os.min() throws a ValueError when the collection is empty.
+        # Same as python's min().
+        pass
     return baseset()
 
 def modifies(repo, subset, x):
@@ -1415,8 +1585,10 @@
     default push location.
     """
     # Avoid cycles.
-    import discovery
-    import hg
+    from . import (
+        discovery,
+        hg,
+    )
     # i18n: "outgoing" is a keyword
     l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
     # i18n: "outgoing" is a keyword
@@ -1597,7 +1769,7 @@
     synonym for the current local branch.
     """
 
-    import hg # avoid start-up nasties
+    from . import hg # avoid start-up nasties
     # i18n: "remote" is a keyword
     l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
 
@@ -2013,14 +2185,17 @@
             r = int(t)
             if str(r) != t or r not in cl:
                 raise ValueError
+            revs = [r]
         except ValueError:
-            r = repo[t].rev()
-        if r in seen:
-            continue
-        if (r in subset
-            or r == node.nullrev and isinstance(subset, fullreposet)):
-            ls.append(r)
-        seen.add(r)
+            revs = stringset(repo, subset, t)
+
+        for r in revs:
+            if r in seen:
+                continue
+            if (r in subset
+                or r == node.nullrev and isinstance(subset, fullreposet)):
+                ls.append(r)
+            seen.add(r)
     return baseset(ls)
 
 # for internal use
@@ -2043,6 +2218,8 @@
     return baseset([r for r in ls if r in s])
 
 symbols = {
+    "_mergedefaultdest": _mergedefaultdest,
+    "_updatedefaultdest": _updatedefaultdest,
     "adds": adds,
     "all": getall,
     "ancestor": ancestor,
@@ -2654,6 +2831,27 @@
     if repo:
         lookup = repo.__contains__
     tree = parse(spec, lookup)
+    return _makematcher(ui, tree, repo)
+
+def matchany(ui, specs, repo=None):
+    """Create a matcher that will include any revisions matching one of the
+    given specs"""
+    if not specs:
+        def mfunc(repo, subset=None):
+            return baseset()
+        return mfunc
+    if not all(specs):
+        raise error.ParseError(_("empty query"))
+    lookup = None
+    if repo:
+        lookup = repo.__contains__
+    if len(specs) == 1:
+        tree = parse(specs[0], lookup)
+    else:
+        tree = ('or',) + tuple(parse(s, lookup) for s in specs)
+    return _makematcher(ui, tree, repo)
+
+def _makematcher(ui, tree, repo):
     if ui:
         tree = findaliases(ui, tree, showwarning=ui.warn)
     tree = foldconcat(tree)
@@ -2813,6 +3011,7 @@
         """True if the set will iterate in descending order"""
         raise NotImplementedError()
 
+    @util.cachefunc
     def min(self):
         """return the minimum element in the set"""
         if self.fastasc is not None:
@@ -2821,6 +3020,7 @@
             raise ValueError('arg is an empty sequence')
         return min(self)
 
+    @util.cachefunc
     def max(self):
         """return the maximum element in the set"""
         if self.fastdesc is not None:
@@ -2896,6 +3096,8 @@
     """
     def __init__(self, data=()):
         if not isinstance(data, list):
+            if isinstance(data, set):
+                self._set = data
             data = list(data)
         self._list = data
         self._ascending = None
@@ -2995,14 +3197,9 @@
         """
         self._subset = subset
         self._condition = condition
-        self._cache = {}
 
     def __contains__(self, x):
-        c = self._cache
-        if x not in c:
-            v = c[x] = x in self._subset and self._condition(x)
-            return v
-        return c[x]
+        return x in self._subset and self._condition(x)
 
     def __iter__(self):
         return self._iterfilter(self._subset)
@@ -3028,7 +3225,15 @@
         return lambda: self._iterfilter(it())
 
     def __nonzero__(self):
-        for r in self:
+        fast = self.fastasc
+        if fast is None:
+            fast = self.fastdesc
+        if fast is not None:
+            it = fast()
+        else:
+            it = self
+
+        for r in it:
             return True
         return False
 
@@ -3073,20 +3278,6 @@
     def __repr__(self):
         return '<%s %r>' % (type(self).__name__, self._subset)
 
-# this function will be removed, or merged to addset or orset, when
-# - scmutil.revrange() can be rewritten to not combine calculated smartsets
-# - or addset can handle more than two sets without balanced tree
-def _combinesets(subsets):
-    """Create balanced tree of addsets representing union of given sets"""
-    if not subsets:
-        return baseset()
-    if len(subsets) == 1:
-        return subsets[0]
-    p = len(subsets) // 2
-    xs = _combinesets(subsets[:p])
-    ys = _combinesets(subsets[p:])
-    return addset(xs, ys)
-
 def _iterordered(ascending, iter1, iter2):
     """produce an ordered iteration from two iterators with the same order
 
--- a/mercurial/scmutil.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/scmutil.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,7 +6,7 @@
 # GNU General Public License version 2 or any later version.
 
 from i18n import _
-from mercurial.node import nullrev, wdirrev
+from mercurial.node import wdirrev
 import util, error, osutil, revset, similar, encoding, phases
 import pathutil
 import match as matchmod
@@ -586,6 +586,8 @@
             raise util.Abort('this vfs is read only')
         return self.vfs(path, mode, *args, **kw)
 
+    def join(self, path, *insidef):
+        return self.vfs.join(path, *insidef)
 
 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
     '''yield every hg repository under path, always recursively.
@@ -690,6 +692,11 @@
         raise util.Abort(_('empty revision set'))
     return repo[l.last()]
 
+def _pairspec(revspec):
+    tree = revset.parse(revspec)
+    tree = revset.optimize(tree, True)[1]  # fix up "x^:y" -> "(x^):y"
+    return tree and tree[0] in ('range', 'rangepre', 'rangepost', 'rangeall')
+
 def revpair(repo, revs):
     if not revs:
         return repo.dirstate.p1(), None
@@ -711,67 +718,21 @@
     if first is None:
         raise util.Abort(_('empty revision range'))
 
-    if first == second and len(revs) == 1 and _revrangesep not in revs[0]:
+    # if top-level is range expression, the result must always be a pair
+    if first == second and len(revs) == 1 and not _pairspec(revs[0]):
         return repo.lookup(first), None
 
     return repo.lookup(first), repo.lookup(second)
 
-_revrangesep = ':'
-
 def revrange(repo, revs):
     """Yield revision as strings from a list of revision specifications."""
-
-    def revfix(repo, val, defval):
-        if not val and val != 0 and defval is not None:
-            return defval
-        return repo[val].rev()
-
-    subsets = []
-
-    revsetaliases = [alias for (alias, _) in
-                     repo.ui.configitems("revsetalias")]
-
+    allspecs = []
     for spec in revs:
-        # attempt to parse old-style ranges first to deal with
-        # things like old-tag which contain query metacharacters
-        try:
-            # ... except for revset aliases without arguments. These
-            # should be parsed as soon as possible, because they might
-            # clash with a hash prefix.
-            if spec in revsetaliases:
-                raise error.RepoLookupError
-
-            if isinstance(spec, int):
-                subsets.append(revset.baseset([spec]))
-                continue
-
-            if _revrangesep in spec:
-                start, end = spec.split(_revrangesep, 1)
-                if start in revsetaliases or end in revsetaliases:
-                    raise error.RepoLookupError
-
-                start = revfix(repo, start, 0)
-                end = revfix(repo, end, len(repo) - 1)
-                if end == nullrev and start < 0:
-                    start = nullrev
-                if start < end:
-                    l = revset.spanset(repo, start, end + 1)
-                else:
-                    l = revset.spanset(repo, start, end - 1)
-                subsets.append(l)
-                continue
-            elif spec and spec in repo: # single unquoted rev
-                rev = revfix(repo, spec, None)
-                subsets.append(revset.baseset([rev]))
-                continue
-        except error.RepoLookupError:
-            pass
-
-        # fall through to new-style queries if old-style fails
-        m = revset.match(repo.ui, spec, repo)
-        subsets.append(m(repo))
-
-    return revset._combinesets(subsets)
+        if isinstance(spec, int):
+            spec = revset.formatspec('rev(%d)', spec)
+        allspecs.append(spec)
+    m = revset.matchany(repo.ui, allspecs, repo)
+    return m(repo)
 
 def expandpats(pats):
     '''Expand bare globs when running on windows.
@@ -792,13 +753,15 @@
         ret.append(kindpat)
     return ret
 
-def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath',
+def matchandpats(ctx, pats=(), opts=None, globbed=False, default='relpath',
                  badfn=None):
     '''Return a matcher and the patterns that were used.
     The matcher will warn about bad matches, unless an alternate badfn callback
     is provided.'''
     if pats == ("",):
         pats = []
+    if opts is None:
+        opts = {}
     if not globbed and default == 'relpath':
         pats = expandpats(pats or [])
 
@@ -815,7 +778,8 @@
         pats = []
     return m, pats
 
-def match(ctx, pats=[], opts={}, globbed=False, default='relpath', badfn=None):
+def match(ctx, pats=(), opts=None, globbed=False, default='relpath',
+          badfn=None):
     '''Return a matcher that will warn about bad matches.'''
     return matchandpats(ctx, pats, opts, globbed, default, badfn=badfn)[0]
 
@@ -827,7 +791,9 @@
     '''Return a matcher that will efficiently match exactly these files.'''
     return matchmod.exact(repo.root, repo.getcwd(), files, badfn=badfn)
 
-def addremove(repo, matcher, prefix, opts={}, dry_run=None, similarity=None):
+def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None):
+    if opts is None:
+        opts = {}
     m = matcher
     if dry_run is None:
         dry_run = opts.get('dry_run')
@@ -1103,7 +1069,7 @@
     Mercurial either atomic renames or appends for files under .hg,
     so to ensure the cache is reliable we need the filesystem to be able
     to tell us if a file has been replaced. If it can't, we fallback to
-    recreating the object on every call (essentially the same behaviour as
+    recreating the object on every call (essentially the same behavior as
     propertycache).
 
     '''
--- a/mercurial/setdiscovery.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/setdiscovery.py	Fri Sep 25 23:10:47 2015 -0500
@@ -40,11 +40,20 @@
 classified with it (since all ancestors or descendants will be marked as well).
 """
 
+from __future__ import absolute_import
+
 import collections
-from node import nullid, nullrev
-from i18n import _
 import random
-import util, dagutil
+
+from .i18n import _
+from .node import (
+    nullid,
+    nullrev,
+)
+from . import (
+    dagutil,
+    util,
+)
 
 def _updatesample(dag, nodes, sample, quicksamplesize=0):
     """update an existing sample to match the expected size
@@ -138,22 +147,12 @@
     sample = _limitsample(ownheads, initialsamplesize)
     # indices between sample and externalized version must match
     sample = list(sample)
-    if remote.local():
-        # stopgap until we have a proper localpeer that supports batch()
-        srvheadhashes = remote.heads()
-        yesno = remote.known(dag.externalizeall(sample))
-    elif remote.capable('batch'):
-        batch = remote.batch()
-        srvheadhashesref = batch.heads()
-        yesnoref = batch.known(dag.externalizeall(sample))
-        batch.submit()
-        srvheadhashes = srvheadhashesref.value
-        yesno = yesnoref.value
-    else:
-        # compatibility with pre-batch, but post-known remotes during 1.9
-        # development
-        srvheadhashes = remote.heads()
-        sample = []
+    batch = remote.batch()
+    srvheadhashesref = batch.heads()
+    yesnoref = batch.known(dag.externalizeall(sample))
+    batch.submit()
+    srvheadhashes = srvheadhashesref.value
+    yesno = yesnoref.value
 
     if cl.tip() == nullid:
         if srvheadhashes != [nullid]:
--- a/mercurial/simplemerge.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/simplemerge.py	Fri Sep 25 23:10:47 2015 -0500
@@ -16,9 +16,17 @@
 # mbp: "you know that thing where cvs gives you conflict markers?"
 # s: "i hate that."
 
-from i18n import _
-import scmutil, util, mdiff
-import sys, os
+from __future__ import absolute_import
+
+import os
+import sys
+
+from .i18n import _
+from . import (
+    mdiff,
+    scmutil,
+    util,
+)
 
 class CantReprocessAndShowBase(Exception):
     pass
@@ -82,7 +90,8 @@
                     start_marker='<<<<<<<',
                     mid_marker='=======',
                     end_marker='>>>>>>>',
-                    base_marker=None):
+                    base_marker=None,
+                    localorother=None):
         """Return merge in cvs-like form.
         """
         self.conflicts = False
@@ -92,9 +101,9 @@
                 newline = '\r\n'
             elif self.a[0].endswith('\r'):
                 newline = '\r'
-        if name_a:
+        if name_a and start_marker:
             start_marker = start_marker + ' ' + name_a
-        if name_b:
+        if name_b and end_marker:
             end_marker = end_marker + ' ' + name_b
         if name_base and base_marker:
             base_marker = base_marker + ' ' + name_base
@@ -111,18 +120,28 @@
                 for i in range(t[1], t[2]):
                     yield self.b[i]
             elif what == 'conflict':
-                self.conflicts = True
-                yield start_marker + newline
-                for i in range(t[3], t[4]):
-                    yield self.a[i]
-                if base_marker is not None:
-                    yield base_marker + newline
-                    for i in range(t[1], t[2]):
-                        yield self.base[i]
-                yield mid_marker + newline
-                for i in range(t[5], t[6]):
-                    yield self.b[i]
-                yield end_marker + newline
+                if localorother == 'local':
+                    for i in range(t[3], t[4]):
+                        yield self.a[i]
+                elif localorother == 'other':
+                    for i in range(t[5], t[6]):
+                        yield self.b[i]
+                else:
+                    self.conflicts = True
+                    if start_marker is not None:
+                        yield start_marker + newline
+                    for i in range(t[3], t[4]):
+                        yield self.a[i]
+                    if base_marker is not None:
+                        yield base_marker + newline
+                        for i in range(t[1], t[2]):
+                            yield self.base[i]
+                    if mid_marker is not None:
+                        yield mid_marker + newline
+                    for i in range(t[5], t[6]):
+                        yield self.b[i]
+                    if end_marker is not None:
+                        yield end_marker + newline
             else:
                 raise ValueError(what)
 
@@ -345,18 +364,24 @@
                 raise util.Abort(msg)
         return text
 
-    name_a = local
-    name_b = other
-    name_base = None
-    labels = opts.get('label', [])
-    if len(labels) > 0:
-        name_a = labels[0]
-    if len(labels) > 1:
-        name_b = labels[1]
-    if len(labels) > 2:
-        name_base = labels[2]
-    if len(labels) > 3:
-        raise util.Abort(_("can only specify three labels."))
+    mode = opts.get('mode','merge')
+    if mode == 'union':
+        name_a = None
+        name_b = None
+        name_base = None
+    else:
+        name_a = local
+        name_b = other
+        name_base = None
+        labels = opts.get('label', [])
+        if len(labels) > 0:
+            name_a = labels[0]
+        if len(labels) > 1:
+            name_b = labels[1]
+        if len(labels) > 2:
+            name_base = labels[2]
+        if len(labels) > 3:
+            raise util.Abort(_("can only specify three labels."))
 
     try:
         localtext = readfile(local)
@@ -373,8 +398,12 @@
         out = sys.stdout
 
     m3 = Merge3Text(basetext, localtext, othertext)
-    extrakwargs = {}
-    if name_base is not None:
+    extrakwargs = {"localorother": opts.get("localorother", None)}
+    if mode == 'union':
+        extrakwargs['start_marker'] = None
+        extrakwargs['mid_marker'] = None
+        extrakwargs['end_marker'] = None
+    elif name_base is not None:
         extrakwargs['base_marker'] = '|||||||'
         extrakwargs['name_base'] = name_base
     for line in m3.merge_lines(name_a=name_a, name_b=name_b, **extrakwargs):
@@ -383,7 +412,7 @@
     if not opts.get('print'):
         out.close()
 
-    if m3.conflicts:
+    if m3.conflicts and not mode == 'union':
         if not opts.get('quiet'):
             ui.warn(_("warning: conflicts during merge.\n"))
         return 1
--- a/mercurial/sshpeer.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/sshpeer.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,16 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import re
-from i18n import _
-import util, error, wireproto
+
+from .i18n import _
+from . import (
+    error,
+    util,
+    wireproto,
+)
 
 class remotelock(object):
     def __init__(self, repo):
--- a/mercurial/sshserver.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/sshserver.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,8 +6,16 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import util, hook, wireproto
-import os, sys
+from __future__ import absolute_import
+
+import os
+import sys
+
+from . import (
+    hook,
+    util,
+    wireproto,
+)
 
 class sshserver(wireproto.abstractserverproto):
     def __init__(self, ui, repo):
--- a/mercurial/sslutil.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/sslutil.py	Fri Sep 25 23:10:47 2015 -0500
@@ -6,10 +6,15 @@
 #
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
-import os, sys, ssl
+
+from __future__ import absolute_import
 
-from mercurial import util
-from mercurial.i18n import _
+import os
+import ssl
+import sys
+
+from .i18n import _
+from . import util
 
 _canloaddefaultcerts = False
 try:
--- a/mercurial/statichttprepo.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/statichttprepo.py	Fri Sep 25 23:10:47 2015 -0500
@@ -7,10 +7,26 @@
 # 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 changelog, byterange, url, error, namespaces
-import localrepo, manifest, util, scmutil, store
-import urllib, urllib2, errno, os
+from __future__ import absolute_import
+
+import errno
+import os
+import urllib
+import urllib2
+
+from .i18n import _
+from . import (
+    byterange,
+    changelog,
+    error,
+    localrepo,
+    manifest,
+    namespaces,
+    scmutil,
+    store,
+    url,
+    util,
+)
 
 class httprangereader(object):
     def __init__(self, url, opener):
--- a/mercurial/strutil.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/strutil.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,6 +5,8 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 def findall(haystack, needle, start=0, end=None):
     if end is None:
         end = len(haystack)
--- a/mercurial/subrepo.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/subrepo.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,15 +5,34 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import copy
-import errno, os, re, posixpath, sys
+import errno
+import os
+import posixpath
+import re
+import stat
+import subprocess
+import sys
+import tarfile
 import xml.dom.minidom
-import stat, subprocess, tarfile
-from i18n import _
-import config, util, node, error, cmdutil, scmutil, match as matchmod
-import phases
-import pathutil
-import exchange
+
+
+from .i18n import _
+from . import (
+    cmdutil,
+    config,
+    error,
+    exchange,
+    match as matchmod,
+    node,
+    pathutil,
+    phases,
+    scmutil,
+    util,
+)
+
 hg = None
 propertycache = util.propertycache
 
@@ -328,7 +347,7 @@
     # so we manually delay the circular imports to not break
     # scripts that don't use our demand-loading
     global hg
-    import hg as h
+    from . import hg as h
     hg = h
 
     pathutil.pathauditor(ctx.repo().root)(path)
@@ -346,7 +365,7 @@
     # so we manually delay the circular imports to not break
     # scripts that don't use our demand-loading
     global hg
-    import hg as h
+    from . import hg as h
     hg = h
 
     pathutil.pathauditor(ctx.repo().root)(path)
--- a/mercurial/tagmerge.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/tagmerge.py	Fri Sep 25 23:10:47 2015 -0500
@@ -71,11 +71,20 @@
 #         - put blocks whose nodes come all from p2 first
 #     - write the tag blocks in the sorted order
 
-import tags as tagsmod
-import util
-from node import nullid, hex
-from i18n import _
+from __future__ import absolute_import
+
 import operator
+
+from .i18n import _
+from .node import (
+    hex,
+    nullid,
+)
+from .import (
+    tags as tagsmod,
+    util,
+)
+
 hexnullid = hex(nullid)
 
 def readtagsformerge(ui, repo, lines, fn='', keeplinenums=False):
--- a/mercurial/tags.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/tags.py	Fri Sep 25 23:10:47 2015 -0500
@@ -10,15 +10,27 @@
 # Eventually, it could take care of updating (adding/removing/moving)
 # tags too.
 
-from node import nullid, bin, hex, short
-from i18n import _
-import util
-import encoding
-import error
-from array import array
+from __future__ import absolute_import
+
+import array
 import errno
 import time
 
+from .i18n import _
+from .node import (
+    bin,
+    hex,
+    nullid,
+    short,
+)
+from . import (
+    encoding,
+    error,
+    util,
+)
+
+array = array.array
+
 # Tags computation can be expensive and caches exist to make it fast in
 # the common case.
 #
@@ -263,7 +275,7 @@
     If the cache is not up to date, the caller is responsible for reading tag
     info from each returned head. (See findglobaltags().)
     '''
-    import scmutil  # avoid cycle
+    from . import scmutil  # avoid cycle
 
     try:
         cachefile = repo.vfs(_filename(repo), 'r')
--- a/mercurial/templatefilters.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templatefilters.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,10 +5,21 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import cgi, re, os, time, urllib
-import encoding, node, util
-import hbisect
-import templatekw
+from __future__ import absolute_import
+
+import cgi
+import os
+import re
+import time
+import urllib
+
+from . import (
+    encoding,
+    hbisect,
+    node,
+    templatekw,
+    util,
+)
 
 def addbreaks(text):
     """:addbreaks: Any text. Add an XHTML "<br />" tag before the end of
@@ -70,12 +81,6 @@
     """:count: List or text. Returns the length as an integer."""
     return len(i)
 
-def datefilter(text):
-    """:date: Date. Returns a date in a Unix date format, including the
-    timezone: "Mon Sep 04 15:13:13 2006 0700".
-    """
-    return util.datestr(text)
-
 def domain(author):
     """:domain: Any text. Finds the first string that looks like an email
     address, and extracts just the domain component. Example: ``User
@@ -230,10 +235,6 @@
         s = s.replace(k, v)
     return ''.join(_uescape(c) for c in s)
 
-def localdate(text):
-    """:localdate: Date. Converts a date to local date."""
-    return (util.parsedate(text)[0], util.makedate()[1])
-
 def lower(text):
     """:lower: Any text. Converts the text to lowercase."""
     return encoding.lower(text)
@@ -337,10 +338,6 @@
         return ""
     return str(thing)
 
-def strip(text):
-    """:strip: Any text. Strips all leading and trailing whitespace."""
-    return text.strip()
-
 def stripdir(text):
     """:stripdir: Treat the text as path and strip a directory level, if
     possible. For example, "foo" and "foo/bar" becomes "foo".
@@ -390,7 +387,6 @@
     "age": age,
     "basename": basename,
     "count": count,
-    "date": datefilter,
     "domain": domain,
     "email": email,
     "escape": escape,
@@ -403,7 +399,6 @@
     "isodatesec": isodatesec,
     "json": json,
     "jsonescape": jsonescape,
-    "localdate": localdate,
     "lower": lower,
     "nonempty": nonempty,
     "obfuscate": obfuscate,
@@ -418,7 +413,6 @@
     "splitlines": splitlines,
     "stringescape": stringescape,
     "stringify": stringify,
-    "strip": strip,
     "stripdir": stripdir,
     "tabindent": tabindent,
     "upper": upper,
--- a/mercurial/templatekw.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templatekw.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,9 +5,16 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from node import hex
-import patch, scmutil, util, error
-import hbisect
+from __future__ import absolute_import
+
+from .node import hex
+from . import (
+    error,
+    hbisect,
+    patch,
+    scmutil,
+    util,
+)
 
 # This helper class allows us to handle both:
 #  "{files}" (legacy command-line-specific list hack) and
@@ -402,6 +409,14 @@
     """:rev: Integer. The repository-local changeset revision number."""
     return scmutil.intrev(ctx.rev())
 
+def showrevslist(name, revs, **args):
+    """helper to generate a list of revisions in which a mapped template will
+    be evaluated"""
+    repo = args['ctx'].repo()
+    f = _showlist(name, revs, **args)
+    return _hybrid(f, revs,
+                   lambda x: {name: x, 'ctx': repo[x], 'revcache': {}})
+
 def showsubrepos(**args):
     """:subrepos: List of strings. Updated subrepositories in the changeset."""
     ctx = args['ctx']
--- a/mercurial/templater.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templater.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,12 +5,23 @@
 # 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 os, re
-import util, config, templatefilters, templatekw, parser, error
-import revset as revsetmod
+from __future__ import absolute_import
+
+import os
+import re
 import types
-import minirst
+
+from .i18n import _
+from . import (
+    config,
+    error,
+    minirst,
+    parser,
+    revset as revsetmod,
+    templatefilters,
+    templatekw,
+    util,
+)
 
 # template parsing
 
@@ -94,11 +105,8 @@
                     pos += 4 # skip over double escaped characters
                     continue
                 if program.startswith(quote, pos, end):
-                    try:
-                        # interpret as if it were a part of an outer string
-                        data = program[s:pos].decode('string-escape')
-                    except ValueError: # unbalanced escapes
-                        raise error.ParseError(_("syntax error"), s)
+                    # interpret as if it were a part of an outer string
+                    data = parser.unescapestr(program[s:pos])
                     if token == 'template':
                         data = _parsetemplate(data, 0, len(data))[0]
                     yield (token, data, s)
@@ -147,19 +155,18 @@
         n = min((tmpl.find(c, pos, stop) for c in sepchars),
                 key=lambda n: (n < 0, n))
         if n < 0:
-            parsed.append(('string', tmpl[pos:stop].decode('string-escape')))
+            parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
             pos = stop
             break
         c = tmpl[n]
         bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
         if bs % 2 == 1:
             # escaped (e.g. '\{', '\\\{', but not '\\{')
-            parsed.append(('string',
-                           tmpl[pos:n - 1].decode('string-escape') + c))
+            parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
             pos = n + 1
             continue
         if n > pos:
-            parsed.append(('string', tmpl[pos:n].decode('string-escape')))
+            parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
         if c == quote:
             return parsed, n + 1
 
@@ -194,12 +201,6 @@
         return getlist(x[1]) + [x[2]]
     return [x]
 
-def getfilter(exp, context):
-    f = getsymbol(exp)
-    if f not in context._filters:
-        raise error.ParseError(_("unknown function '%s'") % f)
-    return context._filters[f]
-
 def gettemplate(exp, context):
     if exp[0] == 'template':
         return [compileexp(e, context, methods) for e in exp[1]]
@@ -210,6 +211,15 @@
         return context._load(exp[1])
     raise error.ParseError(_("expected template specifier"))
 
+def evalfuncarg(context, mapping, arg):
+    func, data = arg
+    # func() may return string, generator of strings or arbitrary object such
+    # as date tuple, but filter does not want generator.
+    thing = func(context, mapping, data)
+    if isinstance(thing, types.GeneratorType):
+        thing = stringify(thing)
+    return thing
+
 def runinteger(context, mapping, data):
     return int(data)
 
@@ -242,24 +252,26 @@
         yield func(context, mapping, data)
 
 def buildfilter(exp, context):
-    func, data = compileexp(exp[1], context, methods)
-    filt = getfilter(exp[2], context)
-    return (runfilter, (func, data, filt))
+    arg = compileexp(exp[1], context, methods)
+    n = getsymbol(exp[2])
+    if n in context._filters:
+        filt = context._filters[n]
+        return (runfilter, (arg, filt))
+    if n in funcs:
+        f = funcs[n]
+        return (f, [arg])
+    raise error.ParseError(_("unknown function '%s'") % n)
 
 def runfilter(context, mapping, data):
-    func, data, filt = data
-    # func() may return string, generator of strings or arbitrary object such
-    # as date tuple, but filter does not want generator.
-    thing = func(context, mapping, data)
-    if isinstance(thing, types.GeneratorType):
-        thing = stringify(thing)
+    arg, filt = data
+    thing = evalfuncarg(context, mapping, arg)
     try:
         return filt(thing)
     except (ValueError, AttributeError, TypeError):
-        if isinstance(data, tuple):
-            dt = data[1]
+        if isinstance(arg[1], tuple):
+            dt = arg[1][1]
         else:
-            dt = data
+            dt = arg[1]
         raise util.Abort(_("template filter '%s' is not compatible with "
                            "keyword '%s'") % (filt.func_name, dt))
 
@@ -297,12 +309,13 @@
         if len(args) != 1:
             raise error.ParseError(_("filter %s expects one argument") % n)
         f = context._filters[n]
-        return (runfilter, (args[0][0], args[0][1], f))
+        return (runfilter, (args[0], f))
     raise error.ParseError(_("unknown function '%s'") % n)
 
 def date(context, mapping, args):
     """:date(date[, fmt]): Format a date. See :hg:`help dates` for formatting
-    strings."""
+    strings. The default is a Unix date format, including the timezone:
+    "Mon Sep 04 15:13:13 2006 0700"."""
     if not (1 <= len(args) <= 2):
         # i18n: "date" is a keyword
         raise error.ParseError(_("date expects one or two arguments"))
@@ -410,7 +423,7 @@
 def get(context, mapping, args):
     """:get(dict, key): Get an attribute/key from an object. Some keywords
     are complex types. This function allows you to obtain the value of an
-    attribute on these type."""
+    attribute on these types."""
     if len(args) != 2:
         # i18n: "get" is a keyword
         raise error.ParseError(_("get() expects two arguments"))
@@ -499,6 +512,34 @@
     # ignore args[0] (the label string) since this is supposed to be a a no-op
     yield args[1][0](context, mapping, args[1][1])
 
+def localdate(context, mapping, args):
+    """:localdate(date[, tz]): Converts a date to the specified timezone.
+    The default is local date."""
+    if not (1 <= len(args) <= 2):
+        # i18n: "localdate" is a keyword
+        raise error.ParseError(_("localdate expects one or two arguments"))
+
+    date = evalfuncarg(context, mapping, args[0])
+    try:
+        date = util.parsedate(date)
+    except AttributeError:  # not str nor date tuple
+        # i18n: "localdate" is a keyword
+        raise error.ParseError(_("localdate expects a date information"))
+    if len(args) >= 2:
+        tzoffset = None
+        tz = evalfuncarg(context, mapping, args[1])
+        if isinstance(tz, str):
+            tzoffset = util.parsetimezone(tz)
+        if tzoffset is None:
+            try:
+                tzoffset = int(tz)
+            except (TypeError, ValueError):
+                # i18n: "localdate" is a keyword
+                raise error.ParseError(_("localdate expects a timezone"))
+    else:
+        tzoffset = util.makedate()[1]
+    return (date[0], tzoffset)
+
 def revset(context, mapping, args):
     """:revset(query[, formatargs...]): Execute a revision set query. See
     :hg:`help revset`."""
@@ -527,7 +568,7 @@
             revs = list([str(r) for r in revs])
             revsetcache[raw] = revs
 
-    return templatekw.showlist("revision", revs, **mapping)
+    return templatekw.showrevslist("revision", revs, **mapping)
 
 def rstdoc(context, mapping, args):
     """:rstdoc(text, style): Format ReStructuredText."""
@@ -593,7 +634,8 @@
                 return shortest
 
 def strip(context, mapping, args):
-    """:strip(text[, chars]): Strip characters from a string."""
+    """:strip(text[, chars]): Strip characters from a string. By default,
+    strips all leading and trailing whitespace."""
     if not (1 <= len(args) <= 2):
         # i18n: "strip" is a keyword
         raise error.ParseError(_("strip expects one or two arguments"))
@@ -614,7 +656,16 @@
     pat = stringify(args[0][0](context, mapping, args[0][1]))
     rpl = stringify(args[1][0](context, mapping, args[1][1]))
     src = stringify(args[2][0](context, mapping, args[2][1]))
-    yield re.sub(pat, rpl, src)
+    try:
+        patre = re.compile(pat)
+    except re.error:
+        # i18n: "sub" is a keyword
+        raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
+    try:
+        yield patre.sub(rpl, src)
+    except re.error:
+        # i18n: "sub" is a keyword
+        raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
 
 def startswith(context, mapping, args):
     """:startswith(pattern, text): Returns the value from the "text" argument
@@ -682,6 +733,7 @@
     "indent": indent,
     "join": join,
     "label": label,
+    "localdate": localdate,
     "pad": pad,
     "revset": revset,
     "rstdoc": rstdoc,
@@ -740,9 +792,13 @@
     filter uses function to transform value. syntax is
     {key|filter1|filter2|...}.'''
 
-    def __init__(self, loader, filters={}, defaults={}):
+    def __init__(self, loader, filters=None, defaults=None):
         self._loader = loader
+        if filters is None:
+            filters = {}
         self._filters = filters
+        if defaults is None:
+            defaults = {}
         self._defaults = defaults
         self._cache = {}
 
@@ -777,12 +833,18 @@
 
 class templater(object):
 
-    def __init__(self, mapfile, filters={}, defaults={}, cache={},
+    def __init__(self, mapfile, filters=None, defaults=None, cache=None,
                  minchunk=1024, maxchunk=65536):
         '''set up template engine.
         mapfile is name of file to read map definitions from.
         filters is dict of functions. each transforms a value into another.
         defaults is dict of default map definitions.'''
+        if filters is None:
+            filters = {}
+        if defaults is None:
+            defaults = {}
+        if cache is None:
+            cache = {}
         self.mapfile = mapfile or 'template'
         self.cache = cache.copy()
         self.map = {}
--- a/mercurial/templates/coal/header.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/coal/header.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -3,5 +3,6 @@
 <head>
 <link rel="icon" href="{staticurl|urlescape}hgicon.png" type="image/png" />
 <meta name="robots" content="index, nofollow" />
-<link rel="stylesheet" href="{staticurl|urlescape}style-coal.css" type="text/css" />
+<link rel="stylesheet" href="{staticurl|urlescape}style-paper.css" type="text/css" />
+<link rel="stylesheet" href="{staticurl|urlescape}style-extra-coal.css" type="text/css" />
 <script type="text/javascript" src="{staticurl|urlescape}mercurial.js"></script>
--- a/mercurial/templates/coal/map	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/coal/map	Fri Sep 25 23:10:47 2015 -0500
@@ -1,7 +1,5 @@
-default = 'shortlog'
+%include paper/map
 
-mimetype = 'text/html; charset={encoding}'
-header = header.tmpl
 footer = ../paper/footer.tmpl
 search = ../paper/search.tmpl
 
@@ -13,23 +11,6 @@
 help = ../paper/help.tmpl
 helptopics = ../paper/helptopics.tmpl
 
-helpentry = '
-  <tr><td>
-    <a href="{url|urlescape}help/{topic|escape}{sessionvars%urlparameter}">
-      {topic|escape}
-    </a>
-  </td><td>
-    {summary|escape}
-  </td></tr>'
-
-naventry = '<a href="{url|urlescape}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navshortentry = '<a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-navgraphentry = '<a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
-filenaventry = '<a href="{url|urlescape}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
-filedifflink = '<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenodelink = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
-filenolink = '{file|escape} '
-fileellipses = '...'
 diffstatlink = ../paper/diffstat.tmpl
 diffstatnolink = ../paper/diffstat.tmpl
 changelogentry = ../paper/shortlogentry.tmpl
@@ -37,212 +18,17 @@
 changeset = ../paper/changeset.tmpl
 manifest = ../paper/manifest.tmpl
 
-nav = '{before%naventry} {after%naventry}'
-navshort = '{before%navshortentry}{after%navshortentry}'
-navgraph = '{before%navgraphentry}{after%navgraphentry}'
-filenav = '{before%filenaventry}{after%filenaventry}'
-
-direntry = '
-  <tr class="fileline">
-    <td class="name">
-      <a href="{url|urlescape}file/{symrev}{path|urlescape}{sessionvars%urlparameter}">
-        <img src="{staticurl|urlescape}coal-folder.png" alt="dir."/> {basename|escape}/
-      </a>
-      <a href="{url|urlescape}file/{symrev}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">
-        {emptydirs|escape}
-      </a>
-    </td>
-    <td class="size"></td>
-    <td class="permissions">drwxr-xr-x</td>
-  </tr>'
-
-fileentry = '
-  <tr class="fileline">
-    <td class="filename">
-      <a href="{url|urlescape}file/{symrev}/{file|urlescape}{sessionvars%urlparameter}">
-        <img src="{staticurl|urlescape}coal-file.png" alt="file"/> {basename|escape}
-      </a>
-    </td>
-    <td class="size">{size}</td>
-    <td class="permissions">{permissions|permissions}</td>
-  </tr>'
-
 filerevision = ../paper/filerevision.tmpl
 fileannotate = ../paper/fileannotate.tmpl
 filediff = ../paper/filediff.tmpl
 filecomparison = ../paper/filecomparison.tmpl
 filelog = ../paper/filelog.tmpl
-fileline = '
-  <div class="source"><a href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</div>'
 filelogentry = ../paper/filelogentry.tmpl
 
-annotateline = '
-  <tr>
-    <td class="annotate">
-      <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#{targetline}"
-         title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
-    </td>
-    <td class="source"><a href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</td>
-  </tr>'
-
-diffblock = '<div class="source bottomline"><pre>{lines}</pre></div>'
-difflineplus = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> <span class="plusline">{line|escape}</span>'
-difflineminus = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> <span class="minusline">{line|escape}</span>'
-difflineat = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> <span class="atline">{line|escape}</span>'
-diffline = '<a href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}'
-
-comparisonblock ='
-  <tbody class="block">
-  {lines}
-  </tbody>'
-comparisonline = '
-  <tr>
-    <td class="source {type}"><a href="#{lineid}" id="{lineid}">{leftlinenumber}</a> {leftline|escape}</td>
-    <td class="source {type}"><a href="#{lineid}" id="{lineid}">{rightlinenumber}</a> {rightline|escape}</td>
-  </tr>'
-
-changelogparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-
-changesetparent = '<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a> '
-
-changesetparentdiff = '
-  {changesetparent}
-  {ifeq(node, basenode, '(current diff)', '({difffrom})')}'
-
-difffrom = '<a href="{url|urlescape}rev/{node|short}:{originalnode|short}{sessionvars%urlparameter}">diff</a>'
-
-filerevparent = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a> '
-filerevchild = '<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a> '
+tags = ../paper/tags.tmpl
+bookmarks = ../paper/bookmarks.tmpl
+branches = ../paper/branches.tmpl
 
-filerename = '{file|escape}@'
-filelogrename = '
-  <span class="base">
-    base
-    <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-      {file|escape}@{node|short}
-    </a>
-  </span>'
-fileannotateparent = '
-  <tr>
-    <td class="metatag">parent:</td>
-    <td>
-      <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {rename%filerename}{node|short}
-      </a>
-    </td>
-  </tr>'
-changesetchild = ' <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
-changelogchild = '
-  <tr>
-    <th class="child">child</th>
-    <td class="child">
-      <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-fileannotatechild = '
-  <tr>
-    <td class="metatag">child:</td>
-    <td>
-      <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-tags = ../paper/tags.tmpl
-tagentry = '
-  <tr class="tagEntry">
-    <td>
-      <a href="{url|urlescape}rev/{tag|revescape}{sessionvars%urlparameter}">
-        {tag|escape}
-      </a>
-    </td>
-    <td class="node">
-      <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-bookmarks = ../paper/bookmarks.tmpl
-bookmarkentry = '
-  <tr class="tagEntry">
-    <td>
-      <a href="{url|urlescape}rev/{bookmark|revescape}{sessionvars%urlparameter}">
-        {bookmark|escape}
-      </a>
-    </td>
-    <td class="node">
-      <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-branches = ../paper/branches.tmpl
-branchentry = '
-  <tr class="tagEntry">
-    <td>
-      <a href="{url|urlescape}shortlog/{branch|revescape}{sessionvars%urlparameter}" class="{status}">
-        {branch|escape}
-      </a>
-    </td>
-    <td class="node">
-      <a href="{url|urlescape}shortlog/{node|short}{sessionvars%urlparameter}" class="{status}">
-        {node|short}
-      </a>
-    </td>
-  </tr>'
-changelogtag = '<span class="tag">{name|escape}</span> '
-changesettag = '<span class="tag">{tag|escape}</span> '
-changesetbookmark = '<span class="tag">{bookmark|escape}</span> '
-changelogbranchhead = '<span class="branchhead">{name|escape}</span> '
-changelogbranchname = '<span class="branchname">{name|escape}</span> '
-
-filediffparent = '
-  <tr>
-    <th class="parent">parent {rev}:</th>
-    <td class="parent"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filelogparent = '
-  <tr>
-    <th>parent {rev}:</th>
-    <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-filediffchild = '
-  <tr>
-    <th class="child">child {rev}:</th>
-    <td class="child"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>
-  </td>
-  </tr>'
-filelogchild = '
-  <tr>
-    <th>child {rev}:</th>
-    <td><a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td>
-  </tr>'
-
-indexentry = '
-  <tr>
-    <td><a href="{url|urlescape}{sessionvars%urlparameter}">{name|escape}</a></td>
-    <td>{description}</td>
-    <td>{contact|obfuscate}</td>
-    <td class="age">{lastchange|rfc822date}</td>
-    <td class="indexlinks">{archives%indexarchiveentry}</td>
-  </tr>\n'
-indexarchiveentry = '<a href="{url|urlescape}archive/{node|short}{extension|urlescape}">&nbsp;&darr;{type|escape}</a>'
 index = ../paper/index.tmpl
-archiveentry = '
-  <li>
-    <a href="{url|urlescape}archive/{symrev}{extension|urlescape}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a>
-  </li>'
 notfound = ../paper/notfound.tmpl
 error = ../paper/error.tmpl
-urlparameter = '{separator}{name}={value|urlescape}'
-hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
-breadcrumb = '&gt; <a href="{url|urlescape}">{name|escape}</a> '
-
-searchhint = 'Find changesets by keywords (author, files, the commit message), revision
-  number or hash, or <a href="{url|urlescape}help/revsets">revset expression</a>.'
--- a/mercurial/templates/gitweb/changeset.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/gitweb/changeset.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -52,6 +52,6 @@
 {files}
 </table></div>
 
-<div class="page_body">{diff}</div>
+<div class="page_body diffblocks">{diff}</div>
 
 {footer}
--- a/mercurial/templates/gitweb/filerevision.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/gitweb/filerevision.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -64,7 +64,7 @@
 </div>
 
 <div class="page_body">
-{text%fileline}
+<pre class="sourcelines stripes">{text%fileline}</pre>
 </div>
 
 {footer}
--- a/mercurial/templates/gitweb/map	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/gitweb/map	Fri Sep 25 23:10:47 2015 -0500
@@ -93,31 +93,33 @@
 filecomparison = filecomparison.tmpl
 filelog = filelog.tmpl
 fileline = '
-  <div style="font-family:monospace" class="parity{parity}">
-    <pre><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</pre>
-  </div>'
+  <span id="{lineid}">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
 annotateline = '
-  <tr style="font-family:monospace" class="parity{parity}">
+  <tr id="{lineid}" style="font-family:monospace" class="parity{parity}">
     <td class="linenr" style="text-align: right;">
       <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
          title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
     </td>
-    <td><pre><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a></pre></td>
+    <td><pre><a class="linenr" href="#{lineid}">{linenumber}</a></pre></td>
     <td><pre>{line|escape}</pre></td>
   </tr>'
-difflineplus = '<span class="difflineplus"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-difflineminus = '<span class="difflineminus"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-difflineat = '<span class="difflineat"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-diffline = '<a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}'
+difflineplus = '
+  <span id="{lineid}" class="difflineplus">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
+difflineminus = '
+  <span id="{lineid}" class="difflineminus">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
+difflineat = '
+  <span id="{lineid}" class="difflineat">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
+diffline = '
+  <span id="{lineid}">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
 
 comparisonblock ='
   <tbody class="block">
   {lines}
   </tbody>'
 comparisonline = '
-  <tr style="font-family:monospace">
-    <td class="{type}"><pre><a class="linenr" href="#{lineid}" id="{lineid}">{leftlinenumber}</a> {leftline|escape}</pre></td>
-    <td class="{type}"><pre><a class="linenr" href="#{lineid}" id="{lineid}">{rightlinenumber}</a> {rightline|escape}</pre></td>
+  <tr id="{lineid}" style="font-family:monospace">
+    <td class="{type}"><pre><a class="linenr" href="#{lineid}">{leftlinenumber}</a> {leftline|escape}</pre></td>
+    <td class="{type}"><pre><a class="linenr" href="#{lineid}">{rightlinenumber}</a> {rightline|escape}</pre></td>
   </tr>'
 
 changelogparent = '
@@ -223,7 +225,7 @@
       <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
     </td>
   </tr>'
-diffblock = '<pre>{lines}</pre>'
+diffblock = '<div class="diffblock"><pre class="sourcelines">{lines}</pre></div>'
 filediffparent = '
   <tr>
     <td>parent {rev}</td>
@@ -290,6 +292,7 @@
 filelogentry = '
   <tr class="parity{parity}">
     <td class="age"><i class="age">{date|rfc822date}</i></td>
+    <td><i>{author|person}</i></td>
     <td>
       <a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
         <b>{desc|strip|firstline|escape|nonempty}</b>
--- a/mercurial/templates/map-cmdline.xml	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/map-cmdline.xml	Fri Sep 25 23:10:47 2015 -0500
@@ -1,5 +1,5 @@
-header = '<?xml version="1.0"?>\n<log>\n'
-footer = '</log>\n'
+docheader = '<?xml version="1.0"?>\n<log>\n'
+docfooter = '</log>\n'
 
 changeset = '<logentry revision="{rev}" node="{node}">\n{branches}{bookmarks}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n</logentry>\n'
 changeset_verbose = '<logentry revision="{rev}" node="{node}">\n{branches}{bookmarks}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n<paths>\n{file_adds}{file_dels}{file_mods}</paths>\n{file_copies}</logentry>\n'
--- a/mercurial/templates/monoblue/changeset.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/monoblue/changeset.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -59,7 +59,7 @@
     {files}
     </table>
 
-    <div class="diff">
+    <div class="diff diffblocks">
     {diff}
     </div>
 
--- a/mercurial/templates/monoblue/filediff.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/monoblue/filediff.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -50,7 +50,7 @@
         {child%filediffchild}
     </dl>
 
-    <div class="diff">
+    <div class="diff diffblocks">
     {diff}
     </div>
 
--- a/mercurial/templates/monoblue/filerevision.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/monoblue/filerevision.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -60,7 +60,7 @@
     <p class="description">{desc|strip|escape|websub|addbreaks|nonempty}</p>
 
     <div class="source">
-    {text%fileline}
+        <pre class="sourcelines stripes">{text%fileline}</pre>
     </div>
 
 {footer}
--- a/mercurial/templates/monoblue/footer.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/monoblue/footer.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -12,11 +12,6 @@
         <p><a href="{logourl}" title="Mercurial"><img src="{staticurl|urlescape}{logoimg}" width=75 height=90 border=0 alt="mercurial" /></a></p>
     </div>
 
-    <div id="corner-top-left"></div>
-    <div id="corner-top-right"></div>
-    <div id="corner-bottom-left"></div>
-    <div id="corner-bottom-right"></div>
-
 </div>
 
 </body>
--- a/mercurial/templates/monoblue/index.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/monoblue/index.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -29,11 +29,6 @@
         <p><a href="{logourl}" title="Mercurial"><img src="{staticurl|urlescape}{logoimg}" width=75 height=90 border=0 alt="mercurial"></a></p>
     </div>
 
-    <div id="corner-top-left"></div>
-    <div id="corner-top-right"></div>
-    <div id="corner-bottom-left"></div>
-    <div id="corner-bottom-right"></div>
-
 </div>
 <script type="text/javascript">process_dates()</script>
 </body>
--- a/mercurial/templates/monoblue/map	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/monoblue/map	Fri Sep 25 23:10:47 2015 -0500
@@ -89,33 +89,35 @@
 filecomparison = filecomparison.tmpl
 filelog = filelog.tmpl
 fileline = '
-  <div style="font-family:monospace" class="parity{parity}">
-    <pre><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</pre>
-  </div>'
+  <span id="{lineid}">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
 annotateline = '
-  <tr class="parity{parity}">
+  <tr id="{lineid}" class="parity{parity}">
     <td class="linenr">
       <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#l{targetline}"
          title="{node|short}: {desc|escape|firstline}">{author|user}@{rev}</a>
     </td>
     <td class="lineno">
-      <a href="#{lineid}" id="{lineid}">{linenumber}</a>
+      <a href="#{lineid}">{linenumber}</a>
     </td>
     <td class="source">{line|escape}</td>
   </tr>'
-difflineplus = '<span class="difflineplus"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-difflineminus = '<span class="difflineminus"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-difflineat = '<span class="difflineat"><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
-diffline = '<span><a class="linenr" href="#{lineid}" id="{lineid}">{linenumber}</a> {line|escape}</span>'
+difflineplus = '
+  <span id="{lineid}" class="difflineplus">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
+difflineminus = '
+  <span id="{lineid}" class="difflineminus">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
+difflineat = '
+  <span id="{lineid}" class="difflineat">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
+diffline = '
+  <span id="{lineid}">{strip(line|escape, '\r\n')}</span><a href="#{lineid}"></a>'
 
 comparisonblock ='
   <tbody class="block">
   {lines}
   </tbody>'
 comparisonline = '
-  <tr>
-    <td class="source {type}"><a class="linenr" href="#{lineid}" id="{lineid}">{leftlinenumber}</a> {leftline|escape}</td>
-    <td class="source {type}"><a class="linenr" href="#{lineid}" id="{lineid}">{rightlinenumber}</a> {rightline|escape}</td>
+  <tr id="{lineid}">
+    <td class="source {type}"><a class="linenr" href="#{lineid}">{leftlinenumber}</a> {leftline|escape}</td>
+    <td class="source {type}"><a class="linenr" href="#{lineid}">{rightlinenumber}</a> {rightline|escape}</td>
   </tr>'
 
 changesetlink = '<a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
@@ -201,7 +203,7 @@
       <a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
     </td>
   </tr>'
-diffblock = '<pre>{lines}</pre>'
+diffblock = '<div class="diffblock"><pre class="sourcelines">{lines}</pre></div>'
 filediffparent = '
   <dt>parent {rev}</dt>
   <dd><a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></dd>'
@@ -247,6 +249,7 @@
 filelogentry = '
   <tr class="parity{parity}">
     <td class="nowrap age">{date|rfc822date}</td>
+    <td>{author|person}</td>
     <td>
       <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
         {desc|strip|firstline|escape|nonempty}
@@ -254,7 +257,9 @@
       </a>
     </td>
     <td class="nowrap">
-      <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a>&nbsp;|&nbsp;<a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a>&nbsp;|&nbsp;<a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
+      <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
+      <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
+      <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
       {rename%filelogrename}
     </td>
   </tr>'
--- a/mercurial/templates/monoblue/summary.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/monoblue/summary.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -26,6 +26,7 @@
             <li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
             <li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
             <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
+            {archives%archiveentry}
             <li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
         </ul>
     </div>
--- a/mercurial/templates/paper/filerevision.tmpl	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/paper/filerevision.tmpl	Fri Sep 25 23:10:47 2015 -0500
@@ -71,8 +71,7 @@
 <div class="overflow">
 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
 <div class="sourcefirst"> line source</div>
-<pre class="sourcelines stripes4 wrap">{text%fileline}</pre>
-<div class="sourcelast"></div>
+<pre class="sourcelines stripes4 wrap bottomline">{text%fileline}</pre>
 </div>
 </div>
 </div>
--- a/mercurial/templates/static/style-coal.css	Fri Sep 25 13:30:49 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,368 +0,0 @@
-body {
-  margin: 0;
-  padding: 0;
-  background: black url(background.png) repeat-x;
-  font-family: sans-serif;
-}
-
-.container {
-  padding-right: 150px;
-}
-
-.main {
-  position: relative;
-  background: white;
-  padding: 2em;
-  border-right: 15px solid black;
-  border-bottom: 15px solid black;
-}
-
-#.main {
-  width: 98%;
-}
-
-.overflow {
-  width: 100%;
-  overflow: auto;
-}
-
-.menu {
-  background: #999;
-  padding: 10px;
-  width: 75px;
-  margin: 0;
-  font-size: 80%;
-  text-align: left;
-  position: fixed;
-  top: 27px;
-  left: auto;
-  right: 27px;
-}
-
-#.menu {
-  position: absolute !important;
-  top:expression(eval(document.body.scrollTop + 27));
-}
-
-.menu ul {
-  list-style: none;
-  padding: 0;
-  margin: 10px 0 0 0;
-}
-
-.menu li {
-  margin-bottom: 3px;
-  padding: 2px 4px;
-  background: white;
-  color: black;
-  font-weight: normal;
-}
-
-.menu li.active {
-  background: black;
-  color: white;
-}
-
-.menu img {
-  width: 75px;
-  height: 90px;
-  border: 0;
-}
-
-.menu a { color: black; display: block; }
-
-.search {
-  position: absolute;
-  top: .7em;
-  right: 2em;
-}
-
-form.search div#hint {
-  display: none;
-  position: absolute;
-  top: 40px;
-  right: 0px;
-  width: 190px;
-  padding: 5px;
-  background: #ffc;
-  font-size: 70%;
-  border: 1px solid yellow;
-  -moz-border-radius: 5px; /* this works only in camino/firefox */
-  -webkit-border-radius: 5px; /* this is just for Safari */
-}
-
-form.search:hover div#hint { display: block; }
-
-a { text-decoration:none; }
-.age { white-space:nowrap; }
-.date { white-space:nowrap; }
-.indexlinks { white-space:nowrap; }
-.parity0,
-.stripes4 > :nth-child(4n+1),
-.stripes2 > :nth-child(2n+1) { background-color: #f0f0f0; }
-.parity1,
-.stripes4 > :nth-child(4n+3),
-.stripes2 > :nth-child(2n+2) { background-color: white; }
-.plusline { color: green; }
-.minusline { color: #dc143c; } /* crimson */
-.atline { color: purple; }
-
-.diffstat-file {
-  white-space: nowrap;
-  font-size: 90%;
-}
-.diffstat-total {
-  white-space: nowrap;
-  font-size: 90%;
-}
-.diffstat-graph {
-  width: 100%;
-}
-.diffstat-add {
-  background-color: green;
-  float: left;
-}
-.diffstat-remove {
-  background-color: red;
-  float: left;
-}
-
-.navigate {
-  text-align: right;
-  font-size: 60%;
-  margin: 1em 0;
-}
-
-.tag {
-  color: #999;
-  font-size: 70%;
-  font-weight: normal;
-  margin-left: .5em;
-  vertical-align: baseline;
-}
-
-.branchhead {
-  color: #000;
-  font-size: 80%;
-  font-weight: normal;
-  margin-left: .5em;
-  vertical-align: baseline;
-}
-
-ul#graphnodes .branchhead {
-  font-size: 75%;
-}
-
-.branchname {
-  color: #000;
-  font-size: 60%;
-  font-weight: normal;
-  margin-left: .5em;
-  vertical-align: baseline;
-}
-
-h3 .branchname {
-  font-size: 80%;
-}
-
-/* Common */
-pre { margin: 0; }
-
-h2 { font-size: 120%; border-bottom: 1px solid #999; }
-h2 a { color: #000; }
-h3 {
-  margin-top: -.7em;
-  font-size: 100%;
-}
-
-/* log and tags tables */
-.bigtable {
-  border-bottom: 1px solid #999;
-  border-collapse: collapse;
-  font-size: 90%;
-  width: 100%;
-  font-weight: normal;
-  text-align: left;
-}
-
-.bigtable td {
-  vertical-align: top;
-}
-
-.bigtable th {
-  padding: 1px 4px;
-  border-bottom: 1px solid #999;
-}
-.bigtable tr { border: none; }
-.bigtable .age { width: 6em; }
-.bigtable .author { width: 15em; }
-.bigtable .description { }
-.bigtable .description .base { font-size: 70%; float: right; line-height: 1.66; }
-.bigtable .node { width: 5em; font-family: monospace;}
-.bigtable .lineno { width: 2em; text-align: right;}
-.bigtable .lineno a { color: #999; font-size: smaller; font-family: monospace;}
-.bigtable .permissions { width: 8em; text-align: left;}
-.bigtable .size { width: 5em; text-align: right; }
-.bigtable .annotate { text-align: right; }
-.bigtable td.annotate { font-size: smaller; }
-.bigtable td.source { font-size: inherit; }
-
-.source, .sourcefirst, .sourcelast {
-  font-family: monospace;
-  white-space: pre;
-  padding: 1px 4px;
-  font-size: 90%;
-}
-.sourcefirst { border-bottom: 1px solid #999; font-weight: bold; }
-.sourcelast { border-top: 1px solid #999; }
-.source a { color: #999; font-size: smaller; font-family: monospace;}
-.bottomline { border-bottom: 1px solid #999; }
-
-.sourcelines > div {
-  display: inline-block;
-  width: 100%;
-  padding: 1px 0px;
-  counter-increment: lineno;
-}
-
-.fileline { font-family: monospace; }
-.fileline img { border: 0; }
-
-.tagEntry .closed { color: #99f; }
-
-/* Changeset entry */
-#changesetEntry {
-  border-collapse: collapse;
-  font-size: 90%;
-  width: 100%;
-  margin-bottom: 1em;
-}
-
-#changesetEntry th {
-  padding: 1px 4px;
-  width: 4em;
-  text-align: right;
-  font-weight: normal;
-  color: #999;
-  margin-right: .5em;
-  vertical-align: top;
-}
-
-div.description {
-  border-left: 3px solid #999;
-  margin: 1em 0 1em 0;
-  padding: .3em;
-  white-space: pre;
-  font-family: monospace;
-}
-
-/* Graph */
-div#wrapper {
-	position: relative;
-	border-top: 1px solid black;
-	border-bottom: 1px solid black;
-	margin: 0;
-	padding: 0;
-}
-
-canvas {
-	position: absolute;
-	z-index: 5;
-	top: -0.7em;
-	margin: 0;
-}
-
-ul#graphnodes {
-	position: absolute;
-	z-index: 10;
-	top: -1.0em;
-	list-style: none inside none;
-	padding: 0;
-}
-
-ul#nodebgs {
-	list-style: none inside none;
-	padding: 0;
-	margin: 0;
-	top: -0.7em;
-}
-
-ul#graphnodes li, ul#nodebgs li {
-	height: 39px;
-}
-
-ul#graphnodes li .info {
-	display: block;
-	font-size: 70%;
-	position: relative;
-	top: -3px;
-}
-
-/* Comparison */
-.legend {
-    padding: 1.5% 0 1.5% 0;
-}
-
-.legendinfo {
-    border: 1px solid #999;
-    font-size: 80%;
-    text-align: center;
-    padding: 0.5%;
-}
-
-.equal {
-    background-color: #ffffff;
-}
-
-.delete {
-    background-color: #faa;
-    color: #333;
-}
-
-.insert {
-    background-color: #ffa;
-}
-
-.replace {
-    background-color: #e8e8e8;
-}
-
-.header {
-    text-align: center;
-}
-
-.block {
-    border-top: 1px solid #999;
-}
-
-.breadcrumb {
-    color: gray;
-}
-
-.breadcrumb a {
-    color: blue;
-}
-
-.scroll-loading {
-    -webkit-animation: change_color 1s linear 0s infinite alternate;
-    -moz-animation: change_color 1s linear 0s infinite alternate;
-    -o-animation: change_color 1s linear 0s infinite alternate;
-    animation: change_color 1s linear 0s infinite alternate;
-}
-
-@-webkit-keyframes change_color {
-  from { background-color: #A0CEFF; } to {  }
-}
-@-moz-keyframes change_color {
-  from { background-color: #A0CEFF; } to {  }
-}
-@-o-keyframes change_color {
-  from { background-color: #A0CEFF; } to {  }
-}
-@keyframes change_color {
-  from { background-color: #A0CEFF; } to {  }
-}
-
-.scroll-loading-error {
-    background-color: #FFCCCC !important;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/templates/static/style-extra-coal.css	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,46 @@
+body {
+    background: black url('background.png') repeat-x;
+}
+
+.container {
+    padding-left: 0;
+    padding-right: 150px;
+}
+
+.main {
+    padding: 2em;
+    border-right: 15px solid black;
+    border-bottom: 15px solid black;
+}
+
+.menu {
+    background: #999;
+    padding: 10px;
+    width: 75px;
+    position: fixed;
+    top: 27px;
+    left: auto;
+    right: 27px;
+}
+
+.menu ul {
+    border-left: 0;
+}
+
+.menu li.active {
+    font-weight: normal;
+    background: black;
+    color: white;
+}
+
+.menu li.active a {
+    color: white;
+}
+
+h3 {
+    margin-top: -.7em;
+}
+
+div.description {
+    border-left-width: 3px;
+}
--- a/mercurial/templates/static/style-gitweb.css	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/static/style-gitweb.css	Fri Sep 25 23:10:47 2015 -0500
@@ -29,9 +29,9 @@
 a.list:hover { text-decoration:underline; color:#880000; }
 table { padding:8px 4px; }
 th { padding:2px 5px; font-size:12px; text-align:left; }
-tr.light:hover, .parity0:hover { background-color:#edece6; }
-tr.dark, .parity1 { background-color:#f6f6f0; }
-tr.dark:hover, .parity1:hover { background-color:#edece6; }
+tr.light:hover, .parity0:hover, pre.sourcelines.stripes > :nth-child(4n+1):hover { background-color:#edece6; }
+tr.dark, .parity1, pre.sourcelines.stripes > :nth-child(4n+3) { background-color:#f6f6f0; }
+tr.dark:hover, .parity1:hover, pre.sourcelines.stripes > :nth-child(4n+3):hover { background-color:#edece6; }
 td { padding:2px 5px; font-size:12px; vertical-align:top; }
 td.closed { background-color: #99f; }
 td.link { padding:2px 5px; font-family:sans-serif; font-size:10px; }
@@ -87,6 +87,43 @@
 span.difflineplus { color:#008800; }
 span.difflineminus { color:#cc0000; }
 span.difflineat { color:#990099; }
+div.diffblocks { counter-reset: lineno; }
+div.diffblock { counter-increment: lineno; }
+pre.sourcelines { position: relative; counter-reset: lineno; }
+pre.sourcelines > span {
+	display: inline-block;
+	box-sizing: border-box;
+	width: 100%;
+	padding: 0 0 0 5em;
+	counter-increment: lineno;
+	vertical-align: top;
+}
+pre.sourcelines > span:before {
+	-moz-user-select: -moz-none;
+	-khtml-user-select: none;
+	-webkit-user-select: none;
+	-ms-user-select: none;
+	user-select: none;
+	display: inline-block;
+	margin-left: -5em;
+	width: 4em;
+	color: #999;
+	text-align: right;
+	content: counters(lineno,".");
+	float: left;
+}
+pre.sourcelines > a {
+	display: inline-block;
+	position: absolute;
+	left: 0px;
+	width: 4em;
+	height: 1em;
+}
+tr:target td,
+pre.sourcelines > span:target,
+pre.sourcelines.stripes > span:target {
+	background-color: #bfdfff;
+}
 
 /* Graph */
 div#wrapper {
@@ -194,3 +231,7 @@
 .scroll-loading-error {
     background-color: #FFCCCC !important;
 }
+
+#doc {
+    margin: 0 8px;
+}
--- a/mercurial/templates/static/style-monoblue.css	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/static/style-monoblue.css	Fri Sep 25 23:10:47 2015 -0500
@@ -255,34 +255,63 @@
   font-family: monospace;
   white-space: pre;
   font-size: 1.2em;
-  padding: 3px 0;
 }
+div.diffblocks { counter-reset: lineno; }
+div.diffblock { counter-increment: lineno; }
 span.difflineplus { color:#008800; }
 span.difflineminus { color:#cc0000; }
 span.difflineat { color:#990099; }
 
+pre.sourcelines { position: relative; counter-reset: lineno; }
+pre.sourcelines > span {
+    display: inline-block;
+    box-sizing: border-box;
+    width: 100%;
+    padding: 0 0 0 5em;
+    font-size: 1.2em;
+    counter-increment: lineno;
+    vertical-align: top;
+}
+div.source > pre.sourcelines > span {
+    padding: 1px 1px 1px 5em;
+}
+pre.sourcelines > span:before {
+    -moz-user-select: -moz-none;
+    -khtml-user-select: none;
+    -webkit-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    display: inline-block;
+    margin-left: -5em;
+    width: 4em;
+    color: #999;
+    text-align: right;
+    content: counters(lineno,".");
+    float: left;
+}
+pre.sourcelines > a {
+    display: inline-block;
+    position: absolute;
+    left: 0px;
+    width: 4em;
+    height: 1em;
+}
+pre.sourcelines.stripes > :nth-child(4n+1) { background-color: #F1F6F7; }
+pre.sourcelines.stripes > :nth-child(4n+3) { background-color: #FFFFFF; }
+pre.sourcelines.stripes > :nth-child(4n+1):hover,
+pre.sourcelines.stripes > :nth-child(4n+3):hover { background-color: #D5E1E6; }
+tr:target td,
+pre.sourcelines > span:target,
+pre.sourcelines.stripes > span:target {
+    background-color: #bfdfff;
+}
+
 td.source {
   white-space: pre;
-  font-family: monospace;
   margin: 10px 30px 0;
   font-size: 1.2em;
   font-family: monospace;
 }
-  div.source div.parity0,
-  div.source div.parity1 {
-    padding: 1px;
-    font-size: 1.2em;
-  }
-  div.source div.parity0 {
-    background: #F1F6F7;
-  }
-  div.source div.parity1 {
-    background: #FFFFFF;
-  }
-div.parity0:hover,
-div.parity1:hover {
-  background: #D5E1E6;
-}
 .linenr {
   color: #999;
   text-align: right;
@@ -311,44 +340,6 @@
 div#powered-by a:hover {
   text-decoration: underline;
 }
-/*
-div#monoblue-corner-top-left {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 10px;
-  height: 10px;
-  background: url(./monoblue-corner.png) top left no-repeat !important;
-  background: none;
-}
-div#monoblue-corner-top-right {
-  position: absolute;
-  top: 0;
-  right: 0;
-  width: 10px;
-  height: 10px;
-  background: url(./monoblue-corner.png) top right no-repeat !important;
-  background: none;
-}
-div#monoblue-corner-bottom-left {
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  width: 10px;
-  height: 10px;
-  background: url(./monoblue-corner.png) bottom left no-repeat !important;
-  background: none;
-}
-div#monoblue-corner-bottom-right {
-  position: absolute;
-  bottom: 0;
-  right: 0;
-  width: 10px;
-  height: 10px;
-  background: url(./monoblue-corner.png) bottom right no-repeat !important;
-  background: none;
-}
-*/
 /** end of common settings **/
 
 /** summary **/
@@ -553,3 +544,7 @@
 .scroll-loading-error {
     background-color: #FFCCCC !important;
 }
+
+#doc {
+    margin: 0 30px;
+}
--- a/mercurial/templates/static/style-paper.css	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/templates/static/style-paper.css	Fri Sep 25 23:10:47 2015 -0500
@@ -209,14 +209,13 @@
 .bigtable td.annotate { font-size: smaller; }
 .bigtable td.source { font-size: inherit; }
 
-.source, .sourcefirst, .sourcelast {
+.source, .sourcefirst {
   font-family: monospace;
   white-space: pre;
   padding: 1px 4px;
   font-size: 90%;
 }
 .sourcefirst { border-bottom: 1px solid #999; font-weight: bold; }
-.sourcelast { border-top: 1px solid #999; }
 .source a { color: #999; font-size: smaller; font-family: monospace;}
 .bottomline { border-bottom: 1px solid #999; }
 
--- a/mercurial/transaction.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/transaction.py	Fri Sep 25 23:10:47 2015 -0500
@@ -11,9 +11,15 @@
 # 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 _
+from __future__ import absolute_import
+
 import errno
-import error, util
+
+from .i18n import _
+from . import (
+    error,
+    util,
+)
 
 version = 2
 
--- a/mercurial/treediscovery.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/treediscovery.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,10 +5,19 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
 import collections
-from node import nullid, short
-from i18n import _
-import util, error
+
+from .i18n import _
+from .node import (
+    nullid,
+    short,
+)
+from . import (
+    error,
+    util,
+)
 
 def findcommonincoming(repo, remote, heads=None, force=False):
     """Return a tuple (common, fetch, heads) used to identify the common
--- a/mercurial/ui.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/ui.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,11 +5,28 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+from __future__ import absolute_import
+
+import errno
+import getpass
 import inspect
-from i18n import _
-import errno, getpass, os, socket, sys, tempfile, traceback
-import config, scmutil, util, error, formatter, progress
-from node import hex
+import os
+import socket
+import sys
+import tempfile
+import traceback
+
+from .i18n import _
+from .node import hex
+
+from . import (
+    config,
+    error,
+    formatter,
+    progress,
+    scmutil,
+    util,
+)
 
 samplehgrcs = {
     'user':
@@ -533,12 +550,21 @@
 
     def expandpath(self, loc, default=None):
         """Return repository location relative to cwd or from [paths]"""
-        if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
-            return loc
+        try:
+            p = self.paths.getpath(loc)
+            if p:
+                return p.rawloc
+        except error.RepoError:
+            pass
 
-        p = self.paths.getpath(loc, default=default)
-        if p:
-            return p.loc
+        if default:
+            try:
+                p = self.paths.getpath(default)
+                if p:
+                    return p.rawloc
+            except error.RepoError:
+                pass
+
         return loc
 
     @util.propertycache
@@ -808,7 +834,9 @@
         if self.debugflag:
             opts['label'] = opts.get('label', '') + ' ui.debug'
             self.write(*msg, **opts)
-    def edit(self, text, user, extra={}, editform=None):
+    def edit(self, text, user, extra=None, editform=None):
+        if extra is None:
+            extra = {}
         (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
                                       text=True)
         try:
@@ -840,7 +868,7 @@
 
         return t
 
-    def system(self, cmd, environ={}, cwd=None, onerr=None, errprefix=None):
+    def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None):
         '''execute shell command with appropriate output stream. command
         output will be redirected if fout is not stdout.
         '''
@@ -943,9 +971,12 @@
 
         service should be a readily-identifiable subsystem, which will
         allow filtering.
-        message should be a newline-terminated string to log.
+
+        *msg should be a newline-terminated format string to log, and
+        then any values to %-format into that format string.
+
+        **opts currently has no defined meanings.
         '''
-        pass
 
     def label(self, msg, label):
         '''style msg based on supplied label
@@ -982,37 +1013,102 @@
             # No location is the same as not existing.
             if not loc:
                 continue
+
+            # TODO ignore default-push once all consumers stop referencing it
+            # since it is handled specifically below.
+
             self[name] = path(name, rawloc=loc)
 
+        # Handle default-push, which is a one-off that defines the push URL for
+        # the "default" path.
+        defaultpush = ui.config('paths', 'default-push')
+        if defaultpush and 'default' in self:
+            self['default']._pushloc = defaultpush
+
     def getpath(self, name, default=None):
-        """Return a ``path`` for the specified name, falling back to a default.
+        """Return a ``path`` from a string, falling back to a default.
+
+        ``name`` can be a named path or locations. Locations are filesystem
+        paths or URIs.
 
-        Returns the first of ``name`` or ``default`` that is present, or None
-        if neither is present.
+        Returns None if ``name`` is not a registered path, a URI, or a local
+        path to a repo.
         """
+        # Only fall back to default if no path was requested.
+        if name is None:
+            if default:
+                try:
+                    return self[default]
+                except KeyError:
+                    return None
+            else:
+                return None
+
+        # Most likely empty string.
+        # This may need to raise in the future.
+        if not name:
+            return None
+
         try:
             return self[name]
         except KeyError:
-            if default is not None:
-                try:
-                    return self[default]
-                except KeyError:
-                    pass
+            # Try to resolve as a local path or URI.
+            try:
+                return path(None, rawloc=name)
+            except ValueError:
+                raise error.RepoError(_('repository %s does not exist') %
+                                        name)
 
-        return None
+        assert False
 
 class path(object):
     """Represents an individual path and its configuration."""
 
-    def __init__(self, name, rawloc=None):
+    def __init__(self, name, rawloc=None, pushloc=None):
         """Construct a path from its config options.
 
         ``name`` is the symbolic name of the path.
         ``rawloc`` is the raw location, as defined in the config.
+        ``pushloc`` is the raw locations pushes should be made to.
+
+        If ``name`` is not defined, we require that the location be a) a local
+        filesystem path with a .hg directory or b) a URL. If not,
+        ``ValueError`` is raised.
         """
+        if not rawloc:
+            raise ValueError('rawloc must be defined')
+
+        # Locations may define branches via syntax <base>#<branch>.
+        u = util.url(rawloc)
+        branch = None
+        if u.fragment:
+            branch = u.fragment
+            u.fragment = None
+
+        self.url = u
+        self.branch = branch
+
         self.name = name
-        # We'll do more intelligent things with rawloc in the future.
-        self.loc = rawloc
+        self.rawloc = rawloc
+        self.loc = str(u)
+        self._pushloc = pushloc
+
+        # When given a raw location but not a symbolic name, validate the
+        # location is valid.
+        if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
+            raise ValueError('location is not a URL or path to a local '
+                             'repo: %s' % rawloc)
+
+    def _isvalidlocalpath(self, path):
+        """Returns True if the given path is a potentially valid repository.
+        This is its own function so that extensions can change the definition of
+        'valid' in this case (like when pulling from a git repo into a hg
+        one)."""
+        return os.path.isdir(os.path.join(path, '.hg'))
+
+    @property
+    def pushloc(self):
+        return self._pushloc or self.loc
 
 # we instantiate one globally shared progress bar to avoid
 # competing progress bars when multiple UI objects get created
--- a/mercurial/unionrepo.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/unionrepo.py	Fri Sep 25 23:10:47 2015 -0500
@@ -11,11 +11,25 @@
 allowing operations like diff and log with revsets.
 """
 
-from node import nullid
-from i18n import _
+from __future__ import absolute_import
+
 import os
-import util, mdiff, cmdutil, scmutil
-import localrepo, changelog, manifest, filelog, revlog, pathutil
+
+from .i18n import _
+from .node import nullid
+
+from . import (
+    changelog,
+    cmdutil,
+    filelog,
+    localrepo,
+    manifest,
+    mdiff,
+    pathutil,
+    revlog,
+    scmutil,
+    util,
+)
 
 class unionrevlog(revlog.revlog):
     def __init__(self, opener, indexfile, revlog2, linkmapper):
@@ -35,7 +49,7 @@
         for rev2 in self.revlog2:
             rev = self.revlog2.index[rev2]
             # rev numbers - in revlog2, very different from self.rev
-            _start, _csize, _rsize, _base, linkrev, p1rev, p2rev, node = rev
+            _start, _csize, _rsize, base, linkrev, p1rev, p2rev, node = rev
 
             if linkmapper is None: # link is to same revlog
                 assert linkrev == rev2 # we never link back
@@ -43,6 +57,9 @@
             else: # rev must be mapped from repo2 cl to unified cl by linkmapper
                 link = linkmapper(linkrev)
 
+            if linkmapper is not None: # link is to same revlog
+                base = linkmapper(base)
+
             if node in self.nodemap:
                 # this happens for the common revlog revisions
                 self.bundlerevs.add(self.nodemap[node])
@@ -51,7 +68,7 @@
             p1node = self.revlog2.node(p1rev)
             p2node = self.revlog2.node(p2rev)
 
-            e = (None, None, None, None,
+            e = (None, None, None, base,
                  link, self.rev(p1node), self.rev(p2node), node)
             self.index.insert(-1, e)
             self.nodemap[node] = n
--- a/mercurial/url.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/url.py	Fri Sep 25 23:10:47 2015 -0500
@@ -7,10 +7,23 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import urllib, urllib2, httplib, os, socket, cStringIO, base64
-from i18n import _
-import keepalive, util, sslutil
-import httpconnection as httpconnectionmod
+from __future__ import absolute_import
+
+import base64
+import cStringIO
+import httplib
+import os
+import socket
+import urllib
+import urllib2
+
+from .i18n import _
+from . import (
+    httpconnection as httpconnectionmod,
+    keepalive,
+    sslutil,
+    util,
+)
 
 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
     def __init__(self, ui):
--- a/mercurial/util.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/util.py	Fri Sep 25 23:10:47 2015 -0500
@@ -21,6 +21,8 @@
 import os, time, datetime, calendar, textwrap, signal, collections
 import imp, socket, urllib
 import gc
+import bz2
+import zlib
 
 if os.name == 'nt':
     import windows as platform
@@ -728,7 +730,7 @@
     global _hgexecutable
     _hgexecutable = path
 
-def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
+def system(cmd, environ=None, cwd=None, onerr=None, errprefix=None, out=None):
     '''enhanced shell command execution.
     run with environment maybe modified, maybe in different dir.
 
@@ -737,6 +739,8 @@
 
     if out is specified, it is assumed to be a file-like object that has a
     write() method. stdout and stderr will be redirected to out.'''
+    if environ is None:
+        environ = {}
     try:
         sys.stdout.flush()
     except Exception:
@@ -1371,22 +1375,22 @@
     """turn (timestamp, tzoff) tuple into iso 8631 date."""
     return datestr(date, format='%Y-%m-%d')
 
+def parsetimezone(tz):
+    """parse a timezone string and return an offset integer"""
+    if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
+        sign = (tz[0] == "+") and 1 or -1
+        hours = int(tz[1:3])
+        minutes = int(tz[3:5])
+        return -sign * (hours * 60 + minutes) * 60
+    if tz == "GMT" or tz == "UTC":
+        return 0
+    return None
+
 def strdate(string, format, defaults=[]):
     """parse a localized time string and return a (unixtime, offset) tuple.
     if the string cannot be parsed, ValueError is raised."""
-    def timezone(string):
-        tz = string.split()[-1]
-        if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
-            sign = (tz[0] == "+") and 1 or -1
-            hours = int(tz[1:3])
-            minutes = int(tz[3:5])
-            return -sign * (hours * 60 + minutes) * 60
-        if tz == "GMT" or tz == "UTC":
-            return 0
-        return None
-
     # NOTE: unixtime = localunixtime + offset
-    offset, date = timezone(string), string
+    offset, date = parsetimezone(string.split()[-1]), string
     if offset is not None:
         date = " ".join(string.split()[:-1])
 
@@ -1412,7 +1416,7 @@
         unixtime = localunixtime + offset
     return unixtime, offset
 
-def parsedate(date, formats=None, bias={}):
+def parsedate(date, formats=None, bias=None):
     """parse a localized date/time and return a (unixtime, offset) tuple.
 
     The date may be a "unixtime offset" string or in one of the specified
@@ -1432,6 +1436,8 @@
     >>> tz == strtz
     True
     """
+    if bias is None:
+        bias = {}
     if not date:
         return 0, 0
     if isinstance(date, tuple) and len(date) == 2:
@@ -1667,7 +1673,7 @@
             elif not cur_line:
                 cur_line.append(reversed_chunks.pop())
 
-        # this overriding code is imported from TextWrapper of python 2.6
+        # this overriding code is imported from TextWrapper of Python 2.6
         # to calculate columns of string by 'encoding.ucolwidth()'
         def _wrap_chunks(self, chunks):
             colwidth = encoding.ucolwidth
@@ -2260,7 +2266,7 @@
 
 class hooks(object):
     '''A collection of hook functions that can be used to extend a
-    function's behaviour. Hooks are called in lexicographic order,
+    function's behavior. Hooks are called in lexicographic order,
     based on the names of their sources.'''
 
     def __init__(self):
@@ -2338,5 +2344,45 @@
         yield path[:pos]
         pos = path.rfind('/', 0, pos)
 
+# compression utility
+
+class nocompress(object):
+    def compress(self, x):
+        return x
+    def flush(self):
+        return ""
+
+compressors = {
+    None: nocompress,
+    # lambda to prevent early import
+    'BZ': lambda: bz2.BZ2Compressor(),
+    'GZ': lambda: zlib.compressobj(),
+    }
+# also support the old form by courtesies
+compressors['UN'] = compressors[None]
+
+def _makedecompressor(decompcls):
+    def generator(f):
+        d = decompcls()
+        for chunk in filechunkiter(f):
+            yield d.decompress(chunk)
+    def func(fh):
+        return chunkbuffer(generator(fh))
+    return func
+
+def _bz2():
+    d = bz2.BZ2Decompressor()
+    # Bzip2 stream start with BZ, but we stripped it.
+    # we put it back for good measure.
+    d.decompress('BZ')
+    return d
+
+decompressors = {None: lambda fh: fh,
+                 'BZ': _makedecompressor(_bz2),
+                 'GZ': _makedecompressor(lambda: zlib.decompressobj()),
+                 }
+# also support the old form by courtesies
+decompressors['UN'] = decompressors[None]
+
 # convenient shortcut
 dst = debugstacktrace
--- a/mercurial/verify.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/verify.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,10 +5,21 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from node import nullid, short
-from i18n import _
+from __future__ import absolute_import
+
 import os
-import revlog, util, error
+
+from .i18n import _
+from .node import (
+    nullid,
+    short,
+)
+
+from . import (
+    error,
+    revlog,
+    util,
+)
 
 def verify(repo):
     lock = repo.lock()
--- a/mercurial/win32.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/win32.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,7 +5,14 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import ctypes, errno, msvcrt, os, subprocess, random
+from __future__ import absolute_import
+
+import ctypes
+import errno
+import msvcrt
+import os
+import random
+import subprocess
 
 _kernel32 = ctypes.windll.kernel32
 _advapi32 = ctypes.windll.advapi32
--- a/mercurial/wireproto.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/wireproto.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,12 +5,29 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import urllib, tempfile, os, sys
-from i18n import _
-from node import bin, hex
-import changegroup as changegroupmod, bundle2, pushkey as pushkeymod
-import peer, error, encoding, util, exchange
+from __future__ import absolute_import
+
+import os
+import sys
+import tempfile
+import urllib
 
+from .i18n import _
+from .node import (
+    bin,
+    hex,
+)
+
+from . import (
+    bundle2,
+    changegroup as changegroupmod,
+    encoding,
+    error,
+    exchange,
+    peer,
+    pushkey as pushkeymod,
+    util,
+)
 
 class abstractserverproto(object):
     """abstract class that summarizes the protocol API
@@ -58,48 +75,12 @@
         Some protocols may have compressed the contents."""
         raise NotImplementedError()
 
-# abstract batching support
-
-class future(object):
-    '''placeholder for a value to be set later'''
-    def set(self, value):
-        if util.safehasattr(self, 'value'):
-            raise error.RepoError("future is already set")
-        self.value = value
-
-class batcher(object):
-    '''base class for batches of commands submittable in a single request
-
-    All methods invoked on instances of this class are simply queued and
-    return a a future for the result. Once you call submit(), all the queued
-    calls are performed and the results set in their respective futures.
-    '''
-    def __init__(self):
-        self.calls = []
-    def __getattr__(self, name):
-        def call(*args, **opts):
-            resref = future()
-            self.calls.append((name, args, opts, resref,))
-            return resref
-        return call
-    def submit(self):
-        pass
-
-class localbatch(batcher):
-    '''performs the queued calls directly'''
-    def __init__(self, local):
-        batcher.__init__(self)
-        self.local = local
-    def submit(self):
-        for name, args, opts, resref in self.calls:
-            resref.set(getattr(self.local, name)(*args, **opts))
-
-class remotebatch(batcher):
+class remotebatch(peer.batcher):
     '''batches the queued calls; uses as few roundtrips as possible'''
     def __init__(self, remote):
         '''remote must support _submitbatch(encbatch) and
         _submitone(op, encargs)'''
-        batcher.__init__(self)
+        peer.batcher.__init__(self)
         self.remote = remote
     def submit(self):
         req, rsp = [], []
@@ -128,41 +109,10 @@
             encresref.set(encres)
             resref.set(batchable.next())
 
-def batchable(f):
-    '''annotation for batchable methods
-
-    Such methods must implement a coroutine as follows:
-
-    @batchable
-    def sample(self, one, two=None):
-        # Handle locally computable results first:
-        if not one:
-            yield "a local result", None
-        # Build list of encoded arguments suitable for your wire protocol:
-        encargs = [('one', encode(one),), ('two', encode(two),)]
-        # Create future for injection of encoded result:
-        encresref = future()
-        # Return encoded arguments and future:
-        yield encargs, encresref
-        # Assuming the future to be filled with the result from the batched
-        # request now. Decode it:
-        yield decode(encresref.value)
-
-    The decorator returns a function which wraps this coroutine as a plain
-    method, but adds the original method as an attribute called "batchable",
-    which is used by remotebatch to split the call into separate encoding and
-    decoding phases.
-    '''
-    def plain(*args, **opts):
-        batchable = f(*args, **opts)
-        encargsorres, encresref = batchable.next()
-        if not encresref:
-            return encargsorres # a local result in this case
-        self = args[0]
-        encresref.set(self._submitone(f.func_name, encargsorres))
-        return batchable.next()
-    setattr(plain, 'batchable', f)
-    return plain
+# Forward a couple of names from peer to make wireproto interactions
+# slightly more sensible.
+batchable = peer.batchable
+future = peer.future
 
 # list of nodes encoding / decoding
 
@@ -216,7 +166,10 @@
 class wirepeer(peer.peerrepository):
 
     def batch(self):
-        return remotebatch(self)
+        if self.capable('batch'):
+            return remotebatch(self)
+        else:
+            return peer.localbatch(self)
     def _submitbatch(self, req):
         cmds = []
         for op, argsdict in req:
--- a/mercurial/worker.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/mercurial/worker.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,30 +5,24 @@
 # 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 errno, os, signal, sys, threading
-import util
+from __future__ import absolute_import
+
+import errno
+import multiprocessing
+import os
+import signal
+import sys
+import threading
+
+from .i18n import _
+from . import util
 
 def countcpus():
     '''try to count the number of CPUs on the system'''
-
-    # posix
     try:
-        n = int(os.sysconf('SC_NPROCESSORS_ONLN'))
-        if n > 0:
-            return n
-    except (AttributeError, ValueError):
-        pass
-
-    # windows
-    try:
-        n = int(os.environ['NUMBER_OF_PROCESSORS'])
-        if n > 0:
-            return n
-    except (KeyError, ValueError):
-        pass
-
-    return 1
+        return multiprocessing.cpu_count()
+    except NotImplementedError:
+        return 1
 
 def _numworkers(ui):
     s = ui.config('worker', 'numcpus')
--- a/tests/bzr-definitions	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/bzr-definitions	Fri Sep 25 23:10:47 2015 -0500
@@ -1,7 +1,5 @@
 # this file holds the definitions that are used in various bzr tests
 
-"$TESTDIR/hghave" bzr || exit 80
-
 TERM=dumb; export TERM
 echo '[extensions]' >> $HGRCPATH
 echo 'convert = ' >> $HGRCPATH
--- a/tests/filterpyflakes.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/filterpyflakes.py	Fri Sep 25 23:10:47 2015 -0500
@@ -2,7 +2,7 @@
 
 # Filter output by pyflakes to control which warnings we check
 
-import sys, re, os
+import sys, re
 
 def makekey(typeandline):
     """
@@ -42,7 +42,7 @@
     else:
         continue # no pattern matched, next line
     fn = line.split(':', 1)[0]
-    f = open(os.path.join(os.path.dirname(os.path.dirname(__file__)), fn))
+    f = open(fn)
     data = f.read()
     f.close()
     if 'no-' 'check-code' in data:
--- a/tests/hghave	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/hghave	Fri Sep 25 23:10:47 2015 -0500
@@ -30,10 +30,8 @@
                   help="test available features")
 parser.add_option("--list-features", action="store_true",
                   help="list available features")
-parser.add_option("-q", "--quiet", action="store_true",
-                  help="check features silently")
 
-def _loadaddon(quiet):
+def _loadaddon():
     if 'TESTDIR' in os.environ:
         # loading from '.' isn't needed, because `hghave` should be
         # running at TESTTMP in this case
@@ -48,15 +46,14 @@
     try:
         import hghaveaddon
     except BaseException, inst:
-        if not quiet:
-            sys.stderr.write('failed to import hghaveaddon.py from %r: %s\n'
-                             % (path, inst))
+        sys.stderr.write('failed to import hghaveaddon.py from %r: %s\n'
+                         % (path, inst))
         sys.exit(2)
     sys.path.pop(0)
 
 if __name__ == '__main__':
     options, args = parser.parse_args()
-    _loadaddon(options.quiet)
+    _loadaddon()
     if options.list_features:
         list_features()
         sys.exit(0)
@@ -64,36 +61,4 @@
     if options.test_features:
         sys.exit(test_features())
 
-    quiet = options.quiet
-
-    failures = 0
-
-    def error(msg):
-        global failures
-        if not quiet:
-            sys.stderr.write(msg + '\n')
-        failures += 1
-
-    for feature in args:
-        negate = feature.startswith('no-')
-        if negate:
-            feature = feature[3:]
-
-        if feature not in checks:
-            error('skipped: unknown feature: ' + feature)
-            sys.exit(2)
-
-        check, desc = checks[feature]
-        try:
-            available = check()
-        except Exception, e:
-            error('hghave check failed: ' + feature)
-            continue
-
-        if not negate and not available:
-            error('skipped: missing feature: ' + desc)
-        elif negate and available:
-            error('skipped: system supports %s' % desc)
-
-    if failures != 0:
-        sys.exit(1)
+    hghave.require(args)
--- a/tests/hghave.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/hghave.py	Fri Sep 25 23:10:47 2015 -0500
@@ -1,6 +1,9 @@
-import os, stat
+import errno
+import os
 import re
 import socket
+import stat
+import subprocess
 import sys
 import tempfile
 
@@ -17,19 +20,68 @@
         return func
     return decorator
 
+def checkfeatures(features):
+    result = {
+        'error': [],
+        'missing': [],
+        'skipped': [],
+    }
+
+    for feature in features:
+        negate = feature.startswith('no-')
+        if negate:
+            feature = feature[3:]
+
+        if feature not in checks:
+            result['missing'].append(feature)
+            continue
+
+        check, desc = checks[feature]
+        try:
+            available = check()
+        except Exception:
+            result['error'].append('hghave check failed: %s' % feature)
+            continue
+
+        if not negate and not available:
+            result['skipped'].append('missing feature: %s' % desc)
+        elif negate and available:
+            result['skipped'].append('system supports %s' % desc)
+
+    return result
+
+def require(features):
+    """Require that features are available, exiting if not."""
+    result = checkfeatures(features)
+
+    for missing in result['missing']:
+        sys.stderr.write('skipped: unknown feature: %s\n' % missing)
+    for msg in result['skipped']:
+        sys.stderr.write('skipped: %s\n' % msg)
+    for msg in result['error']:
+        sys.stderr.write('%s\n' % msg)
+
+    if result['missing']:
+        sys.exit(2)
+
+    if result['skipped'] or result['error']:
+        sys.exit(1)
+
 def matchoutput(cmd, regexp, ignorestatus=False):
     """Return True if cmd executes successfully and its output
     is matched by the supplied regular expression.
     """
     r = re.compile(regexp)
-    fh = os.popen(cmd)
-    s = fh.read()
     try:
-        ret = fh.close()
-    except IOError:
-        # Happen in Windows test environment
-        ret = 1
-    return (ignorestatus or ret is None) and r.search(s)
+        p = subprocess.Popen(
+            cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    except OSError as e:
+        if e.errno != errno.ENOENT:
+            raise
+        ret = -1
+    ret = p.wait()
+    s = p.stdout.read()
+    return (ignorestatus or not ret) and r.search(s)
 
 @check("baz", "GNU Arch baz client")
 def has_baz():
@@ -367,6 +419,33 @@
 def has_osx():
     return sys.platform == 'darwin'
 
+@check("docker", "docker support")
+def has_docker():
+    pat = r'A self-sufficient runtime for linux containers\.'
+    if matchoutput('docker --help', pat):
+        if 'linux' not in sys.platform:
+            # TODO: in theory we should be able to test docker-based
+            # package creation on non-linux using boot2docker, but in
+            # practice that requires extra coordination to make sure
+            # $TESTTEMP is going to be visible at the same path to the
+            # boot2docker VM. If we figure out how to verify that, we
+            # can use the following instead of just saying False:
+            # return 'DOCKER_HOST' in os.environ
+            return False
+
+        return True
+    return False
+
+@check("debhelper", "debian packaging tools")
+def has_debhelper():
+    dpkg = matchoutput('dpkg --version',
+                       "Debian `dpkg' package management program")
+    dh = matchoutput('dh --help',
+                     'dh is a part of debhelper.', ignorestatus=True)
+    dh_py2 = matchoutput('dh_python2 --help',
+                         'other supported Python versions')
+    return dpkg and dh and dh_py2
+
 @check("absimport", "absolute_import in __future__")
 def has_absimport():
     import __future__
@@ -380,3 +459,7 @@
 @check("pure", "running with pure Python code")
 def has_pure():
     return os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure"
+
+@check("slow", "allow slow tests")
+def has_slow():
+    return os.environ.get('HGTEST_SLOW') == 'slow'
--- a/tests/run-tests.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/run-tests.py	Fri Sep 25 23:10:47 2015 -0500
@@ -35,6 +35,8 @@
 #      ./run-tests.py -j2 -c --local test-s*  # unsupported (and broken)
 #  9) parallel, custom tmp dir:
 #      ./run-tests.py -j2 --tmpdir /tmp/myhgtests
+#  10) parallel, pure, tests that call run-tests:
+#      ./run-tests.py --pure `grep -l run-tests.py *.t`
 #
 # (You could use any subset of the tests: test-s* happens to match
 # enough that it's worth doing parallel runs, few enough that it
@@ -259,6 +261,8 @@
                       help='run tests in random order')
     parser.add_option('--profile-runner', action='store_true',
                       help='run statprof on run-tests')
+    parser.add_option('--allow-slow-tests', action='store_true',
+                      help='allow extremely slow tests')
 
     for option, (envvar, default) in defaults.items():
         defaults[option] = type(default)(os.environ.get(envvar, default))
@@ -1835,6 +1839,11 @@
         if self.options.pure:
             os.environ["HGTEST_RUN_TESTS_PURE"] = "--pure"
 
+        if self.options.allow_slow_tests:
+            os.environ["HGTEST_SLOW"] = "slow"
+        elif 'HGTEST_SLOW' in os.environ:
+            del os.environ['HGTEST_SLOW']
+
         self._coveragefile = os.path.join(self._testdir, b'.coverage')
 
         vlog("# Using TESTDIR", self._testdir)
@@ -2078,7 +2087,11 @@
         vlog("# Running", cmd)
         if os.system(cmd) == 0:
             if not self.options.verbose:
-                os.remove(installerrs)
+                try:
+                    os.remove(installerrs)
+                except OSError as e:
+                    if e.errno != errno.ENOENT:
+                        raise
         else:
             f = open(installerrs, 'rb')
             for line in f:
--- a/tests/test-bad-extension.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-bad-extension.t	Fri Sep 25 23:10:47 2015 -0500
@@ -9,31 +9,26 @@
   > badext2 =
   > EOF
 
-  $ hg -q help help
+  $ hg -q help help 2>&1 |grep extension
   *** failed to import extension badext from $TESTTMP/badext.py: bit bucket overflow
   *** failed to import extension badext2: No module named badext2
-  hg help [-ec] [TOPIC]
-  
-  show help for a given topic or a help overview
 
 show traceback
 
-  $ hg -q help help --traceback 2>&1 | grep -v '^  '
+  $ hg -q help help --traceback 2>&1 | egrep ' extension|^Exception|Traceback|ImportError'
   *** failed to import extension badext from $TESTTMP/badext.py: bit bucket overflow
   Traceback (most recent call last):
   Exception: bit bucket overflow
   *** failed to import extension badext2: No module named badext2
   Traceback (most recent call last):
   ImportError: No module named badext2
-  hg help [-ec] [TOPIC]
-  
-  show help for a given topic or a help overview
 
 show traceback for ImportError of hgext.name if debug is set
 (note that --debug option isn't applied yet when loading extensions)
 
-  $ hg help help --traceback --config ui.debug=True 2>&1 \
-  > | grep -v '^  ' | head -n10
+  $ (hg -q help help --traceback --config ui.debug=True 2>&1) \
+  > | grep -v '^ ' \
+  > | egrep 'extension..[^p]|^Exception|Traceback|ImportError|not import'
   *** failed to import extension badext from $TESTTMP/badext.py: bit bucket overflow
   Traceback (most recent call last):
   Exception: bit bucket overflow
@@ -43,4 +38,3 @@
   *** failed to import extension badext2: No module named badext2
   Traceback (most recent call last):
   ImportError: No module named badext2
-  hg help [-ec] [TOPIC]
--- a/tests/test-batching.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-batching.py	Fri Sep 25 23:10:47 2015 -0500
@@ -5,7 +5,8 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from mercurial.wireproto import localbatch, remotebatch, batchable, future
+from mercurial.peer import localbatch, batchable, future
+from mercurial.wireproto import remotebatch
 
 # equivalent of repo.repository
 class thing(object):
--- a/tests/test-blackbox.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-blackbox.t	Fri Sep 25 23:10:47 2015 -0500
@@ -13,8 +13,8 @@
   $ 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 a exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> add a (glob)
+  1970/01/01 00:00:00 bob (*)> add a exited 0 after * seconds (glob)
 
 incoming change tracking
 
@@ -44,11 +44,11 @@
   added 1 changesets with 1 changes to 1 files
   (run 'hg update' to get a working copy)
   $ hg blackbox -l 5
-  1970/01/01 00:00:00 bob> pull
-  1970/01/01 00:00:00 bob> updated served branch cache in ?.???? seconds (glob)
-  1970/01/01 00:00:00 bob> wrote served branch cache with 1 labels and 2 nodes
-  1970/01/01 00:00:00 bob> 1 incoming changes - new heads: d02f48003e62
-  1970/01/01 00:00:00 bob> pull exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> pull (glob)
+  1970/01/01 00:00:00 bob (*)> updated served branch cache in ?.???? seconds (glob)
+  1970/01/01 00:00:00 bob (*)> wrote served branch cache with 1 labels and 2 nodes (glob)
+  1970/01/01 00:00:00 bob (*)> 1 incoming changes - new heads: d02f48003e62 (glob)
+  1970/01/01 00:00:00 bob (*)> pull exited 0 after * seconds (glob)
 
 we must not cause a failure if we cannot write to the log
 
@@ -106,11 +106,11 @@
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
   $ hg blackbox -l 5
-  1970/01/01 00:00:00 bob> strip tip
-  1970/01/01 00:00:00 bob> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
-  1970/01/01 00:00:00 bob> updated base branch cache in ?.???? seconds (glob)
-  1970/01/01 00:00:00 bob> wrote base branch cache with 1 labels and 2 nodes
-  1970/01/01 00:00:00 bob> strip tip exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> strip tip (glob)
+  1970/01/01 00:00:00 bob (*)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
+  1970/01/01 00:00:00 bob (*)> updated base branch cache in ?.???? seconds (glob)
+  1970/01/01 00:00:00 bob (*)> wrote base branch cache with 1 labels and 2 nodes (glob)
+  1970/01/01 00:00:00 bob (*)> strip tip exited 0 after * seconds (glob)
 
 extension and python hooks - use the eol extension for a pythonhook
 
@@ -122,11 +122,11 @@
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   hooked
   $ hg blackbox -l 5
-  1970/01/01 00:00:00 bob> update
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 0 tags
-  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 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> update (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 0 tags (glob)
+  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 0 after * seconds (glob)
 
 log rotation
 
--- a/tests/test-bookmarks.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-bookmarks.t	Fri Sep 25 23:10:47 2015 -0500
@@ -511,10 +511,10 @@
 
 test clone with update to a bookmark
 
-  $ hg clone -u Z . cloned-bookmarks-update
+  $ hg clone -u Z . ../cloned-bookmarks-update
   updating to branch default
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg -R cloned-bookmarks-update bookmarks
+  $ hg -R ../cloned-bookmarks-update bookmarks
      X2                        1:925d80f479bb
      Y                         2:db815d6d32e6
    * Z                         2:db815d6d32e6
@@ -569,10 +569,40 @@
 
   $ hg bookmark -r3 Y
   moving bookmark 'Y' forward from db815d6d32e6
-  $ hg -R cloned-bookmarks-update update Y
+  $ cp -r  ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
+
+(manual version)
+
+  $ hg -R ../cloned-bookmarks-manual-update update Y
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   (activating bookmark Y)
-  $ hg -R cloned-bookmarks-update pull --update .
+  $ hg -R ../cloned-bookmarks-manual-update pull .
+  pulling from .
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files (+1 heads)
+  updating bookmark Y
+  updating bookmark Z
+  (run 'hg heads' to see heads, 'hg merge' to merge)
+
+(# tests strange but with --date crashing when bookmark have to move)
+
+  $ hg -R ../cloned-bookmarks-manual-update update -d 1986
+  abort: revision matching date not found
+  [255]
+  $ hg -R ../cloned-bookmarks-manual-update update
+  updating to active bookmark Y
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (activating bookmark Y)
+
+(all in one version)
+
+  $ hg -R ../cloned-bookmarks-update update Y
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (activating bookmark Y)
+  $ hg -R ../cloned-bookmarks-update pull --update .
   pulling from .
   searching for changes
   adding changesets
--- a/tests/test-bundle2-format.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-bundle2-format.t	Fri Sep 25 23:10:47 2015 -0500
@@ -78,6 +78,7 @@
   >           ('', 'reply', False, 'produce a reply bundle'),
   >           ('', 'pushrace', False, 'includes a check:head part with unknown nodes'),
   >           ('', 'genraise', False, 'includes a part that raise an exception during generation'),
+  >           ('', 'timeout', False, 'emulate a timeout during bundle generation'),
   >           ('r', 'rev', [], 'includes those changeset in the bundle'),],
   >          '[OUTPUTFILE]')
   > def cmdbundle2(ui, repo, path=None, **opts):
@@ -143,6 +144,18 @@
   >     else:
   >         file = open(path, 'wb')
   > 
+  >     if opts['timeout']:
+  >         bundler.newpart('test:song', data=ELEPHANTSSONG, mandatory=False)
+  >         for idx, junk in enumerate(bundler.getchunks()):
+  >             ui.write('%d chunk\n' % idx)
+  >             if idx > 4:
+  >                 # This throws a GeneratorExit inside the generator, which
+  >                 # can cause problems if the exception-recovery code is
+  >                 # too zealous. It's important for this test that the break
+  >                 # occur while we're in the middle of a part.
+  >                 break
+  >         ui.write('fake timeout complete.\n')
+  >         return
   >     try:
   >         for chunk in bundler.getchunks():
   >             file.write(chunk)
@@ -239,6 +252,26 @@
   $ hg bundle2
   HG20\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
 
+Test timeouts during bundling
+  $ hg bundle2 --timeout --debug --config devel.bundle2.debug=yes
+  bundle2-output-bundle: "HG20", 1 parts total
+  bundle2-output: start emission of HG20 stream
+  0 chunk
+  bundle2-output: bundle parameter: 
+  1 chunk
+  bundle2-output: start of parts
+  bundle2-output: bundle part: "test:song"
+  bundle2-output-part: "test:song" (advisory) 178 bytes payload
+  bundle2-output: part 0: "test:song"
+  bundle2-output: header chunk size: 16
+  2 chunk
+  3 chunk
+  bundle2-output: payload chunk size: 178
+  4 chunk
+  5 chunk
+  bundle2-generatorexit
+  fake timeout complete.
+
 Test unbundling
 
   $ hg bundle2 | hg statbundle2
--- a/tests/test-clone-r.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-clone-r.t	Fri Sep 25 23:10:47 2015 -0500
@@ -218,3 +218,26 @@
   4 files, 9 changesets, 7 total revisions
   $ cd ..
 
+  $ hg clone test test-9
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd test-9
+  $ hg branch foobar
+  marked working directory as branch foobar
+  (branches are permanent and global, did you want a bookmark?)
+  $ echo file2 >> file2
+  $ hg add file2
+  $ hg commit -m "changeset9"
+  $ echo file3 >> file3
+  $ hg add file3
+  $ hg commit -m "changeset10"
+  $ cd ..
+  $ hg clone -r 9 -u foobar test-9 test-10
+  adding changesets
+  adding manifests
+  adding file changes
+  added 6 changesets with 6 changes to 3 files
+  updating to branch foobar
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+
--- a/tests/test-clone.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-clone.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1020,7 +1020,7 @@
   $ hg -R a id -r 0
   acb14030fe0a
   $ hg id -R remote -r 0
-  abort: there is no Mercurial repository here (.hg not found)
+  abort: repository remote not found!
   [255]
   $ hg --config share.pool=share -q clone -e "python \"$TESTDIR/dummyssh\"" a ssh://user@dummy/remote
   $ hg -R remote id -r 0
--- a/tests/test-command-template.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-command-template.t	Fri Sep 25 23:10:47 2015 -0500
@@ -343,6 +343,11 @@
 
 Test xml styles:
 
+  $ hg log --style xml -r 'not all()'
+  <?xml version="1.0"?>
+  <log>
+  </log>
+
   $ hg log --style xml
   <?xml version="1.0"?>
   <log>
@@ -2495,10 +2500,14 @@
   abort: template filter 'escape' is not compatible with keyword 'date'
   [255]
 
+  $ hg log -l 3 --template 'line: {extras|localdate}\n'
+  hg: parse error: localdate expects a date information
+  [255]
+
 Behind the scenes, this will throw ValueError
 
   $ hg tip --template '{author|email|date}\n'
-  abort: template filter 'datefilter' is not compatible with keyword 'author'
+  hg: parse error: date expects a date information
   [255]
 
 Error in nested template:
@@ -2727,6 +2736,13 @@
   $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
   xx
 
+  $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
+  hg: parse error: sub got an invalid pattern: [
+  [255]
+  $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
+  hg: parse error: sub got an invalid replacement: \1
+  [255]
+
 Test the strip function with chars specified:
 
   $ hg log -R latesttag --template '{desc}\n'
@@ -2925,10 +2941,10 @@
   hg: parse error at 21: unterminated string
   [255]
   $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
-  hg: parse error at 11: syntax error
+  hg: parse error: trailing \ in string
   [255]
   $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
-  hg: parse error at 12: syntax error
+  hg: parse error: trailing \ in string
   [255]
 
   $ cd ..
@@ -3105,6 +3121,25 @@
   hg: parse error: get() expects a dict as first argument
   [255]
 
+Test localdate(date, tz) function:
+
+  $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
+  1970-01-01 09:00 +0900
+  $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
+  1970-01-01 00:00 +0000
+  $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
+  1970-01-01 02:00 +0200
+  $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
+  1970-01-01 00:00 +0000
+  $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
+  1970-01-01 00:00 +0000
+  $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
+  hg: parse error: localdate expects a timezone
+  [255]
+  $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
+  hg: parse error: localdate expects a timezone
+  [255]
+
 Test shortest(node) function:
 
   $ echo b > b
@@ -3117,6 +3152,8 @@
   e777603221
   bcc7ff960b
   f7769ec2ab
+  $ hg log --template '{node|shortest}\n' -l1
+  e777
 
 Test pad function
 
@@ -3197,6 +3234,23 @@
   $ hg log --template '{revset("TIP"|lower)}\n' -l1
   2
 
+ a list template is evaluated for each item of revset
+
+  $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
+  2 p: 1:bcc7ff960b8e
+  1 p: 0:f7769ec2ab97
+  0 p: 
+
+ therefore, 'revcache' should be recreated for each rev
+
+  $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
+  2 aa b
+  p 
+  1 
+  p a
+  0 a
+  p 
+
 Test active bookmark templating
 
   $ hg book foo
@@ -3385,3 +3439,12 @@
   $ hg log -T "{indent(date, '   ')}\n" -r 2:3 -R a
      1200000.00
      1300000.00
+
+Test broken string escapes:
+
+  $ hg log -T "bogus\\" -R a
+  hg: parse error: trailing \ in string
+  [255]
+  $ hg log -T "\\xy" -R a
+  hg: parse error: invalid \x escape
+  [255]
--- a/tests/test-commandserver.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-commandserver.t	Fri Sep 25 23:10:47 2015 -0500
@@ -322,7 +322,6 @@
   ...     runcommand(server, ['phase', '-r', '.'])
   *** runcommand phase -r . -p
   no phases changed
-   [1]
   *** runcommand commit -Am.
   *** runcommand rollback
   repository tip rolled back to revision 3 (undo commit)
@@ -415,6 +414,30 @@
   *** runcommand branches
   default                        1:731265503d86
 
+in-memory cache must be reloaded if transaction is aborted. otherwise
+changelog and manifest would have invalid node:
+
+  $ echo a >> a
+  >>> from hgclient import readchannel, runcommand, check
+  >>> @check
+  ... def txabort(server):
+  ...     readchannel(server)
+  ...     runcommand(server, ['commit', '--config', 'hooks.pretxncommit=false',
+  ...                         '-mfoo'])
+  ...     runcommand(server, ['verify'])
+  *** runcommand commit --config hooks.pretxncommit=false -mfoo
+  transaction abort!
+  rollback completed
+  abort: pretxncommit hook exited with status 1
+   [255]
+  *** runcommand verify
+  checking changesets
+  checking manifests
+  crosschecking files in changesets and manifests
+  checking files
+  1 files, 2 changesets, 2 total revisions
+  $ hg revert --no-backup -aq
+
   $ cat >> .hg/hgrc << EOF
   > [experimental]
   > evolution=createmarkers
@@ -589,6 +612,15 @@
   000000000000 tip
 
 
+don't fall back to cwd if invalid -R path is specified (issue4805):
+
+  $ cd repo
+  $ hg serve --cmdserver pipe -R ../nonexistent
+  abort: repository ../nonexistent not found!
+  [255]
+  $ cd ..
+
+
 unix domain socket:
 
   $ cd repo
--- a/tests/test-completion.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-completion.t	Fri Sep 25 23:10:47 2015 -0500
@@ -80,6 +80,7 @@
   debugdate
   debugdirstate
   debugdiscovery
+  debugextensions
   debugfileset
   debugfsinfo
   debuggetbundle
@@ -239,6 +240,7 @@
   debugdate: extended
   debugdirstate: nodates, datesort
   debugdiscovery: old, nonheads, ssh, remotecmd, insecure
+  debugextensions: template
   debugfileset: rev
   debugfsinfo: 
   debuggetbundle: head, common, type
@@ -254,7 +256,7 @@
   debugpathcomplete: full, normal, added, removed
   debugpushkey: 
   debugpvec: 
-  debugrebuilddirstate: rev
+  debugrebuilddirstate: rev, minimal
   debugrebuildfncache: 
   debugrename: rev
   debugrevlog: changelog, manifest, dir, dump
--- a/tests/test-conflict.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-conflict.t	Fri Sep 25 23:10:47 2015 -0500
@@ -232,3 +232,65 @@
   5
   >>>>>>> other
   Hop we are done.
+
+Add some unconflicting changes on each head, to make sure we really
+are merging, unlike :local and :other
+
+  $ hg up -C
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ printf "\n\nEnd of file\n" >> a
+  $ hg ci -m "Add some stuff at the end"
+  $ hg up -r 1
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ printf "Start of file\n\n\n" > tmp
+  $ cat a >> tmp
+  $ mv tmp a
+  $ hg ci -m "Add some stuff at the beginning"
+
+Now test :merge-other and :merge-local
+
+  $ hg merge
+  merging a
+  warning: conflicts during merge.
+  merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
+  1 files updated, 0 files merged, 0 files removed, 1 files unresolved
+  use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
+  [1]
+  $ hg resolve --tool :merge-other a
+  merging a
+  (no more unresolved files)
+  $ cat a
+  Start of file
+  
+  
+  Small Mathematical Series.
+  1
+  2
+  3
+  6
+  8
+  Hop we are done.
+  
+  
+  End of file
+
+  $ hg up -C
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge --tool :merge-local
+  merging a
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ cat a
+  Start of file
+  
+  
+  Small Mathematical Series.
+  1
+  2
+  3
+  4
+  5
+  Hop we are done.
+  
+  
+  End of file
--- a/tests/test-convert-bzr-114.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert-bzr-114.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1,4 +1,4 @@
-#require bzr114
+#require bzr bzr114
 
   $ . "$TESTDIR/bzr-definitions"
 
--- a/tests/test-convert-bzr-directories.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert-bzr-directories.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1,3 +1,4 @@
+#require bzr
 
   $ . "$TESTDIR/bzr-definitions"
 
--- a/tests/test-convert-bzr-ghosts.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert-bzr-ghosts.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1,3 +1,4 @@
+#require bzr
 
   $ . "$TESTDIR/bzr-definitions"
   $ cat > ghostcreator.py <<EOF
--- a/tests/test-convert-bzr-merges.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert-bzr-merges.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1,3 +1,5 @@
+#require bzr
+
 N.B. bzr 1.13 has a bug that breaks this test.  If you see this
 test fail, check your bzr version.  Upgrading to bzr 1.13.1
 should fix it.
--- a/tests/test-convert-bzr-treeroot.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert-bzr-treeroot.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1,3 +1,4 @@
+#require bzr
 
   $ . "$TESTDIR/bzr-definitions"
   $ cat > treeset.py <<EOF
--- a/tests/test-convert-bzr.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert-bzr.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1,3 +1,5 @@
+#require bzr
+
   $ . "$TESTDIR/bzr-definitions"
 
 create and rename on the same file in the same step
--- a/tests/test-convert-filemap.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert-filemap.t	Fri Sep 25 23:10:47 2015 -0500
@@ -671,3 +671,73 @@
   |/
   o  0:c334dc3be0da@default "add" files: a
   
+  $ cd ..
+
+test converting merges into a repo that contains other files
+
+  $ hg init merge-test1
+  $ cd merge-test1
+  $ touch a && hg commit -Aqm 'add a'
+  $ echo a > a && hg commit -Aqm 'edit a'
+  $ hg up -q 0
+  $ touch b && hg commit -Aqm 'add b'
+  $ hg merge -q 1 && hg commit -qm 'merge a & b'
+
+  $ cd ..
+  $ hg init merge-test2
+  $ cd merge-test2
+  $ mkdir converted
+  $ touch converted/a toberemoved && hg commit -Aqm 'add converted/a & toberemoved'
+  $ touch x && rm toberemoved && hg commit -Aqm 'add x & remove tobremoved'
+  $ cd ..
+  $ hg log -G -T '{shortest(node)} {desc}' -R merge-test1
+  @    1191 merge a & b
+  |\
+  | o  9077 add b
+  | |
+  o |  d19f edit a
+  |/
+  o  ac82 add a
+  
+  $ hg log -G -T '{shortest(node)} {desc}' -R merge-test2
+  @  150e add x & remove tobremoved
+  |
+  o  bbac add converted/a & toberemoved
+  
+- Build a shamap where the target converted/a is in on top of an unrelated
+- change to 'x'. This simulates using convert to merge several repositories
+- together.
+  $ cat >> merge-test2/.hg/shamap <<EOF
+  > $(hg -R merge-test1 log -r 0 -T '{node}') $(hg -R merge-test2 log -r 0 -T '{node}')
+  > $(hg -R merge-test1 log -r 1 -T '{node}') $(hg -R merge-test2 log -r 1 -T '{node}')
+  > EOF
+  $ cat >> merge-test-filemap <<EOF
+  > rename . converted/
+  > EOF
+  $ hg convert --filemap merge-test-filemap merge-test1 merge-test2 --traceback
+  scanning source...
+  sorting...
+  converting...
+  1 add b
+  0 merge a & b
+  $ hg -R merge-test2 manifest -r tip
+  converted/a
+  converted/b
+  x
+  $ hg -R merge-test2 log -G -T '{shortest(node)} {desc}\n{files % "- {file}\n"}\n'
+  o    6eaa merge a & b
+  |\   - converted/a
+  | |  - toberemoved
+  | |
+  | o  2995 add b
+  | |  - converted/b
+  | |
+  @ |  150e add x & remove tobremoved
+  |/   - toberemoved
+  |    - x
+  |
+  o  bbac add converted/a & toberemoved
+     - converted/a
+     - toberemoved
+  
+
--- a/tests/test-convert-git.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert-git.t	Fri Sep 25 23:10:47 2015 -0500
@@ -652,6 +652,12 @@
   $ hg -R git-repo6-hg tip -T "{file_dels}\n"
   .hgsub .hgsubstate
 
+skip submodules in the conversion
+
+  $ hg convert -q git-repo6 no-submodules --config convert.git.skipsubmodules=True
+  $ hg -R no-submodules manifest --all
+  .gitmodules-renamed
+
 convert using a different remote prefix
   $ git init git-repo7
   Initialized empty Git repository in $TESTTMP/git-repo7/.git/
@@ -678,6 +684,28 @@
      master                    0:03bf38caa4c6
      origin/master             0:03bf38caa4c6
 
+Run convert when the remote branches have changed
+(there was an old bug where the local convert read branches from the server)
+
+  $ cd git-repo7
+  $ echo a >> a
+  $ git commit -am "move master forward"
+  [master 0c81947] move master forward
+   Author: nottest <test@example.org>
+   1 file changed, 1 insertion(+)
+  $ cd ..
+  $ rm -rf hg-repo7
+  $ hg convert --config convert.git.remoteprefix=origin git-repo7-client hg-repo7
+  initializing destination hg-repo7 repository
+  scanning source...
+  sorting...
+  converting...
+  0 commit a
+  updating bookmarks
+  $ hg -R hg-repo7 bookmarks
+     master                    0:03bf38caa4c6
+     origin/master             0:03bf38caa4c6
+
 damaged git repository tests:
 In case the hard-coded hashes change, the following commands can be used to
 list the hashes and their corresponding types in the repository:
--- a/tests/test-convert-hg-startrev.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert-hg-startrev.t	Fri Sep 25 23:10:47 2015 -0500
@@ -201,4 +201,23 @@
   |
   o  0 "0: add a b f" files: a b f
   
-  $ cd ..
+Convert from specified revs
+
+  $ hg convert --rev 3 --rev 2 source multiplerevs
+  initializing destination multiplerevs repository
+  scanning source...
+  sorting...
+  converting...
+  3 0: add a b f
+  2 1: add c, move f to d
+  1 2: copy e from a, change b
+  0 3: change a
+  $ glog multiplerevs
+  o  3 "3: change a" files: a
+  |
+  | o  2 "2: copy e from a, change b" files: b e
+  | |
+  | o  1 "1: add c, move f to d" files: c d f
+  |/
+  o  0 "0: add a b f" files: a b f
+  
--- a/tests/test-convert.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-convert.t	Fri Sep 25 23:10:47 2015 -0500
@@ -265,6 +265,9 @@
                     remote refs are converted as bookmarks with
                     "convert.git.remoteprefix" as a prefix followed by a /. The
                     default is 'remote'.
+      convert.git.skipsubmodules
+                    does not convert root level .gitmodules files or files with
+                    160000 mode indicating a submodule. Default is False.
   
       Perforce Source
       ###############
--- a/tests/test-copy-move-merge.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-copy-move-merge.t	Fri Sep 25 23:10:47 2015 -0500
@@ -59,4 +59,107 @@
   1
   2
 
+Test disabling copy tracing
+
+- first verify copy metadata was kept
+
+  $ hg up -qC 2
+  $ hg rebase --keep -d 1 -b 2 --config extensions.rebase=
+  rebasing 2:add3f11052fa "other" (tip)
+  merging b and a to b
+  merging c and a to c
+
+  $ cat b
+  0
+  1
+  2
+
+- next verify copy metadata is lost when disabled
+
+  $ hg strip -r . --config extensions.strip=
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  saved backup bundle to $TESTTMP/t/.hg/strip-backup/550bd84c0cd3-fc575957-backup.hg (glob)
+  $ hg up -qC 2
+  $ hg rebase --keep -d 1 -b 2 --config extensions.rebase= --config experimental.disablecopytrace=True
+  rebasing 2:add3f11052fa "other" (tip)
+  remote changed a which local deleted
+  use (c)hanged version or leave (d)eleted? c
+
+  $ cat b
+  1
+  2
+
   $ cd ..
+
+Verify disabling copy tracing still keeps copies from rebase source
+
+  $ hg init copydisable
+  $ cd copydisable
+  $ touch a
+  $ hg ci -Aqm 'add a'
+  $ touch b
+  $ hg ci -Aqm 'add b, c'
+  $ hg cp b x
+  $ echo x >> x
+  $ hg ci -qm 'copy b->x'
+  $ hg up -q 1
+  $ touch z
+  $ hg ci -Aqm 'add z'
+  $ hg log -G -T '{rev} {desc}\n'
+  @  3 add z
+  |
+  | o  2 copy b->x
+  |/
+  o  1 add b, c
+  |
+  o  0 add a
+  
+  $ hg rebase -d . -b 2 --config extensions.rebase= --config experimental.disablecopytrace=True
+  rebasing 2:6adcf8c12e7d "copy b->x"
+  saved backup bundle to $TESTTMP/copydisable/.hg/strip-backup/6adcf8c12e7d-ce4b3e75-backup.hg (glob)
+  $ hg up -q 3
+  $ hg log -f x -T '{rev} {desc}\n'
+  3 copy b->x
+  1 add b, c
+
+  $ cd ../
+
+Verify we duplicate existing copies, instead of detecting them
+
+  $ hg init copydisable3
+  $ cd copydisable3
+  $ touch a
+  $ hg ci -Aqm 'add a'
+  $ hg cp a b
+  $ hg ci -Aqm 'copy a->b'
+  $ hg mv b c
+  $ hg ci -Aqm 'move b->c'
+  $ hg up -q 0
+  $ hg cp a b
+  $ echo b >> b
+  $ hg ci -Aqm 'copy a->b (2)'
+  $ hg log -G -T '{rev} {desc}\n'
+  @  3 copy a->b (2)
+  |
+  | o  2 move b->c
+  | |
+  | o  1 copy a->b
+  |/
+  o  0 add a
+  
+  $ hg rebase -d 2 -s 3 --config extensions.rebase= --config experimental.disablecopytrace=True
+  rebasing 3:47e1a9e6273b "copy a->b (2)" (tip)
+  saved backup bundle to $TESTTMP/copydisable3/.hg/strip-backup/47e1a9e6273b-2d099c59-backup.hg (glob)
+
+  $ hg log -G -f b
+  @  changeset:   3:76024fb4b05b
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     copy a->b (2)
+  |
+  o  changeset:   0:ac82d8b1f7c4
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     add a
+  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-debian-packages.t	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,20 @@
+#require test-repo slow debhelper
+
+Ensure debuild doesn't run the testsuite, as that could get silly.
+  $ DEB_BUILD_OPTIONS=nocheck
+  $ export DEB_BUILD_OPTIONS
+  $ OUTPUTDIR=`pwd`
+  $ export OUTPUTDIR
+
+  $ cd "$TESTDIR"/..
+  $ make deb > $OUTPUTDIR/build.log 2>&1
+  $ cd $OUTPUTDIR
+  $ ls *.deb
+  mercurial-common_*.deb (glob)
+  mercurial_*.deb (glob)
+main deb should have .so but no .py
+  $ dpkg --contents mercurial_*.deb | egrep '(localrepo|parsers)'
+  * ./usr/lib/python2.7/dist-packages/mercurial/parsers*.so (glob)
+mercurial-common should have py but no .so or pyc
+  $ dpkg --contents mercurial-common_*.deb | egrep '(localrepo|parsers)'
+  * ./usr/lib/python2.7/dist-packages/mercurial/localrepo.py (glob)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-debugextensions.t	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,83 @@
+  $ hg debugextensions
+
+  $ debugpath=`pwd`/extwithoutinfos.py
+
+  $ cat > extwithoutinfos.py <<EOF
+  > EOF
+
+  $ cat >> $HGRCPATH <<EOF
+  > [extensions]
+  > color=
+  > histedit=
+  > patchbomb=
+  > rebase=
+  > mq=
+  > ext1 = $debugpath
+  > EOF
+
+  $ hg debugextensions
+  color
+  ext1 (untested!)
+  histedit
+  mq
+  patchbomb
+  rebase
+
+  $ hg debugextensions -v
+  color
+    location: */hgext/color.pyc (glob)
+    tested with: internal
+  ext1
+    location: */extwithoutinfos.pyc (glob)
+  histedit
+    location: */hgext/histedit.pyc (glob)
+    tested with: internal
+  mq
+    location: */hgext/mq.pyc (glob)
+    tested with: internal
+  patchbomb
+    location: */hgext/patchbomb.pyc (glob)
+    tested with: internal
+  rebase
+    location: */hgext/rebase.pyc (glob)
+    tested with: internal
+
+  $ hg debugextensions -Tjson
+  [
+   {
+    "buglink": "",
+    "name": "color",
+    "source": "*/hgext/color.pyc", (glob)
+    "testedwith": "internal"
+   },
+   {
+    "buglink": "",
+    "name": "ext1",
+    "source": "*/extwithoutinfos.pyc", (glob)
+    "testedwith": ""
+   },
+   {
+    "buglink": "",
+    "name": "histedit",
+    "source": "*/hgext/histedit.pyc", (glob)
+    "testedwith": "internal"
+   },
+   {
+    "buglink": "",
+    "name": "mq",
+    "source": "*/hgext/mq.pyc", (glob)
+    "testedwith": "internal"
+   },
+   {
+    "buglink": "",
+    "name": "patchbomb",
+    "source": "*/hgext/patchbomb.pyc", (glob)
+    "testedwith": "internal"
+   },
+   {
+    "buglink": "",
+    "name": "rebase",
+    "source": "*/hgext/rebase.pyc", (glob)
+    "testedwith": "internal"
+   }
+  ]
--- a/tests/test-default-push.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-default-push.t	Fri Sep 25 23:10:47 2015 -0500
@@ -18,7 +18,6 @@
 Push should provide a hint when both 'default' and 'default-push' not set:
   $ cd c
   $ hg push --config paths.default=
-  pushing to default-push
   abort: default repository not configured!
   (see the "path" section in "hg help config")
   [255]
@@ -46,3 +45,9 @@
   adding manifests
   adding file changes
   added 1 changesets with 1 changes to 1 files
+
+Pushing to a path that isn't defined should not fall back to default
+
+  $ hg --cwd b push doesnotexist
+  abort: repository doesnotexist does not exist!
+  [255]
--- a/tests/test-diff-change.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-diff-change.t	Fri Sep 25 23:10:47 2015 -0500
@@ -29,15 +29,59 @@
   -first
   +second
 
-Test dumb revspecs (issue3474)
+  $ cd ..
+
+Test dumb revspecs: top-level "x:y", "x:", ":y" and ":" ranges should be handled
+as pairs even if x == y, but not for "f(x:y)" nor "x::y" (issue3474, issue4774)
+
+  $ hg clone -q a dumbspec
+  $ cd dumbspec
+  $ echo "wdir" > file.txt
 
   $ hg diff -r 2:2
+  $ hg diff -r 2:.
+  $ hg diff -r 2:
+  $ hg diff -r :0
+  $ hg diff -r '2:first(2:2)'
+  $ hg diff -r 'first(2:2)' --nodates
+  diff -r bf5ff72eb7e0 file.txt
+  --- a/file.txt
+  +++ b/file.txt
+  @@ -1,1 +1,1 @@
+  -third
+  +wdir
+  $ hg diff -r 2::2 --nodates
+  diff -r bf5ff72eb7e0 file.txt
+  --- a/file.txt
+  +++ b/file.txt
+  @@ -1,1 +1,1 @@
+  -third
+  +wdir
   $ hg diff -r "2 and 1"
   abort: empty revision range
   [255]
 
+  $ cd ..
+
+  $ hg clone -qr0 a dumbspec-rev0
+  $ cd dumbspec-rev0
+  $ echo "wdir" > file.txt
+
+  $ hg diff -r :
+  $ hg diff -r 'first(:)' --nodates
+  diff -r 4bb65dda5db4 file.txt
+  --- a/file.txt
+  +++ b/file.txt
+  @@ -1,1 +1,1 @@
+  -first
+  +wdir
+
+  $ cd ..
+
 Testing diff --change when merge:
 
+  $ cd a
+
   $ for i in 1 2 3 4 5 6 7 8 9 10; do
   >    echo $i >> file.txt
   > done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-docker-packaging.t	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,27 @@
+#require test-repo slow docker
+
+Ensure debuild doesn't run the testsuite, as that could get silly.
+  $ DEB_BUILD_OPTIONS=nocheck
+  $ export DEB_BUILD_OPTIONS
+  $ OUTPUTDIR=`pwd`
+  $ export OUTPUTDIR
+
+  $ cd "$TESTDIR"/..
+  $ make docker-debian-jessie > $OUTPUTDIR/build.log 2>&1
+  $ cd $OUTPUTDIR
+  $ ls *.deb
+  mercurial-common_*.deb (glob)
+  mercurial_*.deb (glob)
+
+We check debian package contents with portable tools so that when
+we're on non-debian machines we can still test the packages that are
+built using docker.
+
+main deb should have .so but no .py
+  $ ar x mercurial_*.deb
+  $ tar tf data.tar* | egrep '(localrepo|parsers)'
+  ./usr/lib/python2.7/dist-packages/mercurial/parsers*.so (glob)
+mercurial-common should have .py but no .so or .pyc
+  $ ar x mercurial-common_*.deb
+  $ tar tf data.tar* | egrep '(localrepo|parsers)'
+  ./usr/lib/python2.7/dist-packages/mercurial/localrepo.py
--- a/tests/test-extdiff.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-extdiff.t	Fri Sep 25 23:10:47 2015 -0500
@@ -46,6 +46,7 @@
    -o --option OPT [+]      pass option to comparison program
    -r --rev REV [+]         revision
    -c --change REV          change made by revision
+      --patch               compare patches for two revisions
    -I --include PATTERN [+] include names matching the given patterns
    -X --exclude PATTERN [+] exclude names matching the given patterns
    -S --subrepos            recurse into subrepositories
--- a/tests/test-extension.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-extension.t	Fri Sep 25 23:10:47 2015 -0500
@@ -115,8 +115,6 @@
   3) bar extsetup
   4) foo reposetup
   4) bar reposetup
-  4) foo reposetup
-  4) bar reposetup
 
   $ echo 'foo = !' >> $HGRCPATH
   $ echo 'bar = !' >> $HGRCPATH
@@ -289,17 +287,23 @@
   $ echo "debugextension = $debugpath" >> $HGRCPATH
 
   $ hg help debugextension
-  debugextension extension - only debugcommands
+  hg debugextensions
+  
+  show information about active extensions
   
-  no commands defined
+  options:
+  
+  (some details hidden, use --verbose to show complete help)
 
 
   $ hg --verbose help debugextension
-  debugextension extension - only debugcommands
+  hg debugextensions
+  
+  show information about active extensions
   
-  list of commands:
+  options:
   
-   foo           yet another foo command
+   -T --template TEMPLATE display with template (EXPERIMENTAL)
   
   global options ([+] can be repeated):
   
@@ -328,12 +332,13 @@
 
 
   $ hg --debug help debugextension
-  debugextension extension - only debugcommands
+  hg debugextensions
+  
+  show information about active extensions
   
-  list of commands:
+  options:
   
-   debugfoobar   yet another debug command
-   foo           yet another foo command
+   -T --template TEMPLATE display with template (EXPERIMENTAL)
   
   global options ([+] can be repeated):
   
@@ -392,6 +397,7 @@
    -o --option OPT [+]      pass option to comparison program
    -r --rev REV [+]         revision
    -c --change REV          change made by revision
+      --patch               compare patches for two revisions
    -I --include PATTERN [+] include names matching the given patterns
    -X --exclude PATTERN [+] exclude names matching the given patterns
    -S --subrepos            recurse into subrepositories
@@ -546,20 +552,7 @@
 
 Issue811: Problem loading extensions twice (by site and by user)
 
-  $ debugpath=`pwd`/debugissue811.py
-  $ cat > debugissue811.py <<EOF
-  > '''show all loaded extensions
-  > '''
-  > from mercurial import cmdutil, commands, extensions
-  > cmdtable = {}
-  > command = cmdutil.command(cmdtable)
-  > @command('debugextensions', [], 'hg debugextensions', norepo=True)
-  > def debugextensions(ui):
-  >     "yet another debug command"
-  >     ui.write("%s\n" % '\n'.join([x for x, y in extensions.extensions()]))
-  > EOF
   $ cat <<EOF >> $HGRCPATH
-  > debugissue811 = $debugpath
   > mq =
   > strip =
   > hgext.mq =
@@ -570,9 +563,8 @@
 (note that mq force load strip, also checking it's not loaded twice)
 
   $ hg debugextensions
-  debugissue811
+  mq
   strip
-  mq
 
 For extensions, which name matches one of its commands, help
 message should ask '-v -e' to get list of built-in aliases
@@ -944,6 +936,15 @@
   ** Mercurial Distributed SCM (version 1.9.3)
   ** Extensions loaded: throw, older
 
+Ability to point to a different point
+  $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
+  >   --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
+  ** unknown exception encountered, please report by visiting
+  ** Your Local Goat Lenders
+  ** Python * (glob)
+  ** Mercurial Distributed SCM (*) (glob)
+  ** Extensions loaded: throw, older
+
 Declare the version as supporting this hg version, show regular bts link:
   $ hgver=`$PYTHON -c 'from mercurial import util; print util.version().split("+")[0]'`
   $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
--- a/tests/test-filecache.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-filecache.py	Fri Sep 25 23:10:47 2015 -0500
@@ -130,7 +130,7 @@
     util.cachestat.__init__ = originit
 
 def test_filecache_synced():
-    # test old behaviour that caused filecached properties to go out of sync
+    # test old behavior that caused filecached properties to go out of sync
     os.system('hg init && echo a >> a && hg ci -qAm.')
     repo = hg.repository(ui.ui())
     # first rollback clears the filecache, but changelog to stays in __dict__
--- a/tests/test-filelog.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-filelog.py	Fri Sep 25 23:10:47 2015 -0500
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 """
-Tests the behaviour of filelog w.r.t. data starting with '\1\n'
+Tests the behavior of filelog w.r.t. data starting with '\1\n'
 """
 from mercurial import ui, hg
 from mercurial.node import nullid, hex
--- a/tests/test-fileset.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-fileset.t	Fri Sep 25 23:10:47 2015 -0500
@@ -49,6 +49,9 @@
   $ fileset 'a* - a1'
   a2
   $ fileset 'a_b'
+  $ fileset '"\xy"'
+  hg: parse error: invalid \x escape
+  [255]
 
 Test files status
 
--- a/tests/test-generaldelta.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-generaldelta.t	Fri Sep 25 23:10:47 2015 -0500
@@ -69,3 +69,37 @@
      rev    offset  length   base linkrev nodeid       p1           p2
        0         0       3      0       1 1406e7411862 000000000000 000000000000
 
+  $ cd ..
+
+Test format.aggressivemergedeltas
+
+  $ hg init --config format.generaldelta=1 aggressive
+  $ cd aggressive
+  $ touch a b c d e
+  $ hg commit -Aqm side1
+  $ hg up -q null
+  $ touch x y
+  $ hg commit -Aqm side2
+
+- Verify non-aggressive merge uses p1 (commit 1) as delta parent
+  $ hg merge -q 0
+  $ hg commit -q -m merge
+  $ hg debugindex -m
+     rev    offset  length  delta linkrev nodeid       p1           p2
+       0         0      59     -1       0 8dde941edb6e 000000000000 000000000000
+       1        59      59     -1       1 315c023f341d 000000000000 000000000000
+       2       118      65      1       2 2ab389a983eb 315c023f341d 8dde941edb6e
+
+  $ hg strip -q -r . --config extensions.strip=
+
+- Verify aggressive merge uses p2 (commit 0) as delta parent
+  $ hg up -q -C 1
+  $ hg merge -q 0
+  $ hg commit -q -m merge --config format.aggressivemergedeltas=True
+  $ hg debugindex -m
+     rev    offset  length  delta linkrev nodeid       p1           p2
+       0         0      59     -1       0 8dde941edb6e 000000000000 000000000000
+       1        59      59     -1       1 315c023f341d 000000000000 000000000000
+       2       118      62      0       2 2ab389a983eb 315c023f341d 8dde941edb6e
+
+  $ cd ..
--- a/tests/test-graft.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-graft.t	Fri Sep 25 23:10:47 2015 -0500
@@ -332,6 +332,54 @@
   skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
   [255]
 
+  $ hg extdiff --config extensions.extdiff= --patch -r 2 -r 13
+  --- */hg-5c095ad7e90f.patch	* +0000 (glob)
+  +++ */hg-7a4785234d87.patch	* +0000 (glob)
+  @@ -1,18 +1,18 @@
+   # HG changeset patch
+  -# User test
+  +# User foo
+   # Date 0 0
+   #      Thu Jan 01 00:00:00 1970 +0000
+  -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
+  -# Parent  5d205f8b35b66bc36375c9534ffd3237730e8f04
+  +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
+  +# Parent  b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
+   2
+   
+  -diff -r 5d205f8b35b6 -r 5c095ad7e90f a
+  +diff -r b592ea63bb0c -r 7a4785234d87 a
+   --- a/a	Thu Jan 01 00:00:00 1970 +0000
+   +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
+   @@ -1,1 +0,0 @@
+  --b
+  -diff -r 5d205f8b35b6 -r 5c095ad7e90f b
+  +-a
+  +diff -r b592ea63bb0c -r 7a4785234d87 b
+   --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+   +++ b/b	Thu Jan 01 00:00:00 1970 +0000
+   @@ -0,0 +1,1 @@
+  -+b
+  ++a
+  [1]
+
+  $ hg extdiff --config extensions.extdiff= --patch -r 2 -r 13 -X .
+  --- */hg-5c095ad7e90f.patch	* +0000 (glob)
+  +++ */hg-7a4785234d87.patch	* +0000 (glob)
+  @@ -1,8 +1,8 @@
+   # HG changeset patch
+  -# User test
+  +# User foo
+   # Date 0 0
+   #      Thu Jan 01 00:00:00 1970 +0000
+  -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
+  -# Parent  5d205f8b35b66bc36375c9534ffd3237730e8f04
+  +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
+  +# Parent  b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
+   2
+   
+  [1]
+
 Disallow grafting already grafted csets with the same origin onto each other
   $ hg up -q 13
   $ hg graft 2
--- a/tests/test-help.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-help.t	Fri Sep 25 23:10:47 2015 -0500
@@ -616,6 +616,23 @@
   [255]
 
 
+Make sure that we don't run afoul of the help system thinking that
+this is a section and erroring out weirdly.
+
+  $ hg .log
+  hg: unknown command '.log'
+  (did you mean one of log?)
+  [255]
+
+  $ hg log.
+  hg: unknown command 'log.'
+  (did you mean one of log?)
+  [255]
+  $ hg pu.lh
+  hg: unknown command 'pu.lh'
+  (did you mean one of pull, push?)
+  [255]
+
   $ cat > helpext.py <<EOF
   > import os
   > from mercurial import cmdutil, commands
@@ -775,6 +792,8 @@
                  show the contents of the current dirstate
    debugdiscovery
                  runs the changeset discovery protocol in isolation
+   debugextensions
+                 show information about active extensions
    debugfileset  parse and apply a fileset specification
    debugfsinfo   show information detected about current filesystem
    debuggetbundle
@@ -912,6 +931,47 @@
       working directory is checked out, it is equivalent to null. If an
       uncommitted merge is in progress, "." is the revision of the first parent.
 
+Test repeated config section name
+
+  $ hg help config.host
+      "http_proxy.host"
+          Host name and (optional) port of the proxy server, for example
+          "myproxy:8000".
+  
+      "smtp.host"
+          Host name of mail server, e.g. "mail.example.com".
+  
+Unrelated trailing paragraphs shouldn't be included
+
+  $ hg help config.extramsg | grep '^$'
+  
+
+Test capitalized section name
+
+  $ hg help scripting.HGPLAIN > /dev/null
+
+Help subsection:
+
+  $ hg help config.charsets |grep "Email example:" > /dev/null
+  [1]
+
+Show nested definitions
+("profiling.type"[break]"ls"[break]"stat"[break])
+
+  $ hg help config.type | egrep '^$'|wc -l
+  \s*3 (re)
+
+Last item in help config.*:
+
+  $ hg help config.`hg help config|grep '^    "'| \
+  >       tail -1|sed 's![ "]*!!g'`| \
+  >   grep "hg help -c config" > /dev/null
+  [1]
+
+note to use help -c for general hg help config:
+
+  $ hg help config |grep "hg help -c config" > /dev/null
+
 Test templating help
 
   $ hg help templating | egrep '(desc|diffstat|firstline|nonempty)  '
@@ -947,6 +1007,28 @@
       helphook1
       helphook2
 
+Test -e / -c / -k combinations
+
+  $ hg help -c progress
+  abort: no such help topic: progress
+  (try "hg help --keyword progress")
+  [255]
+  $ hg help -e progress |head -1
+  progress extension - show progress bars for some actions (DEPRECATED)
+  $ hg help -c -k dates |egrep '^(Topics|Extensions|Commands):'
+  Commands:
+  $ hg help -e -k a |egrep '^(Topics|Extensions|Commands):'
+  Extensions:
+  $ hg help -e -c -k date |egrep '^(Topics|Extensions|Commands):'
+  Extensions:
+  Commands:
+  $ hg help -c commit > /dev/null
+  $ hg help -e -c commit > /dev/null
+  $ hg help -e commit > /dev/null
+  abort: no such help topic: commit
+  (try "hg help --keyword commit")
+  [255]
+
 Test keyword search help
 
   $ cat > prefixedname.py <<EOF
@@ -1095,8 +1177,7 @@
   
       "default"
           Directory or URL to use when pulling if no source is specified.
-          Default is set to repository from which the current repository was
-          cloned.
+          (default: repository from which the current repository was cloned)
   
       "default-push"
           Optional. Directory or URL to use when pushing if no destination is
@@ -1186,6 +1267,14 @@
         partially merged file. Markers will have two sections, one for each side
         of merge.
   
+      ":merge-local"
+        Like :merge, but resolve all conflicts non-interactively in favor of the
+        local changes.
+  
+      ":merge-other"
+        Like :merge, but resolve all conflicts non-interactively in favor of the
+        other changes.
+  
       ":merge3"
         Uses the internal non-interactive simple merge algorithm for merging
         files. It will fail if there are any conflicts and leave markers in the
@@ -1202,6 +1291,11 @@
       ":tagmerge"
         Uses the internal tag merge algorithm (experimental).
   
+      ":union"
+        Uses the internal non-interactive simple merge algorithm for merging
+        files. It will use both left and right sides for conflict regions. No
+        markers are inserted.
+  
       Internal tools are always available and do not require a GUI but will by
       default not handle symlinks or binary files.
   
--- a/tests/test-hghave.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-hghave.t	Fri Sep 25 23:10:47 2015 -0500
@@ -18,7 +18,7 @@
   >   $ echo foo
   >   foo
   > EOF
-  $ run-tests.py test-hghaveaddon.t
+  $ run-tests.py $HGTEST_RUN_TESTS_PURE test-hghaveaddon.t
   .
   # Ran 1 tests, 0 skipped, 0 warned, 0 failed.
 
--- a/tests/test-hgweb-commands.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-hgweb-commands.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1335,9 +1335,8 @@
   <div class="overflow">
   <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
   <div class="sourcefirst"> line source</div>
-  <pre class="sourcelines stripes4 wrap">
+  <pre class="sourcelines stripes4 wrap bottomline">
   <span id="l1">foo</span><a href="#l1"></a></pre>
-  <div class="sourcelast"></div>
   </div>
   </div>
   </div>
@@ -1462,9 +1461,8 @@
   <div class="overflow">
   <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
   <div class="sourcefirst"> line source</div>
-  <pre class="sourcelines stripes4 wrap">
+  <pre class="sourcelines stripes4 wrap bottomline">
   <span id="l1">another</span><a href="#l1"></a></pre>
-  <div class="sourcelast"></div>
   </div>
   </div>
   </div>
@@ -1653,7 +1651,7 @@
   <tr class="parity0">
   <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
   <td><a class="list" href="/shortlog/cad8025a2e87?style=gitweb"><b>cad8025a2e87</b></a></td>
-  <td class="">unstable</td>
+  <td class="open">unstable</td>
   <td class="link">
   <a href="/changeset/cad8025a2e87?style=gitweb">changeset</a> |
   <a href="/log/cad8025a2e87?style=gitweb">changelog</a> |
@@ -1663,7 +1661,7 @@
   <tr class="parity1">
   <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
   <td><a class="list" href="/shortlog/1d22e65f027e?style=gitweb"><b>1d22e65f027e</b></a></td>
-  <td class="">stable</td>
+  <td class="inactive">stable</td>
   <td class="link">
   <a href="/changeset/1d22e65f027e?style=gitweb">changeset</a> |
   <a href="/log/1d22e65f027e?style=gitweb">changelog</a> |
@@ -1673,7 +1671,7 @@
   <tr class="parity0">
   <td class="age"><i class="age">Thu, 01 Jan 1970 00:00:00 +0000</i></td>
   <td><a class="list" href="/shortlog/a4f92ed23982?style=gitweb"><b>a4f92ed23982</b></a></td>
-  <td class="">default</td>
+  <td class="inactive">default</td>
   <td class="link">
   <a href="/changeset/a4f92ed23982?style=gitweb">changeset</a> |
   <a href="/log/a4f92ed23982?style=gitweb">changelog</a> |
@@ -2052,6 +2050,35 @@
   	top: -1px;
   }
 
+Stop and restart the server at the directory different from the repository
+root. Even in such case, file patterns should be resolved relative to the
+repository root. (issue4568)
+
+  $ killdaemons.py
+  $ hg serve --config server.preferuncompressed=True -n test \
+  > -p $HGPORT -d --pid-file=`pwd`/hg.pid -E `pwd`/errors.log \
+  > --cwd .. -R `pwd`
+  $ cat hg.pid >> $DAEMON_PIDS
+
+  $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=adds("foo")&style=raw'
+  200 Script output follows
+  
+  
+  # HG changesets search
+  # Node ID cad8025a2e87f88c06259790adfa15acb4080123
+  # Query "adds("foo")"
+  # Mode revset expression search
+  
+  changeset:   2ef0ac749a14e4f57a5a822464a0902c6f7f448f
+  revision:    0
+  user:        test
+  date:        Thu, 01 Jan 1970 00:00:00 +0000
+  summary:     base
+  tag:         1.0
+  bookmark:    anotherthing
+  
+  
+
 Stop and restart with HGENCODING=cp932 and preferuncompressed
 
   $ killdaemons.py
--- a/tests/test-hgweb-descend-empties.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-hgweb-descend-empties.t	Fri Sep 25 23:10:47 2015 -0500
@@ -156,7 +156,8 @@
   <head>
   <link rel="icon" href="/static/hgicon.png" type="image/png" />
   <meta name="robots" content="index, nofollow" />
-  <link rel="stylesheet" href="/static/style-coal.css" type="text/css" />
+  <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
+  <link rel="stylesheet" href="/static/style-extra-coal.css" type="text/css" />
   <script type="text/javascript" src="/static/mercurial.js"></script>
   
   <title>test: c9f45f7a1659 /</title>
@@ -373,11 +374,6 @@
           <p><a href="http://mercurial.selenic.com/" title="Mercurial"><img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a></p>
       </div>
   
-      <div id="corner-top-left"></div>
-      <div id="corner-top-right"></div>
-      <div id="corner-bottom-left"></div>
-      <div id="corner-bottom-right"></div>
-  
   </div>
   
   </body>
--- a/tests/test-hgweb-non-interactive.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-hgweb-non-interactive.t	Fri Sep 25 23:10:47 2015 -0500
@@ -58,13 +58,15 @@
   > }
   > 
   > i = hgweb('.')
-  > i(env, startrsp)
+  > for c in i(env, startrsp):
+  >     pass
   > print '---- ERRORS'
   > print errors.getvalue()
   > print '---- OS.ENVIRON wsgi variables'
   > print sorted([x for x in os.environ if x.startswith('wsgi')])
   > print '---- request.ENVIRON wsgi variables'
-  > print sorted([x for x in i.repo.ui.environ if x.startswith('wsgi')])
+  > with i._obtainrepo() as repo:
+  >     print sorted([x for x in repo.ui.environ if x.startswith('wsgi')])
   > EOF
   $ python request.py
   ---- STATUS
--- a/tests/test-hgweb-symrev.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-hgweb-symrev.t	Fri Sep 25 23:10:47 2015 -0500
@@ -376,8 +376,8 @@
    annotate foo @ 1:<a href="/rev/a7c1559b7bba?style=coal">a7c1559b7bba</a>
    <td class="author"><a href="/file/43c799df6e75/foo?style=coal">43c799df6e75</a> </td>
    <td class="author"><a href="/file/9d8c40cba617/foo?style=coal">9d8c40cba617</a> </td>
-  <a href="/annotate/43c799df6e75/foo?style=coal#1"
-  <a href="/annotate/a7c1559b7bba/foo?style=coal#2"
+  <a href="/annotate/43c799df6e75/foo?style=coal#l1"
+  <a href="/annotate/a7c1559b7bba/foo?style=coal#l2"
 
   $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'diff/xyzzy/foo?style=coal' | egrep $REVLINKS
   <li><a href="/shortlog/xyzzy?style=coal">log</a></li>
@@ -639,6 +639,7 @@
 (De)referencing symbolic revisions (monoblue)
 
   $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'summary?style=monoblue' | egrep $REVLINKS
+              <li><a href="/archive/tip.zip">zip</a></li>
   <a href="/rev/9d8c40cba617?style=monoblue">
   <a href="/rev/9d8c40cba617?style=monoblue">changeset</a> |
   <a href="/file/9d8c40cba617?style=monoblue">files</a>
@@ -800,9 +801,13 @@
           <li><a href="/comparison/xyzzy/foo?style=monoblue">comparison</a></li>
           <li><a href="/rss-log/tip/foo">rss</a></li>
   <a href="/rev/a7c1559b7bba?style=monoblue">
-  <a href="/file/a7c1559b7bba/foo?style=monoblue">file</a>&nbsp;|&nbsp;<a href="/diff/a7c1559b7bba/foo?style=monoblue">diff</a>&nbsp;|&nbsp;<a href="/annotate/a7c1559b7bba/foo?style=monoblue">annotate</a>
+  <a href="/file/a7c1559b7bba/foo?style=monoblue">file</a> |
+  <a href="/diff/a7c1559b7bba/foo?style=monoblue">diff</a> |
+  <a href="/annotate/a7c1559b7bba/foo?style=monoblue">annotate</a>
   <a href="/rev/43c799df6e75?style=monoblue">
-  <a href="/file/43c799df6e75/foo?style=monoblue">file</a>&nbsp;|&nbsp;<a href="/diff/43c799df6e75/foo?style=monoblue">diff</a>&nbsp;|&nbsp;<a href="/annotate/43c799df6e75/foo?style=monoblue">annotate</a>
+  <a href="/file/43c799df6e75/foo?style=monoblue">file</a> |
+  <a href="/diff/43c799df6e75/foo?style=monoblue">diff</a> |
+  <a href="/annotate/43c799df6e75/foo?style=monoblue">annotate</a>
       <a href="/log/43c799df6e75/foo?style=monoblue">(0)</a><a href="/log/tip/foo?style=monoblue">tip</a>
 
   $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'annotate/xyzzy/foo?style=monoblue' | egrep $REVLINKS
--- a/tests/test-hgweb.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-hgweb.t	Fri Sep 25 23:10:47 2015 -0500
@@ -340,7 +340,7 @@
 
   $ get-with-headers.py --twice localhost:$HGPORT 'static/style-gitweb.css' - date etag server
   200 Script output follows
-  content-length: 5372
+  content-length: 6379
   content-type: text/css
   
   body { font-family: sans-serif; font-size: 12px; border:solid #d9d8d1; border-width:1px; margin:10px; }
@@ -374,9 +374,9 @@
   a.list:hover { text-decoration:underline; color:#880000; }
   table { padding:8px 4px; }
   th { padding:2px 5px; font-size:12px; text-align:left; }
-  tr.light:hover, .parity0:hover { background-color:#edece6; }
-  tr.dark, .parity1 { background-color:#f6f6f0; }
-  tr.dark:hover, .parity1:hover { background-color:#edece6; }
+  tr.light:hover, .parity0:hover, pre.sourcelines.stripes > :nth-child(4n+1):hover { background-color:#edece6; }
+  tr.dark, .parity1, pre.sourcelines.stripes > :nth-child(4n+3) { background-color:#f6f6f0; }
+  tr.dark:hover, .parity1:hover, pre.sourcelines.stripes > :nth-child(4n+3):hover { background-color:#edece6; }
   td { padding:2px 5px; font-size:12px; vertical-align:top; }
   td.closed { background-color: #99f; }
   td.link { padding:2px 5px; font-family:sans-serif; font-size:10px; }
@@ -432,6 +432,43 @@
   span.difflineplus { color:#008800; }
   span.difflineminus { color:#cc0000; }
   span.difflineat { color:#990099; }
+  div.diffblocks { counter-reset: lineno; }
+  div.diffblock { counter-increment: lineno; }
+  pre.sourcelines { position: relative; counter-reset: lineno; }
+  pre.sourcelines > span {
+  	display: inline-block;
+  	box-sizing: border-box;
+  	width: 100%;
+  	padding: 0 0 0 5em;
+  	counter-increment: lineno;
+  	vertical-align: top;
+  }
+  pre.sourcelines > span:before {
+  	-moz-user-select: -moz-none;
+  	-khtml-user-select: none;
+  	-webkit-user-select: none;
+  	-ms-user-select: none;
+  	user-select: none;
+  	display: inline-block;
+  	margin-left: -5em;
+  	width: 4em;
+  	color: #999;
+  	text-align: right;
+  	content: counters(lineno,".");
+  	float: left;
+  }
+  pre.sourcelines > a {
+  	display: inline-block;
+  	position: absolute;
+  	left: 0px;
+  	width: 4em;
+  	height: 1em;
+  }
+  tr:target td,
+  pre.sourcelines > span:target,
+  pre.sourcelines.stripes > span:target {
+  	background-color: #bfdfff;
+  }
   
   /* Graph */
   div#wrapper {
@@ -539,6 +576,10 @@
   .scroll-loading-error {
       background-color: #FFCCCC !important;
   }
+  
+  #doc {
+      margin: 0 8px;
+  }
   304 Not Modified
   
 
--- a/tests/test-hgwebdir.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-hgwebdir.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1245,6 +1245,67 @@
   $ get-with-headers.py localhost:$HGPORT2 'a/rss-log' | grep '<guid'
       <guid isPermaLink="true">http://hg.example.com:8080/foo/a/rev/8580ff50825a</guid>
 
+Path refreshing works as expected
+
+  $ killdaemons.py
+  $ mkdir $root/refreshtest
+  $ hg init $root/refreshtest/a
+  $ cat > paths.conf << EOF
+  > [paths]
+  > / = $root/refreshtest/*
+  > EOF
+  $ hg serve -p $HGPORT1 -d --pid-file hg.pid --webdir-conf paths.conf
+  $ cat hg.pid >> $DAEMON_PIDS
+
+  $ get-with-headers.py localhost:$HGPORT1 '?style=raw'
+  200 Script output follows
+  
+  
+  /a/
+  
+
+By default refreshing occurs every 20s and a new repo won't be listed
+immediately.
+
+  $ hg init $root/refreshtest/b
+  $ get-with-headers.py localhost:$HGPORT1 '?style=raw'
+  200 Script output follows
+  
+  
+  /a/
+  
+
+Restart the server with no refresh interval. New repo should appear
+immediately.
+
+  $ killdaemons.py
+  $ cat > paths.conf << EOF
+  > [web]
+  > refreshinterval = -1
+  > [paths]
+  > / = $root/refreshtest/*
+  > EOF
+  $ hg serve -p $HGPORT1 -d --pid-file hg.pid --webdir-conf paths.conf
+  $ cat hg.pid >> $DAEMON_PIDS
+
+  $ get-with-headers.py localhost:$HGPORT1 '?style=raw'
+  200 Script output follows
+  
+  
+  /a/
+  /b/
+  
+
+  $ hg init $root/refreshtest/c
+  $ get-with-headers.py localhost:$HGPORT1 '?style=raw'
+  200 Script output follows
+  
+  
+  /a/
+  /b/
+  /c/
+  
+
 paths errors 1
 
   $ cat error-paths-1.log
--- a/tests/test-highlight.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-highlight.t	Fri Sep 25 23:10:47 2015 -0500
@@ -5,6 +5,7 @@
   > highlight =
   > [web]
   > pygments_style = friendly
+  > highlightfiles = **.py and size('<100KB')
   > EOF
   $ hg init test
   $ cd test
@@ -142,7 +143,7 @@
   <div class="overflow">
   <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
   <div class="sourcefirst"> line source</div>
-  <pre class="sourcelines stripes4 wrap">
+  <pre class="sourcelines stripes4 wrap bottomline">
   <span id="l1"><span class="c">#!/usr/bin/env python</span></span><a href="#l1"></a>
   <span id="l2"></span><a href="#l2"></a>
   <span id="l3"><span class="sd">&quot;&quot;&quot;Fun with generators. Corresponding Haskell implementation:</span></span><a href="#l3"></a>
@@ -176,7 +177,6 @@
   <span id="l31">    <span class="n">p</span> <span class="o">=</span> <span class="n">primes</span><span class="p">()</span></span><a href="#l31"></a>
   <span id="l32">    <span class="kn">print</span> <span class="s">&quot;The first </span><span class="si">%d</span><span class="s"> primes: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">n</span><span class="p">)))</span></span><a href="#l32"></a>
   <span id="l33"></span><a href="#l33"></a></pre>
-  <div class="sourcelast"></div>
   </div>
   </div>
   </div>
@@ -591,6 +591,28 @@
 errors encountered
 
   $ cat errors.log
+  $ killdaemons.py
+
+only highlight C source files
+
+  $ cat > .hg/hgrc <<EOF
+  > [web]
+  > highlightfiles = **.c
+  > EOF
+
+hg serve again
+
+  $ hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
+  $ cat hg.pid >> $DAEMON_PIDS
+
+test that fileset in highlightfiles works and primes.py is not highlighted
+
+  $ get-with-headers.py localhost:$HGPORT 'file/tip/primes.py' | grep 'id="l11"'
+  <span id="l11">def primes():</span><a href="#l11"></a>
+
+errors encountered
+
+  $ cat errors.log
   $ cd ..
   $ hg init eucjp
   $ cd eucjp
--- a/tests/test-histedit-arguments.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-histedit-arguments.t	Fri Sep 25 23:10:47 2015 -0500
@@ -69,7 +69,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
@@ -292,7 +292,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
--- a/tests/test-histedit-bookmark-motion.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-histedit-bookmark-motion.t	Fri Sep 25 23:10:47 2015 -0500
@@ -75,7 +75,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg histedit 1 --commands - --verbose << EOF | grep histedit
@@ -136,7 +136,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg histedit 1 --commands - --verbose << EOF | grep histedit
--- a/tests/test-histedit-commute.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-histedit-commute.t	Fri Sep 25 23:10:47 2015 -0500
@@ -69,7 +69,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
@@ -347,7 +347,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
--- a/tests/test-histedit-fold.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-histedit-fold.t	Fri Sep 25 23:10:47 2015 -0500
@@ -509,4 +509,64 @@
   $ hg add amended.txt
   $ hg ci -q --config extensions.largefiles= --amend -I amended.txt
 
+Test that folding multiple changes in a row doesn't show multiple
+editors.
+
+  $ echo foo >> foo
+  $ hg add foo
+  $ hg ci -m foo1
+  $ echo foo >> foo
+  $ hg ci -m foo2
+  $ echo foo >> foo
+  $ hg ci -m foo3
+  $ hg logt
+  4:21679ff7675c foo3
+  3:b7389cc4d66e foo2
+  2:0e01aeef5fa8 foo1
+  1:578c7455730c a
+  0:79b99e9c8e49 b
+  $ cat > $TESTTMP/editor.sh <<EOF
+  > echo ran editor >> $TESTTMP/editorlog.txt
+  > cat \$1 >> $TESTTMP/editorlog.txt
+  > echo END >> $TESTTMP/editorlog.txt
+  > echo merged foos > \$1
+  > EOF
+  $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit 1 --commands - 2>&1 <<EOF | fixbundle
+  > pick 578c7455730c 1 a
+  > pick 0e01aeef5fa8 2 foo1
+  > fold b7389cc4d66e 3 foo2
+  > fold 21679ff7675c 4 foo3
+  > EOF
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  reverting foo
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  merging foo
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg logt
+  2:e8bedbda72c1 merged foos
+  1:578c7455730c a
+  0:79b99e9c8e49 b
+Editor should have run only once
+  $ cat $TESTTMP/editorlog.txt
+  ran editor
+  foo1
+  ***
+  foo2
+  ***
+  foo3
+  
+  
+  
+  HG: Enter commit message.  Lines beginning with 'HG:' are removed.
+  HG: Leave message empty to abort commit.
+  HG: --
+  HG: user: test
+  HG: branch 'default'
+  HG: added foo
+  END
+
   $ cd ..
--- a/tests/test-histedit-obsolete.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-histedit-obsolete.t	Fri Sep 25 23:10:47 2015 -0500
@@ -54,7 +54,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg histedit 1 --commands - --verbose <<EOF | grep histedit
--- a/tests/test-histedit-outgoing.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-histedit-outgoing.t	Fri Sep 25 23:10:47 2015 -0500
@@ -51,7 +51,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd ..
@@ -83,7 +83,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd ..
@@ -107,7 +107,7 @@
   #  f, fold = use commit, but combine it with the one above
   #  r, roll = like fold, but discard this commit's description
   #  d, drop = remove commit from history
-  #  m, mess = edit message without changing commit content
+  #  m, mess = edit commit message without changing commit content
   #
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
--- a/tests/test-i18n.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-i18n.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1,8 +1,6 @@
-#require gettext
-
 (Translations are optional)
 
-#if no-outer-repo
+#if gettext no-outer-repo
 
 Test that translations are compiled and installed correctly.
 
@@ -27,6 +25,8 @@
 
 #endif
 
+#if gettext
+
 Test keyword search in translated help text:
 
   $ HGENCODING=UTF-8 LANGUAGE=de hg help -k blättern
@@ -38,6 +38,8 @@
   
    pager Verwendet einen externen Pager zum Bl\xc3\xa4ttern in der Ausgabe von Befehlen (esc)
 
+#endif
+
 Check Mercurial specific translation problems in each *.po files, and
 tool itself by doctest
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-lock.py	Fri Sep 25 23:10:47 2015 -0500
@@ -0,0 +1,137 @@
+from __future__ import absolute_import
+
+import os
+import silenttestrunner
+import tempfile
+import unittest
+
+from mercurial import (
+    lock,
+    scmutil,
+)
+
+testlockname = 'testlock'
+
+class teststate(object):
+    def __init__(self, testcase):
+        self._testcase = testcase
+        self._acquirecalled = False
+        self._releasecalled = False
+        self._postreleasecalled = False
+        d = tempfile.mkdtemp(dir=os.getcwd())
+        self.vfs = scmutil.vfs(d, audit=False)
+
+    def makelock(self, *args, **kwargs):
+        l = lock.lock(self.vfs, testlockname, releasefn=self.releasefn,
+                      acquirefn=self.acquirefn, *args, **kwargs)
+        l.postrelease.append(self.postreleasefn)
+        return l
+
+    def acquirefn(self):
+        self._acquirecalled = True
+
+    def releasefn(self):
+        self._releasecalled = True
+
+    def postreleasefn(self):
+        self._postreleasecalled = True
+
+    def assertacquirecalled(self, called):
+        self._testcase.assertEqual(
+            self._acquirecalled, called,
+            'expected acquire to be %s but was actually %s' % (
+                self._tocalled(called),
+                self._tocalled(self._acquirecalled),
+            ))
+
+    def resetacquirefn(self):
+        self._acquirecalled = False
+
+    def assertreleasecalled(self, called):
+        self._testcase.assertEqual(
+            self._releasecalled, called,
+            'expected release to be %s but was actually %s' % (
+                self._tocalled(called),
+                self._tocalled(self._releasecalled),
+            ))
+
+    def assertpostreleasecalled(self, called):
+        self._testcase.assertEqual(
+            self._postreleasecalled, called,
+            'expected postrelease to be %s but was actually %s' % (
+                self._tocalled(called),
+                self._tocalled(self._postreleasecalled),
+            ))
+
+    def assertlockexists(self, exists):
+        actual = self.vfs.lexists(testlockname)
+        self._testcase.assertEqual(
+            actual, exists,
+            'expected lock to %s but actually did %s' % (
+                self._toexists(exists),
+                self._toexists(actual),
+            ))
+
+    def _tocalled(self, called):
+        if called:
+            return 'called'
+        else:
+            return 'not called'
+
+    def _toexists(self, exists):
+        if exists:
+            return 'exists'
+        else:
+            return 'not exists'
+
+class testlock(unittest.TestCase):
+    def testlock(self):
+        state = teststate(self)
+        lock = state.makelock()
+        state.assertacquirecalled(True)
+        lock.release()
+        state.assertreleasecalled(True)
+        state.assertpostreleasecalled(True)
+        state.assertlockexists(False)
+
+    def testrecursivelock(self):
+        state = teststate(self)
+        lock = state.makelock()
+        state.assertacquirecalled(True)
+
+        state.resetacquirefn()
+        lock.lock()
+        # recursive lock should not call acquirefn again
+        state.assertacquirecalled(False)
+
+        lock.release() # brings lock refcount down from 2 to 1
+        state.assertreleasecalled(False)
+        state.assertpostreleasecalled(False)
+        state.assertlockexists(True)
+
+        lock.release() # releases the lock
+        state.assertreleasecalled(True)
+        state.assertpostreleasecalled(True)
+        state.assertlockexists(False)
+
+    def testlockfork(self):
+        state = teststate(self)
+        lock = state.makelock()
+        state.assertacquirecalled(True)
+        lock.lock()
+        # fake a fork
+        lock.pid += 1
+        lock.release()
+        state.assertreleasecalled(False)
+        state.assertpostreleasecalled(False)
+        state.assertlockexists(True)
+
+        # release the actual lock
+        lock.pid -= 1
+        lock.release()
+        state.assertreleasecalled(True)
+        state.assertpostreleasecalled(True)
+        state.assertlockexists(False)
+
+if __name__ == '__main__':
+    silenttestrunner.main(__name__)
--- a/tests/test-log.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-log.t	Fri Sep 25 23:10:47 2015 -0500
@@ -620,6 +620,21 @@
   $ hg up -C 1
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ echo b1 > b1
+
+log -r "follow('set:clean()')"
+
+  $ hg log -r "follow('set:clean()')"
+  changeset:   0:67e992f2c4f3
+  user:        test
+  date:        Thu Jan 01 00:00:01 1970 +0000
+  summary:     base
+  
+  changeset:   1:3d5bf5654eda
+  user:        test
+  date:        Thu Jan 01 00:00:01 1970 +0000
+  summary:     r1
+  
+
   $ hg ci -Amb1 -d '1 0'
   adding b1
   created new head
@@ -646,7 +661,26 @@
   summary:     base
   
 
+log -r follow('glob:b*')
 
+  $ hg log -r "follow('glob:b*')"
+  changeset:   0:67e992f2c4f3
+  user:        test
+  date:        Thu Jan 01 00:00:01 1970 +0000
+  summary:     base
+  
+  changeset:   1:3d5bf5654eda
+  user:        test
+  date:        Thu Jan 01 00:00:01 1970 +0000
+  summary:     r1
+  
+  changeset:   3:e62f78d544b4
+  tag:         tip
+  parent:      1:3d5bf5654eda
+  user:        test
+  date:        Thu Jan 01 00:00:01 1970 +0000
+  summary:     b1
+  
 log -f -r '1 + 4'
 
   $ hg up -C 0
@@ -673,6 +707,16 @@
   date:        Thu Jan 01 00:00:01 1970 +0000
   summary:     base
   
+log -r "follow('set:grep(b2)')"
+
+  $ hg log -r "follow('set:grep(b2)')"
+  changeset:   4:ddb82e70d1a1
+  tag:         tip
+  parent:      0:67e992f2c4f3
+  user:        test
+  date:        Thu Jan 01 00:00:01 1970 +0000
+  summary:     b2
+  
 log -f -r null
 
   $ hg log -f -r null
--- a/tests/test-merge-internal-tools-pattern.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-merge-internal-tools-pattern.t	Fri Sep 25 23:10:47 2015 -0500
@@ -1,5 +1,6 @@
-Make sure that the internal merge tools (internal:fail, internal:local, and
-internal:other) are used when matched by a merge-pattern in hgrc
+Make sure that the internal merge tools (internal:fail, internal:local,
+internal:union and internal:other) are used when matched by a
+merge-pattern in hgrc
 
 Make sure HGMERGE doesn't interfere with the test:
 
@@ -110,3 +111,31 @@
   $ hg stat
   M f
 
+Merge using internal:union tool:
+
+  $ hg update -C 2
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ echo "line 4a" >>f
+  $ hg ci -Am "Adding fourth line (commit 4)"
+  $ hg update 2
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ echo "line 4b" >>f
+  $ hg ci -Am "Adding fourth line v2 (commit 5)"
+  created new head
+
+  $ echo "[merge-patterns]" > .hg/hgrc
+  $ echo "* = internal:union" >> .hg/hgrc
+
+  $ hg merge 3
+  merging f
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+
+  $ cat f
+  line 1
+  line 2
+  third line
+  line 4b
+  line 4a
--- a/tests/test-merge-tools.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-merge-tools.t	Fri Sep 25 23:10:47 2015 -0500
@@ -65,7 +65,7 @@
 override $PATH to ensure hgmerge not visible; use $PYTHON in case we're
 running from a devel copy, not a temp installation
 
-  $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg merge -r 2
+  $ PATH="$BINDIR:/usr/sbin" $PYTHON "$BINDIR"/hg merge -r 2
   merging f
   warning: conflicts during merge.
   merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
@@ -111,7 +111,7 @@
 
   $ echo "echo fail" > false
   $ hg up -qC 1
-  $ PATH="`pwd`:$BINDIR" $PYTHON "$BINDIR"/hg merge -r 2
+  $ PATH="`pwd`:$BINDIR:/usr/sbin" $PYTHON "$BINDIR"/hg merge -r 2
   merging f
   warning: conflicts during merge.
   merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
@@ -126,7 +126,7 @@
 
   $ mkdir false
   $ hg up -qC 1
-  $ PATH="`pwd`:$BINDIR" $PYTHON "$BINDIR"/hg merge -r 2
+  $ PATH="`pwd`:$BINDIR:/usr/sbin" $PYTHON "$BINDIR"/hg merge -r 2
   merging f
   warning: conflicts during merge.
   merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
--- a/tests/test-merge9.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-merge9.t	Fri Sep 25 23:10:47 2015 -0500
@@ -77,7 +77,7 @@
 resolve all warning
   $ hg resolve
   abort: no files or directories specified
-  (use --all to remerge all files)
+  (use --all to re-merge all unresolved files)
   [255]
 
 resolve all
--- a/tests/test-module-imports.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-module-imports.t	Fri Sep 25 23:10:47 2015 -0500
@@ -112,22 +112,5 @@
 these may expose other cycles.
 
   $ hg locate 'mercurial/**.py' 'hgext/**.py' | sed 's-\\-/-g' | python "$import_checker" -
-  mercurial/dispatch.py mixed imports
-     stdlib:    commands
-     relative:  error, extensions, fancyopts, hg, hook, util
-  mercurial/fileset.py mixed imports
-     stdlib:    parser
-     relative:  error, merge, util
-  mercurial/revset.py mixed imports
-     stdlib:    parser
-     relative:  error, hbisect, phases, util
-  mercurial/templater.py mixed imports
-     stdlib:    parser
-     relative:  config, error, templatefilters, templatekw, util
-  mercurial/ui.py mixed imports
-     stdlib:    formatter
-     relative:  config, error, progress, scmutil, util
-  Import cycle: mercurial.cmdutil -> mercurial.context -> mercurial.subrepo -> mercurial.cmdutil
   Import cycle: hgext.largefiles.basestore -> hgext.largefiles.localstore -> hgext.largefiles.basestore
-  Import cycle: mercurial.commands -> mercurial.commandserver -> mercurial.dispatch -> mercurial.commands
   [1]
--- a/tests/test-mq.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-mq.t	Fri Sep 25 23:10:47 2015 -0500
@@ -39,7 +39,7 @@
   
   By default, mq will automatically use git patches when required to avoid
   losing file mode changes, copy records, binary files or empty files creations
-  or deletions. This behaviour can be configured with:
+  or deletions. This behavior can be configured with:
   
     [mq]
     git = auto/keep/yes/no
--- a/tests/test-obsolete-tag-cache.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-obsolete-tag-cache.t	Fri Sep 25 23:10:47 2015 -0500
@@ -68,10 +68,10 @@
   55482a6fb4b1881fa8f746fd52cf6f096bb21c89 test1
 
   $ hg blackbox -l 4
-  1970/01/01 00:00:00 bob> tags
-  1970/01/01 00:00:00 bob> 2/2 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 2 tags
-  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> tags (glob)
+  1970/01/01 00:00:00 bob (*)> 2/2 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 2 tags (glob)
+  1970/01/01 00:00:00 bob (*)> tags exited 0 after * seconds (glob)
 
 Hiding another changeset should cause the filtered hash to change
 
@@ -87,10 +87,10 @@
   042eb6bfcc4909bad84a1cbf6eb1ddf0ab587d41 head2
 
   $ hg blackbox -l 4
-  1970/01/01 00:00:00 bob> tags
-  1970/01/01 00:00:00 bob> 1/1 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
-  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> tags (glob)
+  1970/01/01 00:00:00 bob (*)> 1/1 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 1 tags (glob)
+  1970/01/01 00:00:00 bob (*)> tags exited 0 after * seconds (glob)
 
 Resolving tags on an unfiltered repo writes a separate tags cache
 
@@ -107,7 +107,7 @@
   d75775ffbc6bca1794d300f5571272879bd280da test2
 
   $ hg blackbox -l 4
-  1970/01/01 00:00:00 bob> --hidden tags
-  1970/01/01 00:00:00 bob> 2/2 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2 with 3 tags
-  1970/01/01 00:00:00 bob> --hidden tags exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> --hidden tags (glob)
+  1970/01/01 00:00:00 bob (*)> 2/2 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2 with 3 tags (glob)
+  1970/01/01 00:00:00 bob (*)> --hidden tags exited 0 after * seconds (glob)
--- a/tests/test-parseindex.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-parseindex.t	Fri Sep 25 23:10:47 2015 -0500
@@ -60,9 +60,66 @@
 
   $ cd ..
 
-Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
+#if no-pure
+
+Test SEGV caused by bad revision passed to reachableroots() (issue4775):
+
+  $ cd a
 
-#if no-pure
+  $ python <<EOF
+  > from mercurial import changelog, scmutil
+  > cl = changelog.changelog(scmutil.vfs('.hg/store'))
+  > print 'good heads:'
+  > for head in [0, len(cl) - 1, -1]:
+  >     print'%s: %r' % (head, cl.reachableroots(0, [head], [0]))
+  > print 'bad heads:'
+  > for head in [len(cl), 10000, -2, -10000, None]:
+  >     print '%s:' % head,
+  >     try:
+  >         cl.reachableroots(0, [head], [0])
+  >         print 'uncaught buffer overflow?'
+  >     except (IndexError, TypeError) as inst:
+  >         print inst
+  > print 'good roots:'
+  > for root in [0, len(cl) - 1, -1]:
+  >     print '%s: %r' % (root, cl.reachableroots(root, [len(cl) - 1], [root]))
+  > print 'out-of-range roots are ignored:'
+  > for root in [len(cl), 10000, -2, -10000]:
+  >     print '%s: %r' % (root, cl.reachableroots(root, [len(cl) - 1], [root]))
+  > print 'bad roots:'
+  > for root in [None]:
+  >     print '%s:' % root,
+  >     try:
+  >         cl.reachableroots(root, [len(cl) - 1], [root])
+  >         print 'uncaught error?'
+  >     except TypeError as inst:
+  >         print inst
+  > EOF
+  good heads:
+  0: [0]
+  1: [0]
+  -1: []
+  bad heads:
+  2: head out of range
+  10000: head out of range
+  -2: head out of range
+  -10000: head out of range
+  None: an integer is required
+  good roots:
+  0: [0]
+  1: [1]
+  -1: [-1]
+  out-of-range roots are ignored:
+  2: []
+  10000: []
+  -2: []
+  -10000: []
+  bad roots:
+  None: an integer is required
+
+  $ cd ..
+
+Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
 
   $ mkdir invalidparent
   $ cd invalidparent
@@ -94,6 +151,8 @@
   > cl = changelog.changelog(scmutil.vfs(sys.argv[1]))
   > n0, n1 = cl.node(0), cl.node(1)
   > ops = [
+  >     ('reachableroots',
+  >      lambda: cl.index.reachableroots2(0, [1], [0], False)),
   >     ('compute_phases_map_sets', lambda: cl.computephases([[0], []])),
   >     ('index_headrevs', lambda: cl.headrevs()),
   >     ('find_gca_candidates', lambda: cl.commonancestorsheads(n0, n1)),
@@ -109,11 +168,13 @@
   > EOF
 
   $ python test.py limit/.hg/store
+  reachableroots: parent out of range
   compute_phases_map_sets: parent out of range
   index_headrevs: parent out of range
   find_gca_candidates: parent out of range
   find_deepest: parent out of range
   $ python test.py segv/.hg/store
+  reachableroots: parent out of range
   compute_phases_map_sets: parent out of range
   index_headrevs: parent out of range
   find_gca_candidates: parent out of range
--- a/tests/test-pathencode.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-pathencode.py	Fri Sep 25 23:10:47 2015 -0500
@@ -2,7 +2,7 @@
 # time it is invoked, and tests the encoding of those pathnames.
 #
 # It uses a simple probabilistic model to generate valid pathnames
-# that have proven likely to expose bugs and divergent behaviour in
+# that have proven likely to expose bugs and divergent behavior in
 # different encoding implementations.
 
 from mercurial import store
--- a/tests/test-profile.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-profile.t	Fri Sep 25 23:10:47 2015 -0500
@@ -14,6 +14,9 @@
   $ hg --profile --config profiling.output=../out st
   $ grep CallCount ../out > /dev/null || cat ../out
 
+  $ hg --profile --config profiling.output=blackbox --config extensions.blackbox= st
+  $ grep CallCount .hg/blackbox.log > /dev/null || cat .hg/blackbox.log
+
   $ hg --profile --config profiling.format=text st 2>../out
   $ grep CallCount ../out > /dev/null || cat ../out
 
--- a/tests/test-push-http-bundle1.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-push-http-bundle1.t	Fri Sep 25 23:10:47 2015 -0500
@@ -114,6 +114,36 @@
   $ hg rollback
   repository tip rolled back to revision 0 (undo serve)
 
+expect success, pre-d1b16a746db6 server supports the unbundle capability, but
+has no parameter
+
+  $ cat <<EOF > notcapable-unbundleparam.py
+  > from mercurial import extensions, httppeer
+  > def capable(orig, self, name):
+  >     if name == 'unbundle':
+  >         return True
+  >     return orig(self, name)
+  > def uisetup(ui):
+  >     extensions.wrapfunction(httppeer.httppeer, 'capable', capable)
+  > EOF
+  $ cp $HGRCPATH $HGRCPATH.orig
+  $ cat <<EOF >> $HGRCPATH
+  > [extensions]
+  > notcapable-unbundleparam = `pwd`/notcapable-unbundleparam.py
+  > EOF
+  $ req
+  pushing to http://localhost:$HGPORT/
+  searching for changes
+  remote: adding changesets
+  remote: adding manifests
+  remote: adding file changes
+  remote: added 1 changesets with 1 changes to 1 files
+  remote: changegroup hook: * (glob)
+  % serve errors
+  $ hg rollback
+  repository tip rolled back to revision 0 (undo serve)
+  $ mv $HGRCPATH.orig $HGRCPATH
+
 expect push success, phase change failure
 
   $ cat > .hg/hgrc <<EOF
--- a/tests/test-rebase-named-branches.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-rebase-named-branches.t	Fri Sep 25 23:10:47 2015 -0500
@@ -97,7 +97,6 @@
   
   $ hg rebase -s dev-one -d 0 --keepbranches
   rebasing 5:643fc9128048 "dev-one named branch"
-  note: rebase of 5:643fc9128048 created no changes to commit
   rebasing 6:24de4aff8e28 "F"
   rebasing 7:4b988a958030 "G"
   rebasing 8:31d0e4ba75e6 "H"
@@ -105,13 +104,15 @@
   saved backup bundle to $TESTTMP/a1/.hg/strip-backup/643fc9128048-c4ee9ef5-backup.hg (glob)
 
   $ hg tglog
-  @  8: 'dev-two named branch' dev-two
+  @  9: 'dev-two named branch' dev-two
   |
-  o  7: 'H'
+  o  8: 'H'
   |
-  | o  6: 'G'
+  | o  7: 'G'
   |/|
-  o |  5: 'F'
+  o |  6: 'F'
+  | |
+  o |  5: 'dev-one named branch' dev-one
   | |
   | o  4: 'E'
   |/
@@ -125,20 +126,23 @@
   
   $ hg update 3
   3 files updated, 0 files merged, 3 files removed, 0 files unresolved
-  $ hg branch dev-one
+  $ hg branch -f dev-one
   marked working directory as branch dev-one
   $ hg ci -m 'dev-one named branch'
+  created new head
 
   $ hg tglog
-  @  9: 'dev-one named branch' dev-one
+  @  10: 'dev-one named branch' dev-one
   |
-  | o  8: 'dev-two named branch' dev-two
+  | o  9: 'dev-two named branch' dev-two
+  | |
+  | o  8: 'H'
   | |
-  | o  7: 'H'
-  | |
-  | | o  6: 'G'
+  | | o  7: 'G'
   | |/|
-  | o |  5: 'F'
+  | o |  6: 'F'
+  | | |
+  | o |  5: 'dev-one named branch' dev-one
   | | |
   | | o  4: 'E'
   | |/
@@ -151,11 +155,13 @@
   o  0: 'A'
   
   $ hg rebase -b 'max(branch("dev-two"))' -d dev-one --keepbranches
-  rebasing 5:77854864208c "F"
-  rebasing 6:63b4f9c788a1 "G"
-  rebasing 7:87861e68abd3 "H"
-  rebasing 8:ec00d4e0efca "dev-two named branch"
-  saved backup bundle to $TESTTMP/a1/.hg/strip-backup/77854864208c-74d59436-backup.hg (glob)
+  rebasing 5:bc8139ee757c "dev-one named branch"
+  note: rebase of 5:bc8139ee757c created no changes to commit
+  rebasing 6:42aa3cf0fa7a "F"
+  rebasing 7:1a1e6f72ec38 "G"
+  rebasing 8:904590360559 "H"
+  rebasing 9:59c2e59309fe "dev-two named branch"
+  saved backup bundle to $TESTTMP/a1/.hg/strip-backup/bc8139ee757c-f11c1080-backup.hg (glob)
 
   $ hg tglog
   o  9: 'dev-two named branch' dev-two
@@ -180,21 +186,22 @@
   
   $ hg rebase -s 'max(branch("dev-one"))' -d 0 --keepbranches
   rebasing 5:643fc9128048 "dev-one named branch"
-  note: rebase of 5:643fc9128048 created no changes to commit
-  rebasing 6:05584c618d45 "F"
-  rebasing 7:471695f5257d "G"
-  rebasing 8:8382a539a2df "H"
-  rebasing 9:11f718458b32 "dev-two named branch" (tip)
-  saved backup bundle to $TESTTMP/a1/.hg/strip-backup/643fc9128048-177f3c5c-backup.hg (glob)
+  rebasing 6:679f28760620 "F"
+  rebasing 7:549f007a9f5f "G"
+  rebasing 8:12b2bc666e20 "H"
+  rebasing 9:71325f8bc082 "dev-two named branch" (tip)
+  saved backup bundle to $TESTTMP/a1/.hg/strip-backup/643fc9128048-6cdd1a52-backup.hg (glob)
 
   $ hg tglog
-  o  8: 'dev-two named branch' dev-two
+  o  9: 'dev-two named branch' dev-two
   |
-  o  7: 'H'
+  o  8: 'H'
   |
-  | o  6: 'G'
+  | o  7: 'G'
   |/|
-  o |  5: 'F'
+  o |  6: 'F'
+  | |
+  @ |  5: 'dev-one named branch' dev-one
   | |
   | o  4: 'E'
   |/
@@ -204,61 +211,66 @@
   | |
   | o  1: 'B'
   |/
-  @  0: 'A'
+  o  0: 'A'
   
+  $ hg up -r 0 > /dev/null
 
 Rebasing descendant onto ancestor across different named branches
 
-  $ hg rebase -s 1 -d 8 --keepbranches
+  $ hg rebase -s 1 -d 9 --keepbranches
   rebasing 1:42ccdea3bb16 "B"
   rebasing 2:5fddd98957c8 "C"
   rebasing 3:32af7686d403 "D"
   saved backup bundle to $TESTTMP/a1/.hg/strip-backup/42ccdea3bb16-3cb021d3-backup.hg (glob)
 
   $ hg tglog
-  o  8: 'D'
+  o  9: 'D'
+  |
+  o  8: 'C'
   |
-  o  7: 'C'
+  o  7: 'B'
   |
-  o  6: 'B'
+  o  6: 'dev-two named branch' dev-two
   |
-  o  5: 'dev-two named branch' dev-two
-  |
-  o  4: 'H'
+  o  5: 'H'
   |
-  | o  3: 'G'
+  | o  4: 'G'
   |/|
-  o |  2: 'F'
+  o |  3: 'F'
+  | |
+  o |  2: 'dev-one named branch' dev-one
   | |
   | o  1: 'E'
   |/
   @  0: 'A'
   
-  $ hg rebase -s 4 -d 5
+  $ hg rebase -s 5 -d 6
   abort: source is ancestor of destination
   [255]
 
-  $ hg rebase -s 5 -d 4
-  rebasing 5:32d3b0de7f37 "dev-two named branch"
-  rebasing 6:580fcd9fd48f "B"
-  rebasing 7:32aba0402ed2 "C"
-  rebasing 8:e4787b575338 "D" (tip)
-  saved backup bundle to $TESTTMP/a1/.hg/strip-backup/32d3b0de7f37-c37815ca-backup.hg (glob)
+  $ hg rebase -s 6 -d 5
+  rebasing 6:3944801ae4ea "dev-two named branch"
+  rebasing 7:3bdb949809d9 "B"
+  rebasing 8:a0d543090fa4 "C"
+  rebasing 9:e9f862ce8bad "D" (tip)
+  saved backup bundle to $TESTTMP/a1/.hg/strip-backup/3944801ae4ea-fb46ed74-backup.hg (glob)
 
   $ hg tglog
-  o  8: 'D'
+  o  9: 'D'
+  |
+  o  8: 'C'
   |
-  o  7: 'C'
+  o  7: 'B'
   |
-  o  6: 'B'
+  o  6: 'dev-two named branch'
   |
-  o  5: 'dev-two named branch'
-  |
-  o  4: 'H'
+  o  5: 'H'
   |
-  | o  3: 'G'
+  | o  4: 'G'
   |/|
-  o |  2: 'F'
+  o |  3: 'F'
+  | |
+  o |  2: 'dev-one named branch' dev-one
   | |
   | o  1: 'E'
   |/
@@ -272,13 +284,13 @@
   $ hg ci -m 'create b'
   $ hg ci -m 'close b' --close
   $ hg rebase -b 8 -d b
-  reopening closed branch head ea9de14a36c6
-  rebasing 4:86693275b2ef "H"
-  rebasing 5:2149726d0970 "dev-two named branch"
-  rebasing 6:81e55225e95d "B"
-  rebasing 7:09eda3dc3195 "C"
-  rebasing 8:31298fc9d159 "D"
-  saved backup bundle to $TESTTMP/a1/.hg/strip-backup/86693275b2ef-f9fcf4e2-backup.hg (glob)
+  reopening closed branch head 2b586e70108d
+  rebasing 5:8e279d293175 "H"
+  rebasing 6:c57724c84928 "dev-two named branch"
+  rebasing 7:160b0930ccc6 "B"
+  rebasing 8:810110211f50 "C"
+  rebasing 9:e522577ccdbd "D"
+  saved backup bundle to $TESTTMP/a1/.hg/strip-backup/8e279d293175-b023e27c-backup.hg (glob)
 
   $ cd ..
 
--- a/tests/test-rebase-obsolete.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-rebase-obsolete.t	Fri Sep 25 23:10:47 2015 -0500
@@ -203,10 +203,9 @@
   |/
   o  0:cd010b8cd998 A
   
-  $ hg rebase --source 'desc(B)' --dest 'tip'
+  $ hg rebase --source 'desc(B)' --dest 'tip' --config experimental.rebaseskipobsolete=True
   rebasing 8:8877864f1edb "B"
-  rebasing 9:08483444fef9 "D"
-  note: rebase of 9:08483444fef9 created no changes to commit
+  note: not rebasing 9:08483444fef9 "D", already in destination as 11:4596109a6a43 "D"
   rebasing 10:5ae4c968c6ac "C"
   $ hg debugobsolete
   42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
@@ -214,7 +213,6 @@
   32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
   08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob)
   8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 (*) {'user': 'test'} (glob)
-  08483444fef91d6224f6655ee586a65d263ad34c 0 {8877864f1edb05d0e07dc4ba77b67a80a7b86672} (*) {'user': 'test'} (glob)
   5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 (*) {'user': 'test'} (glob)
   $ hg log --rev 'divergent()'
   $ hg log -G
@@ -540,3 +538,55 @@
   |/
   o  0:cd010b8cd998 A
   
+  $ hg up 14 -C
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo "K" > K
+  $ hg add K
+  $ hg commit --amend -m "K"
+  $ echo "L" > L
+  $ hg add L
+  $ hg commit -m "L"
+  $ hg up '.^'
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ echo "M" > M
+  $ hg add M
+  $ hg commit --amend -m "M"
+  $ hg log -G
+  @  20:bfaedf8eb73b M
+  |
+  | o  18:97219452e4bd L
+  | |
+  | x  17:fc37a630c901 K
+  |/
+  | o  15:5ae8a643467b J
+  | |
+  | x  14:9ad579b4a5de I
+  |/
+  | o  12:acd174b7ab39 I
+  | |
+  | o  11:6c11a6218c97 H
+  | |
+  o |  10:b5313c85b22e D
+  |/
+  | o    8:53a6a128b2b7 M
+  | |\
+  | | x  7:02de42196ebe H
+  | | |
+  o---+  6:eea13746799a G
+  | | |
+  | | o  5:24b6387c8c8c F
+  | | |
+  o---+  4:9520eea781bc E
+   / /
+  x |  3:32af7686d403 D
+  | |
+  o |  2:5fddd98957c8 C
+  | |
+  o |  1:42ccdea3bb16 B
+  |/
+  o  0:cd010b8cd998 A
+  
+  $ hg rebase -s 14 -d 18 --config experimental.rebaseskipobsolete=True
+  note: not rebasing 14:9ad579b4a5de "I", already in destination as 17:fc37a630c901 "K"
+  rebasing 15:5ae8a643467b "J"
+
--- a/tests/test-rebase-parameters.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-rebase-parameters.t	Fri Sep 25 23:10:47 2015 -0500
@@ -485,7 +485,6 @@
   $ hg resolve -m c2
   (no more unresolved files)
   $ hg rebase -c --tool internal:fail
-  tool option will be ignored
   rebasing 2:e4e3f3546619 "c2b" (tip)
   note: rebase of 2:e4e3f3546619 created no changes to commit
   saved backup bundle to $TESTTMP/b3/.hg/strip-backup/e4e3f3546619-b0841178-backup.hg (glob)
--- a/tests/test-resolve.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-resolve.t	Fri Sep 25 23:10:47 2015 -0500
@@ -129,7 +129,7 @@
 resolve without arguments should suggest --all
   $ hg resolve
   abort: no files or directories specified
-  (use --all to remerge all files)
+  (use --all to re-merge all unresolved files)
   [255]
 
 resolve --all should re-merge all unresolved files
--- a/tests/test-revset.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-revset.t	Fri Sep 25 23:10:47 2015 -0500
@@ -141,7 +141,7 @@
     ('symbol', '3')
     ('symbol', '6'))
   * set:
-  <baseset [3, 5, 6]>
+  <baseset+ [3, 5, 6]>
   3
   5
   6
@@ -197,11 +197,53 @@
   <filteredset
     <baseset [7]>>
   7
-  $ try -- '-a-b-c-' # complains
-  hg: parse error at 7: not a prefix: end
-  [255]
-  $ log -a-b-c- # succeeds with fallback
+
+names that should be caught by fallback mechanism
+
+  $ try -- '-a-b-c-'
+  ('symbol', '-a-b-c-')
+  * set:
+  <baseset [4]>
+  4
+  $ log -a-b-c-
+  4
+  $ try '+a+b+c+'
+  ('symbol', '+a+b+c+')
+  * set:
+  <baseset [3]>
+  3
+  $ try '+a+b+c+:'
+  (rangepost
+    ('symbol', '+a+b+c+'))
+  * set:
+  <spanset+ 3:9>
+  3
   4
+  5
+  6
+  7
+  8
+  9
+  $ try ':+a+b+c+'
+  (rangepre
+    ('symbol', '+a+b+c+'))
+  * set:
+  <spanset+ 0:3>
+  0
+  1
+  2
+  3
+  $ try -- '-a-b-c-:+a+b+c+'
+  (range
+    ('symbol', '-a-b-c-')
+    ('symbol', '+a+b+c+'))
+  * set:
+  <spanset- 3:4>
+  4
+  3
+  $ log '-a-b-c-:+a+b+c+'
+  4
+  3
 
   $ try -- -a-b-c--a # complains
   (minus
@@ -311,6 +353,9 @@
   $ log 'date('
   hg: parse error at 5: not a prefix: end
   [255]
+  $ log 'date("\xy")'
+  hg: parse error: invalid \x escape
+  [255]
   $ log 'date(tip)'
   abort: invalid date: 'tip'
   [255]
@@ -949,7 +994,7 @@
       ('symbol', '4')))
   * set:
   <addset
-    <baseset [5, 3, 1]>,
+    <baseset- [1, 3, 5]>,
     <generatorset+>>
   5
   3
@@ -972,7 +1017,7 @@
   * set:
   <addset+
     <generatorset+>,
-    <baseset [5, 3, 1]>>
+    <baseset- [1, 3, 5]>>
   0
   1
   2
@@ -1473,10 +1518,16 @@
 (single rev)
 
   $ hg diff -r 'tip^' -r 'tip^'
-  $ hg diff -r 'tip^::tip^ or tip^'
+  $ hg diff -r 'tip^:tip^'
 
 (single rev that does not looks like a range)
 
+  $ hg diff -r 'tip^::tip^ or tip^'
+  diff -r d5d0dcbdc4d9 .hgtags
+  --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/.hgtags	* (glob)
+  @@ -0,0 +1,1 @@
+  +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
   $ hg diff -r 'tip^ or tip^'
   diff -r d5d0dcbdc4d9 .hgtags
   --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
--- a/tests/test-run-tests.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-run-tests.t	Fri Sep 25 23:10:47 2015 -0500
@@ -580,7 +580,7 @@
   >   $ echo foo
   >   foo
   > EOF
-  $ run-tests.py test-hghave.t
+  $ run-tests.py $HGTEST_RUN_TESTS_PURE test-hghave.t
   .
   # Ran 1 tests, 0 skipped, 0 warned, 0 failed.
 
@@ -599,7 +599,7 @@
   >   #
   >   # check-code - a style and portability checker for Mercurial
   > EOF
-  $ run-tests.py test-runtestdir.t
+  $ run-tests.py $HGTEST_RUN_TESTS_PURE test-runtestdir.t
   .
   # Ran 1 tests, 0 skipped, 0 warned, 0 failed.
 
@@ -616,8 +616,22 @@
   >   $ custom-command.sh
   >   hello world
   > EOF
-  $ run-tests.py test-testdir-path.t
+  $ run-tests.py $HGTEST_RUN_TESTS_PURE test-testdir-path.t
   .
   # Ran 1 tests, 0 skipped, 0 warned, 0 failed.
 
 #endif
+
+test support for --allow-slow-tests
+  $ cat > test-very-slow-test.t <<EOF
+  > #require slow
+  >   $ echo pass
+  >   pass
+  > EOF
+  $ run-tests.py $HGTEST_RUN_TESTS_PURE test-very-slow-test.t
+  s
+  Skipped test-very-slow-test.t: skipped
+  # Ran 0 tests, 1 skipped, 0 warned, 0 failed.
+  $ run-tests.py $HGTEST_RUN_TESTS_PURE --allow-slow-tests test-very-slow-test.t
+  .
+  # Ran 1 tests, 0 skipped, 0 warned, 0 failed.
--- a/tests/test-ssh-bundle1.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-ssh-bundle1.t	Fri Sep 25 23:10:47 2015 -0500
@@ -43,14 +43,14 @@
 repo not found error
 
   $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
-  remote: abort: there is no Mercurial repository here (.hg not found)!
+  remote: abort: repository nonexistent not found!
   abort: no suitable response from remote hg!
   [255]
 
 non-existent absolute path
 
   $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
-  remote: abort: there is no Mercurial repository here (.hg not found)!
+  remote: abort: repository /$TESTTMP/nonexistent not found!
   abort: no suitable response from remote hg!
   [255]
 
@@ -128,7 +128,7 @@
 
   $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
   pulling from ssh://user@dummy/doesnotexist
-  remote: abort: there is no Mercurial repository here (.hg not found)!
+  remote: abort: repository doesnotexist not found!
   abort: no suitable response from remote hg!
   [255]
 
--- a/tests/test-ssh.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-ssh.t	Fri Sep 25 23:10:47 2015 -0500
@@ -34,14 +34,14 @@
 repo not found error
 
   $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
-  remote: abort: there is no Mercurial repository here (.hg not found)!
+  remote: abort: repository nonexistent not found!
   abort: no suitable response from remote hg!
   [255]
 
 non-existent absolute path
 
-  $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
-  remote: abort: there is no Mercurial repository here (.hg not found)!
+  $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/`pwd`/nonexistent local
+  remote: abort: repository $TESTTMP/nonexistent not found!
   abort: no suitable response from remote hg!
   [255]
 
@@ -119,7 +119,7 @@
 
   $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
   pulling from ssh://user@dummy/doesnotexist
-  remote: abort: there is no Mercurial repository here (.hg not found)!
+  remote: abort: repository doesnotexist not found!
   abort: no suitable response from remote hg!
   [255]
 
@@ -471,7 +471,7 @@
 
   $ cat dummylog
   Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
-  Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
+  Got arguments 1:user@dummy 2:hg -R $TESTTMP/nonexistent serve --stdio
   Got arguments 1:user@dummy 2:hg -R remote serve --stdio
   Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
   Got arguments 1:user@dummy 2:hg -R remote serve --stdio
--- a/tests/test-strip.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-strip.t	Fri Sep 25 23:10:47 2015 -0500
@@ -697,7 +697,7 @@
 Test that we only bundle the stripped changesets (issue4736)
 ------------------------------------------------------------
 
-initialisation (previous repo is empty anyway)
+initialization (previous repo is empty anyway)
 
   $ hg init issue4736
   $ cd issue4736
--- a/tests/test-tags.t	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-tags.t	Fri Sep 25 23:10:47 2015 -0500
@@ -137,11 +137,11 @@
   $ hg identify
   b9154636be93 tip
   $ hg blackbox -l 5
-  1970/01/01 00:00:00 bob> identify
-  1970/01/01 00:00:00 bob> writing 48 bytes to cache/hgtagsfnodes1
-  1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
-  1970/01/01 00:00:00 bob> identify exited 0 after ?.?? seconds (glob)
+  1970/01/01 00:00:00 bob (*)> identify (glob)
+  1970/01/01 00:00:00 bob (*)> writing 48 bytes to cache/hgtagsfnodes1 (glob)
+  1970/01/01 00:00:00 bob (*)> 0/1 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 1 tags (glob)
+  1970/01/01 00:00:00 bob (*)> identify exited 0 after ?.?? seconds (glob)
 
 Failure to acquire lock results in no write
 
@@ -150,11 +150,11 @@
   $ hg identify
   b9154636be93 tip
   $ hg blackbox -l 5
-  1970/01/01 00:00:00 bob> identify
-  1970/01/01 00:00:00 bob> not writing .hg/cache/hgtagsfnodes1 because lock cannot be acquired
-  1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
-  1970/01/01 00:00:00 bob> identify exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> identify (glob)
+  1970/01/01 00:00:00 bob (*)> not writing .hg/cache/hgtagsfnodes1 because lock cannot be acquired (glob)
+  1970/01/01 00:00:00 bob (*)> 0/1 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 1 tags (glob)
+  1970/01/01 00:00:00 bob (*)> identify exited 0 after * seconds (glob)
 
   $ fnodescacheexists
   no fnodes cache
@@ -349,11 +349,11 @@
   bar                                1:78391a272241
 
   $ hg blackbox -l 5
-  1970/01/01 00:00:00 bob> tags
-  1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
-  1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
-  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> tags (glob)
+  1970/01/01 00:00:00 bob (*)> writing 24 bytes to cache/hgtagsfnodes1 (glob)
+  1970/01/01 00:00:00 bob (*)> 2/3 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 1 tags (glob)
+  1970/01/01 00:00:00 bob (*)> tags exited 0 after * seconds (glob)
 
 #if unix-permissions no-root
 Errors writing to .hgtags fnodes cache are silently ignored
@@ -369,11 +369,11 @@
   bar                                1:78391a272241
 
   $ hg blackbox -l 5
-  1970/01/01 00:00:00 bob> tags
-  1970/01/01 00:00:00 bob> couldn't write cache/hgtagsfnodes1: [Errno 13] Permission denied: '$TESTTMP/t2/.hg/cache/hgtagsfnodes1'
-  1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
-  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> tags (glob)
+  1970/01/01 00:00:00 bob (*)> couldn't write cache/hgtagsfnodes1: [Errno 13] Permission denied: '$TESTTMP/t2/.hg/cache/hgtagsfnodes1' (glob)
+  1970/01/01 00:00:00 bob (*)> 2/3 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 1 tags (glob)
+  1970/01/01 00:00:00 bob (*)> tags exited 0 after * seconds (glob)
 
   $ chmod a+w .hg/cache/hgtagsfnodes1
 
@@ -383,11 +383,11 @@
   bar                                1:78391a272241
 
   $ hg blackbox -l 5
-  1970/01/01 00:00:00 bob> tags
-  1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
-  1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
-  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> tags (glob)
+  1970/01/01 00:00:00 bob (*)> writing 24 bytes to cache/hgtagsfnodes1 (glob)
+  1970/01/01 00:00:00 bob (*)> 2/3 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 1 tags (glob)
+  1970/01/01 00:00:00 bob (*)> tags exited 0 after * seconds (glob)
 
   $ f --size .hg/cache/hgtagsfnodes1
   .hg/cache/hgtagsfnodes1: size=168
@@ -411,10 +411,10 @@
   bar                                1:78391a272241
 
   $ hg blackbox -l 4
-  1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
-  1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
-  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing 24 bytes to cache/hgtagsfnodes1 (glob)
+  1970/01/01 00:00:00 bob (*)> 2/3 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 1 tags (glob)
+  1970/01/01 00:00:00 bob (*)> tags exited 0 after * seconds (glob)
 
   $ f --size .hg/cache/hgtagsfnodes1
   .hg/cache/hgtagsfnodes1: size=120
@@ -427,11 +427,11 @@
   bar                                1:78391a272241
 
   $ hg blackbox -l 5
-  1970/01/01 00:00:00 bob> tags
-  1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
-  1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
-  1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
-  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> tags (glob)
+  1970/01/01 00:00:00 bob (*)> writing 24 bytes to cache/hgtagsfnodes1 (glob)
+  1970/01/01 00:00:00 bob (*)> 2/3 cache hits/lookups in * seconds (glob)
+  1970/01/01 00:00:00 bob (*)> writing .hg/cache/tags2-visible with 1 tags (glob)
+  1970/01/01 00:00:00 bob (*)> tags exited 0 after * seconds (glob)
   $ f --size .hg/cache/hgtagsfnodes1
   .hg/cache/hgtagsfnodes1: size=144
 
--- a/tests/test-wireproto.py	Fri Sep 25 13:30:49 2015 -0700
+++ b/tests/test-wireproto.py	Fri Sep 25 23:10:47 2015 -0500
@@ -12,6 +12,10 @@
 class clientpeer(wireproto.wirepeer):
     def __init__(self, serverrepo):
         self.serverrepo = serverrepo
+
+    def _capabilities(self):
+        return ['batch']
+
     def _call(self, cmd, **args):
         return wireproto.dispatch(self.serverrepo, proto(args), cmd)