changeset 3667:d5032b951c5c

merge with upstream
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Mon, 13 Nov 2006 21:50:09 +0100
parents adbf440a81e0 (current diff) b984dcb1df71 (diff)
children 6f6696962986
files
diffstat 12 files changed, 511 insertions(+), 568 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/bugzilla.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/hgext/bugzilla.py	Mon Nov 13 21:50:09 2006 +0100
@@ -55,7 +55,7 @@
 from mercurial.demandload import *
 from mercurial.i18n import gettext as _
 from mercurial.node import *
-demandload(globals(), 'mercurial:templater,util os re time')
+demandload(globals(), 'mercurial:cmdutil,templater,util os re time')
 
 MySQLdb = None
 
@@ -267,8 +267,8 @@
 
         mapfile = self.ui.config('bugzilla', 'style')
         tmpl = self.ui.config('bugzilla', 'template')
-        sio = templater.stringio()
-        t = templater.changeset_templater(self.ui, self.repo, mapfile, sio)
+        sio = cmdutil.stringio()
+        t = cmdutil.changeset_templater(self.ui, self.repo, mapfile, sio)
         if not mapfile and not tmpl:
             tmpl = _('changeset {node|short} in repo {root} refers '
                      'to bug {bug}.\ndetails:\n\t{desc|tabindent}')
--- a/hgext/hbisect.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/hgext/hbisect.py	Mon Nov 13 21:50:09 2006 +0100
@@ -8,7 +8,7 @@
 
 from mercurial.i18n import gettext as _
 from mercurial.demandload import demandload
-demandload(globals(), "os sys sets mercurial:hg,util,commands")
+demandload(globals(), "os sys sets mercurial:hg,util,commands,cmdutil")
 
 versionstr = "0.0.3"
 
@@ -169,7 +169,7 @@
             if ancestors.pop() != self.badrev:
                 raise util.Abort(_("Could not find the first bad revision"))
             self.ui.write(_("The first bad revision is:\n"))
-            displayer = commands.show_changeset(self.ui, self.repo, {})
+            displayer = cmdutil.show_changeset(self.ui, self.repo, {})
             displayer.show(changenode=self.badrev)
             return None
         best_rev = None
--- a/hgext/notify.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/hgext/notify.py	Mon Nov 13 21:50:09 2006 +0100
@@ -68,7 +68,7 @@
 from mercurial.demandload import *
 from mercurial.i18n import gettext as _
 from mercurial.node import *
-demandload(globals(), 'mercurial:commands,patch,templater,util,mail')
+demandload(globals(), 'mercurial:commands,patch,cmdutil,templater,util,mail')
 demandload(globals(), 'email.Parser fnmatch socket time')
 
 # template for single changeset can include email headers.
@@ -107,13 +107,13 @@
         self.stripcount = int(self.ui.config('notify', 'strip', 0))
         self.root = self.strip(self.repo.root)
         self.domain = self.ui.config('notify', 'domain')
-        self.sio = templater.stringio()
+        self.sio = cmdutil.stringio()
         self.subs = self.subscribers()
 
         mapfile = self.ui.config('notify', 'style')
         template = (self.ui.config('notify', hooktype) or
                     self.ui.config('notify', 'template'))
-        self.t = templater.changeset_templater(self.ui, self.repo, mapfile,
+        self.t = cmdutil.changeset_templater(self.ui, self.repo, mapfile,
                                                self.sio)
         if not mapfile and not template:
             template = deftemplates.get(hooktype) or single_template
@@ -237,7 +237,7 @@
         maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
         if maxdiff == 0:
             return
-        fp = templater.stringio()
+        fp = cmdutil.stringio()
         prev = self.repo.changelog.parents(node)[0]
         patch.diff(self.repo, prev, ref, fp=fp)
         difflines = fp.getvalue().splitlines(1)
--- a/mercurial/cmdutil.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/mercurial/cmdutil.py	Mon Nov 13 21:50:09 2006 +0100
@@ -8,8 +8,8 @@
 from demandload import demandload
 from node import *
 from i18n import gettext as _
-demandload(globals(), 'mdiff util')
 demandload(globals(), 'os sys')
+demandload(globals(), 'mdiff util templater cStringIO patch')
 
 revrangesep = ':'
 
@@ -195,3 +195,391 @@
                                (oldrel, newrel, score * 100))
             if not dry_run:
                 repo.copy(old, new, wlock=wlock)
+
+class uibuffer(object):
+    # Implement and delegate some ui protocol.  Save hunks of
+    # output for later display in the desired order.
+    def __init__(self, ui):
+        self.ui = ui
+        self.hunk = {}
+        self.header = {}
+        self.quiet = ui.quiet
+        self.verbose = ui.verbose
+        self.debugflag = ui.debugflag
+        self.lastheader = None
+    def note(self, *args):
+        if self.verbose:
+            self.write(*args)
+    def status(self, *args):
+        if not self.quiet:
+            self.write(*args)
+    def debug(self, *args):
+        if self.debugflag:
+            self.write(*args)
+    def write(self, *args):
+        self.hunk.setdefault(self.rev, []).extend(args)
+    def write_header(self, *args):
+        self.header.setdefault(self.rev, []).extend(args)
+    def mark(self, rev):
+        self.rev = rev
+    def flush(self, rev):
+        if rev in self.header:
+            h = "".join(self.header[rev])
+            if h != self.lastheader:
+                self.lastheader = h
+                self.ui.write(h)
+            del self.header[rev]
+        if rev in self.hunk:
+            self.ui.write("".join(self.hunk[rev]))
+            del self.hunk[rev]
+            return 1
+        return 0
+
+class changeset_printer(object):
+    '''show changeset information when templating not requested.'''
+
+    def __init__(self, ui, repo, patch, buffered):
+        self.ui = ui
+        self.repo = repo
+        self.buffered = buffered
+        self.patch = patch
+        if buffered:
+            self.ui = uibuffer(ui)
+
+    def flush(self, rev):
+        return self.ui.flush(rev)
+
+    def show(self, rev=0, changenode=None, brinfo=None, copies=None):
+        '''show a single changeset or file revision'''
+        if self.buffered:
+            self.ui.mark(rev)
+        log = self.repo.changelog
+        if changenode is None:
+            changenode = log.node(rev)
+        elif not rev:
+            rev = log.rev(changenode)
+
+        if self.ui.quiet:
+            self.ui.write("%d:%s\n" % (rev, short(changenode)))
+            return
+
+        changes = log.read(changenode)
+        date = util.datestr(changes[2])
+        extra = changes[5]
+        branch = extra.get("branch")
+
+        hexfunc = self.ui.debugflag and hex or short
+
+        parents = log.parentrevs(rev)
+        if not self.ui.debugflag:
+            if parents[1] == nullrev:
+                if parents[0] >= rev - 1:
+                    parents = []
+                else:
+                    parents = [parents[0]]
+        parents = [(p, hexfunc(log.node(p))) for p in parents]
+
+        self.ui.write(_("changeset:   %d:%s\n") % (rev, hexfunc(changenode)))
+
+        if branch:
+            self.ui.write(_("branch:      %s\n") % branch)
+        for tag in self.repo.nodetags(changenode):
+            self.ui.write(_("tag:         %s\n") % tag)
+        for parent in parents:
+            self.ui.write(_("parent:      %d:%s\n") % parent)
+
+        if brinfo and changenode in brinfo:
+            br = brinfo[changenode]
+            self.ui.write(_("branch:      %s\n") % " ".join(br))
+
+        if self.ui.debugflag:
+            self.ui.write(_("manifest:    %d:%s\n") %
+                          (self.repo.manifest.rev(changes[0]), hex(changes[0])))
+        self.ui.write(_("user:        %s\n") % changes[1])
+        self.ui.write(_("date:        %s\n") % date)
+
+        if self.ui.debugflag:
+            files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
+            for key, value in zip([_("files:"), _("files+:"), _("files-:")],
+                                  files):
+                if value:
+                    self.ui.write("%-12s %s\n" % (key, " ".join(value)))
+        elif changes[3] and self.ui.verbose:
+            self.ui.write(_("files:       %s\n") % " ".join(changes[3]))
+        if copies and self.ui.verbose:
+            copies = ['%s (%s)' % c for c in copies]
+            self.ui.write(_("copies:      %s\n") % ' '.join(copies))
+
+        if extra and self.ui.debugflag:
+            extraitems = extra.items()
+            extraitems.sort()
+            for key, value in extraitems:
+                self.ui.write(_("extra:       %s=%s\n")
+                              % (key, value.encode('string_escape')))
+
+        description = changes[4].strip()
+        if description:
+            if self.ui.verbose:
+                self.ui.write(_("description:\n"))
+                self.ui.write(description)
+                self.ui.write("\n\n")
+            else:
+                self.ui.write(_("summary:     %s\n") %
+                              description.splitlines()[0])
+        self.ui.write("\n")
+
+        self.showpatch(changenode)
+
+    def showpatch(self, node):
+        if self.patch:
+            prev = self.repo.changelog.parents(node)[0]
+            patch.diff(self.repo, prev, node, fp=self.ui)
+            self.ui.write("\n")
+
+class changeset_templater(changeset_printer):
+    '''format changeset information.'''
+
+    def __init__(self, ui, repo, patch, mapfile, buffered):
+        changeset_printer.__init__(self, ui, repo, patch, buffered)
+        self.t = templater.templater(mapfile, templater.common_filters,
+                                     cache={'parent': '{rev}:{node|short} ',
+                                            'manifest': '{rev}:{node|short}',
+                                            'filecopy': '{name} ({source})'})
+
+    def use_template(self, t):
+        '''set template string to use'''
+        self.t.cache['changeset'] = t
+
+    def show(self, rev=0, changenode=None, brinfo=None, copies=[], **props):
+        '''show a single changeset or file revision'''
+        if self.buffered:
+            self.ui.mark(rev)
+        log = self.repo.changelog
+        if changenode is None:
+            changenode = log.node(rev)
+        elif not rev:
+            rev = log.rev(changenode)
+
+        changes = log.read(changenode)
+
+        def showlist(name, values, plural=None, **args):
+            '''expand set of values.
+            name is name of key in template map.
+            values is list of strings or dicts.
+            plural is plural of name, if not simply name + 's'.
+
+            expansion works like this, given name 'foo'.
+
+            if values is empty, expand 'no_foos'.
+
+            if 'foo' not in template map, return values as a string,
+            joined by space.
+
+            expand 'start_foos'.
+
+            for each value, expand 'foo'. if 'last_foo' in template
+            map, expand it instead of 'foo' for last key.
+
+            expand 'end_foos'.
+            '''
+            if plural: names = plural
+            else: names = name + 's'
+            if not values:
+                noname = 'no_' + names
+                if noname in self.t:
+                    yield self.t(noname, **args)
+                return
+            if name not in self.t:
+                if isinstance(values[0], str):
+                    yield ' '.join(values)
+                else:
+                    for v in values:
+                        yield dict(v, **args)
+                return
+            startname = 'start_' + names
+            if startname in self.t:
+                yield self.t(startname, **args)
+            vargs = args.copy()
+            def one(v, tag=name):
+                try:
+                    vargs.update(v)
+                except (AttributeError, ValueError):
+                    try:
+                        for a, b in v:
+                            vargs[a] = b
+                    except ValueError:
+                        vargs[name] = v
+                return self.t(tag, **vargs)
+            lastname = 'last_' + name
+            if lastname in self.t:
+                last = values.pop()
+            else:
+                last = None
+            for v in values:
+                yield one(v)
+            if last is not None:
+                yield one(last, tag=lastname)
+            endname = 'end_' + names
+            if endname in self.t:
+                yield self.t(endname, **args)
+
+        def showbranches(**args):
+            branch = changes[5].get("branch")
+            if branch:
+                yield showlist('branch', [branch], plural='branches', **args)
+            # add old style branches if requested
+            if brinfo and changenode in brinfo:
+                yield showlist('branch', brinfo[changenode],
+                               plural='branches', **args)
+
+        def showparents(**args):
+            parents = [[('rev', log.rev(p)), ('node', hex(p))]
+                       for p in log.parents(changenode)
+                       if self.ui.debugflag or p != nullid]
+            if (not self.ui.debugflag and len(parents) == 1 and
+                parents[0][0][1] == rev - 1):
+                return
+            return showlist('parent', parents, **args)
+
+        def showtags(**args):
+            return showlist('tag', self.repo.nodetags(changenode), **args)
+
+        def showextras(**args):
+            extras = changes[5].items()
+            extras.sort()
+            for key, value in extras:
+                args = args.copy()
+                args.update(dict(key=key, value=value))
+                yield self.t('extra', **args)
+
+        def showcopies(**args):
+            c = [{'name': x[0], 'source': x[1]} for x in copies]
+            return showlist('file_copy', c, plural='file_copies', **args)
+
+        if self.ui.debugflag:
+            files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
+            def showfiles(**args):
+                return showlist('file', files[0], **args)
+            def showadds(**args):
+                return showlist('file_add', files[1], **args)
+            def showdels(**args):
+                return showlist('file_del', files[2], **args)
+            def showmanifest(**args):
+                args = args.copy()
+                args.update(dict(rev=self.repo.manifest.rev(changes[0]),
+                                 node=hex(changes[0])))
+                return self.t('manifest', **args)
+        else:
+            def showfiles(**args):
+                yield showlist('file', changes[3], **args)
+            showadds = ''
+            showdels = ''
+            showmanifest = ''
+
+        defprops = {
+            'author': changes[1],
+            'branches': showbranches,
+            'date': changes[2],
+            'desc': changes[4],
+            'file_adds': showadds,
+            'file_dels': showdels,
+            'files': showfiles,
+            'file_copies': showcopies,
+            'manifest': showmanifest,
+            'node': hex(changenode),
+            'parents': showparents,
+            'rev': rev,
+            'tags': showtags,
+            'extras': showextras,
+            }
+        props = props.copy()
+        props.update(defprops)
+
+        try:
+            if self.ui.debugflag and 'header_debug' in self.t:
+                key = 'header_debug'
+            elif self.ui.quiet and 'header_quiet' in self.t:
+                key = 'header_quiet'
+            elif self.ui.verbose and 'header_verbose' in self.t:
+                key = 'header_verbose'
+            elif 'header' in self.t:
+                key = 'header'
+            else:
+                key = ''
+            if key:
+                h = templater.stringify(self.t(key, **props))
+                if self.buffered:
+                    self.ui.write_header(h)
+                else:
+                    self.ui.write(h)
+            if self.ui.debugflag and 'changeset_debug' in self.t:
+                key = 'changeset_debug'
+            elif self.ui.quiet and 'changeset_quiet' in self.t:
+                key = 'changeset_quiet'
+            elif self.ui.verbose and 'changeset_verbose' in self.t:
+                key = 'changeset_verbose'
+            else:
+                key = 'changeset'
+            self.ui.write(templater.stringify(self.t(key, **props)))
+            self.showpatch(changenode)
+        except KeyError, inst:
+            raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
+                                                           inst.args[0]))
+        except SyntaxError, inst:
+            raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
+
+class stringio(object):
+    '''wrap cStringIO for use by changeset_templater.'''
+    def __init__(self):
+        self.fp = cStringIO.StringIO()
+
+    def write(self, *args):
+        for a in args:
+            self.fp.write(a)
+
+    write_header = write
+
+    def __getattr__(self, key):
+        return getattr(self.fp, key)
+
+def show_changeset(ui, repo, opts, buffered=False):
+    """show one changeset using template or regular display.
+
+    Display format will be the first non-empty hit of:
+    1. option 'template'
+    2. option 'style'
+    3. [ui] setting 'logtemplate'
+    4. [ui] setting 'style'
+    If all of these values are either the unset or the empty string,
+    regular display via changeset_printer() is done.
+    """
+    # options
+    patch = opts.get('patch')
+    tmpl = opts.get('template')
+    mapfile = None
+    if tmpl:
+        tmpl = templater.parsestring(tmpl, quoted=False)
+    else:
+        mapfile = opts.get('style')
+        # ui settings
+        if not mapfile:
+            tmpl = ui.config('ui', 'logtemplate')
+            if tmpl:
+                tmpl = templater.parsestring(tmpl)
+            else:
+                mapfile = ui.config('ui', 'style')
+
+    if tmpl or mapfile:
+        if mapfile:
+            if not os.path.split(mapfile)[0]:
+                mapname = (templater.templatepath('map-cmdline.' + mapfile)
+                           or templater.templatepath(mapfile))
+                if mapname: mapfile = mapname
+        try:
+            t = changeset_templater(ui, repo, patch, mapfile, buffered)
+        except SyntaxError, inst:
+            raise util.Abort(inst.args[0])
+        if tmpl: t.use_template(tmpl)
+        return t
+    return changeset_printer(ui, repo, patch, buffered)
+
--- a/mercurial/commands.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/mercurial/commands.py	Mon Nov 13 21:50:09 2006 +0100
@@ -8,12 +8,11 @@
 from demandload import demandload
 from node import *
 from i18n import gettext as _
-demandload(globals(), "os re sys signal shutil imp urllib pdb shlex")
-demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
-demandload(globals(), "fnmatch difflib patch random signal tempfile time")
-demandload(globals(), "traceback errno socket version struct atexit sets bz2")
-demandload(globals(), "archival cStringIO changegroup")
-demandload(globals(), "cmdutil hgweb.server sshserver")
+demandload(globals(), "os re sys signal imp urllib pdb shlex")
+demandload(globals(), "fancyopts ui hg util lock revlog bundlerepo")
+demandload(globals(), "difflib patch tempfile time")
+demandload(globals(), "traceback errno version atexit bz2")
+demandload(globals(), "archival changegroup cmdutil hgweb.server sshserver")
 
 class UnknownCommand(Exception):
     """Exception raised if command is not in the command table."""
@@ -296,130 +295,6 @@
         if cleanup is not None:
             os.unlink(cleanup)
 
-class changeset_printer(object):
-    '''show changeset information when templating not requested.'''
-
-    def __init__(self, ui, repo):
-        self.ui = ui
-        self.repo = repo
-
-    def show(self, rev=0, changenode=None, brinfo=None, copies=None):
-        '''show a single changeset or file revision'''
-        log = self.repo.changelog
-        if changenode is None:
-            changenode = log.node(rev)
-        elif not rev:
-            rev = log.rev(changenode)
-
-        if self.ui.quiet:
-            self.ui.write("%d:%s\n" % (rev, short(changenode)))
-            return
-
-        changes = log.read(changenode)
-        date = util.datestr(changes[2])
-        extra = changes[5]
-        branch = extra.get("branch")
-
-        hexfunc = self.ui.debugflag and hex or short
-
-        parents = log.parentrevs(rev)
-        if not self.ui.debugflag:
-            if parents[1] == nullrev:
-                if parents[0] >= rev - 1:
-                    parents = []
-                else:
-                    parents = [parents[0]]
-        parents = [(p, hexfunc(log.node(p))) for p in parents]
-
-        self.ui.write(_("changeset:   %d:%s\n") % (rev, hexfunc(changenode)))
-
-        if branch:
-            self.ui.write(_("branch:      %s\n") % branch)
-        for tag in self.repo.nodetags(changenode):
-            self.ui.write(_("tag:         %s\n") % tag)
-        for parent in parents:
-            self.ui.write(_("parent:      %d:%s\n") % parent)
-
-        if brinfo and changenode in brinfo:
-            br = brinfo[changenode]
-            self.ui.write(_("branch:      %s\n") % " ".join(br))
-
-        if self.ui.debugflag:
-            self.ui.write(_("manifest:    %d:%s\n") %
-                          (self.repo.manifest.rev(changes[0]), hex(changes[0])))
-        self.ui.write(_("user:        %s\n") % changes[1])
-        self.ui.write(_("date:        %s\n") % date)
-
-        if self.ui.debugflag:
-            files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
-            for key, value in zip([_("files:"), _("files+:"), _("files-:")],
-                                  files):
-                if value:
-                    self.ui.write("%-12s %s\n" % (key, " ".join(value)))
-        elif changes[3] and self.ui.verbose:
-            self.ui.write(_("files:       %s\n") % " ".join(changes[3]))
-        if copies and self.ui.verbose:
-            copies = ['%s (%s)' % c for c in copies]
-            self.ui.write(_("copies:      %s\n") % ' '.join(copies))
-
-        if extra and self.ui.debugflag:
-            extraitems = extra.items()
-            extraitems.sort()
-            for key, value in extraitems:
-                self.ui.write(_("extra:       %s=%s\n")
-                              % (key, value.encode('string_escape')))
-
-        description = changes[4].strip()
-        if description:
-            if self.ui.verbose:
-                self.ui.write(_("description:\n"))
-                self.ui.write(description)
-                self.ui.write("\n\n")
-            else:
-                self.ui.write(_("summary:     %s\n") %
-                              description.splitlines()[0])
-        self.ui.write("\n")
-
-def show_changeset(ui, repo, opts):
-    """show one changeset using template or regular display.
-
-    Display format will be the first non-empty hit of:
-    1. option 'template'
-    2. option 'style'
-    3. [ui] setting 'logtemplate'
-    4. [ui] setting 'style'
-    If all of these values are either the unset or the empty string,
-    regular display via changeset_printer() is done.
-    """
-    # options
-    tmpl = opts.get('template')
-    mapfile = None
-    if tmpl:
-        tmpl = templater.parsestring(tmpl, quoted=False)
-    else:
-        mapfile = opts.get('style')
-        # ui settings
-        if not mapfile:
-            tmpl = ui.config('ui', 'logtemplate')
-            if tmpl:
-                tmpl = templater.parsestring(tmpl)
-            else:
-                mapfile = ui.config('ui', 'style')
-
-    if tmpl or mapfile:
-        if mapfile:
-            if not os.path.split(mapfile)[0]:
-                mapname = (templater.templatepath('map-cmdline.' + mapfile)
-                           or templater.templatepath(mapfile))
-                if mapname: mapfile = mapname
-        try:
-            t = templater.changeset_templater(ui, repo, mapfile)
-        except SyntaxError, inst:
-            raise util.Abort(inst.args[0])
-        if tmpl: t.use_template(tmpl)
-        return t
-    return changeset_printer(ui, repo)
-
 def setremoteconfig(ui, opts):
     "copy remote options to ui tree"
     if opts.get('ssh'):
@@ -828,24 +703,23 @@
         # create the right base
         # XXX: nodesbetween / changegroup* should be "fixed" instead
         o = []
-        has_set = sets.Set(base)
+        has = {nullid: None} 
         for n in base:
-            has_set.update(repo.changelog.reachable(n))
+            has.update(repo.changelog.reachable(n))
         if revs:
             visit = list(revs)
         else:
             visit = repo.changelog.heads()
-        seen = sets.Set(visit)
+        seen = {}
         while visit:
             n = visit.pop(0)
-            parents = [p for p in repo.changelog.parents(n)
-                       if p != nullid and p not in has_set]
+            parents = [p for p in repo.changelog.parents(n) if p not in has]
             if len(parents) == 0:
                 o.insert(0, n)
             else:
                 for p in parents:
                     if p not in seen:
-                        seen.add(p)
+                        seen[p] = 1
                         visit.append(p)
     else:
         setremoteconfig(ui, opts)
@@ -1005,14 +879,11 @@
                     repo.undelete([abstarget], wlock)
                 try:
                     if not opts.get('dry_run'):
-                        shutil.copyfile(relsrc, reltarget)
-                        shutil.copymode(relsrc, reltarget)
+                        util.copyfile(relsrc, reltarget)
                     restore = False
                 finally:
                     if restore:
                         repo.remove([abstarget], wlock)
-            except shutil.Error, inst:
-                raise util.Abort(str(inst))
             except IOError, inst:
                 if inst.errno == errno.ENOENT:
                     ui.warn(_('%s: deleted in working copy\n') % relsrc)
@@ -1568,7 +1439,7 @@
         ui.warn(_("the --branches option is deprecated, "
                   "please use 'hg branches' instead\n"))
         br = repo.branchlookup(heads)
-    displayer = show_changeset(ui, repo, opts)
+    displayer = cmdutil.show_changeset(ui, repo, opts)
     for n in heads:
         displayer.show(changenode=n, brinfo=br)
 
@@ -1715,16 +1586,12 @@
         o = other.changelog.nodesbetween(incoming, revs)[0]
         if opts['newest_first']:
             o.reverse()
-        displayer = show_changeset(ui, other, opts)
+        displayer = cmdutil.show_changeset(ui, other, opts)
         for n in o:
             parents = [p for p in other.changelog.parents(n) if p != nullid]
             if opts['no_merges'] and len(parents) == 2:
                 continue
             displayer.show(changenode=n)
-            if opts['patch']:
-                prev = (parents and parents[0]) or nullid
-                patch.diff(other, prev, n, fp=repo.ui)
-                ui.write("\n")
     finally:
         if hasattr(other, 'close'):
             other.close()
@@ -1801,35 +1668,6 @@
     commit. When the -v/--verbose switch is used, the list of changed
     files and full commit message is shown.
     """
-    class dui(object):
-        # Implement and delegate some ui protocol.  Save hunks of
-        # output for later display in the desired order.
-        def __init__(self, ui):
-            self.ui = ui
-            self.hunk = {}
-            self.header = {}
-            self.quiet = ui.quiet
-            self.verbose = ui.verbose
-            self.debugflag = ui.debugflag
-        def bump(self, rev):
-            self.rev = rev
-            self.hunk[rev] = []
-            self.header[rev] = []
-        def note(self, *args):
-            if self.verbose:
-                self.write(*args)
-        def status(self, *args):
-            if not self.quiet:
-                self.write(*args)
-        def write(self, *args):
-            self.hunk[self.rev].extend(args)
-        def write_header(self, *args):
-            self.header[self.rev].extend(args)
-        def debug(self, *args):
-            if self.debugflag:
-                self.write(*args)
-        def __getattr__(self, key):
-            return getattr(self.ui, key)
 
     getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
     changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
@@ -1884,13 +1722,9 @@
             return ncache[fn].get(dcache[1][fn])
         return None
 
-    displayer = show_changeset(ui, repo, opts)
+    displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
     for st, rev, fns in changeiter:
-        if st == 'window':
-            du = dui(ui)
-            displayer.ui = du
-        elif st == 'add':
-            du.bump(rev)
+        if st == 'add':
             changenode = repo.changelog.node(rev)
             parents = [p for p in repo.changelog.parentrevs(rev)
                        if p != nullrev]
@@ -1923,21 +1757,10 @@
                     if rename:
                         copies.append((fn, rename[0]))
             displayer.show(rev, changenode, brinfo=br, copies=copies)
-            if opts['patch']:
-                if parents:
-                    prev = parents[0]
-                else:
-                    prev = nullrev
-                prev = repo.changelog.node(prev)
-                patch.diff(repo, prev, changenode, match=matchfn, fp=du)
-                du.write("\n\n")
         elif st == 'iter':
             if count == limit: break
-            if du.header[rev]:
-                ui.write_header(*du.header[rev])
-            if du.hunk[rev]:
+            if displayer.flush(rev):
                 count += 1
-                ui.write(*du.hunk[rev])
 
 def manifest(ui, repo, rev=None):
     """output the latest or given revision of the project manifest
@@ -2020,16 +1843,12 @@
     o = repo.changelog.nodesbetween(o, revs)[0]
     if opts['newest_first']:
         o.reverse()
-    displayer = show_changeset(ui, repo, opts)
+    displayer = cmdutil.show_changeset(ui, repo, opts)
     for n in o:
         parents = [p for p in repo.changelog.parents(n) if p != nullid]
         if opts['no_merges'] and len(parents) == 2:
             continue
         displayer.show(changenode=n)
-        if opts['patch']:
-            prev = (parents and parents[0]) or nullid
-            patch.diff(repo, prev, n)
-            ui.write("\n")
 
 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
     """show the parents of the working dir or revision
@@ -2061,7 +1880,7 @@
         ui.warn(_("the --branches option is deprecated, "
                   "please use 'hg branches' instead\n"))
         br = repo.branchlookup(p)
-    displayer = show_changeset(ui, repo, opts)
+    displayer = cmdutil.show_changeset(ui, repo, opts)
     for n in p:
         if n != nullid:
             displayer.show(changenode=n, brinfo=br)
@@ -2420,8 +2239,7 @@
                 ui.note(_('saving current version of %s as %s\n') %
                         (rel, bakname))
                 if not opts.get('dry_run'):
-                    shutil.copyfile(rel, bakname)
-                    shutil.copymode(rel, bakname)
+                    util.copyfile(rel, bakname)
             if ui.verbose or not exact:
                 ui.status(xlist[1] % rel)
         for table, hitlist, misslist, backuphit, backupmiss in disptable:
@@ -2532,24 +2350,14 @@
         os.read(rfd, 1)
         os._exit(0)
 
-    try:
-        httpd = hgweb.server.create_server(ui, repo)
-    except socket.error, inst:
-        raise util.Abort(_('cannot start server: %s') % inst.args[1])
+    httpd = hgweb.server.create_server(ui, repo)
 
     if ui.verbose:
-        addr, port = httpd.socket.getsockname()
-        if addr == '0.0.0.0':
-            addr = socket.gethostname()
+        if httpd.port != 80:
+            ui.status(_('listening at http://%s:%d/\n') %
+                      (httpd.addr, httpd.port))
         else:
-            try:
-                addr = socket.gethostbyaddr(addr)[0]
-            except socket.error:
-                pass
-        if port != 80:
-            ui.status(_('listening at http://%s:%d/\n') % (addr, port))
-        else:
-            ui.status(_('listening at http://%s/\n') % addr)
+            ui.status(_('listening at http://%s/\n') % httpd.addr)
 
     if opts['pid_file']:
         fp = open(opts['pid_file'], 'w')
@@ -2699,9 +2507,7 @@
         ui.warn(_("the --branches option is deprecated, "
                   "please use 'hg branches' instead\n"))
         br = repo.branchlookup([n])
-    show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
-    if opts['patch']:
-        patch.diff(repo, repo.changelog.parents(n)[0], n)
+    cmdutil.show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
 
 def unbundle(ui, repo, fname, **opts):
     """apply a changegroup file
@@ -2768,7 +2574,8 @@
         if len(found) > 1:
             repo.ui.warn(_("Found multiple heads for %s\n") % branch)
             for x in found:
-                show_changeset(ui, repo, {}).show(changenode=x, brinfo=br)
+                cmdutil.show_changeset(ui, repo, {}).show(
+                    changenode=x, brinfo=br)
             raise util.Abort("")
         if len(found) == 1:
             node = found[0]
--- a/mercurial/hgweb/server.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/mercurial/hgweb/server.py	Mon Nov 13 21:50:09 2006 +0100
@@ -200,6 +200,16 @@
             self.reqmaker = wsgiapplication(self.make_handler)
             self.daemon_threads = True
 
+            addr, port = self.socket.getsockname()
+            if addr == '0.0.0.0':
+                addr = socket.gethostname()
+            else:
+                try:
+                    addr = socket.gethostbyaddr(addr)[0]
+                except socket.error:
+                    pass
+            self.addr, self.port = addr, port
+
         def make_handler(self):
             if self.webdir_conf:
                 hgwebobj = self.webdirmaker(self.webdir_conf)
@@ -219,7 +229,10 @@
                 raise hg.RepoError(_('IPv6 not available on this system'))
             super(IPv6HTTPServer, self).__init__(*args, **kwargs)
 
-    if use_ipv6:
-        return IPv6HTTPServer((address, port), _hgwebhandler)
-    else:
-        return MercurialHTTPServer((address, port), _hgwebhandler)
+    try:
+        if use_ipv6:
+            return IPv6HTTPServer((address, port), _hgwebhandler)
+        else:
+            return MercurialHTTPServer((address, port), _hgwebhandler)
+    except socket.error, inst:
+        raise util.Abort(_('cannot start server: %s') % inst.args[1])
--- a/mercurial/patch.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/mercurial/patch.py	Mon Nov 13 21:50:09 2006 +0100
@@ -26,11 +26,8 @@
     targetdir = os.path.dirname(absdst)
     if not os.path.isdir(targetdir):
         os.makedirs(targetdir)
-    try:
-        shutil.copyfile(abssrc, absdst)
-        shutil.copymode(abssrc, absdst)
-    except shutil.Error, inst:
-        raise util.Abort(str(inst))
+
+    util.copyfile(abssrc, absdst)
 
 # public functions
 
--- a/mercurial/revlog.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/mercurial/revlog.py	Mon Nov 13 21:50:09 2006 +0100
@@ -542,10 +542,10 @@
         else:
             return self.index[rev][-5]
 
-    def reachable(self, rev, stop=None):
+    def reachable(self, node, stop=None):
         reachable = {}
-        visit = [rev]
-        reachable[rev] = 1
+        visit = [node]
+        reachable[node] = 1
         if stop:
             stopn = self.rev(stop)
         else:
--- a/mercurial/templater.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/mercurial/templater.py	Mon Nov 13 21:50:09 2006 +0100
@@ -8,36 +8,17 @@
 from demandload import demandload
 from i18n import gettext as _
 from node import *
-demandload(globals(), "cStringIO cgi re sys os time urllib util textwrap")
-
-esctable = {
-    '\\': '\\',
-    'r': '\r',
-    't': '\t',
-    'n': '\n',
-    'v': '\v',
-    }
+demandload(globals(), "cgi re sys os time urllib util textwrap")
 
 def parsestring(s, quoted=True):
     '''parse a string using simple c-like syntax.
     string must be in quotes if quoted is True.'''
-    fp = cStringIO.StringIO()
     if quoted:
-        first = s[0]
-        if len(s) < 2: raise SyntaxError(_('string too short'))
-        if first not in "'\"": raise SyntaxError(_('invalid quote'))
-        if s[-1] != first: raise SyntaxError(_('unmatched quotes'))
-        s = s[1:-1]
-    escape = False
-    for c in s:
-        if escape:
-            fp.write(esctable.get(c, c))
-            escape = False
-        elif c == '\\': escape = True
-        elif quoted and c == first: raise SyntaxError(_('string ends early'))
-        else: fp.write(c)
-    if escape: raise SyntaxError(_('unterminated escape'))
-    return fp.getvalue()
+        if len(s) < 2 or s[0] != s[-1]:
+            raise SyntaxError(_('unmatched quotes'))
+        return s[1:-1].decode('string_escape')
+
+    return s.decode('string_escape')
 
 class templater(object):
     '''template expansion engine.
@@ -59,6 +40,9 @@
     filter uses function to transform value. syntax is
     {key|filter1|filter2|...}.'''
 
+    template_re = re.compile(r"(?:(?:#(?=[\w\|%]+#))|(?:{(?=[\w\|%]+})))"
+                             r"(\w+)(?:(?:%(\w+))|((?:\|\w+)*))[#}]")
+
     def __init__(self, mapfile, filters={}, defaults={}, cache={}):
         '''set up template engine.
         mapfile is name of file to read map definitions from.
@@ -93,69 +77,53 @@
                 raise SyntaxError(_("%s:%s: parse error") % (mapfile, i))
 
     def __contains__(self, key):
-        return key in self.cache
+        return key in self.cache or key in self.map
 
     def __call__(self, t, **map):
         '''perform expansion.
         t is name of map element to expand.
         map is added elements to use during expansion.'''
-        m = self.defaults.copy()
-        m.update(map)
-        try:
-            tmpl = self.cache[t]
-        except KeyError:
+        if not self.cache.has_key(t):
             try:
-                tmpl = self.cache[t] = file(self.map[t]).read()
+                self.cache[t] = file(self.map[t]).read()
             except IOError, inst:
                 raise IOError(inst.args[0], _('template file %s: %s') %
                               (self.map[t], inst.args[1]))
-        return self.template(tmpl, self.filters, **m)
+        tmpl = self.cache[t]
 
-    template_re = re.compile(r"[#{]([a-zA-Z_][a-zA-Z0-9_]*)"
-                             r"((%[a-zA-Z_][a-zA-Z0-9_]*)*)"
-                             r"((\|[a-zA-Z_][a-zA-Z0-9_]*)*)[#}]")
-
-    def template(self, tmpl, filters={}, **map):
-        lm = map.copy()
         while tmpl:
             m = self.template_re.search(tmpl)
-            if m:
-                start, end = m.span(0)
-                s, e = tmpl[start], tmpl[end - 1]
-                key = m.group(1)
-                if ((s == '#' and e != '#') or (s == '{' and e != '}')):
-                    raise SyntaxError(_("'%s'/'%s' mismatch expanding '%s'") %
-                                      (s, e, key))
-                if start:
-                    yield tmpl[:start]
-                v = map.get(key, "")
-                v = callable(v) and v(**map) or v
-
-                format = m.group(2)
-                fl = m.group(4)
-
-                if format:
-                    try:
-                        q = v.__iter__
-                    except AttributeError:
-                        raise SyntaxError(_("Error expanding '%s%s'")
-                                          % (key, format))
-                    for i in q():
-                        lm.update(i)
-                        yield self(format[1:], **lm)
-
-                    v = ""
-
-                elif fl:
-                    for f in fl.split("|")[1:]:
-                        v = filters[f](v)
-
-                yield v
-                tmpl = tmpl[end:]
-            else:
+            if not m:
                 yield tmpl
                 break
 
+            start, end = m.span(0)
+            key, format, fl = m.groups()
+
+            if start:
+                yield tmpl[:start]
+            tmpl = tmpl[end:]
+
+            if key in map:
+                v = map[key]
+            else:
+                v = self.defaults.get(key, "")
+            if callable(v):
+                v = v(**map)
+            if format:
+                if not hasattr(v, '__iter__'):
+                    raise SyntaxError(_("Error expanding '%s%s'")
+                                      % (key, format))
+                lm = map.copy()
+                for i in v:
+                    lm.update(i)
+                    yield self(format, **lm)
+            else:
+                if fl:
+                    for f in fl.split("|")[1:]:
+                        v = self.filters[f](v)
+                yield v
+
 agescales = [("second", 1),
              ("minute", 60),
              ("hour", 3600),
@@ -187,15 +155,10 @@
 
 def stringify(thing):
     '''turn nested template iterator into string.'''
-    cs = cStringIO.StringIO()
-    def walk(things):
-        for t in things:
-            if hasattr(t, '__iter__'):
-                walk(t)
-            else:
-                cs.write(t)
-    walk(thing)
-    return cs.getvalue()
+    if hasattr(thing, '__iter__'):
+        return "".join([stringify(t) for t in thing])
+    if thing is None: return ""
+    return str(thing)
 
 para_re = None
 space_re = None
@@ -219,11 +182,8 @@
             yield text[start:m.start(0)], m.group(1)
             start = m.end(1)
 
-    fp = cStringIO.StringIO()
-    for para, rest in findparas():
-        fp.write(space_re.sub(' ', textwrap.fill(para, width)))
-        fp.write(rest)
-    return fp.getvalue()
+    return "".join([space_re.sub(' ', textwrap.fill(para, width)) + rest
+                    for para, rest in findparas()])
 
 def firstline(text):
     '''return the first line of text'''
@@ -275,16 +235,17 @@
 
 def indent(text, prefix):
     '''indent each non-empty line of text after first with prefix.'''
-    fp = cStringIO.StringIO()
     lines = text.splitlines()
     num_lines = len(lines)
-    for i in xrange(num_lines):
-        l = lines[i]
-        if i and l.strip(): fp.write(prefix)
-        fp.write(l)
-        if i < num_lines - 1 or text.endswith('\n'):
-            fp.write('\n')
-    return fp.getvalue()
+    def indenter():
+        for i in xrange(num_lines):
+            l = lines[i]
+            if i and l.strip():
+                yield prefix
+            yield l
+            if i < num_lines - 1 or text.endswith('\n'):
+                yield '\n'
+    return "".join(indenter())
 
 common_filters = {
     "addbreaks": nl2br,
@@ -329,228 +290,3 @@
         if (name and os.path.exists(p)) or os.path.isdir(p):
             return os.path.normpath(p)
 
-class changeset_templater(object):
-    '''format changeset information.'''
-
-    def __init__(self, ui, repo, mapfile, dest=None):
-        self.t = templater(mapfile, common_filters,
-                           cache={'parent': '{rev}:{node|short} ',
-                                  'manifest': '{rev}:{node|short}',
-                                  'filecopy': '{name} ({source})'})
-        self.ui = ui
-        self.dest = dest
-        self.repo = repo
-
-    def use_template(self, t):
-        '''set template string to use'''
-        self.t.cache['changeset'] = t
-
-    def write(self, thing, header=False):
-        '''write expanded template.
-        uses in-order recursive traverse of iterators.'''
-        dest = self.dest or self.ui
-        for t in thing:
-            if hasattr(t, '__iter__'):
-                self.write(t, header=header)
-            elif header:
-                dest.write_header(t)
-            else:
-                dest.write(t)
-
-    def write_header(self, thing):
-        self.write(thing, header=True)
-
-    def show(self, rev=0, changenode=None, brinfo=None, changes=None,
-             copies=[], **props):
-        '''show a single changeset or file revision'''
-        log = self.repo.changelog
-        if changenode is None:
-            changenode = log.node(rev)
-        elif not rev:
-            rev = log.rev(changenode)
-        if changes is None:
-            changes = log.read(changenode)
-
-        def showlist(name, values, plural=None, **args):
-            '''expand set of values.
-            name is name of key in template map.
-            values is list of strings or dicts.
-            plural is plural of name, if not simply name + 's'.
-
-            expansion works like this, given name 'foo'.
-
-            if values is empty, expand 'no_foos'.
-
-            if 'foo' not in template map, return values as a string,
-            joined by space.
-
-            expand 'start_foos'.
-
-            for each value, expand 'foo'. if 'last_foo' in template
-            map, expand it instead of 'foo' for last key.
-
-            expand 'end_foos'.
-            '''
-            if plural: names = plural
-            else: names = name + 's'
-            if not values:
-                noname = 'no_' + names
-                if noname in self.t:
-                    yield self.t(noname, **args)
-                return
-            if name not in self.t:
-                if isinstance(values[0], str):
-                    yield ' '.join(values)
-                else:
-                    for v in values:
-                        yield dict(v, **args)
-                return
-            startname = 'start_' + names
-            if startname in self.t:
-                yield self.t(startname, **args)
-            vargs = args.copy()
-            def one(v, tag=name):
-                try:
-                    vargs.update(v)
-                except (AttributeError, ValueError):
-                    try:
-                        for a, b in v:
-                            vargs[a] = b
-                    except ValueError:
-                        vargs[name] = v
-                return self.t(tag, **vargs)
-            lastname = 'last_' + name
-            if lastname in self.t:
-                last = values.pop()
-            else:
-                last = None
-            for v in values:
-                yield one(v)
-            if last is not None:
-                yield one(last, tag=lastname)
-            endname = 'end_' + names
-            if endname in self.t:
-                yield self.t(endname, **args)
-
-        def showbranches(**args):
-            branch = changes[5].get("branch")
-            if branch:
-                yield showlist('branch', [branch], plural='branches', **args)
-            # add old style branches if requested
-            if brinfo and changenode in brinfo:
-                for x in showlist('branch', brinfo[changenode],
-                                  plural='branches', **args):
-                    yield x
-
-        if self.ui.debugflag:
-            def showmanifest(**args):
-                args = args.copy()
-                args.update(dict(rev=self.repo.manifest.rev(changes[0]),
-                                 node=hex(changes[0])))
-                yield self.t('manifest', **args)
-        else:
-            showmanifest = ''
-
-        def showparents(**args):
-            parents = [[('rev', log.rev(p)), ('node', hex(p))]
-                       for p in log.parents(changenode)
-                       if self.ui.debugflag or p != nullid]
-            if (not self.ui.debugflag and len(parents) == 1 and
-                parents[0][0][1] == rev - 1):
-                return
-            for x in showlist('parent', parents, **args):
-                yield x
-
-        def showtags(**args):
-            for x in showlist('tag', self.repo.nodetags(changenode), **args):
-                yield x
-
-        def showextras(**args):
-            extras = changes[5].items()
-            extras.sort()
-            for key, value in extras:
-                args = args.copy()
-                args.update(dict(key=key, value=value))
-                yield self.t('extra', **args)
-
-        if self.ui.debugflag:
-            files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
-            def showfiles(**args):
-                for x in showlist('file', files[0], **args): yield x
-            def showadds(**args):
-                for x in showlist('file_add', files[1], **args): yield x
-            def showdels(**args):
-                for x in showlist('file_del', files[2], **args): yield x
-        else:
-            def showfiles(**args):
-                for x in showlist('file', changes[3], **args): yield x
-            showadds = ''
-            showdels = ''
-
-        copies = [{'name': x[0], 'source': x[1]}
-                  for x in copies]
-        def showcopies(**args):
-            for x in showlist('file_copy', copies, plural='file_copies',
-                              **args):
-                yield x
-
-        defprops = {
-            'author': changes[1],
-            'branches': showbranches,
-            'date': changes[2],
-            'desc': changes[4],
-            'file_adds': showadds,
-            'file_dels': showdels,
-            'files': showfiles,
-            'file_copies': showcopies,
-            'manifest': showmanifest,
-            'node': hex(changenode),
-            'parents': showparents,
-            'rev': rev,
-            'tags': showtags,
-            'extras': showextras,
-            }
-        props = props.copy()
-        props.update(defprops)
-
-        try:
-            if self.ui.debugflag and 'header_debug' in self.t:
-                key = 'header_debug'
-            elif self.ui.quiet and 'header_quiet' in self.t:
-                key = 'header_quiet'
-            elif self.ui.verbose and 'header_verbose' in self.t:
-                key = 'header_verbose'
-            elif 'header' in self.t:
-                key = 'header'
-            else:
-                key = ''
-            if key:
-                self.write_header(self.t(key, **props))
-            if self.ui.debugflag and 'changeset_debug' in self.t:
-                key = 'changeset_debug'
-            elif self.ui.quiet and 'changeset_quiet' in self.t:
-                key = 'changeset_quiet'
-            elif self.ui.verbose and 'changeset_verbose' in self.t:
-                key = 'changeset_verbose'
-            else:
-                key = 'changeset'
-            self.write(self.t(key, **props))
-        except KeyError, inst:
-            raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
-                                                           inst.args[0]))
-        except SyntaxError, inst:
-            raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
-
-class stringio(object):
-    '''wrap cStringIO for use by changeset_templater.'''
-    def __init__(self):
-        self.fp = cStringIO.StringIO()
-
-    def write(self, *args):
-        for a in args:
-            self.fp.write(a)
-
-    write_header = write
-
-    def __getattr__(self, key):
-        return getattr(self.fp, key)
--- a/mercurial/ui.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/mercurial/ui.py	Mon Nov 13 21:50:09 2006 +0100
@@ -370,10 +370,6 @@
         for a in args:
             sys.stdout.write(str(a))
 
-    def write_header(self, *args):
-        for a in args:
-            self.header.append(str(a))
-
     def write_err(self, *args):
         try:
             if not sys.stdout.closed: sys.stdout.flush()
--- a/mercurial/util.py	Thu Nov 09 14:44:17 2006 -0800
+++ b/mercurial/util.py	Mon Nov 13 21:50:09 2006 +0100
@@ -460,6 +460,14 @@
     except OSError:
         pass
 
+def copyfile(src, dest):
+    "copy a file, preserving mode"
+    try:
+        shutil.copyfile(src, dest)
+        shutil.copymode(src, dest)
+    except shutil.Error, inst:
+        raise util.Abort(str(inst))
+
 def copyfiles(src, dst, hardlink=None):
     """Copy a directory tree using hardlinks if possible"""
 
--- a/tests/test-remove.out	Thu Nov 09 14:44:17 2006 -0800
+++ b/tests/test-remove.out	Mon Nov 13 21:50:09 2006 +0100
@@ -37,7 +37,6 @@
 @@ -0,0 +1,1 @@
 +a
 
-
 changeset:   1:a1fce69c50d9
 tag:         tip
 user:        test
@@ -50,7 +49,6 @@
 @@ -1,1 +0,0 @@
 -a
 
-
 not removing a: file has been marked for add (use -f to force removal)
 adding a
 adding b