Merge with crew
authorBenoit Boissinot <benoit.boissinot@ens-lyon.org>
Wed, 01 Feb 2006 19:18:15 +0100
changeset 1680 c21b54f7f7b8
parent 1679 675ca845c2f8 (current diff)
parent 1676 0690d0f202e1 (diff)
child 1681 98eef041f9c7
Merge with crew
contrib/patchbomb
mercurial/filelog.py
mercurial/localrepo.py
mercurial/manifest.py
mercurial/revlog.py
mercurial/statichttprepo.py
--- a/.hgtags	Thu Dec 15 18:04:39 2005 +0100
+++ b/.hgtags	Wed Feb 01 19:18:15 2006 +0100
@@ -8,3 +8,4 @@
 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
+3a56574f329a368d645853e0f9e09472aee62349 0.8
--- a/contrib/bash_completion	Thu Dec 15 18:04:39 2005 +0100
+++ b/contrib/bash_completion	Wed Feb 01 19:18:15 2006 +0100
@@ -1,23 +1,54 @@
 shopt -s extglob
 
+_hg_command_list()
+{
+    hg --debug help 2>/dev/null | \
+	awk 'function command_line(line) {
+		 gsub(/,/, "", line)
+		 gsub(/:.*/, "", line)
+		 split(line, aliases)
+		 command = aliases[1]
+		 delete aliases[1]
+		 print command
+		 for (i in aliases)
+		     if (index(command, aliases[i]) != 1)
+			 print aliases[i]
+	     }
+	     /^list of commands:/ {commands=1}
+	     commands && /^ debug/ {a[i++] = $0; next;}
+	     commands && /^ [^ ]/ {command_line($0)}
+	     /^global options:/ {exit 0}
+	     END {for (i in a) command_line(a[i])}'
+
+}
+
+_hg_option_list()
+{
+    hg -v help $1 2> /dev/null | \
+        awk '/^ *-/ {
+		 for (i = 1; i <= NF; i ++) {
+		    if (index($i, "-") != 1)
+			 break;
+		    print $i;
+		 }
+	     }'
+}
+
+
 _hg_commands()
 {
     local all commands result
 
-    all=($(hg --debug help | sed -e '1,/^list of commands:/d' \
-				 -e '/^global options:/,$d' \
-				 -e '/^ [^ ]/!d; s/^ //; s/[,:]//g;'))
-
-    commands="${all[*]##debug*}"
-    result=$(compgen -W "${commands[*]}" -- "$cur")
+    all=$(_hg_command_list)
+    commands=${all%%$'\n'debug*}
+    result=$(compgen -W '$commands' -- "$cur")
 
     # hide debug commands from users, but complete them if
     # there is no other possible command
     if [ "$result" = "" ]; then
 	local debug
-	debug=(${all[*]##!(debug*)})
-	debug="${debug[*]/g/debug}"
-	result=$(compgen -W "$debug" -- "$cur")
+	debug=debug${all#*$'\n'debug}
+	result=$(compgen -W '$debug' -- "$cur")
     fi
 
     COMPREPLY=(${COMPREPLY[@]:-} $result)
@@ -25,8 +56,8 @@
 
 _hg_paths()
 {
-    local paths="$(hg paths | sed -e 's/ = .*$//')"
-    COMPREPLY=(${COMPREPLY[@]:-} $( compgen -W "$paths" -- "$cur" ))
+    local paths="$(hg paths 2> /dev/null | sed -e 's/ = .*$//')"
+    COMPREPLY=(${COMPREPLY[@]:-} $( compgen -W '$paths' -- "$cur" ))
 }
 
 _hg_repos()
@@ -39,14 +70,15 @@
 
 _hg_status()
 {
-    local files="$( hg status -$1 | cut -b 3- )"
-    COMPREPLY=(${COMPREPLY[@]:-} $( compgen -W "$files" -- "$cur" ))
+    local files="$( hg status -n$1 . 2> /dev/null)"
+    COMPREPLY=(${COMPREPLY[@]:-} $( compgen -W '$files' -- "$cur" ))
 }
 
 _hg_tags()
 {
-    local tags="$(hg tags | sed -e 's/[0-9]*:[a-f0-9]\{40\}$//; s/ *$//')"
-    COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "$tags" -- "$cur") )
+    local tags="$(hg tags 2> /dev/null |
+                      sed -e 's/[0-9]*:[a-f0-9]\{40\}$//; s/ *$//')"
+    COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W '$tags' -- "$cur") )
 }
 
 # this is "kind of" ugly...
@@ -90,10 +122,9 @@
     done
 
     if [[ "$cur" == -* ]]; then
-	# this assumes that there are no commands with spaces in the name
-	opts=$(hg -v help $cmd | sed -e '/^ *-/!d; s/ [^- ].*//')
+	opts=$(_hg_option_list $cmd)
 
-	COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "$opts" -- "$cur") )
+	COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur") )
 	return
     fi
 
@@ -115,7 +146,7 @@
     fi
 
     # canonicalize command name
-    cmd=$(hg -q help "$cmd" | sed -e 's/^hg //; s/ .*//; 1q')
+    cmd=$(hg -q help "$cmd" 2> /dev/null | sed -e 's/^hg //; s/ .*//; 1q')
 
     if [ "$cmd" != status ] && [ "$prev" = -r ] || [ "$prev" = --rev ]; then
 	_hg_tags
@@ -140,19 +171,19 @@
 	    _hg_status "u"
 	;;
 	commit)
-	    _hg_status "mra"
+	    _hg_status "mar"
 	;;
 	remove)
-	    _hg_status "r"
+	    _hg_status "d"
 	;;
 	forget)
 	    _hg_status "a"
 	;;
 	diff)
-	    _hg_status "mra"
+	    _hg_status "mar"
 	;;
 	revert)
-	    _hg_status "mra"
+	    _hg_status "mard"
 	;;
 	clone)
 	    local count=$(_hg_count_non_option)
@@ -167,17 +198,6 @@
 	debugdata)
 	    COMPREPLY=(${COMPREPLY[@]:-} $( compgen -f -X "!*.d" -- "$cur" ))
 	;;
-	cat)
-	    local count=$(_hg_count_non_option '-o|--output')
-	    if [ $count = 2 ]; then
-		_hg_tags
-	    else
-		COMPREPLY=(${COMPREPLY[@]:-} $( compgen -f -- "$cur" ))
-	    fi
-	;;
-	*)
-	    COMPREPLY=(${COMPREPLY[@]:-} $( compgen -f -- "$cur" ))
-	;;
     esac
 
 }
--- a/contrib/convert-repo	Thu Dec 15 18:04:39 2005 +0100
+++ b/contrib/convert-repo	Wed Feb 01 19:18:15 2006 +0100
@@ -21,7 +21,7 @@
 # interrupted and can be run repeatedly to copy new commits.
 
 import sys, os, zlib, sha, time
-from mercurial import hg, ui, util
+from mercurial import hg, ui, util, commands
 
 class convert_git:
     def __init__(self, path):
@@ -113,7 +113,7 @@
         except:
             pass
 
-    def putcommit(self, files, parents, author, dest, text):
+    def putcommit(self, files, parents, author, date, text):
         seen = {}
         pl = []
         for p in parents:
@@ -129,8 +129,13 @@
         while parents:
             p1 = p2
             p2 = parents.pop(0)
-            self.repo.rawcommit(files, text, author, dest,
-                                hg.bin(p1), hg.bin(p2))
+            self.repo.dirstate.setparents(hg.bin(p1), hg.bin(p2))
+            if len(files) > 0:
+                olddir = os.getcwd()
+                os.chdir(self.path)
+                commands.addremove(self.repo.ui, self.repo, *files)
+                os.chdir(olddir)
+            self.repo.commit(files, text, author, date)
             text = "(octopus merge fixup)\n"
             p2 = hg.hex(self.repo.changelog.tip())
 
@@ -171,9 +176,12 @@
         self.commitcache = {}
 
         self.map = {}
-        for l in file(self.mapfile):
-            sv, dv = l[:-1].split()
-            self.map[sv] = dv
+        try:
+            for l in file(self.mapfile):
+                sv, dv = l[:-1].split()
+                self.map[sv] = dv
+        except IOError:
+            pass
 
     def walktree(self, heads):
         visit = heads
--- a/contrib/hbisect.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/contrib/hbisect.py	Wed Feb 01 19:18:15 2006 +0100
@@ -21,8 +21,8 @@
     return parents.pop()
 
 def check_clean(ui, repo):
-        c, a, d, u = repo.changes()
-        if c or a or d:
+        modified, added, removed, deleted, unknown = repo.changes()
+        if modified or added or removed:
             ui.warn("Repository is not clean, please commit or revert\n")
             sys.exit(1)
 
--- a/contrib/hg-ssh	Thu Dec 15 18:04:39 2005 +0100
+++ b/contrib/hg-ssh	Wed Feb 01 19:18:15 2006 +0100
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2005 by Intevation GmbH <intevation@intevation.de>
+# Copyright 2005, 2006 by Intevation GmbH <intevation@intevation.de>
 # Author(s):
 # Thomas Arendsen Hein <thomas@intevation.de>
 #
@@ -20,6 +20,9 @@
 If all your repositories are subdirectories of a common directory, you can
 allow shorter paths with:
 command="cd path/to/my/repositories && hg-ssh repo1 subdir/repo2"
+
+You can use pattern matching of your normal shell, e.g.:
+command="cd repos && hg-ssh user/thomas/* projects/{mercurial,foo}"
 """
 
 from mercurial import commands
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/hgdiff	Wed Feb 01 19:18:15 2006 +0100
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+
+import os, sys, struct, stat
+import difflib
+import re
+from optparse import OptionParser
+from mercurial.bdiff import bdiff, blocks
+from mercurial.mdiff import bunidiff
+
+VERSION="0.2"
+usage = "usage: %prog [options] file1 file2"
+parser = OptionParser(usage=usage)
+
+parser.add_option("-d", "--difflib", action="store_true", default=False)
+parser.add_option('-x', '--count', default=1)
+parser.add_option('-c', '--context', type="int", default=3)
+parser.add_option('-p', '--show-c-function', action="store_true", default=False)
+parser.add_option('-w', '--ignore-all-space', action="store_true", 
+                  default=False)
+
+(options, args) = parser.parse_args()
+
+if not args:
+    parser.print_help()
+    sys.exit(1)
+
+# simple utility function to put all the
+# files from a directory tree into a dict
+def buildlist(names, top):
+    tlen = len(top)
+    for root, dirs, files in os.walk(top):
+        l = root[tlen + 1:]
+        for x in files:
+            p = os.path.join(root, x)
+            st = os.lstat(p)
+            if stat.S_ISREG(st.st_mode):
+                names[os.path.join(l, x)] = (st.st_dev, st.st_ino)
+
+def diff_files(file1, file2):
+    if file1 == None:
+        b = file(file2).read().splitlines(1)
+        l1 = "--- %s\n" % (file2)
+        l2 = "+++ %s\n" % (file2)
+        l3 = "@@ -0,0 +1,%d @@\n" % len(b)
+        l = [l1, l2, l3] + ["+" + e for e in b]
+    elif file2 == None:
+        a = file(file1).read().splitlines(1)
+        l1 = "--- %s\n" % (file1)
+        l2 = "+++ %s\n" % (file1)
+        l3 = "@@ -1,%d +0,0 @@\n" % len(a)
+        l = [l1, l2, l3] + ["-" + e for e in a]
+    else:
+        t1 = file(file1).read()
+        t2 = file(file2).read()
+        l1 = t1.splitlines(1)
+        l2 = t2.splitlines(1)
+        if options.difflib:
+            l = difflib.unified_diff(l1, l2, file1, file2)
+        else:
+            l = bunidiff(t1, t2, l1, l2, file1, file2, context=options.context,
+                     showfunc=options.show_c_function,
+                     ignorews=options.ignore_all_space)
+    for x in l:
+        if x[-1] != '\n':
+            x += "\n\ No newline at end of file\n"
+        print x,
+
+file1 = args[0]
+file2 = args[1]
+
+if os.path.isfile(file1) and os.path.isfile(file2):
+    diff_files(file1, file2)
+elif os.path.isdir(file1):
+    if not os.path.isdir(file2):
+        sys.stderr.write("file types don't match\n")
+        sys.exit(1)
+
+    d1 = {}
+    d2 = {}
+
+    buildlist(d1, file1)
+    buildlist(d2, file2)
+    keys = d1.keys()
+    keys.sort()
+    for x in keys:
+        if x not in d2:
+            f2 = None
+        else:
+            f2 = os.path.join(file2, x)
+            st1 = d1[x]
+            st2 = d2[x]
+            del d2[x]
+            if st1[0] == st2[0] and st1[1] == st2[1]:
+                sys.stderr.write("%s is a hard link\n" % x)
+                continue
+        x = os.path.join(file1, x)
+        diff_files(x, f2)
+    keys = d2.keys()
+    keys.sort()
+    for x in keys:
+        f1 = None
+        x = os.path.join(file2, x)
+        diff_files(f1, x)
+
--- a/contrib/hgk.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/contrib/hgk.py	Wed Feb 01 19:18:15 2006 +0100
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-#
 # Minimal support for git commands on an hg repository
 #
 # Copyright 2005 Chris Mason <mason@suse.com>
@@ -16,13 +14,13 @@
         return time.asctime(time.gmtime(c[2][0]))
 
     if not changes:
-        (c, a, d, u) = repo.changes(node1, node2, files, match=match)
-    else:
-        (c, a, d, u) = changes
+        changes = repo.changes(node1, node2, files, match=match)
+    modified, added, removed, deleted, unknown = changes
     if files:
-        c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
+        modified, added, removed = map(lambda x: filterfiles(files, x),
+                                       (modified, added, removed))
 
-    if not c and not a and not d:
+    if not modified and not added and not removed:
         return
 
     if node2:
@@ -42,19 +40,19 @@
     mmap = repo.manifest.read(change[0])
     date1 = date(change)
 
-    for f in c:
+    for f in modified:
         to = None
         if f in mmap:
             to = repo.file(f).read(mmap[f])
         tn = read(f)
         fp.write("diff --git a/%s b/%s\n" % (f, f))
         fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
-    for f in a:
+    for f in added:
         to = None
         tn = read(f)
         fp.write("diff --git /dev/null b/%s\n" % (f))
         fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
-    for f in d:
+    for f in removed:
         to = repo.file(f).read(mmap[f])
         tn = None
         fp.write("diff --git a/%s /dev/null\n" % (f))
@@ -69,12 +67,12 @@
         if node2:
             change = repo.changelog.read(node2)
             mmap2 = repo.manifest.read(change[0])
-            (c, a, d, u) = repo.changes(node1, node2)
+            modified, added, removed, deleted, unknown = repo.changes(node1, node2)
             def read(f): return repo.file(f).read(mmap2[f])
             date2 = date(change)
         else:
             date2 = time.asctime()
-            (c, a, d, u) = repo.changes(node1, None)
+            modified, added, removed, deleted, unknown = repo.changes(node1)
             if not node1:
                 node1 = repo.dirstate.parents()[0]
             def read(f): return file(os.path.join(repo.root, f)).read()
@@ -84,13 +82,13 @@
         date1 = date(change)
         empty = "0" * 40;
 
-        for f in c:
+        for f in modified:
             # TODO get file permissions
             print ":100664 100664 %s %s M\t%s\t%s" % (hg.hex(mmap[f]),
                                                       hg.hex(mmap2[f]), f, f)
-        for f in a:
+        for f in added:
             print ":000000 100664 %s %s N\t%s\t%s" % (empty, hg.hex(mmap2[f]), f, f)
-        for f in d:
+        for f in removed:
             print ":100664 000000 %s %s D\t%s\t%s" % (hg.hex(mmap[f]), empty, f, f)
     ##
 
--- a/contrib/patchbomb	Thu Dec 15 18:04:39 2005 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,270 +0,0 @@
-#!/usr/bin/python
-#
-# Interactive script for sending a collection of Mercurial changesets
-# as a series of patch emails.
-#
-# The series is started off with a "[PATCH 0 of N]" introduction,
-# which describes the series as a whole.
-#
-# Each patch email has a Subject line of "[PATCH M of N] ...", using
-# the first line of the changeset description as the subject text.
-# The message contains two or three body parts:
-#
-#   The remainder of the changeset description.
-#
-#   [Optional] If the diffstat program is installed, the result of
-#   running diffstat on the patch.
-#
-#   The patch itself, as generated by "hg export".
-#
-# Each message refers to all of its predecessors using the In-Reply-To
-# and References headers, so they will show up as a sequence in
-# threaded mail and news readers, and in mail archives.
-#
-# For each changeset, you will be prompted with a diffstat summary and
-# the changeset summary, so you can be sure you are sending the right
-# changes.
-#
-# It is best to run this script with the "-n" (test only) flag before
-# firing it up "for real", in which case it will use your pager to
-# display each of the messages that it would send.
-#
-# To configure a default mail host, add a section like this to your
-# hgrc file:
-#
-# [smtp]
-# host = my_mail_host
-# port = 1025
-# tls = yes # or omit if not needed
-# username = user     # if SMTP authentication required
-# password = password # if SMTP authentication required - PLAINTEXT
-#
-# To configure other defaults, add a section like this to your hgrc
-# file:
-#
-# [patchbomb]
-# from = My Name <my@email>
-# to = recipient1, recipient2, ...
-# cc = cc1, cc2, ...
-
-from email.MIMEMultipart import MIMEMultipart
-from email.MIMEText import MIMEText
-from mercurial import commands
-from mercurial import fancyopts
-from mercurial import hg
-from mercurial import ui
-import os
-import popen2
-import smtplib
-import socket
-import sys
-import tempfile
-import time
-
-try:
-    # readline gives raw_input editing capabilities, but is not
-    # present on windows
-    import readline
-except ImportError: pass
-
-def diffstat(patch):
-    fd, name = tempfile.mkstemp()
-    try:
-        p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
-        try:
-            for line in patch: print >> p.tochild, line
-            p.tochild.close()
-            if p.wait(): return
-            fp = os.fdopen(fd, 'r')
-            stat = []
-            for line in fp: stat.append(line.lstrip())
-            last = stat.pop()
-            stat.insert(0, last)
-            stat = ''.join(stat)
-            if stat.startswith('0 files'): raise ValueError
-            return stat
-        except: raise
-    finally:
-        try: os.unlink(name)
-        except: pass
-
-def patchbomb(ui, repo, *revs, **opts):
-    def prompt(prompt, default = None, rest = ': ', empty_ok = False):
-        if default: prompt += ' [%s]' % default
-        prompt += rest
-        while True:
-            r = raw_input(prompt)
-            if r: return r
-            if default is not None: return default
-            if empty_ok: return r
-            ui.warn('Please enter a valid value.\n')
-
-    def confirm(s):
-        if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'):
-            raise ValueError
-
-    def cdiffstat(summary, patch):
-        s = diffstat(patch)
-        if s:
-            if summary:
-                ui.write(summary, '\n')
-                ui.write(s, '\n')
-            confirm('Does the diffstat above look okay')
-        return s
-
-    def makepatch(patch, idx, total):
-        desc = []
-        node = None
-        body = ''
-        for line in patch:
-            if line.startswith('#'):
-                if line.startswith('# Node ID'): node = line.split()[-1]
-                continue
-            if line.startswith('diff -r'): break
-            desc.append(line)
-        if not node: raise ValueError
-
-        #body = ('\n'.join(desc[1:]).strip() or
-        #        'Patch subject is complete summary.')
-        #body += '\n\n\n'
-
-        if opts['diffstat']:
-            body += cdiffstat('\n'.join(desc), patch) + '\n\n'
-        body += '\n'.join(patch)
-        msg = MIMEText(body)
-        subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
-        if subj.endswith('.'): subj = subj[:-1]
-        msg['Subject'] = subj
-        msg['X-Mercurial-Node'] = node
-        return msg
-
-    start_time = int(time.time())
-
-    def genmsgid(id):
-        return '<%s.%s@%s>' % (id[:20], start_time, socket.getfqdn())
-
-    patches = []
-
-    class exportee:
-        def __init__(self, container):
-            self.lines = []
-            self.container = container
-            self.name = 'email'
-
-        def write(self, data):
-            self.lines.append(data)
-
-        def close(self):
-            self.container.append(''.join(self.lines).split('\n'))
-            self.lines = []
-
-    commands.export(ui, repo, *args, **{'output': exportee(patches),
-                                        'text': None})
-
-    jumbo = []
-    msgs = []
-
-    ui.write('This patch series consists of %d patches.\n\n' % len(patches))
-
-    for p, i in zip(patches, range(len(patches))):
-        jumbo.extend(p)
-        msgs.append(makepatch(p, i + 1, len(patches)))
-
-    ui.write('\nWrite the introductory message for the patch series.\n\n')
-
-    sender = (opts['from'] or ui.config('patchbomb', 'from') or
-              prompt('From', ui.username()))
-
-    msg = MIMEMultipart()
-    msg['Subject'] = '[PATCH 0 of %d] %s' % (
-        len(patches),
-        opts['subject'] or
-        prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
-
-    def getaddrs(opt, prpt, default = None):
-        addrs = opts[opt] or (ui.config('patchbomb', opt) or
-                              prompt(prpt, default = default)).split(',')
-        return [a.strip() for a in addrs if a.strip()]
-    to = getaddrs('to', 'To')
-    cc = getaddrs('cc', 'Cc', '')
-
-    ui.write('Finish with ^D or a dot on a line by itself.\n\n')
-
-    body = []
-
-    while True:
-        try: l = raw_input()
-        except EOFError: break
-        if l == '.': break
-        body.append(l)
-
-    msg.attach(MIMEText('\n'.join(body) + '\n'))
-
-    ui.write('\n')
-
-    if opts['diffstat']:
-        d = cdiffstat('Final summary:\n', jumbo)
-        if d: msg.attach(MIMEText(d))
-
-    msgs.insert(0, msg)
-
-    if not opts['test']:
-        s = smtplib.SMTP()
-        s.connect(host = ui.config('smtp', 'host', 'mail'),
-                  port = int(ui.config('smtp', 'port', 25)))
-        if ui.configbool('smtp', 'tls'):
-            s.ehlo()
-            s.starttls()
-            s.ehlo()
-        username = ui.config('smtp', 'username')
-        password = ui.config('smtp', 'password')
-        if username and password:
-            s.login(username, password)
-    parent = None
-    tz = time.strftime('%z')
-    for m in msgs:
-        try:
-            m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
-        except TypeError:
-            m['Message-Id'] = genmsgid('patchbomb')
-        if parent:
-            m['In-Reply-To'] = parent
-        else:
-            parent = m['Message-Id']
-        m['Date'] = time.strftime('%a, %e %b %Y %T ', time.localtime(start_time)) + tz
-        start_time += 1
-        m['From'] = sender
-        m['To'] = ', '.join(to)
-        if cc: m['Cc'] = ', '.join(cc)
-        ui.status('Sending ', m['Subject'], ' ...\n')
-        if opts['test']:
-            fp = os.popen(os.getenv('PAGER', 'more'), 'w')
-            fp.write(m.as_string(0))
-            fp.write('\n')
-            fp.close()
-        else:
-            s.sendmail(sender, to + cc, m.as_string(0))
-    if not opts['test']:
-        s.close()
-
-if __name__ == '__main__':
-    optspec = [('c', 'cc', [], 'email addresses of copy recipients'),
-               ('d', 'diffstat', None, 'add diffstat output to messages'),
-               ('f', 'from', '', 'email address of sender'),
-               ('n', 'test', None, 'print messages that would be sent'),
-               ('s', 'subject', '', 'subject of introductory message'),
-               ('t', 'to', [], 'email addresses of recipients')]
-    options = {}
-    try:
-        args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts + optspec,
-                                   options)
-    except fancyopts.getopt.GetoptError, inst:
-        u = ui.ui()
-        u.warn('error: %s' % inst)
-        sys.exit(1)
-
-    u = ui.ui(options["verbose"], options["debug"], options["quiet"],
-              not options["noninteractive"])
-    repo = hg.repository(ui = u)
-
-    patchbomb(u, repo, *args, **options)
--- a/doc/hg.1.txt	Thu Dec 15 18:04:39 2005 +0100
+++ b/doc/hg.1.txt	Wed Feb 01 19:18:15 2006 +0100
@@ -155,6 +155,8 @@
     errors.  In these cases, use the --pull option to avoid
     hardlinking.
 
+    See pull for valid source format details.
+
     options:
     -U, --noupdate   do not update the new working directory
     --pull           use pull protocol to copy metadata
@@ -388,6 +390,8 @@
     default push repo. These are the changesets that would be pushed
     if a push was requested.
 
+    See pull for valid source format details.
+
     options:
     -p, --patch           show patch
 
@@ -454,11 +458,14 @@
     --remotecmd  specify hg command to run on the remote side
 
 rawcommit [-p -d -u -F -m -l]::
-    Lowlevel commit, for use in helper scripts.
+    Lowlevel commit, for use in helper scripts. (DEPRECATED)
 
     This command is not intended to be used by normal users, as it is
     primarily useful for importing from other SCMs.
 
+    This command is now deprecated and will be removed in a future
+    release, please use debugsetparents and commit instead.
+
 recover::
     Recover from an interrupted commit or pull.
 
@@ -497,9 +504,18 @@
     aliases: mv
 
 revert [names ...]::
-    Revert any uncommitted modifications made to the named files or
-    directories.  This restores the contents of the affected files to
-    an unmodified state.
+    The revert command has two modes of operation.
+
+    In its default mode, it reverts any uncommitted modifications made
+    to the named files or directories.  This restores the contents of
+    the affected files to an unmodified state.
+
+    Using the -r option, it reverts the given files or directories to
+    their state as of an earlier revision.  This can be helpful to "roll
+    back" some or all of a change that should not have been committed.
+
+    Revert modifies the working directory.  It does not commit any
+    changes, or change the parent of the current working directory.
 
     If a file has been deleted, it is recreated.  If the executable
     mode of a file was changed, it is reset.
--- a/hgeditor	Thu Dec 15 18:04:39 2005 +0100
+++ b/hgeditor	Wed Feb 01 19:18:15 2006 +0100
@@ -1,10 +1,7 @@
 #!/bin/sh
 #
-# This is an example of using HGEDITOR to automate the signing of
-# commits and so on.
-
-# change this to one to turn on GPG support
-SIGN=0
+# This is an example of using HGEDITOR to create of diff to review the
+# changes while commiting.
 
 # If you want to pass your favourite editor some other parameters
 # only for Mercurial, modify this:
@@ -43,12 +40,7 @@
     done
 )
 
-echo > "$HGTMP/msg"
-if [ "$SIGN" == "1" ]; then
-    MANIFEST=`grep '^HG: manifest hash' "$1" | cut -b 19-`
-    echo -e "\nmanifest hash: $MANIFEST" >> "$HGTMP/msg"
-fi
-grep -vE '^(HG: manifest hash .*)?$' "$1" >> "$HGTMP/msg"
+cat "$1" > "$HGTMP/msg"
 
 CHECKSUM=`md5sum "$HGTMP/msg"`
 if [ -s "$HGTMP/diff" ]; then
@@ -58,14 +50,6 @@
 fi
 echo "$CHECKSUM" | md5sum -c >/dev/null 2>&1 && exit 13
 
-if [ "$SIGN" == "1" ]; then
-    {
-        head -n 1 "$HGTMP/msg"
-        echo
-        grep -v "^HG:" "$HGTMP/msg" | gpg -t -a -u "${HGUSER}" --clearsign
-    } > "$HGTMP/msg.gpg" && mv "$HGTMP/msg.gpg" "$1"
-else
-    mv "$HGTMP/msg" "$1"
-fi
+mv "$HGTMP/msg" "$1"
 
 exit $?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/gpg.py	Wed Feb 01 19:18:15 2006 +0100
@@ -0,0 +1,206 @@
+import os, tempfile, binascii, errno
+from mercurial import util
+from mercurial import node as hgnode
+
+class gpg:
+    def __init__(self, path, key=None):
+        self.path = path
+        self.key = (key and " --local-user \"%s\"" % key) or ""
+
+    def sign(self, data):
+        gpgcmd = "%s --sign --detach-sign%s" % (self.path, self.key)
+        return util.filter(data, gpgcmd)
+
+    def verify(self, data, sig):
+        """ returns of the good and bad signatures"""
+        try:
+            fd, sigfile = tempfile.mkstemp(prefix="hggpgsig")
+            fp = os.fdopen(fd, 'wb')
+            fp.write(sig)
+            fp.close()
+            fd, datafile = tempfile.mkstemp(prefix="hggpgdata")
+            fp = os.fdopen(fd, 'wb')
+            fp.write(data)
+            fp.close()
+            gpgcmd = "%s --logger-fd 1 --status-fd 1 --verify \"%s\" \"%s\"" % (self.path, sigfile, datafile)
+            #gpgcmd = "%s --status-fd 1 --verify \"%s\" \"%s\"" % (self.path, sigfile, datafile)
+            ret = util.filter("", gpgcmd)
+        except:
+            for f in (sigfile, datafile):
+                try:
+                    if f: os.unlink(f)
+                except: pass
+            raise
+        keys = []
+        key, fingerprint = None, None
+        err = ""
+        for l in ret.splitlines():
+            # see DETAILS in the gnupg documentation
+            # filter the logger output
+            if not l.startswith("[GNUPG:]"):
+                continue
+            l = l[9:]
+            if l.startswith("ERRSIG"):
+                err = "error while verifying signature"
+                break
+            elif l.startswith("VALIDSIG"):
+                # fingerprint of the primary key
+                fingerprint = l.split()[10]
+            elif (l.startswith("GOODSIG") or
+                  l.startswith("EXPSIG") or
+                  l.startswith("EXPKEYSIG") or
+                  l.startswith("BADSIG")):
+                if key is not None:
+                    keys.append(key + [fingerprint])
+                key = l.split(" ", 2)
+                fingerprint = None
+        if err:
+            return err, []
+        if key is not None:
+            keys.append(key + [fingerprint])
+        return err, keys
+
+def newgpg(ui, **opts):
+    gpgpath = ui.config("gpg", "cmd", "gpg")
+    gpgkey = opts.get('key')
+    if not gpgkey:
+        gpgkey = ui.config("gpg", "key", None)
+    return gpg(gpgpath, gpgkey)
+
+def check(ui, repo, rev):
+    """verify all the signatures there may be for a particular revision"""
+    mygpg = newgpg(ui)
+    rev = repo.lookup(rev)
+    hexrev = hgnode.hex(rev)
+    keys = []
+
+    def addsig(fn, ln, l):
+        if not l: return
+        n, v, sig = l.split(" ", 2)
+        if n == hexrev:
+            data = node2txt(repo, rev, v)
+            sig = binascii.a2b_base64(sig)
+            err, k = mygpg.verify(data, sig)
+            if not err:
+                keys.append((k, fn, ln))
+            else:
+                ui.warn("%s:%d %s\n" % (fn, ln , err))
+
+    fl = repo.file(".hgsigs")
+    h = fl.heads()
+    h.reverse()
+    # read the heads
+    for r in h:
+        ln = 1
+        for l in fl.read(r).splitlines():
+            addsig(".hgsigs|%s" % hgnode.short(r), ln, l)
+            ln +=1
+    try:
+        # read local signatures
+        ln = 1
+        f = repo.opener("localsigs")
+        for l in f:
+            addsig("localsigs", ln, l)
+            ln +=1
+    except IOError:
+        pass
+
+    if not keys:
+        ui.write("%s not signed\n" % hgnode.short(rev))
+        return
+    valid = []
+    # warn for expired key and/or sigs
+    for k, fn, ln in keys:
+        prefix = "%s:%d" % (fn, ln)
+        for key in k:
+            if key[0] == "BADSIG":
+                ui.write("%s Bad signature from \"%s\"\n" % (prefix, key[2]))
+                continue
+            if key[0] == "EXPSIG":
+                ui.write("%s Note: Signature has expired"
+                         " (signed by: \"%s\")\n" % (prefix, key[2]))
+            elif key[0] == "EXPKEYSIG":
+                ui.write("%s Note: This key has expired"
+                         " (signed by: \"%s\")\n" % (prefix, key[2]))
+            valid.append((key[1], key[2], key[3]))
+    # print summary
+    ui.write("%s is signed by:\n" % hgnode.short(rev))
+    for keyid, user, fingerprint in valid:
+        role = getrole(ui, fingerprint)
+        ui.write("  %s (%s)\n" % (user, role))
+
+def getrole(ui, fingerprint):
+    return ui.config("gpg", fingerprint, "no role defined")
+
+def sign(ui, repo, *revs, **opts):
+    """add a signature for the current tip or a given revision"""
+    mygpg = newgpg(ui, **opts)
+    sigver = "0"
+    sigmessage = ""
+    if revs:
+        nodes = [repo.lookup(n) for n in revs]
+    else:
+        nodes = [repo.changelog.tip()]
+
+    for n in nodes:
+        hexnode = hgnode.hex(n)
+        ui.write("Signing %d:%s\n" % (repo.changelog.rev(n),
+                                      hgnode.short(n)))
+        # build data
+        data = node2txt(repo, n, sigver)
+        sig = mygpg.sign(data)
+        if not sig:
+            raise util.Abort("Error while signing")
+        sig = binascii.b2a_base64(sig)
+        sig = sig.replace("\n", "")
+        sigmessage += "%s %s %s\n" % (hexnode, sigver, sig)
+
+    # write it
+    if opts['local']:
+        repo.opener("localsigs", "ab").write(sigmessage)
+        return
+
+    for x in repo.changes():
+        if ".hgsigs" in x and not opts["force"]:
+            raise util.Abort("working copy of .hgsigs is changed "
+                             "(please commit .hgsigs manually "
+                             "or use --force)")
+
+    repo.wfile(".hgsigs", "ab").write(sigmessage)
+
+    if repo.dirstate.state(".hgsigs") == '?':
+        repo.add([".hgsigs"])
+
+    if opts["no_commit"]:
+        return
+
+    message = opts['message']
+    if not message:
+        message = "\n".join(["Added signature for changeset %s" % hgnode.hex(n)
+                             for n in nodes])
+    try:
+        repo.commit([".hgsigs"], message, opts['user'], opts['date'])
+    except ValueError, inst:
+        raise util.Abort(str(inst))
+
+def node2txt(repo, node, ver):
+    """map a manifest into some text"""
+    if ver == "0":
+        return "%s\n" % hgnode.hex(node)
+    else:
+        util.Abort("unknown signature version")
+
+cmdtable = {
+    "sign":
+        (sign,
+         [('l', 'local', None, "make the signature local"),
+          ('f', 'force', None, "sign even if the sigfile is modified"),
+          ('', 'no-commit', None, "do not commit the sigfile after signing"),
+          ('m', 'message', "", "commit message"),
+          ('d', 'date', "", "date code"),
+          ('u', 'user', "", "user"),
+          ('k', 'key', "", "the key id to sign with")],
+         "hg sign [OPTION]... REVISIONS"),
+    "sigcheck": (check, [], 'hg sigcheck REVISION')
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/patchbomb.py	Wed Feb 01 19:18:15 2006 +0100
@@ -0,0 +1,275 @@
+# Command for sending a collection of Mercurial changesets as a series
+# of patch emails.
+#
+# The series is started off with a "[PATCH 0 of N]" introduction,
+# which describes the series as a whole.
+#
+# Each patch email has a Subject line of "[PATCH M of N] ...", using
+# the first line of the changeset description as the subject text.
+# The message contains two or three body parts:
+#
+#   The remainder of the changeset description.
+#
+#   [Optional] If the diffstat program is installed, the result of
+#   running diffstat on the patch.
+#
+#   The patch itself, as generated by "hg export".
+#
+# Each message refers to all of its predecessors using the In-Reply-To
+# and References headers, so they will show up as a sequence in
+# threaded mail and news readers, and in mail archives.
+#
+# For each changeset, you will be prompted with a diffstat summary and
+# the changeset summary, so you can be sure you are sending the right
+# changes.
+#
+# It is best to run this script with the "-n" (test only) flag before
+# firing it up "for real", in which case it will use your pager to
+# display each of the messages that it would send.
+#
+# To configure a default mail host, add a section like this to your
+# hgrc file:
+#
+# [smtp]
+# host = my_mail_host
+# port = 1025
+# tls = yes # or omit if not needed
+# username = user     # if SMTP authentication required
+# password = password # if SMTP authentication required - PLAINTEXT
+#
+# To configure other defaults, add a section like this to your hgrc
+# file:
+#
+# [patchbomb]
+# from = My Name <my@email>
+# to = recipient1, recipient2, ...
+# cc = cc1, cc2, ...
+
+from email.MIMEMultipart import MIMEMultipart
+from email.MIMEText import MIMEText
+from mercurial import commands
+from mercurial import hg
+from mercurial import ui
+from mercurial.i18n import gettext as _
+import os
+import popen2
+import smtplib
+import socket
+import sys
+import tempfile
+import time
+
+try:
+    # readline gives raw_input editing capabilities, but is not
+    # present on windows
+    import readline
+except ImportError: pass
+
+def diffstat(patch):
+    fd, name = tempfile.mkstemp()
+    try:
+        p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
+        try:
+            for line in patch: print >> p.tochild, line
+            p.tochild.close()
+            if p.wait(): return
+            fp = os.fdopen(fd, 'r')
+            stat = []
+            for line in fp: stat.append(line.lstrip())
+            last = stat.pop()
+            stat.insert(0, last)
+            stat = ''.join(stat)
+            if stat.startswith('0 files'): raise ValueError
+            return stat
+        except: raise
+    finally:
+        try: os.unlink(name)
+        except: pass
+
+def patchbomb(ui, repo, *revs, **opts):
+    '''send changesets as a series of patch emails
+
+    The series starts with a "[PATCH 0 of N]" introduction, which
+    describes the series as a whole.
+
+    Each patch email has a Subject line of "[PATCH M of N] ...", using
+    the first line of the changeset description as the subject text.
+    The message contains two or three body parts.  First, the rest of
+    the changeset description.  Next, (optionally) if the diffstat
+    program is installed, the result of running diffstat on the patch.
+    Finally, the patch itself, as generated by "hg export".'''
+    def prompt(prompt, default = None, rest = ': ', empty_ok = False):
+        if default: prompt += ' [%s]' % default
+        prompt += rest
+        while True:
+            r = raw_input(prompt)
+            if r: return r
+            if default is not None: return default
+            if empty_ok: return r
+            ui.warn(_('Please enter a valid value.\n'))
+
+    def confirm(s):
+        if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'):
+            raise ValueError
+
+    def cdiffstat(summary, patch):
+        s = diffstat(patch)
+        if s:
+            if summary:
+                ui.write(summary, '\n')
+                ui.write(s, '\n')
+            confirm(_('Does the diffstat above look okay'))
+        return s
+
+    def makepatch(patch, idx, total):
+        desc = []
+        node = None
+        body = ''
+        for line in patch:
+            if line.startswith('#'):
+                if line.startswith('# Node ID'): node = line.split()[-1]
+                continue
+            if line.startswith('diff -r'): break
+            desc.append(line)
+        if not node: raise ValueError
+
+        #body = ('\n'.join(desc[1:]).strip() or
+        #        'Patch subject is complete summary.')
+        #body += '\n\n\n'
+
+        if opts['plain']:
+            while patch and patch[0].startswith('# '): patch.pop(0)
+            if patch: patch.pop(0)
+            while patch and not patch[0].strip(): patch.pop(0)
+        if opts['diffstat']:
+            body += cdiffstat('\n'.join(desc), patch) + '\n\n'
+        body += '\n'.join(patch)
+        msg = MIMEText(body)
+        subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
+        if subj.endswith('.'): subj = subj[:-1]
+        msg['Subject'] = subj
+        msg['X-Mercurial-Node'] = node
+        return msg
+
+    start_time = int(time.time())
+
+    def genmsgid(id):
+        return '<%s.%s@%s>' % (id[:20], start_time, socket.getfqdn())
+
+    patches = []
+
+    class exportee:
+        def __init__(self, container):
+            self.lines = []
+            self.container = container
+            self.name = 'email'
+
+        def write(self, data):
+            self.lines.append(data)
+
+        def close(self):
+            self.container.append(''.join(self.lines).split('\n'))
+            self.lines = []
+
+    commands.export(ui, repo, *revs, **{'output': exportee(patches),
+                                        'switch_parent': False,
+                                        'text': None})
+
+    jumbo = []
+    msgs = []
+
+    ui.write(_('This patch series consists of %d patches.\n\n') % len(patches))
+
+    for p, i in zip(patches, range(len(patches))):
+        jumbo.extend(p)
+        msgs.append(makepatch(p, i + 1, len(patches)))
+
+    ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
+
+    sender = (opts['from'] or ui.config('patchbomb', 'from') or
+              prompt('From', ui.username()))
+
+    msg = MIMEMultipart()
+    msg['Subject'] = '[PATCH 0 of %d] %s' % (
+        len(patches),
+        opts['subject'] or
+        prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
+
+    def getaddrs(opt, prpt, default = None):
+        addrs = opts[opt] or (ui.config('patchbomb', opt) or
+                              prompt(prpt, default = default)).split(',')
+        return [a.strip() for a in addrs if a.strip()]
+    to = getaddrs('to', 'To')
+    cc = getaddrs('cc', 'Cc', '')
+
+    ui.write(_('Finish with ^D or a dot on a line by itself.\n\n'))
+
+    body = []
+
+    while True:
+        try: l = raw_input()
+        except EOFError: break
+        if l == '.': break
+        body.append(l)
+
+    msg.attach(MIMEText('\n'.join(body) + '\n'))
+
+    ui.write('\n')
+
+    if opts['diffstat']:
+        d = cdiffstat(_('Final summary:\n'), jumbo)
+        if d: msg.attach(MIMEText(d))
+
+    msgs.insert(0, msg)
+
+    if not opts['test']:
+        s = smtplib.SMTP()
+        s.connect(host = ui.config('smtp', 'host', 'mail'),
+                  port = int(ui.config('smtp', 'port', 25)))
+        if ui.configbool('smtp', 'tls'):
+            s.ehlo()
+            s.starttls()
+            s.ehlo()
+        username = ui.config('smtp', 'username')
+        password = ui.config('smtp', 'password')
+        if username and password:
+            s.login(username, password)
+    parent = None
+    tz = time.strftime('%z')
+    for m in msgs:
+        try:
+            m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
+        except TypeError:
+            m['Message-Id'] = genmsgid('patchbomb')
+        if parent:
+            m['In-Reply-To'] = parent
+        else:
+            parent = m['Message-Id']
+        m['Date'] = time.strftime('%a, %e %b %Y %T ', time.localtime(start_time)) + tz
+        start_time += 1
+        m['From'] = sender
+        m['To'] = ', '.join(to)
+        if cc: m['Cc'] = ', '.join(cc)
+        ui.status('Sending ', m['Subject'], ' ...\n')
+        if opts['test']:
+            fp = os.popen(os.getenv('PAGER', 'more'), 'w')
+            fp.write(m.as_string(0))
+            fp.write('\n')
+            fp.close()
+        else:
+            s.sendmail(sender, to + cc, m.as_string(0))
+    if not opts['test']:
+        s.close()
+
+cmdtable = {
+    'email':
+    (patchbomb,
+     [('c', 'cc', [], 'email addresses of copy recipients'),
+      ('d', 'diffstat', None, 'add diffstat output to messages'),
+      ('f', 'from', '', 'email address of sender'),
+      ('', 'plain', None, 'omit hg patch header'),
+      ('n', 'test', None, 'print messages that would be sent'),
+      ('s', 'subject', '', 'subject of introductory message'),
+      ('t', 'to', [], 'email addresses of recipients')],
+     "hg email [OPTION]... [REV]...")
+    }
--- a/hgmerge	Thu Dec 15 18:04:39 2005 +0100
+++ b/hgmerge	Wed Feb 01 19:18:15 2006 +0100
@@ -44,6 +44,39 @@
     cp "$LOCAL.orig" "$LOCAL"
 fi
 
+# on MacOS X try FileMerge.app, shipped with Apple's developer tools
+# TODO: make proper temp files. foo.orig and foo.link are dangerous
+FILEMERGE='/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge'
+if type "$FILEMERGE" > /dev/null 2>&1; then
+    cp "$LOCAL.orig" "$LOCAL"
+    ln "$LOCAL" "$LOCAL.link"
+    # filemerge prefers the right by default
+    if ! "$FILEMERGE" -left "$OTHER" -right "$LOCAL" -ancestor "$BASE" -merge "$LOCAL"
+    then
+        echo "FileMerge failed to launch"
+        exit 1
+    fi
+    if ! test "$LOCAL" -ef "$LOCAL.link"
+    then
+        rm "$LOCAL.orig" "$LOCAL.link"
+        exit 0
+    else
+        rm "$LOCAL.link"
+        echo "$LOCAL is unchanged. Was the merge successful?"
+        select answer in yes no
+        do
+            if test "$answer" == "yes"
+            then
+                rm "$LOCAL.orig"
+                exit 0
+            else
+                exit 1
+            fi
+        done
+        exit 1
+    fi
+fi
+
 if [ -n "$DISPLAY" ]; then
     # try using kdiff3, which is fairly nice
     if type kdiff3 > /dev/null 2>&1; then
--- a/mercurial/commands.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/commands.py	Wed Feb 01 19:18:15 2006 +0100
@@ -40,14 +40,14 @@
         opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
         cwd = ''
     return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
-                        opts.get('exclude'), head) + (cwd,)
+                           opts.get('exclude'), head)
 
 def makewalk(repo, pats, opts, node=None, head=''):
-    files, matchfn, anypats, cwd = matchpats(repo, pats, opts, head)
+    files, matchfn, anypats = matchpats(repo, pats, opts, head)
     exact = dict(zip(files, files))
     def walk():
         for src, fn in repo.walk(node=node, files=files, match=matchfn):
-            yield src, fn, util.pathto(cwd, fn), fn in exact
+            yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
     return files, matchfn, walk()
 
 def walk(repo, pats, opts, node=None, head=''):
@@ -82,7 +82,7 @@
     "iter", rev, None: in-order traversal of the revs earlier iterated
     over with "add" - use to display data'''
 
-    files, matchfn, anypats, cwd = matchpats(repo, pats, opts)
+    files, matchfn, anypats = matchpats(repo, pats, opts)
 
     if repo.changelog.count() == 0:
         return [], False, matchfn
@@ -170,8 +170,10 @@
             num = int(val)
             if str(num) != val:
                 raise ValueError
-            if num < 0: num += revcount
-            if num < 0: num = 0
+            if num < 0:
+                num += revcount
+            if num < 0:
+                num = 0
             elif num >= revcount:
                 raise ValueError
         except ValueError:
@@ -191,12 +193,14 @@
             end = fix(end, revcount - 1)
             step = start > end and -1 or 1
             for rev in xrange(start, end+step, step):
-                if rev in seen: continue
+                if rev in seen:
+                    continue
                 seen[rev] = 1
                 yield str(rev)
         else:
             rev = fix(spec, None)
-            if rev in seen: continue
+            if rev in seen:
+                continue
             seen[rev] = 1
             yield str(rev)
 
@@ -259,13 +263,13 @@
 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
            changes=None, text=False):
     if not changes:
-        (c, a, d, u) = repo.changes(node1, node2, files, match=match)
-    else:
-        (c, a, d, u) = changes
+        changes = repo.changes(node1, node2, files, match=match)
+    modified, added, removed, deleted, unknown = changes
     if files:
-        c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
-
-    if not c and not a and not d:
+        modified, added, removed = map(lambda x: filterfiles(files, x),
+                                       (modified, added, removed))
+
+    if not modified and not added and not removed:
         return
 
     if node2:
@@ -279,7 +283,7 @@
         if not node1:
             node1 = repo.dirstate.parents()[0]
         def read(f):
-            return repo.wfile(f).read()
+            return repo.wread(f)
 
     if ui.quiet:
         r = None
@@ -291,20 +295,26 @@
     mmap = repo.manifest.read(change[0])
     date1 = util.datestr(change[2])
 
-    for f in c:
+    diffopts = ui.diffopts()
+    showfunc = diffopts['showfunc']
+    ignorews = diffopts['ignorews']
+    for f in modified:
         to = None
         if f in mmap:
             to = repo.file(f).read(mmap[f])
         tn = read(f)
-        fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
-    for f in a:
+        fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text,
+                               showfunc=showfunc, ignorews=ignorews))
+    for f in added:
         to = None
         tn = read(f)
-        fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
-    for f in d:
+        fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text,
+                               showfunc=showfunc, ignorews=ignorews))
+    for f in removed:
         to = repo.file(f).read(mmap[f])
         tn = None
-        fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
+        fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text,
+                               showfunc=showfunc, ignorews=ignorews))
 
 def trimuser(ui, name, rev, revcache):
     """trim the name of the user who committed a change"""
@@ -439,7 +449,7 @@
             if e[0].__doc__:
                 d = e[0].__doc__.splitlines(0)[0].rstrip()
             h[f] = d
-            cmds[f]=c.lstrip("^")
+            cmds[f] = c.lstrip("^")
 
         fns = h.keys()
         fns.sort()
@@ -447,7 +457,7 @@
         for f in fns:
             if ui.verbose:
                 commands = cmds[f].replace("|",", ")
-                ui.write(" %s:\n      %s\n"%(commands,h[f]))
+                ui.write(" %s:\n      %s\n"%(commands, h[f]))
             else:
                 ui.write(' %-*s   %s\n' % (m, f, h[f]))
 
@@ -463,7 +473,8 @@
             opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
                                           longopt and " --%s" % longopt),
                                "%s%s" % (desc,
-                                         default and _(" (default: %s)") % default
+                                         default
+                                         and _(" (default: %s)") % default
                                          or "")))
 
     if opt_output:
@@ -489,7 +500,8 @@
     names = []
     for src, abs, rel, exact in walk(repo, pats, opts):
         if exact:
-            if ui.verbose: ui.status(_('adding %s\n') % rel)
+            if ui.verbose:
+                ui.status(_('adding %s\n') % rel)
             names.append(abs)
         elif repo.dirstate.state(abs) == '?':
             ui.status(_('adding %s\n') % rel)
@@ -509,11 +521,11 @@
         if src == 'f' and repo.dirstate.state(abs) == '?':
             add.append(abs)
             if ui.verbose or not exact:
-                ui.status(_('adding %s\n') % rel)
+                ui.status(_('adding %s\n') % ((pats and rel) or abs))
         if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
             remove.append(abs)
             if ui.verbose or not exact:
-                ui.status(_('removing %s\n') % rel)
+                ui.status(_('removing %s\n') % ((pats and rel) or abs))
     repo.add(add)
     repo.remove(remove)
 
@@ -539,11 +551,11 @@
 
     dcache = {}
     def getdate(rev):
-    	datestr = dcache.get(rev)
+        datestr = dcache.get(rev)
         if datestr is None:
             cl = repo.changelog.read(repo.changelog.node(rev))
             datestr = dcache[rev] = util.datestr(cl[2])
-	return datestr
+        return datestr
 
     if not pats:
         raise util.Abort(_('at least one file name or pattern required'))
@@ -562,12 +574,13 @@
 
     for src, abs, rel, exact in walk(repo, pats, opts):
         if abs not in mmap:
-            ui.warn(_("warning: %s is not in the repository!\n") % rel)
+            ui.warn(_("warning: %s is not in the repository!\n") %
+                    ((pats and rel) or abs))
             continue
 
         f = repo.file(abs)
         if not opts['text'] and util.binary(f.read(mmap[abs])):
-            ui.write(_("%s: binary file\n") % rel)
+            ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
             continue
 
         lines = f.annotate(mmap[abs])
@@ -722,7 +735,8 @@
             try:
                 util.copyfiles(src, dst)
             except OSError, inst:
-                if inst.errno != errno.ENOENT: raise
+                if inst.errno != errno.ENOENT:
+                    raise
 
         repo = hg.repository(ui, dest)
 
@@ -730,7 +744,8 @@
         revs = None
         if opts['rev']:
             if not other.local():
-                raise util.Abort("clone -r not supported yet for remote repositories.")
+                error = _("clone -r not supported yet for remote repositories.")
+                raise util.Abort(error)
             else:
                 revs = [other.lookup(rev) for rev in opts['rev']]
         repo = hg.repository(ui, dest, create=1)
@@ -775,10 +790,11 @@
 
     if opts['addremove']:
         addremove(ui, repo, *pats, **opts)
-    fns, match, anypats, cwd = matchpats(repo, pats, opts)
+    fns, match, anypats = matchpats(repo, pats, opts)
     if pats:
-        c, a, d, u = repo.changes(files=fns, match=match)
-        files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
+        modified, added, removed, deleted, unknown = (
+            repo.changes(files=fns, match=match))
+        files = modified + added + removed
     else:
         files = []
     try:
@@ -794,10 +810,12 @@
 
     def okaytocopy(abs, rel, exact):
         reasons = {'?': _('is not managed'),
-                   'a': _('has been marked for add')}
+                   'a': _('has been marked for add'),
+                   'r': _('has been marked for remove')}
         reason = reasons.get(repo.dirstate.state(abs))
         if reason:
-            if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
+            if exact:
+                ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
         else:
             return True
 
@@ -845,12 +863,11 @@
 
     def targetpathfn(pat, dest, srcs):
         if os.path.isdir(pat):
-            if pat.endswith(os.sep):
-                pat = pat[:-len(os.sep)]
+            abspfx = util.canonpath(repo.root, cwd, pat)
             if destdirexists:
-                striplen = len(os.path.split(pat)[0])
+                striplen = len(os.path.split(abspfx)[0])
             else:
-                striplen = len(pat)
+                striplen = len(abspfx)
             if striplen:
                 striplen += len(os.sep)
             res = lambda p: os.path.join(dest, p[striplen:])
@@ -864,34 +881,36 @@
         if util.patkind(pat, None)[0]:
             # a mercurial pattern
             res = lambda p: os.path.join(dest, os.path.basename(p))
-        elif len(util.canonpath(repo.root, cwd, pat)) < len(srcs[0][0]):
-            # A directory. Either the target path contains the last
-            # component of the source path or it does not.
-            def evalpath(striplen):
-                score = 0
-                for s in srcs:
-                    t = os.path.join(dest, s[1][striplen:])
-                    if os.path.exists(t):
-                        score += 1
-                return score
-
-            if pat.endswith(os.sep):
-                pat = pat[:-len(os.sep)]
-            striplen = len(pat) + len(os.sep)
-            if os.path.isdir(os.path.join(dest, os.path.split(pat)[1])):
-                score = evalpath(striplen)
-                striplen1 = len(os.path.split(pat)[0])
-                if striplen1:
-                    striplen1 += len(os.sep)
-                if evalpath(striplen1) > score:
-                    striplen = striplen1
-            res = lambda p: os.path.join(dest, p[striplen:])
         else:
-            # a file
-            if destdirexists:
-                res = lambda p: os.path.join(dest, os.path.basename(p))
+            abspfx = util.canonpath(repo.root, cwd, pat)
+            if len(abspfx) < len(srcs[0][0]):
+                # A directory. Either the target path contains the last
+                # component of the source path or it does not.
+                def evalpath(striplen):
+                    score = 0
+                    for s in srcs:
+                        t = os.path.join(dest, s[0][striplen:])
+                        if os.path.exists(t):
+                            score += 1
+                    return score
+
+                striplen = len(abspfx)
+                if striplen:
+                    striplen += len(os.sep)
+                if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
+                    score = evalpath(striplen)
+                    striplen1 = len(os.path.split(abspfx)[0])
+                    if striplen1:
+                        striplen1 += len(os.sep)
+                    if evalpath(striplen1) > score:
+                        striplen = striplen1
+                res = lambda p: os.path.join(dest, p[striplen:])
             else:
-                res = lambda p: dest
+                # a file
+                if destdirexists:
+                    res = lambda p: os.path.join(dest, os.path.basename(p))
+                else:
+                    res = lambda p: dest
         return res
 
 
@@ -923,7 +942,7 @@
 
     for targetpath, srcs in copylist:
         for abssrc, relsrc, exact in srcs:
-            copy(abssrc, relsrc, targetpath(relsrc), exact)
+            copy(abssrc, relsrc, targetpath(abssrc), exact)
 
     if errors:
         ui.warn(_('(consider using --after)\n'))
@@ -985,7 +1004,8 @@
             ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
             errors += 1
     if errors:
-        raise util.Abort(_(".hg/dirstate inconsistent with current parent's manifest"))
+        error = _(".hg/dirstate inconsistent with current parent's manifest")
+        raise util.Abort(error)
 
 def debugconfig(ui):
     """show combined config settings from all hgrc files"""
@@ -1111,7 +1131,7 @@
     if len(revs) > 2:
         raise util.Abort(_("too many revisions to diff"))
 
-    fns, matchfn, anypats, cwd = matchpats(repo, pats, opts)
+    fns, matchfn, anypats = matchpats(repo, pats, opts)
 
     dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
            text=opts['text'])
@@ -1119,11 +1139,11 @@
 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
     node = repo.lookup(changeset)
     parents = [p for p in repo.changelog.parents(node) if p != nullid]
+    if opts['switch_parent']:
+        parents.reverse()
     prev = (parents and parents[0]) or nullid
     change = repo.changelog.read(node)
 
-    if opts['switch_parent']:
-        parents.reverse()
     fp = make_file(repo, repo.changelog, opts['output'],
                    node=node, total=total, seqno=seqno,
                    revwidth=revwidth)
@@ -1176,7 +1196,8 @@
     revs = list(revrange(ui, repo, changesets))
     total = len(revs)
     revwidth = max(map(len, revs))
-    ui.note(len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n"))
+    msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
+    ui.note(msg)
     for cset in revs:
         seqno += 1
         doexport(ui, repo, cset, seqno, total, revwidth, opts)
@@ -1191,7 +1212,7 @@
         if repo.dirstate.state(abs) == 'a':
             forget.append(abs)
             if ui.verbose or not exact:
-                ui.status(_('forgetting %s\n') % rel)
+                ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
     repo.forget(forget)
 
 def grep(ui, repo, pattern, *pats, **opts):
@@ -1272,13 +1293,17 @@
                 change = ((l in states) and '-') or '+'
                 r = prev[fn]
             cols = [fn, str(rev)]
-            if opts['line_number']: cols.append(str(l.linenum))
-            if opts['all']: cols.append(change)
-            if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
+            if opts['line_number']:
+                cols.append(str(l.linenum))
+            if opts['all']:
+                cols.append(change)
+            if opts['user']:
+                cols.append(trimuser(ui, getchange(rev)[1], rev,
                                                   ucache))
             if opts['files_with_matches']:
                 c = (fn, rev)
-                if c in filerevmatches: continue
+                if c in filerevmatches:
+                    continue
                 filerevmatches[c] = 1
             else:
                 cols.append(l.line)
@@ -1300,7 +1325,8 @@
             mf = repo.manifest.read(change[0])
             matches[rev] = {}
             for fn in fns:
-                if fn in skip: continue
+                if fn in skip:
+                    continue
                 fstate.setdefault(fn, {})
                 try:
                     grepbody(fn, rev, getfile(fn).read(mf[fn]))
@@ -1310,7 +1336,8 @@
             states = matches[rev].items()
             states.sort()
             for fn, m in states:
-                if fn in skip: continue
+                if fn in skip:
+                    continue
                 if incrementing or not opts['all'] or fstate[fn]:
                     pos, neg = display(fn, rev, m, fstate[fn])
                     count += pos + neg
@@ -1323,7 +1350,8 @@
         fstate = fstate.items()
         fstate.sort()
         for fn, state in fstate:
-            if fn in skip: continue
+            if fn in skip:
+                continue
             display(fn, rev, {}, state)
     return (count == 0 and 1) or 0
 
@@ -1361,9 +1389,10 @@
         return
 
     hexfunc = ui.verbose and hex or short
-    (c, a, d, u) = repo.changes()
-    output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
-                        (c or a or d) and "+" or "")]
+    modified, added, removed, deleted, unknown = repo.changes()
+    output = ["%s%s" %
+              ('+'.join([hexfunc(parent) for parent in parents]),
+              (modified or added or removed or deleted) and "+" or "")]
 
     if not ui.quiet:
         # multiple tags for a single parent separated by '/'
@@ -1392,8 +1421,8 @@
     patches = (patch1,) + patches
 
     if not opts['force']:
-        (c, a, d, u) = repo.changes()
-        if c or a or d:
+        modified, added, removed, deleted, unknown = repo.changes()
+        if modified or added or removed or deleted:
             raise util.Abort(_("outstanding uncommitted changes"))
 
     d = opts["base"]
@@ -1418,7 +1447,8 @@
             line = line.rstrip()
             if (not message and not hgpatch and
                    mailre.match(line) and not opts['force']):
-                if len(line) > 35: line = line[:32] + '...'
+                if len(line) > 35:
+                    line = line[:32] + '...'
                 raise util.Abort(_('first line looks like a '
                                    'mail header: ') + line)
             if diffre.match(line):
@@ -1510,14 +1540,20 @@
     that contain white space as multiple filenames.
     """
     end = opts['print0'] and '\0' or '\n'
-
-    for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
-        if repo.dirstate.state(abs) == '?':
+    rev = opts['rev']
+    if rev:
+        node = repo.lookup(rev)
+    else:
+        node = None
+
+    for src, abs, rel, exact in walk(repo, pats, opts, node=node,
+                                     head='(?:.*/|)'):
+        if not node and repo.dirstate.state(abs) == '?':
             continue
         if opts['fullpath']:
             ui.write(os.path.join(repo.root, abs), end)
         else:
-            ui.write(rel, end)
+            ui.write(((pats and rel) or abs), end)
 
 def log(ui, repo, *pats, **opts):
     """show revision history of entire repository or files
@@ -1561,9 +1597,9 @@
             parents = [p for p in repo.changelog.parents(changenode)
                        if p != nullid]
             if opts['no_merges'] and len(parents) == 2:
-                 continue
+                continue
             if opts['only_merges'] and len(parents) != 2:
-                 continue
+                continue
 
             br = None
             if opts['keyword']:
@@ -1710,7 +1746,7 @@
     other = hg.repository(ui, source)
     revs = None
     if opts['rev'] and not other.local():
-        raise util.Abort("pull -r doesn't work for remote repositories yet")
+        raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
     elif opts['rev']:
         revs = [other.lookup(rev) for rev in opts['rev']]
     r = repo.pull(other, heads=revs)
@@ -1757,13 +1793,19 @@
     return r
 
 def rawcommit(ui, repo, *flist, **rc):
-    """raw commit interface
+    """raw commit interface (DEPRECATED)
 
     Lowlevel commit, for use in helper scripts.
 
     This command is not intended to be used by normal users, as it is
     primarily useful for importing from other SCMs.
+
+    This command is now deprecated and will be removed in a future
+    release, please use debugsetparents and commit instead.
     """
+
+    ui.warn(_("(the rawcommit command is deprecated)\n"))
+
     message = rc['message']
     if not message and rc['logfile']:
         try:
@@ -1808,18 +1850,23 @@
     """
     names = []
     def okaytoremove(abs, rel, exact):
-        c, a, d, u = repo.changes(files = [abs])
+        modified, added, removed, deleted, unknown = repo.changes(files=[abs])
         reason = None
-        if c: reason = _('is modified')
-        elif a: reason = _('has been marked for add')
-        elif u: reason = _('is not managed')
+        if modified:
+            reason = _('is modified')
+        elif added:
+            reason = _('has been marked for add')
+        elif unknown:
+            reason = _('is not managed')
         if reason:
-            if exact: ui.warn(_('not removing %s: file %s\n') % (rel, reason))
+            if exact:
+                ui.warn(_('not removing %s: file %s\n') % (rel, reason))
         else:
             return True
     for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
         if okaytoremove(abs, rel, exact):
-            if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
+            if ui.verbose or not exact:
+                ui.status(_('removing %s\n') % rel)
             names.append(abs)
     repo.remove(names, unlink=True)
 
@@ -1843,7 +1890,8 @@
     errs, copied = docopy(ui, repo, pats, opts)
     names = []
     for abs, rel, exact in copied:
-        if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
+        if ui.verbose or not exact:
+            ui.status(_('removing %s\n') % rel)
         names.append(abs)
     repo.remove(names, unlink=True)
     return errs
@@ -1865,10 +1913,10 @@
     node = opts['rev'] and repo.lookup(opts['rev']) or \
            repo.dirstate.parents()[0]
 
-    files, choose, anypats, cwd = matchpats(repo, pats, opts)
-    (c, a, d, u) = repo.changes(match=choose)
-    repo.forget(a)
-    repo.undelete(d)
+    files, choose, anypats = matchpats(repo, pats, opts)
+    modified, added, removed, deleted, unknown = repo.changes(match=choose)
+    repo.forget(added)
+    repo.undelete(removed + deleted)
 
     return repo.update(node, False, True, choose, False)
 
@@ -1968,7 +2016,7 @@
     try:
         httpd = hgweb.create_server(repo)
     except socket.error, inst:
-        raise util.Abort('cannot start server: ' + inst.args[1])
+        raise util.Abort(_('cannot start server: ') + inst.args[1])
 
     if ui.verbose:
         addr, port = httpd.socket.getsockname()
@@ -1995,17 +2043,21 @@
     M = modified
     A = added
     R = removed
+    ! = deleted, but still tracked
     ? = not tracked
     """
 
-    files, matchfn, anypats, cwd = matchpats(repo, pats, opts)
-    (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
-                    for n in repo.changes(files=files, match=matchfn)]
-
-    changetypes = [(_('modified'), 'M', c),
-                   (_('added'), 'A', a),
-                   (_('removed'), 'R', d),
-                   (_('unknown'), '?', u)]
+    files, matchfn, anypats = matchpats(repo, pats, opts)
+    cwd = (pats and repo.getcwd()) or ''
+    modified, added, removed, deleted, unknown = [
+        [util.pathto(cwd, x) for x in n]
+        for n in repo.changes(files=files, match=matchfn)]
+
+    changetypes = [(_('modified'), 'M', modified),
+                   (_('added'), 'A', added),
+                   (_('removed'), 'R', removed),
+                   (_('deleted'), '!', deleted),
+                   (_('unknown'), '?', unknown)]
 
     end = opts['print0'] and '\0' or '\n'
 
@@ -2019,7 +2071,7 @@
         for f in changes:
             ui.write(format % f)
 
-def tag(ui, repo, name, rev=None, **opts):
+def tag(ui, repo, name, rev_=None, **opts):
     """add a tag for the current tip or a given revision
 
     Name a particular revision using <name>.
@@ -2033,14 +2085,20 @@
     To facilitate version control, distribution, and merging of tags,
     they are stored as a file named ".hgtags" which is managed
     similarly to other project files and can be hand-edited if
-    necessary.
+    necessary.  The file '.hg/localtags' is used for local tags (not
+    shared among repositories).
     """
     if name == "tip":
         raise util.Abort(_("the name 'tip' is reserved"))
-    if 'rev' in opts:
-        rev = opts['rev']
-    if rev:
-        r = hex(repo.lookup(rev))
+    if rev_ is not None:
+        ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
+                  "please use 'hg tag [-r REV] NAME' instead\n"))
+        if opts['rev']:
+            raise util.Abort(_("use only one form to specify the revision"))
+    if opts['rev']:
+        rev_ = opts['rev']
+    if rev_:
+        r = hex(repo.lookup(rev_))
     else:
         r = hex(repo.changelog.tip())
 
@@ -2053,8 +2111,7 @@
         repo.opener("localtags", "a").write("%s %s\n" % (r, name))
         return
 
-    (c, a, d, u) = repo.changes()
-    for x in (c, a, d, u):
+    for x in repo.changes():
         if ".hgtags" in x:
             raise util.Abort(_("working copy of .hgtags is changed "
                                "(please commit .hgtags manually)"))
@@ -2095,7 +2152,7 @@
     n = repo.changelog.tip()
     show_changeset(ui, repo, changenode=n)
 
-def unbundle(ui, repo, fname):
+def unbundle(ui, repo, fname, **opts):
     """apply a changegroup file
 
     Apply a compressed changegroup file generated by the bundle
@@ -2112,7 +2169,13 @@
             yield zd.decompress(chunk)
 
     bzgen = bzgenerator(util.filechunkiter(f, 4096))
-    repo.addchangegroup(util.chunkbuffer(bzgen))
+    if repo.addchangegroup(util.chunkbuffer(bzgen)):
+        return 1
+
+    if opts['update']:
+        return update(ui, repo)
+    else:
+        ui.status(_("(run 'hg update' to get a working copy)\n"))
 
 def undo(ui, repo):
     """undo the last commit or pull
@@ -2188,12 +2251,12 @@
         (add,
          [('I', 'include', [], _('include names matching the given patterns')),
           ('X', 'exclude', [], _('exclude names matching the given patterns'))],
-         "hg add [OPTION]... [FILE]..."),
+         _('hg add [OPTION]... [FILE]...')),
     "addremove":
         (addremove,
          [('I', 'include', [], _('include names matching the given patterns')),
           ('X', 'exclude', [], _('exclude names matching the given patterns'))],
-         "hg addremove [OPTION]... [FILE]..."),
+         _('hg addremove [OPTION]... [FILE]...')),
     "^annotate":
         (annotate,
          [('r', 'rev', '', _('annotate the specified revision')),
@@ -2213,33 +2276,37 @@
         (cat,
          [('I', 'include', [], _('include names matching the given patterns')),
           ('X', 'exclude', [], _('exclude names matching the given patterns')),
-          ('o', 'output', "", _('print output to file with formatted name')),
+          ('o', 'output', '', _('print output to file with formatted name')),
           ('r', 'rev', '', _('print the given revision'))],
          _('hg cat [OPTION]... FILE...')),
     "^clone":
         (clone,
          [('U', 'noupdate', None, _('do not update the new working directory')),
-          ('e', 'ssh', "", _('specify ssh command to use')),
+          ('e', 'ssh', '', _('specify ssh command to use')),
           ('', 'pull', None, _('use pull protocol to copy metadata')),
-          ('r', 'rev', [], _('a changeset you would like to have after cloning')),
-          ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
+          ('r', 'rev', [],
+           _('a changeset you would like to have after cloning')),
+          ('', 'remotecmd', '',
+           _('specify hg command to run on the remote side'))],
          _('hg clone [OPTION]... SOURCE [DEST]')),
     "^commit|ci":
         (commit,
          [('A', 'addremove', None, _('run addremove during commit')),
           ('I', 'include', [], _('include names matching the given patterns')),
           ('X', 'exclude', [], _('exclude names matching the given patterns')),
-          ('m', 'message', "", _('use <text> as commit message')),
-          ('l', 'logfile', "", _('read the commit message from <file>')),
-          ('d', 'date', "", _('record datecode as commit date')),
-          ('u', 'user', "", _('record user as commiter'))],
+          ('m', 'message', '', _('use <text> as commit message')),
+          ('l', 'logfile', '', _('read the commit message from <file>')),
+          ('d', 'date', '', _('record datecode as commit date')),
+          ('u', 'user', '', _('record user as commiter'))],
          _('hg commit [OPTION]... [FILE]...')),
-    "copy|cp": (copy,
-             [('I', 'include', [], _('include names matching the given patterns')),
-              ('X', 'exclude', [], _('exclude names matching the given patterns')),
-              ('A', 'after', None, _('record a copy that has already occurred')),
-              ('f', 'force', None, _('forcibly copy over an existing managed file'))],
-             _('hg copy [OPTION]... [SOURCE]... DEST')),
+    "copy|cp":
+        (copy,
+         [('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns')),
+          ('A', 'after', None, _('record a copy that has already occurred')),
+          ('f', 'force', None,
+           _('forcibly copy over an existing managed file'))],
+         _('hg copy [OPTION]... [SOURCE]... DEST')),
     "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
     "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
     "debugconfig": (debugconfig, [], _('debugconfig')),
@@ -2263,15 +2330,15 @@
          _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
     "^export":
         (export,
-         [('o', 'output', "", _('print output to file with formatted name')),
+         [('o', 'output', '', _('print output to file with formatted name')),
           ('a', 'text', None, _('treat all files as text')),
           ('', 'switch-parent', None, _('diff against the second parent'))],
-         "hg export [-a] [-o OUTFILE] REV..."),
+         _('hg export [-a] [-o OUTFILE] REV...')),
     "forget":
         (forget,
          [('I', 'include', [], _('include names matching the given patterns')),
           ('X', 'exclude', [], _('exclude names matching the given patterns'))],
-         "hg forget [OPTION]... FILE..."),
+         _('hg forget [OPTION]... FILE...')),
     "grep":
         (grep,
          [('0', 'print0', None, _('end fields with NUL')),
@@ -2279,27 +2346,30 @@
           ('X', 'exclude', [], _('exclude names matching the given patterns')),
           ('', 'all', None, _('print all revisions that match')),
           ('i', 'ignore-case', None, _('ignore case when matching')),
-          ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
+          ('l', 'files-with-matches', None,
+           _('print only filenames and revs that match')),
           ('n', 'line-number', None, _('print matching line numbers')),
           ('r', 'rev', [], _('search in given revision range')),
           ('u', 'user', None, _('print user who committed change'))],
-         "hg grep [OPTION]... PATTERN [FILE]..."),
+         _('hg grep [OPTION]... PATTERN [FILE]...')),
     "heads":
         (heads,
          [('b', 'branches', None, _('find branch info')),
-          ('r', 'rev', "", _('show only heads which are descendants of rev'))],
+          ('r', 'rev', '', _('show only heads which are descendants of rev'))],
          _('hg heads [-b] [-r <rev>]')),
     "help": (help_, [], _('hg help [COMMAND]')),
     "identify|id": (identify, [], _('hg identify')),
     "import|patch":
         (import_,
-         [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
-                            _('meaning as the corresponding patch option')),
-          ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
-          ('b', 'base', "", _('base path'))],
-         "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
+         [('p', 'strip', 1,
+           _('directory strip option for patch. This has the same\n') +
+           _('meaning as the corresponding patch option')),
+          ('f', 'force', None,
+           _('skip check for outstanding uncommitted changes')),
+          ('b', 'base', '', _('base path'))],
+         _('hg import [-f] [-p NUM] [-b BASE] PATCH...')),
     "incoming|in": (incoming,
-         [('M', 'no-merges', None, _("do not show merges")),
+         [('M', 'no-merges', None, _('do not show merges')),
           ('p', 'patch', None, _('show patch')),
           ('n', 'newest-first', None, _('show newest record first'))],
          _('hg incoming [-p] [-n] [-M] [SOURCE]')),
@@ -2307,8 +2377,10 @@
     "locate":
         (locate,
          [('r', 'rev', '', _('search the repository as it stood at rev')),
-          ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
-          ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
+          ('0', 'print0', None,
+           _('end filenames with NUL, for use with xargs')),
+          ('f', 'fullpath', None,
+           _('print complete paths from the filesystem root')),
           ('I', 'include', [], _('include names matching the given patterns')),
           ('X', 'exclude', [], _('exclude names matching the given patterns'))],
          _('hg locate [OPTION]... [PATTERN]...')),
@@ -2319,13 +2391,13 @@
           ('b', 'branch', None, _('show branches')),
           ('k', 'keyword', [], _('search for a keyword')),
           ('r', 'rev', [], _('show the specified revision or range')),
-          ('M', 'no-merges', None, _("do not show merges")),
-          ('m', 'only-merges', None, _("show only merges")),
+          ('M', 'no-merges', None, _('do not show merges')),
+          ('m', 'only-merges', None, _('show only merges')),
           ('p', 'patch', None, _('show patch'))],
          _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
     "manifest": (manifest, [], _('hg manifest [REV]')),
     "outgoing|out": (outgoing,
-         [('M', 'no-merges', None, _("do not show merges")),
+         [('M', 'no-merges', None, _('do not show merges')),
           ('p', 'patch', None, _('show patch')),
           ('n', 'newest-first', None, _('show newest record first'))],
          _('hg outgoing [-p] [-n] [-M] [DEST]')),
@@ -2333,85 +2405,95 @@
     "paths": (paths, [], _('hg paths [NAME]')),
     "^pull":
         (pull,
-         [('u', 'update', None, _('update the working directory to tip after pull')),
-          ('e', 'ssh', "", _('specify ssh command to use')),
+         [('u', 'update', None,
+           _('update the working directory to tip after pull')),
+          ('e', 'ssh', '', _('specify ssh command to use')),
           ('r', 'rev', [], _('a specific revision you would like to pull')),
-          ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
+          ('', 'remotecmd', '',
+           _('specify hg command to run on the remote side'))],
          _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
     "^push":
         (push,
          [('f', 'force', None, _('force push')),
-          ('e', 'ssh', "", _('specify ssh command to use')),
-          ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
+          ('e', 'ssh', '', _('specify ssh command to use')),
+          ('', 'remotecmd', '',
+           _('specify hg command to run on the remote side'))],
          _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
     "rawcommit":
         (rawcommit,
          [('p', 'parent', [], _('parent')),
-          ('d', 'date', "", _('date code')),
-          ('u', 'user', "", _('user')),
-          ('F', 'files', "", _('file list')),
-          ('m', 'message', "", _('commit message')),
-          ('l', 'logfile', "", _('commit message file'))],
+          ('d', 'date', '', _('date code')),
+          ('u', 'user', '', _('user')),
+          ('F', 'files', '', _('file list')),
+          ('m', 'message', '', _('commit message')),
+          ('l', 'logfile', '', _('commit message file'))],
          _('hg rawcommit [OPTION]... [FILE]...')),
-    "recover": (recover, [], _("hg recover")),
-    "^remove|rm": (remove,
-                   [('I', 'include', [], _('include names matching the given patterns')),
-                    ('X', 'exclude', [], _('exclude names matching the given patterns'))],
-                   _("hg remove [OPTION]... FILE...")),
-    "rename|mv": (rename,
-                  [('I', 'include', [], _('include names matching the given patterns')),
-                   ('X', 'exclude', [], _('exclude names matching the given patterns')),
-                   ('A', 'after', None, _('record a rename that has already occurred')),
-                   ('f', 'force', None, _('forcibly copy over an existing managed file'))],
-                  _('hg rename [OPTION]... [SOURCE]... DEST')),
+    "recover": (recover, [], _('hg recover')),
+    "^remove|rm":
+        (remove,
+         [('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         _('hg remove [OPTION]... FILE...')),
+    "rename|mv":
+        (rename,
+         [('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns')),
+          ('A', 'after', None, _('record a rename that has already occurred')),
+          ('f', 'force', None,
+           _('forcibly copy over an existing managed file'))],
+         _('hg rename [OPTION]... [SOURCE]... DEST')),
     "^revert":
         (revert,
          [('I', 'include', [], _('include names matching the given patterns')),
           ('X', 'exclude', [], _('exclude names matching the given patterns')),
-          ("r", "rev", "", _("revision to revert to"))],
-         _("hg revert [-n] [-r REV] [NAME]...")),
-    "root": (root, [], _("hg root")),
+          ('r', 'rev', '', _('revision to revert to'))],
+         _('hg revert [-n] [-r REV] [NAME]...')),
+    "root": (root, [], _('hg root')),
     "^serve":
         (serve,
          [('A', 'accesslog', '', _('name of access log file to write to')),
           ('E', 'errorlog', '', _('name of error log file to write to')),
           ('p', 'port', 0, _('port to use (default: 8000)')),
           ('a', 'address', '', _('address to use')),
-          ('n', 'name', "", _('name to show in web pages (default: working dir)')),
+          ('n', 'name', '',
+           _('name to show in web pages (default: working dir)')),
           ('', 'stdio', None, _('for remote clients')),
-          ('t', 'templates', "", _('web templates to use')),
-          ('', 'style', "", _('template style to use')),
+          ('t', 'templates', '', _('web templates to use')),
+          ('', 'style', '', _('template style to use')),
           ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
-         _("hg serve [OPTION]...")),
+         _('hg serve [OPTION]...')),
     "^status|st":
         (status,
          [('m', 'modified', None, _('show only modified files')),
           ('a', 'added', None, _('show only added files')),
           ('r', 'removed', None, _('show only removed files')),
+          ('d', 'deleted', None, _('show only deleted (but tracked) files')),
           ('u', 'unknown', None, _('show only unknown (not tracked) files')),
           ('n', 'no-status', None, _('hide status prefix')),
-          ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
+          ('0', 'print0', None,
+           _('end filenames with NUL, for use with xargs')),
           ('I', 'include', [], _('include names matching the given patterns')),
           ('X', 'exclude', [], _('exclude names matching the given patterns'))],
-         _("hg status [OPTION]... [FILE]...")),
+         _('hg status [OPTION]... [FILE]...')),
     "tag":
         (tag,
          [('l', 'local', None, _('make the tag local')),
-          ('m', 'message', "", _('message for tag commit log entry')),
-          ('d', 'date', "", _('record datecode as commit date')),
-          ('u', 'user', "", _('record user as commiter')),
-          ('r', 'rev', "", _('revision to tag'))],
-         _('hg tag [OPTION]... NAME [REV]')),
+          ('m', 'message', '', _('message for tag commit log entry')),
+          ('d', 'date', '', _('record datecode as commit date')),
+          ('u', 'user', '', _('record user as commiter')),
+          ('r', 'rev', '', _('revision to tag'))],
+         _('hg tag [-r REV] [OPTION]... NAME')),
     "tags": (tags, [], _('hg tags')),
     "tip": (tip, [], _('hg tip')),
     "unbundle":
         (unbundle,
-         [],
-         _('hg unbundle FILE')),
+         [('u', 'update', None,
+           _('update the working directory to tip after unbundle'))],
+         _('hg unbundle [-u] FILE')),
     "undo": (undo, [], _('hg undo')),
     "^update|up|checkout|co":
         (update,
-         [('b', 'branch', "", _('checkout the head of a specific branch')),
+         [('b', 'branch', '', _('checkout the head of a specific branch')),
           ('m', 'merge', None, _('allow merging of branches')),
           ('C', 'clean', None, _('overwrite locally modified files')),
           ('f', 'force', None, _('force a merge with outstanding changes'))],
@@ -2421,18 +2503,19 @@
 }
 
 globalopts = [
-    ('R', 'repository', "", _("repository root directory")),
-    ('', 'cwd', '', _("change working directory")),
-    ('y', 'noninteractive', None, _("do not prompt, assume 'yes' for any required answers")),
-    ('q', 'quiet', None, _("suppress output")),
-    ('v', 'verbose', None, _("enable additional output")),
-    ('', 'debug', None, _("enable debugging output")),
-    ('', 'debugger', None, _("start debugger")),
-    ('', 'traceback', None, _("print traceback on exception")),
-    ('', 'time', None, _("time how long the command takes")),
-    ('', 'profile', None, _("print command execution profile")),
-    ('', 'version', None, _("output version information and exit")),
-    ('h', 'help', None, _("display help and exit")),
+    ('R', 'repository', '', _('repository root directory')),
+    ('', 'cwd', '', _('change working directory')),
+    ('y', 'noninteractive', None,
+     _('do not prompt, assume \'yes\' for any required answers')),
+    ('q', 'quiet', None, _('suppress output')),
+    ('v', 'verbose', None, _('enable additional output')),
+    ('', 'debug', None, _('enable debugging output')),
+    ('', 'debugger', None, _('start debugger')),
+    ('', 'traceback', None, _('print traceback on exception')),
+    ('', 'time', None, _('time how long the command takes')),
+    ('', 'profile', None, _('print command execution profile')),
+    ('', 'version', None, _('output version information and exit')),
+    ('h', 'help', None, _('display help and exit')),
 ]
 
 norepo = ("clone init version help debugancestor debugconfig debugdata"
@@ -2615,7 +2698,8 @@
                 path = options["repository"] or ""
                 repo = hg.repository(ui=u, path=path)
                 for x in external:
-                    if hasattr(x, 'reposetup'): x.reposetup(u, repo)
+                    if hasattr(x, 'reposetup'):
+                        x.reposetup(u, repo)
                 d = lambda: func(u, repo, *args, **cmdoptions)
             else:
                 d = lambda: func(u, *args, **cmdoptions)
--- a/mercurial/dirstate.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/dirstate.py	Wed Feb 01 19:18:15 2006 +0100
@@ -68,7 +68,8 @@
                     try:
                         syntax = syntaxes[s]
                     except KeyError:
-                        self.ui.warn(_("ignoring invalid syntax '%s'\n") % s)
+                        self.ui.warn(_(".hgignore: ignoring invalid "
+                                       "syntax '%s'\n") % s)
                     continue
                 pat = syntax + line
                 for s in syntaxes.values():
@@ -88,7 +89,8 @@
             ignore = self.hgignore()
             if ignore:
                 files, self.ignorefunc, anypats = util.matcher(self.root,
-                                                               inc=ignore)
+                                                               inc=ignore,
+                                                               src='.hgignore')
             else:
                 self.ignorefunc = util.never
         return self.ignorefunc(fn)
@@ -415,4 +417,4 @@
             elif type == 'r':
                 removed.append(fn)
 
-        return (lookup, modified, added, removed + deleted, unknown)
+        return (lookup, modified, added, removed, deleted, unknown)
--- a/mercurial/filelog.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/filelog.py	Wed Feb 01 19:18:15 2006 +0100
@@ -58,7 +58,7 @@
         return self.addrevision(text, transaction, link, p1, p2)
 
     def renamed(self, node):
-        if 0 and self.parents(node)[0] != nullid: # XXX
+        if self.parents(node)[0] != nullid:
             return False
         m = self.readmeta(node)
         if m and m.has_key("copy"):
--- a/mercurial/hgweb.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/hgweb.py	Wed Feb 01 19:18:15 2006 +0100
@@ -6,7 +6,7 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import os, cgi, sys
+import os, cgi, sys, urllib
 from demandload import demandload
 demandload(globals(), "mdiff time re socket zlib errno ui hg ConfigParser")
 demandload(globals(), "zipfile tempfile StringIO tarfile BaseHTTPServer util")
@@ -163,7 +163,8 @@
                 return
 
 common_filters = {
-    "escape": cgi.escape,
+    "escape": lambda x: cgi.escape(x, True),
+    "urlescape": urllib.quote,
     "strip": lambda x: x.strip(),
     "age": age,
     "date": lambda x: util.datestr(x),
@@ -212,27 +213,33 @@
         if len(files) > self.maxfiles:
             yield self.t("fileellipses")
 
-    def parents(self, node, parents=[], rev=None, hide=False, **args):
+    def siblings(self, siblings=[], rev=None, hiderev=None, **args):
         if not rev:
             rev = lambda x: ""
-        parents = [p for p in parents if p != nullid]
-        if hide and len(parents) == 1 and rev(parents[0]) == rev(node) - 1:
+        siblings = [s for s in siblings if s != nullid]
+        if len(siblings) == 1 and rev(siblings[0]) == hiderev:
             return
-        for p in parents:
-            yield dict(node=hex(p), rev=rev(p), **args)
+        for s in siblings:
+            yield dict(node=hex(s), rev=rev(s), **args)
+
+    def renamelink(self, fl, node):
+        r = fl.renamed(node)
+        if r:
+            return [dict(file=r[0], node=hex(r[1]))]
+        return []
 
     def showtag(self, t1, node=nullid, **args):
         for t in self.repo.nodetags(node):
              yield self.t(t1, tag=t, **args)
 
     def diff(self, node1, node2, files):
-        def filterfiles(list, files):
-            l = [x for x in list if x in files]
+        def filterfiles(filters, files):
+            l = [x for x in files if x in filters]
 
-            for f in files:
-                if f[-1] != os.sep:
-                    f += os.sep
-                l += [x for x in list if x.startswith(f)]
+            for t in filters:
+                if t and t[-1] != os.sep:
+                    t += os.sep
+                l += [x for x in files if x.startswith(t)]
             return l
 
         parity = [0]
@@ -265,22 +272,29 @@
         date1 = util.datestr(change1[2])
         date2 = util.datestr(change2[2])
 
-        c, a, d, u = r.changes(node1, node2)
+        modified, added, removed, deleted, unknown = r.changes(node1, node2)
         if files:
-            c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
+            modified, added, removed = map(lambda x: filterfiles(files, x),
+                                           (modified, added, removed))
 
-        for f in c:
+        diffopts = self.repo.ui.diffopts()
+        showfunc = diffopts['showfunc']
+        ignorews = diffopts['ignorews']
+        for f in modified:
             to = r.file(f).read(mmap1[f])
             tn = r.file(f).read(mmap2[f])
-            yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
-        for f in a:
+            yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
+                            showfunc=showfunc, ignorews=ignorews), f, tn)
+        for f in added:
             to = None
             tn = r.file(f).read(mmap2[f])
-            yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
-        for f in d:
+            yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
+                            showfunc=showfunc, ignorews=ignorews), f, tn)
+        for f in removed:
             to = r.file(f).read(mmap1[f])
             tn = None
-            yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
+            yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
+                            showfunc=showfunc, ignorews=ignorews), f, tn)
 
     def changelog(self, pos):
         def changenav(**map):
@@ -321,8 +335,10 @@
 
                 l.insert(0, {"parity": parity,
                              "author": changes[1],
-                             "parent": self.parents(n, cl.parents(n), cl.rev,
-                                                    hide=True),
+                             "parent": self.siblings(cl.parents(n), cl.rev,
+                                                     cl.rev(n) - 1),
+                             "child": self.siblings(cl.children(n), cl.rev,
+                                                    cl.rev(n) + 1),
                              "changelogtag": self.showtag("changelogtag",n),
                              "manifest": hex(changes[0]),
                              "desc": changes[4],
@@ -382,7 +398,8 @@
                 yield self.t('searchentry',
                              parity=count & 1,
                              author=changes[1],
-                             parent=self.parents(n, cl.parents(n), cl.rev),
+                             parent=self.siblings(cl.parents(n), cl.rev),
+                             child=self.siblings(cl.children(n), cl.rev),
                              changelogtag=self.showtag("changelogtag",n),
                              manifest=hex(changes[0]),
                              desc=changes[4],
@@ -422,7 +439,8 @@
                      diff=diff,
                      rev=cl.rev(n),
                      node=nodeid,
-                     parent=self.parents(n, cl.parents(n), cl.rev),
+                     parent=self.siblings(cl.parents(n), cl.rev),
+                     child=self.siblings(cl.children(n), cl.rev),
                      changesettag=self.showtag("changesettag",n),
                      manifest=hex(changes[0]),
                      author=changes[1],
@@ -454,7 +472,10 @@
                              "node": hex(cn),
                              "author": cs[1],
                              "date": cs[2],
-                             "parent": self.parents(n, fl.parents(n),
+                             "rename": self.renamelink(fl, n),
+                             "parent": self.siblings(fl.parents(n),
+                                                     fl.rev, file=f),
+                             "child": self.siblings(fl.children(n),
                                                     fl.rev, file=f),
                              "desc": cs[4]})
                 parity = 1 - parity
@@ -498,7 +519,9 @@
                      manifest=hex(mfn),
                      author=cs[1],
                      date=cs[2],
-                     parent=self.parents(n, fl.parents(n), fl.rev, file=f),
+                     parent=self.siblings(fl.parents(n), fl.rev, file=f),
+                     child=self.siblings(fl.children(n), fl.rev, file=f),
+                     rename=self.renamelink(fl, n),
                      permissions=self.repo.manifest.readflags(mfn)[f])
 
     def fileannotate(self, f, node):
@@ -550,7 +573,9 @@
                      manifest=hex(mfn),
                      author=cs[1],
                      date=cs[2],
-                     parent=self.parents(n, fl.parents(n), fl.rev, file=f),
+                     rename=self.renamelink(fl, n),
+                     parent=self.siblings(fl.parents(n), fl.rev, file=f),
+                     child=self.siblings(fl.children(n), fl.rev, file=f),
                      permissions=self.repo.manifest.readflags(mfn)[f])
 
     def manifest(self, mnode, path):
@@ -565,6 +590,8 @@
         files = {}
 
         p = path[1:]
+        if p and p[-1] != "/":
+            p += "/"
         l = len(p)
 
         for f,n in mf.items():
@@ -727,7 +754,8 @@
                      filenode=hex(mf.get(file, nullid)),
                      node=changeset,
                      rev=self.repo.changelog.rev(n),
-                     parent=self.parents(n, cl.parents(n), cl.rev),
+                     parent=self.siblings(cl.parents(n), cl.rev),
+                     child=self.siblings(cl.children(n), cl.rev),
                      diff=diff)
 
     def archive(self, req, cnode, type):
@@ -785,6 +813,12 @@
     # find tag, changeset, file
 
     def run(self, req=hgrequest()):
+        def clean(path):
+            p = os.path.normpath(path)
+            if p[:2] == "..":
+                raise "suspicious path"
+            return p
+
         def header(**map):
             yield self.t("header", **map)
 
@@ -865,7 +899,8 @@
             req.write(self.changeset(req.form['node'][0]))
 
         elif req.form['cmd'][0] == 'manifest':
-            req.write(self.manifest(req.form['manifest'][0], req.form['path'][0]))
+            req.write(self.manifest(req.form['manifest'][0],
+                                    clean(req.form['path'][0])))
 
         elif req.form['cmd'][0] == 'tags':
             req.write(self.tags())
@@ -874,16 +909,20 @@
             req.write(self.summary())
 
         elif req.form['cmd'][0] == 'filediff':
-            req.write(self.filediff(req.form['file'][0], req.form['node'][0]))
+            req.write(self.filediff(clean(req.form['file'][0]),
+                                    req.form['node'][0]))
 
         elif req.form['cmd'][0] == 'file':
-            req.write(self.filerevision(req.form['file'][0], req.form['filenode'][0]))
+            req.write(self.filerevision(clean(req.form['file'][0]),
+                                        req.form['filenode'][0]))
 
         elif req.form['cmd'][0] == 'annotate':
-            req.write(self.fileannotate(req.form['file'][0], req.form['filenode'][0]))
+            req.write(self.fileannotate(clean(req.form['file'][0]),
+                                        req.form['filenode'][0]))
 
         elif req.form['cmd'][0] == 'filelog':
-            req.write(self.filelog(req.form['file'][0], req.form['filenode'][0]))
+            req.write(self.filelog(clean(req.form['file'][0]),
+                                   req.form['filenode'][0]))
 
         elif req.form['cmd'][0] == 'heads':
             req.httphdr("application/mercurial-0.1")
--- a/mercurial/localrepo.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/localrepo.py	Wed Feb 01 19:18:15 2006 +0100
@@ -19,7 +19,8 @@
             while not os.path.isdir(os.path.join(p, ".hg")):
                 oldp = p
                 p = os.path.dirname(p)
-                if p == oldp: raise repo.RepoError(_("no repo found"))
+                if p == oldp:
+                    raise repo.RepoError(_("no repo found"))
             path = p
         self.path = os.path.join(path, ".hg")
 
@@ -44,7 +45,8 @@
         self.dirstate = dirstate.dirstate(self.opener, ui, self.root)
         try:
             self.ui.readconfig(self.join("hgrc"))
-        except IOError: pass
+        except IOError:
+            pass
 
     def hook(self, name, **args):
         def runhook(name, cmd):
@@ -126,16 +128,16 @@
                 r = self.changelog.rev(n)
             except:
                 r = -2 # sort to the beginning of the list if unknown
-            l.append((r,t,n))
+            l.append((r, t, n))
         l.sort()
-        return [(t,n) for r,t,n in l]
+        return [(t, n) for r, t, n in l]
 
     def nodetags(self, node):
         '''return the tags associated with a node'''
         if not self.nodetagscache:
             self.nodetagscache = {}
-            for t,n in self.tags().items():
-                self.nodetagscache.setdefault(n,[]).append(t)
+            for t, n in self.tags().items():
+                self.nodetagscache.setdefault(n, []).append(t)
         return self.nodetagscache.get(node, [])
 
     def lookup(self, key):
@@ -160,7 +162,8 @@
         return os.path.join(self.root, f)
 
     def file(self, f):
-        if f[0] == '/': f = f[1:]
+        if f[0] == '/':
+            f = f[1:]
         return filelog.filelog(self.opener, f)
 
     def getcwd(self):
@@ -226,6 +229,8 @@
         if os.path.exists(self.join("journal")):
             self.ui.status(_("rolling back interrupted transaction\n"))
             transaction.rollback(self.opener, self.join("journal"))
+            self.manifest = manifest.manifest(self.opener)
+            self.changelog = changelog.changelog(self.opener)
             return True
         else:
             self.ui.warn(_("no interrupted transaction available\n"))
@@ -334,8 +339,8 @@
         if update_dirstate:
             self.dirstate.setparents(n, nullid)
 
-    def commit(self, files = None, text = "", user = None, date = None,
-               match = util.always, force=False):
+    def commit(self, files=None, text="", user=None, date=None,
+               match=util.always, force=False):
         commit = []
         remove = []
         changed = []
@@ -350,9 +355,9 @@
                 else:
                     self.ui.warn(_("%s not tracked!\n") % f)
         else:
-            (c, a, d, u) = self.changes(match=match)
-            commit = c + a
-            remove = d
+            modified, added, removed, deleted, unknown = self.changes(match=match)
+            commit = modified + added
+            remove = removed
 
         p1, p2 = self.dirstate.parents()
         c1 = self.changelog.read(p1)
@@ -398,10 +403,6 @@
                 fp1 = m1.get(f, nullid)
                 fp2 = m2.get(f, nullid)
 
-            # is the same revision on two branches of a merge?
-            if fp2 == fp1:
-                fp2 = nullid
-
             if fp2 != nullid:
                 # is one parent an ancestor of the other?
                 fpa = r.ancestor(fp1, fp2)
@@ -411,7 +412,7 @@
                     fp2 = nullid
 
                 # is the file unmodified from the parent?
-                if not meta and t == r.read(fp1):
+                if not meta and t == r.read(fp1) and fp2 == nullid:
                     # record the proper existing parent in manifest
                     # no need to add a revision
                     new[f] = fp1
@@ -423,6 +424,7 @@
             changed.append(f)
 
         # update manifest
+        m1 = m1.copy()
         m1.update(new)
         for f in remove:
             if f in m1:
@@ -449,7 +451,7 @@
             text = edittext
 
         user = user or self.ui.username()
-        n = self.changelog.add(mn, changed, text, tr, p1, p2, user, date)
+        n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date)
         tr.close()
 
         self.dirstate.setparents(n)
@@ -474,9 +476,12 @@
             for src, fn in self.dirstate.walk(files, match):
                 yield src, fn
 
-    def changes(self, node1 = None, node2 = None, files = [],
-                match = util.always):
-        mf2, u = None, []
+    def changes(self, node1=None, node2=None, files=[], match=util.always):
+        """return changes between two nodes or node and working directory
+
+        If node1 is None, use the first dirstate parent instead.
+        If node2 is None, compare node1 with working directory.
+        """
 
         def fcmp(fn, mf):
             t1 = self.wread(fn)
@@ -484,7 +489,8 @@
             return cmp(t1, t2)
 
         def mfmatches(node):
-            mf = dict(self.manifest.read(node))
+            change = self.changelog.read(node)
+            mf = dict(self.manifest.read(change[0]))
             for fn in mf.keys():
                 if not match(fn):
                     del mf[fn]
@@ -496,60 +502,53 @@
                 wlock = self.wlock(wait=0)
             except lock.LockHeld:
                 wlock = None
-            l, c, a, d, u = self.dirstate.changes(files, match)
+            lookup, modified, added, removed, deleted, unknown = (
+                self.dirstate.changes(files, match))
 
             # are we comparing working dir against its parent?
             if not node1:
-                if l:
+                if lookup:
                     # do a full compare of any files that might have changed
-                    change = self.changelog.read(self.dirstate.parents()[0])
-                    mf2 = mfmatches(change[0])
-                    for f in l:
+                    mf2 = mfmatches(self.dirstate.parents()[0])
+                    for f in lookup:
                         if fcmp(f, mf2):
-                            c.append(f)
+                            modified.append(f)
                         elif wlock is not None:
                             self.dirstate.update([f], "n")
-
-                for l in c, a, d, u:
-                    l.sort()
-
-                return (c, a, d, u)
-
-        # are we comparing working dir against non-tip?
-        # generate a pseudo-manifest for the working dir
-        if not node2:
-            if not mf2:
-                change = self.changelog.read(self.dirstate.parents()[0])
-                mf2 = mfmatches(change[0])
-            for f in a + c + l:
-                mf2[f] = ""
-            for f in d:
-                if f in mf2: del mf2[f]
+            else:
+                # we are comparing working dir against non-parent
+                # generate a pseudo-manifest for the working dir
+                mf2 = mfmatches(self.dirstate.parents()[0])
+                for f in lookup + modified + added:
+                    mf2[f] = ""
+                for f in removed:
+                    if f in mf2:
+                        del mf2[f]
         else:
-            change = self.changelog.read(node2)
-            mf2 = mfmatches(change[0])
+            # we are comparing two revisions
+            deleted, unknown = [], []
+            mf2 = mfmatches(node2)
 
-        # flush lists from dirstate before comparing manifests
-        c, a = [], []
+        if node1:
+            # flush lists from dirstate before comparing manifests
+            modified, added = [], []
 
-        change = self.changelog.read(node1)
-        mf1 = mfmatches(change[0])
+            mf1 = mfmatches(node1)
 
-        for fn in mf2:
-            if mf1.has_key(fn):
-                if mf1[fn] != mf2[fn]:
-                    if mf2[fn] != "" or fcmp(fn, mf1):
-                        c.append(fn)
-                del mf1[fn]
-            else:
-                a.append(fn)
+            for fn in mf2:
+                if mf1.has_key(fn):
+                    if mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1)):
+                        modified.append(fn)
+                    del mf1[fn]
+                else:
+                    added.append(fn)
 
-        d = mf1.keys()
+            removed = mf1.keys()
 
-        for l in c, a, d, u:
+        # sort and return results:
+        for l in modified, added, removed, deleted, unknown:
             l.sort()
-
-        return (c, a, d, u)
+        return (modified, added, removed, deleted, unknown)
 
     def add(self, list):
         wlock = self.wlock()
@@ -558,7 +557,8 @@
             if not os.path.exists(p):
                 self.ui.warn(_("%s does not exist!\n") % f)
             elif not os.path.isfile(p):
-                self.ui.warn(_("%s not added: only files supported currently\n") % f)
+                self.ui.warn(_("%s not added: only files supported currently\n")
+                             % f)
             elif self.dirstate.state(f) in 'an':
                 self.ui.warn(_("%s already tracked!\n") % f)
             else:
@@ -578,7 +578,8 @@
                 try:
                     util.unlink(self.wjoin(f))
                 except OSError, inst:
-                    if inst.errno != errno.ENOENT: raise
+                    if inst.errno != errno.ENOENT:
+                        raise
         wlock = self.wlock()
         for f in list:
             p = self.wjoin(f)
@@ -733,7 +734,8 @@
         return out
 
     def branches(self, nodes):
-        if not nodes: nodes = [self.changelog.tip()]
+        if not nodes:
+            nodes = [self.changelog.tip()]
         b = []
         for n in nodes:
             t = n
@@ -805,7 +807,8 @@
                 if n[0] in seen:
                     continue
 
-                self.ui.debug(_("examining %s:%s\n") % (short(n[0]), short(n[1])))
+                self.ui.debug(_("examining %s:%s\n")
+                              % (short(n[0]), short(n[1])))
                 if n[0] == nullid:
                     break
                 if n in seenbranch:
@@ -841,7 +844,8 @@
                         self.ui.debug(_("received %s:%s\n") %
                                       (short(b[0]), short(b[1])))
                         if b[0] in m:
-                            self.ui.debug(_("found base node %s\n") % short(b[0]))
+                            self.ui.debug(_("found base node %s\n")
+                                          % short(b[0]))
                             base[b[0]] = 1
                         elif b[0] not in seen:
                             unknown.append(b)
@@ -914,7 +918,7 @@
         # this is the set of all roots we have to push
         return subset
 
-    def pull(self, remote, heads = None):
+    def pull(self, remote, heads=None):
         lock = self.lock()
 
         # if we have an empty repo, fetch everything
@@ -1199,8 +1203,11 @@
                 filerevlog = self.file(fname)
                 # Toss out the filenodes that the recipient isn't really
                 # missing.
-                prune_filenodes(fname, filerevlog)
-                msng_filenode_lst = msng_filenode_set[fname].keys()
+                if msng_filenode_set.has_key(fname):
+                    prune_filenodes(fname, filerevlog)
+                    msng_filenode_lst = msng_filenode_set[fname].keys()
+                else:
+                    msng_filenode_lst = []
                 # If any filenodes are left, generate the group for them,
                 # otherwise don't bother.
                 if len(msng_filenode_lst) > 0:
@@ -1214,8 +1221,9 @@
                                              lookup_filenode_link_func(fname))
                     for chnk in group:
                         yield chnk
-                # Don't need this anymore, toss it to free memory.
-                del msng_filenode_set[fname]
+                if msng_filenode_set.has_key(fname):
+                    # Don't need this anymore, toss it to free memory.
+                    del msng_filenode_set[fname]
             # Signal that no more groups are left.
             yield struct.pack(">l", 0)
 
@@ -1285,9 +1293,11 @@
 
         def getchunk():
             d = source.read(4)
-            if not d: return ""
+            if not d:
+                return ""
             l = struct.unpack(">l", d)[0]
-            if l <= 4: return ""
+            if l <= 4:
+                return ""
             d = source.read(l - 4)
             if len(d) < l - 4:
                 raise repo.RepoError(_("premature EOF reading chunk"
@@ -1298,7 +1308,8 @@
         def getgroup():
             while 1:
                 c = getchunk()
-                if not c: break
+                if not c:
+                    break
                 yield c
 
         def csmap(x):
@@ -1308,7 +1319,8 @@
         def revmap(x):
             return self.changelog.rev(x)
 
-        if not source: return
+        if not source:
+            return
         changesets = files = revisions = 0
 
         tr = self.transaction()
@@ -1333,7 +1345,8 @@
         self.ui.status(_("adding file changes\n"))
         while 1:
             f = getchunk()
-            if not f: break
+            if not f:
+                break
             self.ui.debug(_("adding %s revisions\n") % f)
             fl = self.file(f)
             o = fl.count()
@@ -1354,7 +1367,7 @@
 
         if changesets > 0:
             if not self.hook("changegroup",
-                              node=hex(self.changelog.node(cor+1))):
+                             node=hex(self.changelog.node(cor+1))):
                 self.ui.warn(_("abort: changegroup hook returned failure!\n"))
                 return 1
 
@@ -1370,6 +1383,8 @@
             self.ui.warn(_("aborting: outstanding uncommitted merges\n"))
             return 1
 
+        err = False
+
         p1, p2 = pl[0], node
         pa = self.changelog.ancestor(p1, p2)
         m1n = self.changelog.read(p1)[0]
@@ -1377,29 +1392,32 @@
         man = self.manifest.ancestor(m1n, m2n)
         m1 = self.manifest.read(m1n)
         mf1 = self.manifest.readflags(m1n)
-        m2 = self.manifest.read(m2n)
+        m2 = self.manifest.read(m2n).copy()
         mf2 = self.manifest.readflags(m2n)
         ma = self.manifest.read(man)
         mfa = self.manifest.readflags(man)
 
-        (c, a, d, u) = self.changes()
-
-        if allow and not forcemerge:
-            if c or a or d:
-                raise util.Abort(_("outstanding uncommited changes"))
-        if not forcemerge and not force:
-            for f in u:
-                if f in m2:
-                     t1 = self.wread(f)
-                     t2 = self.file(f).read(m2[f])
-                     if cmp(t1, t2) != 0:
-                        raise util.Abort(_("'%s' already exists in the working"
-                                           " dir and differs from remote") % f)
+        modified, added, removed, deleted, unknown = self.changes()
 
         # is this a jump, or a merge?  i.e. is there a linear path
         # from p1 to p2?
         linear_path = (pa == p1 or pa == p2)
 
+        if allow and linear_path:
+            raise util.Abort(_("there is nothing to merge, "
+                               "just use 'hg update'"))
+        if allow and not forcemerge:
+            if modified or added or removed:
+                raise util.Abort(_("outstanding uncommited changes"))
+        if not forcemerge and not force:
+            for f in unknown:
+                if f in m2:
+                    t1 = self.wread(f)
+                    t2 = self.file(f).read(m2[f])
+                    if cmp(t1, t2) != 0:
+                        raise util.Abort(_("'%s' already exists in the working"
+                                           " dir and differs from remote") % f)
+
         # resolve the manifest to determine which files
         # we care about merging
         self.ui.note(_("resolving manifests\n"))
@@ -1415,17 +1433,18 @@
         # construct a working dir manifest
         mw = m1.copy()
         mfw = mf1.copy()
-        umap = dict.fromkeys(u)
+        umap = dict.fromkeys(unknown)
 
-        for f in a + c + u:
+        for f in added + modified + unknown:
             mw[f] = ""
             mfw[f] = util.is_exec(self.wjoin(f), mfw.get(f, False))
 
         if moddirstate:
             wlock = self.wlock()
 
-        for f in d:
-            if f in mw: del mw[f]
+        for f in deleted + removed:
+            if f in mw:
+                del mw[f]
 
             # If we're jumping between revisions (as opposed to merging),
             # and if neither the working directory nor the target rev has
@@ -1437,7 +1456,8 @@
 
         # Compare manifests
         for f, n in mw.iteritems():
-            if choose and not choose(f): continue
+            if choose and not choose(f):
+                continue
             if f in m2:
                 s = 0
 
@@ -1480,7 +1500,8 @@
                         a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
                         mode = ((a^b) | (a^c)) ^ a
                         if mode != b:
-                            self.ui.debug(_(" updating permissions for %s\n") % f)
+                            self.ui.debug(_(" updating permissions for %s\n")
+                                          % f)
                             util.set_exec(self.wjoin(f), mode)
                 del m2[f]
             elif f in ma:
@@ -1510,15 +1531,18 @@
                     self.ui.debug(_("working dir created %s, keeping\n") % f)
 
         for f, n in m2.iteritems():
-            if choose and not choose(f): continue
-            if f[0] == "/": continue
+            if choose and not choose(f):
+                continue
+            if f[0] == "/":
+                continue
             if f in ma and n != ma[f]:
                 r = _("k")
                 if not force and (linear_path or allow):
                     r = self.ui.prompt(
                         (_("remote changed %s which local deleted\n") % f) +
                          _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
-                if r == _("k"): get[f] = n
+                if r == _("k"):
+                    get[f] = n
             elif f not in ma:
                 self.ui.debug(_("remote created %s\n") % f)
                 get[f] = n
@@ -1548,7 +1572,8 @@
                 fl.sort()
                 for f in fl:
                     cf = ""
-                    if f in merge: cf = _(" (resolve)")
+                    if f in merge:
+                        cf = _(" (resolve)")
                     self.ui.status(" %s%s\n" % (f, cf))
                 self.ui.warn(_("aborting update spanning branches!\n"))
                 self.ui.status(_("(use update -m to merge across branches"
@@ -1560,7 +1585,8 @@
         files = get.keys()
         files.sort()
         for f in files:
-            if f[0] == "/": continue
+            if f[0] == "/":
+                continue
             self.ui.note(_("getting %s\n") % f)
             t = self.file(f).read(get[f])
             self.wwrite(f, t)
@@ -1577,7 +1603,9 @@
         for f in files:
             self.ui.status(_("merging %s\n") % f)
             my, other, flag = merge[f]
-            self.merge3(f, my, other)
+            ret = self.merge3(f, my, other)
+            if ret:
+                err = True
             util.set_exec(self.wjoin(f), flag)
             if moddirstate:
                 if branch_merge:
@@ -1610,6 +1638,7 @@
 
         if moddirstate:
             self.dirstate.setparents(p1, p2)
+        return err
 
     def merge3(self, fn, my, other):
         """perform a 3-way merge in the working directory"""
@@ -1640,6 +1669,7 @@
 
         os.unlink(b)
         os.unlink(c)
+        return r
 
     def verify(self):
         filelinkrevs = {}
@@ -1652,11 +1682,17 @@
             self.ui.warn(msg + "\n")
             errors[0] += 1
 
+        def checksize(obj, name):
+            d = obj.checksize()
+            if d[0]:
+                err(_("%s data length off by %d bytes") % (name, d[0]))
+            if d[1]:
+                err(_("%s index contains %d extra bytes") % (name, d[1]))
+
         seen = {}
         self.ui.status(_("checking changesets\n"))
-        d = self.changelog.checksize()
-        if d:
-            err(_("changeset data short %d bytes") % d)
+        checksize(self.changelog, "changelog")
+
         for i in range(self.changelog.count()):
             changesets += 1
             n = self.changelog.node(i)
@@ -1686,9 +1722,8 @@
 
         seen = {}
         self.ui.status(_("checking manifests\n"))
-        d = self.manifest.checksize()
-        if d:
-            err(_("manifest data short %d bytes") % d)
+        checksize(self.manifest, "manifest")
+
         for i in range(self.manifest.count()):
             n = self.manifest.node(i)
             l = self.manifest.linkrev(n)
@@ -1723,7 +1758,7 @@
 
         self.ui.status(_("crosschecking files in changesets and manifests\n"))
 
-        for m,c in neededmanifests.items():
+        for m, c in neededmanifests.items():
             err(_("Changeset %s refers to unknown manifest %s") %
                 (short(m), short(c)))
         del neededmanifests
@@ -1740,14 +1775,13 @@
         ff = filenodes.keys()
         ff.sort()
         for f in ff:
-            if f == "/dev/null": continue
+            if f == "/dev/null":
+                continue
             files += 1
             fl = self.file(f)
-            d = fl.checksize()
-            if d:
-                err(_("%s file data short %d bytes") % (f, d))
+            checksize(fl, f)
 
-            nodes = { nullid: 1 }
+            nodes = {nullid: 1}
             seen = {}
             for i in range(fl.count()):
                 revisions += 1
--- a/mercurial/manifest.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/manifest.py	Wed Feb 01 19:18:15 2006 +0100
@@ -108,6 +108,8 @@
             files = map.keys()
             files.sort()
 
+            # if this is changed to support newlines in filenames,
+            # be sure to check the templates/ dir again (especially *-raw.tmpl)
             text = ["%s\000%s%s\n" %
                             (f, hex(map[f]), flags[f] and "x" or '')
                             for f in files]
--- a/mercurial/mdiff.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/mdiff.py	Wed Feb 01 19:18:15 2006 +0100
@@ -5,9 +5,13 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import difflib, struct, bdiff, util, mpatch
+from demandload import demandload
+import struct, bdiff, util, mpatch
+demandload(globals(), "re")
 
-def unidiff(a, ad, b, bd, fn, r=None, text=False):
+
+def unidiff(a, ad, b, bd, fn, r=None, text=False,
+            showfunc=False, ignorews=False):
 
     if not a and not b: return ""
     epoch = util.datestr((0, 0))
@@ -27,9 +31,10 @@
         l3 = "@@ -1,%d +0,0 @@\n" % len(a)
         l = [l1, l2, l3] + ["-" + e for e in a]
     else:
-        a = a.splitlines(1)
-        b = b.splitlines(1)
-        l = list(difflib.unified_diff(a, b, "a/" + fn, "b/" + fn))
+        al = a.splitlines(1)
+        bl = b.splitlines(1)
+        l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn,
+                          showfunc=showfunc, ignorews=ignorews))
         if not l: return ""
         # difflib uses a space, rather than a tab
         l[0] = "%s\t%s\n" % (l[0][:-2], ad)
@@ -45,6 +50,128 @@
 
     return "".join(l)
 
+# somewhat self contained replacement for difflib.unified_diff
+# t1 and t2 are the text to be diffed
+# l1 and l2 are the text broken up into lines
+# header1 and header2 are the filenames for the diff output
+# context is the number of context lines
+# showfunc enables diff -p output
+# ignorews ignores all whitespace changes in the diff
+def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False,
+             ignorews=False):
+    def contextend(l, len):
+        ret = l + context
+        if ret > len:
+            ret = len
+        return ret
+
+    def contextstart(l):
+        ret = l - context
+        if ret < 0:
+            return 0
+        return ret
+
+    def yieldhunk(hunk, header):
+        if header:
+            for x in header:
+                yield x
+        (astart, a2, bstart, b2, delta) = hunk
+        aend = contextend(a2, len(l1))
+        alen = aend - astart
+        blen = b2 - bstart + aend - a2
+
+        func = ""
+        if showfunc:
+            # walk backwards from the start of the context
+            # to find a line starting with an alphanumeric char.
+            for x in xrange(astart, -1, -1):
+                t = l1[x].rstrip()
+                if funcre.match(t):
+                    func = ' ' + t[:40]
+                    break
+
+        yield "@@ -%d,%d +%d,%d @@%s\n" % (astart + 1, alen,
+                                           bstart + 1, blen, func)
+        for x in delta:
+            yield x
+        for x in xrange(a2, aend):
+            yield ' ' + l1[x]
+
+    header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ]
+
+    if showfunc:
+        funcre = re.compile('\w')
+    if ignorews:
+        wsre = re.compile('[ \t]')
+
+    # bdiff.blocks gives us the matching sequences in the files.  The loop
+    # below finds the spaces between those matching sequences and translates
+    # them into diff output.
+    #
+    diff = bdiff.blocks(t1, t2)
+    hunk = None
+    for i in xrange(len(diff)):
+        # The first match is special.
+        # we've either found a match starting at line 0 or a match later
+        # in the file.  If it starts later, old and new below will both be
+        # empty and we'll continue to the next match.
+        if i > 0:
+            s = diff[i-1]
+        else:
+            s = [0, 0, 0, 0]
+        delta = []
+        s1 = diff[i]
+        a1 = s[1]
+        a2 = s1[0]
+        b1 = s[3]
+        b2 = s1[2]
+
+        old = l1[a1:a2]
+        new = l2[b1:b2]
+
+        # bdiff sometimes gives huge matches past eof, this check eats them,
+        # and deals with the special first match case described above
+        if not old and not new:
+            continue
+
+        if ignorews:
+            wsold = wsre.sub('', "".join(old))
+            wsnew = wsre.sub('', "".join(new))
+            if wsold == wsnew:
+                continue
+
+        astart = contextstart(a1)
+        bstart = contextstart(b1)
+        prev = None
+        if hunk:
+            # join with the previous hunk if it falls inside the context
+            if astart < hunk[1] + context + 1:
+                prev = hunk
+                astart = hunk[1]
+                bstart = hunk[3]
+            else:
+                for x in yieldhunk(hunk, header):
+                    yield x
+                # we only want to yield the header if the files differ, and
+                # we only want to yield it once.
+                header = None
+        if prev:
+            # we've joined the previous hunk, record the new ending points.
+            hunk[1] = a2
+            hunk[3] = b2
+            delta = hunk[4]
+        else:
+            # create a new hunk
+            hunk = [ astart, a2, bstart, b2, delta ]
+
+        delta[len(delta):] = [ ' ' + x for x in l1[astart:a1] ]
+        delta[len(delta):] = [ '-' + x for x in old ]
+        delta[len(delta):] = [ '+' + x for x in new ]
+
+    if hunk:
+        for x in yieldhunk(hunk, header):
+            yield x
+
 def patchtext(bin):
     pos = 0
     t = []
--- a/mercurial/revlog.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/revlog.py	Wed Feb 01 19:18:15 2006 +0100
@@ -188,6 +188,7 @@
         self.datafile = datafile
         self.opener = opener
         self.cache = None
+        self.chunkcache = None
 
         try:
             i = self.opener(self.indexfile).read()
@@ -196,6 +197,10 @@
                 raise
             i = ""
 
+        if i and i[:4] != "\0\0\0\0":
+            raise RevlogError(_("incompatible revlog signature on %s") %
+                              self.indexfile)
+
         if len(i) > 10000:
             # big index, let's parse it on demand
             parser = lazyparser(i, self)
@@ -208,7 +213,7 @@
             m = [None] * l
 
             n = 0
-            for f in xrange(0, len(i), s):
+            for f in xrange(0, l * s, s):
                 # offset, size, base, linkrev, p1, p2, nodeid
                 e = struct.unpack(indexformat, i[f:f + s])
                 m[n] = (e[6], n)
@@ -473,6 +478,35 @@
         """apply a list of patches to a string"""
         return mdiff.patches(t, pl)
 
+    def chunk(self, rev):
+        start, length = self.start(rev), self.length(rev)
+        end = start + length
+
+        def loadcache():
+            cache_length = max(4096 * 1024, length) # 4Mo
+            df = self.opener(self.datafile)
+            df.seek(start)
+            self.chunkcache = (start, df.read(cache_length))
+
+        if not self.chunkcache:
+            loadcache()
+
+        cache_start = self.chunkcache[0]
+        cache_end = cache_start + len(self.chunkcache[1])
+        if start >= cache_start and end <= cache_end:
+            # it is cached
+            offset = start - cache_start
+        else:
+            loadcache()
+            offset = 0
+
+        #def checkchunk():
+        #    df = self.opener(self.datafile)
+        #    df.seek(start)
+        #    return df.read(length)
+        #assert s == checkchunk()
+        return decompress(self.chunkcache[1][offset:offset + length])
+
     def delta(self, node):
         """return or calculate a delta between a node and its predecessor"""
         r = self.rev(node)
@@ -481,10 +515,7 @@
             return self.diff(self.revision(self.node(r - 1)),
                              self.revision(node))
         else:
-            f = self.opener(self.datafile)
-            f.seek(self.start(r))
-            data = f.read(self.length(r))
-        return decompress(data)
+            return self.chunk(r)
 
     def revision(self, node):
         """return an uncompressed revision of a given"""
@@ -494,33 +525,22 @@
         # look up what we need to read
         text = None
         rev = self.rev(node)
-        start, length, base, link, p1, p2, node = self.index[rev]
-        end = start + length
-        if base != rev: start = self.start(base)
+        base = self.base(rev)
 
         # do we have useful data cached?
         if self.cache and self.cache[1] >= base and self.cache[1] < rev:
             base = self.cache[1]
-            start = self.start(base + 1)
             text = self.cache[2]
-            last = 0
-
-        f = self.opener(self.datafile)
-        f.seek(start)
-        data = f.read(end - start)
-
-        if text is None:
-            last = self.length(base)
-            text = decompress(data[:last])
+        else:
+            text = self.chunk(base)
 
         bins = []
         for r in xrange(base + 1, rev + 1):
-            s = self.length(r)
-            bins.append(decompress(data[last:last + s]))
-            last = last + s
+            bins.append(self.chunk(r))
 
         text = mdiff.patches(text, bins)
 
+        p1, p2 = self.parents(node)
         if node != hash(text, p1, p2):
             raise RevlogError(_("integrity check failed on %s:%d")
                           % (self.datafile, rev))
@@ -650,7 +670,7 @@
                 #print "next x"
                 gx = x.next()
 
-    def group(self, nodelist, lookup, infocollect = None):
+    def group(self, nodelist, lookup, infocollect=None):
         """calculate a delta group
 
         Given a list of changeset revs, return a set of deltas and
@@ -660,7 +680,6 @@
         changesets. parent is parent[0]
         """
         revs = [self.rev(n) for n in nodelist]
-        needed = dict.fromkeys(revs, 1)
 
         # if we don't have any revisions touched by these changesets, bail
         if not revs:
@@ -671,88 +690,30 @@
         p = self.parents(self.node(revs[0]))[0]
         revs.insert(0, self.rev(p))
 
-        # for each delta that isn't contiguous in the log, we need to
-        # reconstruct the base, reconstruct the result, and then
-        # calculate the delta. We also need to do this where we've
-        # stored a full version and not a delta
-        for i in xrange(0, len(revs) - 1):
-            a, b = revs[i], revs[i + 1]
-            if a + 1 != b or self.base(b) == b:
-                for j in xrange(self.base(a), a + 1):
-                    needed[j] = 1
-                for j in xrange(self.base(b), b + 1):
-                    needed[j] = 1
-
-        # calculate spans to retrieve from datafile
-        needed = needed.keys()
-        needed.sort()
-        spans = []
-        oo = -1
-        ol = 0
-        for n in needed:
-            if n < 0: continue
-            o = self.start(n)
-            l = self.length(n)
-            if oo + ol == o: # can we merge with the previous?
-                nl = spans[-1][2]
-                nl.append((n, l))
-                ol += l
-                spans[-1] = (oo, ol, nl)
-            else:
-                oo = o
-                ol = l
-                spans.append((oo, ol, [(n, l)]))
-
-        # read spans in, divide up chunks
-        chunks = {}
-        for span in spans:
-            # we reopen the file for each span to make http happy for now
-            f = self.opener(self.datafile)
-            f.seek(span[0])
-            data = f.read(span[1])
-
-            # divide up the span
-            pos = 0
-            for r, l in span[2]:
-                chunks[r] = decompress(data[pos: pos + l])
-                pos += l
-
         # helper to reconstruct intermediate versions
         def construct(text, base, rev):
-            bins = [chunks[r] for r in xrange(base + 1, rev + 1)]
+            bins = [self.chunk(r) for r in xrange(base + 1, rev + 1)]
             return mdiff.patches(text, bins)
 
         # build deltas
-        deltas = []
         for d in xrange(0, len(revs) - 1):
             a, b = revs[d], revs[d + 1]
-            n = self.node(b)
+            na = self.node(a)
+            nb = self.node(b)
 
             if infocollect is not None:
-                infocollect(n)
+                infocollect(nb)
 
             # do we need to construct a new delta?
             if a + 1 != b or self.base(b) == b:
-                if a >= 0:
-                    base = self.base(a)
-                    ta = chunks[self.base(a)]
-                    ta = construct(ta, base, a)
-                else:
-                    ta = ""
-
-                base = self.base(b)
-                if a > base:
-                    base = a
-                    tb = ta
-                else:
-                    tb = chunks[self.base(b)]
-                tb = construct(tb, base, b)
+                ta = self.revision(na)
+                tb = self.revision(nb)
                 d = self.diff(ta, tb)
             else:
-                d = chunks[b]
+                d = self.chunk(b)
 
-            p = self.parents(n)
-            meta = n + p[0] + p[1] + lookup(n)
+            p = self.parents(nb)
+            meta = nb + p[0] + p[1] + lookup(nb)
             l = struct.pack(">l", len(meta) + len(d) + 4)
             yield l
             yield meta
@@ -880,14 +841,29 @@
         expected = 0
         if self.count():
             expected = self.end(self.count() - 1)
+
         try:
             f = self.opener(self.datafile)
             f.seek(0, 2)
             actual = f.tell()
-            return expected - actual
+            dd = actual - expected
         except IOError, inst:
-            if inst.errno == errno.ENOENT:
-                return 0
-            raise
+            if inst.errno != errno.ENOENT:
+                raise
+            dd = 0
+
+        try:
+            f = self.opener(self.indexfile)
+            f.seek(0, 2)
+            actual = f.tell()
+            s = struct.calcsize(indexformat)
+            i = actual / s
+            di = actual - (i * s)
+        except IOError, inst:
+            if inst.errno != errno.ENOENT:
+                raise
+            di = 0
+
+        return (dd, di)
 
 
--- a/mercurial/statichttprepo.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/statichttprepo.py	Wed Feb 01 19:18:15 2006 +0100
@@ -35,6 +35,8 @@
         self.changelog = changelog.changelog(self.opener)
         self.tagscache = None
         self.nodetagscache = None
+        self.encodepats = None
+        self.decodepats = None
 
     def dev(self):
         return -1
--- a/mercurial/ui.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/ui.py	Wed Feb 01 19:18:15 2006 +0100
@@ -23,6 +23,7 @@
         self.interactive = self.configbool("ui", "interactive", True)
 
         self.updateopts(verbose, debug, quiet, interactive)
+        self.diffcache = None
 
     def updateopts(self, verbose=False, debug=False, quiet=False,
                  interactive=True):
@@ -76,6 +77,23 @@
     def extensions(self):
         return self.configitems("extensions")
 
+    def diffopts(self):
+        if self.diffcache:
+            return self.diffcache
+        ret = { 'showfunc' : True, 'ignorews' : False}
+        for x in self.configitems("diff"):
+            k = x[0].lower()
+            v = x[1]
+            if v:
+                v = v.lower()
+                if v == 'true':
+                    value = True
+                else:
+                    value = False
+                ret[k] = value
+        self.diffcache = ret
+        return ret
+
     def username(self):
         return (os.environ.get("HGUSER") or
                 self.config("ui", "username") or
@@ -110,7 +128,7 @@
             sys.stdout.write(str(a))
 
     def write_err(self, *args):
-        sys.stdout.flush()
+        if not sys.stdout.closed: sys.stdout.flush()
         for a in args:
             sys.stderr.write(str(a))
 
--- a/mercurial/util.py	Thu Dec 15 18:04:39 2005 +0100
+++ b/mercurial/util.py	Wed Feb 01 19:18:15 2006 +0100
@@ -13,7 +13,8 @@
 import os, errno
 from i18n import gettext as _
 from demandload import *
-demandload(globals(), "re cStringIO shutil popen2 sys tempfile threading time")
+demandload(globals(), "cStringIO errno popen2 re shutil sys tempfile")
+demandload(globals(), "threading time")
 
 def pipefilter(s, cmd):
     '''filter string S through command CMD, returning its output'''
@@ -190,17 +191,17 @@
     else:
         raise Abort('%s not under root' % myname)
 
-def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head=''):
-    return _matcher(canonroot, cwd, names, inc, exc, head, 'glob')
+def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
+    return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src)
 
-def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head=''):
+def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
     if os.name == 'nt':
         dflt_pat = 'glob'
     else:
         dflt_pat = 'relpath'
-    return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat)
+    return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src)
 
-def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat):
+def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src):
     """build a function to match a set of file patterns
 
     arguments:
@@ -261,7 +262,8 @@
                 pat = '(?:%s)' % regex(k, p, tail)
                 matches.append(re.compile(pat).match)
             except re.error:
-                raise Abort("invalid pattern: %s:%s" % (k, p))
+                if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
+                else: raise Abort("invalid pattern (%s): %s" % (k, p))
 
         def buildfn(text):
             for m in matches:
@@ -357,9 +359,9 @@
                 os_link(src, dst)
             except:
                 hardlink = False
-                shutil.copy2(src, dst)
+                shutil.copy(src, dst)
         else:
-            shutil.copy2(src, dst)
+            shutil.copy(src, dst)
 
 def opener(base):
     """
@@ -442,12 +444,36 @@
 if os.name == 'nt':
     demandload(globals(), "msvcrt")
     nulldev = 'NUL:'
-    
+
+    class winstdout:
+        '''stdout on windows misbehaves if sent through a pipe'''
+
+        def __init__(self, fp):
+            self.fp = fp
+
+        def __getattr__(self, key):
+            return getattr(self.fp, key)
+
+        def close(self):
+            try:
+                self.fp.close()
+            except: pass
+
+        def write(self, s):
+            try:
+                return self.fp.write(s)
+            except IOError, inst:
+                if inst.errno != 0: raise
+                self.close()
+                raise IOError(errno.EPIPE, 'Broken pipe')
+
+    sys.stdout = winstdout(sys.stdout)
+
     try:
         import win32api, win32process
         filename = win32process.GetModuleFileNameEx(win32api.GetCurrentProcess(), 0)
         systemrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
-        
+
     except ImportError:
         systemrc = r'c:\mercurial\mercurial.ini'
         pass
@@ -518,14 +544,19 @@
                         if f.endswith(".rc")])
         except OSError, inst: pass
         return rcs
-    rcpath = rcfiles(os.path.dirname(sys.argv[0]) + '/../etc/mercurial')
+    rcpath = []
+    if len(sys.argv) > 0:
+        rcpath.extend(rcfiles(os.path.dirname(sys.argv[0]) + '/../etc/mercurial'))
     rcpath.extend(rcfiles('/etc/mercurial'))
     rcpath.append(os.path.expanduser('~/.hgrc'))
     rcpath = [os.path.normpath(f) for f in rcpath]
 
     def parse_patch_output(output_line):
         """parses the output produced by patch and returns the file name"""
-        return output_line[14:]
+        pf = output_line[14:]
+        if pf.startswith("'") and pf.endswith("'") and pf.find(" ") >= 0:
+            pf = pf[1:-1] # Remove the quotes
+        return pf
 
     def is_exec(f, last):
         """check whether a file is executable"""
--- a/templates/changelog-gitweb.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/changelog-gitweb.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -11,7 +11,7 @@
 
 <form action="#">
 <div class="search">
-<input type="hidden" name="repo" value="#repo#"  />
+<input type="hidden" name="repo" value="#repo|escape#"  />
 <input type="hidden" name="style" value="gitweb"  />
 <input type="hidden" name="cmd" value="changelog"  />
 <input type="text" name="rev"  />
--- a/templates/changelogentry-gitweb.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/changelogentry-gitweb.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -8,7 +8,7 @@
 <i>#author|obfuscate# [#date|rfc822date#]</i><br/>
 </div>
 <div class="log_body">
-#desc|addbreaks#
+#desc|escape|addbreaks#
 <br/>
 <br/>
 </div>
--- a/templates/changelogentry.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/changelogentry.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -8,6 +8,7 @@
   <td class="changesetNode"><a href="?cs=#node|short#">#node|short#</a></td>
  </tr>
  #parent%changelogparent#
+ #child%changelogchild#
  #changelogtag#
  <tr>
   <th class="author">author:</th>
--- a/templates/changeset-gitweb.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/changeset-gitweb.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;rev=#rev#;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a> | changeset | <a href="?cmd=changeset;node=#node#;style=raw">raw</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;rev=#rev#;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a> | changeset | <a href="?cmd=changeset;node=#node#;style=raw">raw</a> #archives%archiveentry#<br/>
 </div>
 
 <div>
@@ -23,11 +23,12 @@
 <tr><td>changeset</td><td style="font-family:monospace">#node|short#</td></tr>
 <tr><td>manifest</td><td style="font-family:monospace"><a class="list" href="?cmd=manifest;manifest=#manifest|short#;path=/;style=gitweb">#manifest|short#</a></td></tr>
 #parent%changesetparent#
+#child%changesetchild#
 #changesettag#
 </table></div>
 
 <div class="title_text">
-#desc|addbreaks#
+#desc|escape|addbreaks#
 </div>
 
 <div class="title_text">
--- a/templates/changeset.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/changeset.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -19,6 +19,7 @@
  <td class="changeset"><a href="?cs=#node|short#">#node|short#</a></td>
 </tr>
 #parent%changesetparent#
+#child%changesetchild#
 #changesettag#
 <tr>
  <th class="author">author:</th>
--- a/templates/fileannotate-gitweb.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/fileannotate-gitweb.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -10,16 +10,17 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file#;filenode=#filenode#;style=gitweb">revisions</a> | annotate<br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | annotate<br/>
 </div>
 
-<div class="title">#file#</div>
+<div class="title">#file|escape#</div>
 
 <table>
 <tr>
  <td class="metatag">changeset #rev#:</td>
  <td><a href="?cs=#node|short#;style=gitweb">#node|short#</a></td></tr>
 #parent%fileannotateparent#
+#child%fileannotatechild#
 <tr>
  <td class="metatag">manifest:</td>
  <td><a href="?mf=#manifest|short#;path=/;style=gitweb">#manifest|short#</a></td></tr>
--- a/templates/fileannotate.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/fileannotate.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -1,5 +1,5 @@
 #header#
-<title>#repo|escape#: #file# annotate</title>
+<title>#repo|escape#: #file|escape# annotate</title>
 </head>
 <body>
 
@@ -7,18 +7,20 @@
 <a href="?cl=#rev#">changelog</a>
 <a href="?tags=">tags</a>
 <a href="?cs=#node|short#">changeset</a>
-<a href="?mf=#manifest|short#;path=#path#">manifest</a>
-<a href="?f=#filenode|short#;file=#file#">file</a>
-<a href="?fl=#filenode|short#;file=#file#">revisions</a>
+<a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a>
+<a href="?f=#filenode|short#;file=#file|urlescape#">file</a>
+<a href="?fl=#filenode|short#;file=#file|urlescape#">revisions</a>
 </div>
 
-<h2>Annotate #file#</h2>
+<h2>Annotate #file|escape#</h2>
 
 <table>
 <tr>
  <td class="metatag">changeset #rev#:</td>
  <td><a href="?cs=#node|short#">#node|short#</a></td></tr>
+#rename%filerename#
 #parent%fileannotateparent#
+#child%fileannotatechild#
 <tr>
  <td class="metatag">author:</td>
  <td>#author|obfuscate#</td></tr>
--- a/templates/filediff.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/filediff.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -1,5 +1,5 @@
 #header#
-<title>#repo|escape#: #file# diff</title>
+<title>#repo|escape#: #file|escape# diff</title>
 </head>
 <body>
 
@@ -7,13 +7,13 @@
 <a href="?cl=#rev#">changelog</a>
 <a href="?tags=">tags</a>
 <a href="?cs=#node|short#">changeset</a>
-<a href="?f=#filenode|short#;file=#file#">file</a>
-<a href="?fl=#filenode|short#;file=#file#">revisions</a>
-<a href="?fa=#filenode|short#;file=#file#">annotate</a>
-<a href="?fd=#node|short#;file=#file#;style=raw">raw</a>
+<a href="?f=#filenode|short#;file=#file|urlescape#">file</a>
+<a href="?fl=#filenode|short#;file=#file|urlescape#">revisions</a>
+<a href="?fa=#filenode|short#;file=#file|urlescape#">annotate</a>
+<a href="?fd=#node|short#;file=#file|urlescape#;style=raw">raw</a>
 </div>
 
-<h2>#file#</h2>
+<h2>#file|escape#</h2>
 
 <table id="filediffEntry">
 <tr>
@@ -21,6 +21,7 @@
  <td class="revision"><a href="?cs=#node|short#">#node|short#</a></td>
 </tr>
 #parent%filediffparent#
+#child%filediffchild#
 </table>
 
 <div id="fileDiff">
--- a/templates/filelog-gitweb.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/filelog-gitweb.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=file;file=#file#;filenode=#filenode#;style=gitweb">file</a> | revisions | <a href="?cmd=annotate;file=#file#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?fl=#filenode|short#;file=#file#;style=rss">rss</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | revisions | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?fl=#filenode|short#;file=#file|urlescape#;style=rss">rss</a><br/>
 </div>
 
 <table>
--- a/templates/filelog-rss.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/filelog-rss.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -1,6 +1,6 @@
 #header#
-    <title>#repo|escape#: #file# history</title>
-    <description>#file# revision history</description>
+    <title>#repo|escape#: #file|escape# history</title>
+    <description>#file|escape# revision history</description>
     #entries%filelogentry#
   </channel>
-</rss>
\ No newline at end of file
+</rss>
--- a/templates/filelog.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/filelog.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -1,7 +1,7 @@
 #header#
-<title>#repo|escape#: #file# history</title>
+<title>#repo|escape#: #file|escape# history</title>
 <link rel="alternate" type="application/rss+xml"
-   href="?fl=0;file=#file#;style=rss" title="RSS feed for #repo|escape#:#file#">
+   href="?fl=0;file=#file|urlescape#;style=rss" title="RSS feed for #repo|escape#:#file#">
 </head>
 </head>
 <body>
@@ -9,12 +9,12 @@
 <div class="buttons">
 <a href="?cl=tip">changelog</a>
 <a href="?tags=">tags</a>
-<a href="?f=#filenode|short#;file=#file#">file</a>
-<a href="?fa=#filenode|short#;file=#file#">annotate</a>
-<a type="application/rss+xml" href="?fl=0;file=#file#;style=rss">rss</a>
+<a href="?f=#filenode|short#;file=#file|urlescape#">file</a>
+<a href="?fa=#filenode|short#;file=#file|urlescape#">annotate</a>
+<a type="application/rss+xml" href="?fl=0;file=#file|urlescape#;style=rss">rss</a>
 </div>
 
-<h2>#file# revision history</h2>
+<h2>#file|escape# revision history</h2>
 
 #entries%filelogentry#
 
--- a/templates/filelogentry-rss.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/filelogentry-rss.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -1,6 +1,6 @@
 <item>
     <title>#desc|strip|firstline|strip|escape#</title>
-    <link>#url#?f=#filenode|short#;file=#file#</link>
+    <link>#url#?f=#filenode|short#;file=#file|urlescape#</link>
     <description><![CDATA[#desc|strip|escape|addbreaks#]]></description>
     <author>#author|obfuscate#</author>
     <pubDate>#date|rfc822date#</pubDate>>
--- a/templates/filelogentry.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/filelogentry.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -4,10 +4,11 @@
  <td><b><a href="?cs=#node|short#">#desc|strip|firstline|escape#</a></b></td></tr>
 <tr>
  <td align="right">revision #filerev#:&nbsp;</td>
- <td><a href="?f=#filenode|short#;file=#file#">#filenode|short#</a>
-<a href="?fd=#node|short#;file=#file#">(diff)</a>
-<a href="?fa=#filenode|short#;file=#file#">(annotate)</a>
+ <td><a href="?f=#filenode|short#;file=#file|urlescape#">#filenode|short#</a>
+<a href="?fd=#node|short#;file=#file|urlescape#">(diff)</a>
+<a href="?fa=#filenode|short#;file=#file|urlescape#">(annotate)</a>
 </td></tr>
+#rename%filelogrename#
 <tr>
  <td align="right">author:&nbsp;</td>
  <td>#author|obfuscate#</td></tr>
--- a/templates/filerevision-gitweb.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/filerevision-gitweb.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -10,16 +10,17 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?mf=#manifest|short#;path=#path#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | file | <a href="?cmd=filelog;file=#file#;filenode=#filenode#;style=gitweb">revisions</a> | <a href="?cmd=annotate;file=#file#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?cmd=file;file=#file#;filenode=#filenode#;style=raw">raw</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?mf=#manifest|short#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | file | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/>
 </div>
 
-<div class="title">#file#</div>
+<div class="title">#file|escape#</div>
 
 <table>
 <tr>
  <td class="metatag">changeset #rev#:</td>
  <td><a href="?cs=#node|short#;style=gitweb">#node|short#</a></td></tr>
 #parent%fileannotateparent#
+#child%fileannotatechild#
 <tr>
  <td class="metatag">manifest:</td>
  <td><a href="?mf=#manifest|short#;path=/;style=gitweb">#manifest|short#</a></td></tr>
--- a/templates/filerevision.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/filerevision.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -1,5 +1,5 @@
 #header#
-<title>#repo|escape#:#file#</title>
+<title>#repo|escape#:#file|escape#</title>
 </head>
 <body>
 
@@ -7,19 +7,21 @@
 <a href="?cl=#rev#">changelog</a>
 <a href="?tags=">tags</a>
 <a href="?cs=#node|short#">changeset</a>
-<a href="?mf=#manifest|short#;path=#path#">manifest</a>
-<a href="?fl=#filenode|short#;file=#file#">revisions</a>
-<a href="?fa=#filenode|short#;file=#file#">annotate</a>
-<a href="?f=#filenode|short#;file=#file#;style=raw">raw</a>
+<a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a>
+<a href="?fl=#filenode|short#;file=#file|urlescape#">revisions</a>
+<a href="?fa=#filenode|short#;file=#file|urlescape#">annotate</a>
+<a href="?f=#filenode|short#;file=#file|urlescape#;style=raw">raw</a>
 </div>
 
-<h2>#file#</h2>
+<h2>#file|escape#</h2>
 
 <table>
 <tr>
  <td class="metatag">changeset #rev#:</td>
  <td><a href="?cs=#node|short#">#node|short#</a></td></tr>
+#rename%filerename#
 #parent%filerevparent#
+#child%filerevchild#
 <tr>
  <td class="metatag">author:</td>
  <td>#author|obfuscate#</td></tr>
--- a/templates/header.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/header.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -3,6 +3,7 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
+<meta name="robots" content="index, nofollow" />
 <style type="text/css">
 <!--
 a { text-decoration:none; }
--- a/templates/manifest-gitweb.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/manifest-gitweb.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | manifest | <a href="?cs=#node|short#;style=gitweb">changeset</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | manifest | <a href="?cs=#node|short#;style=gitweb">changeset</a> #archives%archiveentry#<br/>
 </div>
 
 <div class="title" >#path|escape#</div>
@@ -18,7 +18,7 @@
 <table cellspacing="0">
 <tr class="light">
 <td style="font-family:monospace">drwxr-xr-x</td>
-<td><a href="?cmd=manifest;manifest=#manifest#;path=#up#;style=gitweb">[up]</a></td>
+<td><a href="?cmd=manifest;manifest=#manifest#;path=#up|urlescape#;style=gitweb">[up]</a></td>
 <td class="link">&nbsp;</td>
 </tr>
 #dentries%manifestdirentry#
--- a/templates/manifest.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/manifest.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -10,12 +10,12 @@
 #archives%archiveentry#
 </div>
 
-<h2>manifest for changeset #node|short#: #path#</h2>
+<h2>manifest for changeset #node|short#: #path|escape#</h2>
 
 <table cellpadding="0" cellspacing="0">
 <tr class="parity1">
   <td><tt>drwxr-xr-x</tt>&nbsp;
-  <td><a href="?mf=#manifest|short#;path=#up#">[up]</a>
+  <td><a href="?mf=#manifest|short#;path=#up|urlescape#">[up]</a>
 #dentries%manifestdirentry#
 #fentries%manifestfileentry#
 </table>
--- a/templates/map	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/map	Wed Feb 01 19:18:15 2006 +0100
@@ -3,16 +3,16 @@
 footer = footer.tmpl
 search = search.tmpl
 changelog = changelog.tmpl
-naventry = "<a href="?cl=#rev#">#label#</a> "
-filedifflink = "<a href="?fd=#node|short#;file=#file#">#file#</a> "
-filenodelink = "<a href="?f=#filenode|short#;file=#file#">#file#</a> "
+naventry = "<a href="?cl=#rev#">#label|escape#</a> "
+filedifflink = "<a href="?fd=#node|short#;file=#file|urlescape#">#file|escape#</a> "
+filenodelink = "<a href="?f=#filenode|short#;file=#file|urlescape#">#file|escape#</a> "
 fileellipses = "..."
 changelogentry = changelogentry.tmpl
 searchentry = changelogentry.tmpl
 changeset = changeset.tmpl
 manifest = manifest.tmpl
-manifestdirentry = "<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td><a href="?cmd=manifest;manifest=#manifest#;path=#path#">#basename#/</a>"
-manifestfileentry = "<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td><a href="?f=#filenode|short#;file=#file#">#basename#</a>"
+manifestdirentry = "<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td><a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#">#basename|escape#/</a>"
+manifestfileentry = "<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td><a href="?f=#filenode|short#;file=#file|urlescape#">#basename|escape#</a>"
 filerevision = filerevision.tmpl
 fileannotate = fileannotate.tmpl
 filediff = filediff.tmpl
@@ -26,17 +26,25 @@
 diffline = "#line|escape#"
 changelogparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
 changesetparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
-filerevparent = "<tr><td class="metatag">parent:</td><td><a href="?f=#node|short#;file=#file#">#node|short#</a></td></tr>"
-fileannotateparent = "<tr><td class="metatag">parent:</td><td><a href="?fa=#filenode|short#;file=#file#">#node|short#</a></td></tr>"
+filerevparent = "<tr><td class="metatag">parent:</td><td><a href="?f=#node|short#;file=#file|urlescape#">#node|short#</a></td></tr>"
+filerename = "<tr><td class="metatag">parent:</td><td><a href="?f=#node|short#;file=#file|urlescape#">#file|escape#@#node|short#</a></td></tr>"
+filelogrename = "<tr><td align="right">base:&nbsp;</td><td><a href="?f=#node|short#;file=#file|urlescape#">#file|escape#@#node|short#</a></td></tr>"
+fileannotateparent = "<tr><td class="metatag">parent:</td><td><a href="?fa=#filenode|short#;file=#file|urlescape#">#node|short#</a></td></tr>"
+changesetchild = "<tr><th class="child">child #rev#:</th><td class="child"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
+changelogchild = "<tr><th class="child">child #rev#:</th><td class="child"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
+filerevchild = "<tr><td class="metatag">child:</td><td><a href="?f=#node|short#;file=#file|urlescape#">#node|short#</a></td></tr>"
+fileannotatechild = "<tr><td class="metatag">child:</td><td><a href="?fa=#filenode|short#;file=#file|urlescape#">#node|short#</a></td></tr>"
 tags = tags.tmpl
-tagentry = "<li class="tagEntry parity#parity#"><span class="node">#node#</span> <a href="?cs=#node|short#">#tag#</a></li>"
+tagentry = "<li class="tagEntry parity#parity#"><span class="node">#node#</span> <a href="?cs=#node|short#">#tag|escape#</a></li>"
 diffblock = "<pre class="parity#parity#">#lines#</pre>"
-changelogtag = "<tr><th class="tag">tag:</th><td class="tag">#tag#</td></tr>"
-changesettag = "<tr><th class="tag">tag:</th><td class="tag">#tag#</td></tr>"
+changelogtag = "<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>"
+changesettag = "<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>"
 filediffparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
-filelogparent = "<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="?f=#node|short#;file=#file#">#node|short#</a></td></tr>"
-indexentry = "<tr class="parity#parity#"><td><a href="#url#">#name#</a></td><td>#shortdesc#</td><td>#contact|obfuscate#</td><td>#lastupdate|age# ago</td><td><a href="#url#?cl=tip;style=rss">RSS</a></td></tr>"
+filelogparent = "<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="?f=#node|short#;file=#file|urlescape#">#node|short#</a></td></tr>"
+filediffchild = "<tr><th class="child">child #rev#:</th><td class="child"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
+filelogchild = "<tr><td align="right">child #rev#:&nbsp;</td><td><a href="?f=#node|short#;file=#file|urlescape#">#node|short#</a></td></tr>"
+indexentry = "<tr class="parity#parity#"><td><a href="#url#">#name|escape#</a></td><td>#shortdesc|escape#</td><td>#contact|obfuscate#</td><td>#lastupdate|age# ago</td><td><a href="#url#?cl=tip;style=rss">RSS</a></td></tr>"
 index = index.tmpl
-archiveentry = "<a href="?ca=#node|short#;type=#type#">#type#</a> "
+archiveentry = "<a href="?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> "
 notfound = notfound.tmpl
 error = error.tmpl
--- a/templates/map-gitweb	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/map-gitweb	Wed Feb 01 19:18:15 2006 +0100
@@ -5,17 +5,17 @@
 changelog = changelog-gitweb.tmpl
 summary = summary-gitweb.tmpl
 error = error-gitweb.tmpl
-naventry = "<a href="?cmd=changelog;rev=#rev#;style=gitweb">#label#</a> "
-navshortentry = "<a href="?cmd=shortlog;rev=#rev#;style=gitweb">#label#</a> "
-filedifflink = "<a href="?cmd=filediff;node=#node#;file=#file#;style=gitweb">#file#</a> "
-filenodelink = "<tr class="light"><td><a class="list" href="">#file#</a></td><td></td><td class="link"><a href="?cmd=file;filenode=#filenode#;file=#file#;style=gitweb">file</a> | <!-- FIXME: <a href="?fd=#filenode|short#;file=#file#;style=gitweb">diff</a> | --> <a href="?cmd=filelog;filenode=#filenode|short#;file=#file#;style=gitweb">revisions</a></td></tr>"
+naventry = "<a href="?cmd=changelog;rev=#rev#;style=gitweb">#label|escape#</a> "
+navshortentry = "<a href="?cmd=shortlog;rev=#rev#;style=gitweb">#label|escape#</a> "
+filedifflink = "<a href="?cmd=filediff;node=#node#;file=#file|urlescape#;style=gitweb">#file|escape#</a> "
+filenodelink = "<tr class="light"><td><a class="list" href="">#file|escape#</a></td><td></td><td class="link"><a href="?cmd=file;filenode=#filenode#;file=#file|urlescape#;style=gitweb">file</a> | <!-- FIXME: <a href="?fd=#filenode|short#;file=#file|urlescape#;style=gitweb">diff</a> | --> <a href="?cmd=filelog;filenode=#filenode|short#;file=#file|urlescape#;style=gitweb">revisions</a></td></tr>"
 fileellipses = "..."
 changelogentry = changelogentry-gitweb.tmpl
 searchentry = changelogentry-gitweb.tmpl
 changeset = changeset-gitweb.tmpl
 manifest = manifest-gitweb.tmpl
-manifestdirentry = "<tr class="parity#parity#"><td style="font-family:monospace">drwxr-xr-x</td><td><a href="?mf=#manifest|short#;path=#path#;style=gitweb">#basename#/</a></td><td class="link"><a href="?mf=#manifest|short#;path=#path#;style=gitweb">manifest</a></td></tr>"
-manifestfileentry = "<tr class="parity#parity#"><td style="font-family:monospace">#permissions|permissions#</td><td class="list"><a class="list" href="?f=#filenode|short#;file=#file#;style=gitweb">#basename#</a></td><td class="link"><a href="?f=#filenode|short#;file=#file#;style=gitweb">file</a> | <a href="?fl=#filenode|short#;file=#file#;style=gitweb">revisions</a> | <a href="?fa=#filenode|short#;file=#file#;style=gitweb">annotate</a></td></tr>"
+manifestdirentry = "<tr class="parity#parity#"><td style="font-family:monospace">drwxr-xr-x</td><td><a href="?mf=#manifest|short#;path=#path|urlescape#;style=gitweb">#basename|escape#/</a></td><td class="link"><a href="?mf=#manifest|short#;path=#path|urlescape#;style=gitweb">manifest</a></td></tr>"
+manifestfileentry = "<tr class="parity#parity#"><td style="font-family:monospace">#permissions|permissions#</td><td class="list"><a class="list" href="?f=#filenode|short#;file=#file|urlescape#;style=gitweb">#basename|escape#</a></td><td class="link"><a href="?f=#filenode|short#;file=#file|urlescape#;style=gitweb">file</a> | <a href="?fl=#filenode|short#;file=#file|urlescape#;style=gitweb">revisions</a> | <a href="?fa=#filenode|short#;file=#file|urlescape#;style=gitweb">annotate</a></td></tr>"
 filerevision = filerevision-gitweb.tmpl
 fileannotate = fileannotate-gitweb.tmpl
 filelog = filelog-gitweb.tmpl
@@ -28,15 +28,22 @@
 diffline = "<div class="pre">#line|escape#</div>"
 changelogparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>"
 changesetparent = "<tr><td>parent</td><td style="font-family:monospace"><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb">#node|short#</a></td></tr>"
-filerevparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=file;file=#file#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>"
-fileannotateparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=annotate;file=#file#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>"
+filerevparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=file;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>"
+fileannotateparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=annotate;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>"
+changelogchild = "<tr><th class="child">child #rev#:</th><td class="child"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>"
+changesetchild = "<tr><td>child</td><td style="font-family:monospace"><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb">#node|short#</a></td></tr>"
+filerevchild = "<tr><td class="metatag">child:</td><td><a href="?cmd=file;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>"
+fileannotatechild = "<tr><td class="metatag">child:</td><td><a href="?cmd=annotate;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>"
 tags = tags-gitweb.tmpl
-tagentry = "<tr class="parity#parity#"><td><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#tag#</b></a></td><td class="link"><a href="?cmd=changeset;node=#node|short#;style=gitweb">changeset</a> | <a href="?cmd=changelog;rev=#node|short#;style=gitweb">changelog</a> |  <a href="?mf=#tagmanifest|short#;path=/;style=gitweb">manifest</a></td></tr>"
+tagentry = "<tr class="parity#parity#"><td><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#tag|escape#</b></a></td><td class="link"><a href="?cmd=changeset;node=#node|short#;style=gitweb">changeset</a> | <a href="?cmd=changelog;rev=#node|short#;style=gitweb">changelog</a> |  <a href="?mf=#tagmanifest|short#;path=/;style=gitweb">manifest</a></td></tr>"
 diffblock = "#lines#"
-changelogtag = "<tr><th class="tag">tag:</th><td class="tag">#tag#</td></tr>"
-changesettag = "<tr><td>tag</td><td>#tag#</td></tr>"
+changelogtag = "<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>"
+changesettag = "<tr><td>tag</td><td>#tag|escape#</td></tr>"
 filediffparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>"
-filelogparent = "<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="?cmd=file;file=#file#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>"
+filelogparent = "<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="?cmd=file;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>"
+filediffchild = "<tr><th class="child">child #rev#:</th><td class="child"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>"
+filelogchild = "<tr><td align="right">child #rev#:&nbsp;</td><td><a href="?cmd=file;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>"
 shortlog = shortlog-gitweb.tmpl
 shortlogentry = "<tr class="parity#parity#"><td><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|firstline|escape#</b></a></td><td class="link"><a href="?cmd=changeset;node=#node|short#;style=gitweb">changeset</a> |  <a href="?cmd=manifest;manifest=#manifest|short#;path=/;style=gitweb">manifest</a></td></tr>"
-filelogentry = "<tr class="parity#parity#"><td><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|firstline|escape#</b></a></td><td class="link"><!-- FIXME: <a href="?fd=#node|short#;file=#file#;style=gitweb">diff</a> | --> <a href="?fa=#filenode|short#;file=#file#;style=gitweb">annotate</a></td></tr>"
+filelogentry = "<tr class="parity#parity#"><td><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|firstline|escape#</b></a></td><td class="link"><!-- FIXME: <a href="?fd=#node|short#;file=#file|urlescape#;style=gitweb">diff</a> | --> <a href="?fa=#filenode|short#;file=#file|urlescape#;style=gitweb">annotate</a></td></tr>"
+archiveentry = " | <a href="?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> "
--- a/templates/map-raw	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/map-raw	Wed Feb 01 19:18:15 2006 +0100
@@ -1,14 +1,15 @@
 header = header-raw.tmpl
 footer = ""
 changeset = changeset-raw.tmpl
-annotateline = "<tr class="parity#parity#"><td class="annotate"><a href="?cmd=changeset;node=#node#">#author#@#rev#</a></td><td><pre>#line#</pre></td></tr>"
-difflineplus = "#line#"
-difflineminus = "#line#"
-difflineat = "#line#"
-diffline = "#line#"
+annotateline = "<tr class="parity#parity#"><td class="annotate"><a href="?cmd=changeset;node=#node#">#author#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>"
+difflineplus = "#line|escape#"
+difflineminus = "#line|escape#"
+difflineat = "#line|escape#"
+diffline = "#line|escape#"
 changesetparent = "# parent: #node#"
-filenodelink = "#file#"
+changesetchild = "# child: #node#"
+filenodelink = "#file|urlescape#"
 filerevision = filerevision-raw.tmpl
-fileline = "#line#"
+fileline = "#line|escape#"
 diffblock = "#lines#"
 filediff = filediff-raw.tmpl
--- a/templates/summary-gitweb.tmpl	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/summary-gitweb.tmpl	Wed Feb 01 19:18:15 2006 +0100
@@ -14,8 +14,8 @@
 
 <div class="title">&nbsp;</div>
 <table cellspacing="0">
-<tr><td>description</td><td>#desc#</td></tr>
-<tr><td>owner</td><td>#owner#</td></tr>
+<tr><td>description</td><td>#desc|escape#</td></tr>
+<tr><td>owner</td><td>#owner|escape#</td></tr>
 <!-- <tr><td>last change</td><td>#lastchange|rfc822date#</td></tr> -->
 </table>
 
--- a/templates/template-vars.txt	Thu Dec 15 18:04:39 2005 +0100
+++ b/templates/template-vars.txt	Wed Feb 01 19:18:15 2006 +0100
@@ -18,6 +18,7 @@
 shortdesc         a short description (escaped)
 author        a name or email addressv(obfuscated)
 parent        a list of the parent
+child         a list of the children
 tags          a list of tag
 
 header        the global page header
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-addremove	Wed Feb 01 19:18:15 2006 +0100
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+hg init rep
+cd rep
+mkdir dir
+touch foo dir/bar
+hg -v addremove
+hg -v commit -m "add 1" -d "0 0"
+cd dir/
+touch ../foo_2 bar_2
+hg -v addremove
+hg -v commit -m "add 2" -d "0 0"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-addremove.out	Wed Feb 01 19:18:15 2006 +0100
@@ -0,0 +1,8 @@
+adding dir/bar
+adding foo
+dir/bar
+foo
+adding dir/bar_2
+adding foo_2
+dir/bar_2
+foo_2
--- a/tests/test-cat.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-cat.out	Wed Feb 01 19:18:15 2006 +0100
@@ -3,5 +3,5 @@
 0
 0
 0
-a: No such file in rev 551e7cb14b32
+a: No such file in rev 7040230c159c
 1
--- a/tests/test-help.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-help.out	Wed Feb 01 19:18:15 2006 +0100
@@ -64,7 +64,7 @@
  paths       show definition of symbolic path names
  pull        pull changes from the specified source
  push        push changes to the specified destination
- rawcommit   raw commit interface
+ rawcommit   raw commit interface (DEPRECATED)
  recover     roll back an interrupted transaction
  remove      remove the specified files on the next commit
  rename      rename files; equivalent of copy + remove
@@ -106,7 +106,7 @@
  paths       show definition of symbolic path names
  pull        pull changes from the specified source
  push        push changes to the specified destination
- rawcommit   raw commit interface
+ rawcommit   raw commit interface (DEPRECATED)
  recover     roll back an interrupted transaction
  remove      remove the specified files on the next commit
  rename      rename files; equivalent of copy + remove
@@ -186,6 +186,7 @@
     M = modified
     A = added
     R = removed
+    ! = deleted, but still tracked
     ? = not tracked
 
 aliases: st
@@ -195,6 +196,7 @@
  -m --modified   show only modified files
  -a --added      show only added files
  -r --removed    show only removed files
+ -d --deleted    show only deleted (but tracked) files
  -u --unknown    show only unknown (not tracked) files
  -n --no-status  hide status prefix
  -0 --print0     end filenames with NUL, for use with xargs
--- a/tests/test-hgignore.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-hgignore.out	Wed Feb 01 19:18:15 2006 +0100
@@ -5,14 +5,14 @@
 ? dir/c.o
 ? syntax
 --
-abort: invalid pattern: relre:*.o
+abort: .hgignore: invalid pattern (relre): *.o
 --
 A dir/b.o
 ? .hgignore
 ? a.c
 ? syntax
 --
-ignoring invalid syntax 'invalid'
+.hgignore: ignoring invalid syntax 'invalid'
 A dir/b.o
 ? .hgignore
 ? a.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-locate	Wed Feb 01 19:18:15 2006 +0100
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+mkdir t
+cd t
+hg init
+echo 0 > a
+echo 0 > b
+hg ci -A -m m -d "0 0"
+touch nottracked
+hg locate a
+hg locate NONEXISTENT
+hg locate
+hg rm a
+hg ci -m m -d "0 0"
+hg locate a
+hg locate NONEXISTENT
+hg locate
+hg locate -r 0 a
+hg locate -r 0 NONEXISTENT
+hg locate -r 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-locate.out	Wed Feb 01 19:18:15 2006 +0100
@@ -0,0 +1,13 @@
+adding a
+adding b
+a
+NONEXISTENT: No such file or directory
+a
+b
+a: No such file or directory
+NONEXISTENT: No such file or directory
+b
+a
+NONEXISTENT: No such file in rev 9e1684505872
+a
+b
--- a/tests/test-merge-revert2.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-merge-revert2.out	Wed Feb 01 19:18:15 2006 +0100
@@ -11,7 +11,7 @@
 diff -r f4d7a8c73d23 file1
 --- a/file1
 +++ b/file1
-@@ -1,3 +1,7 @@
+@@ -1,3 +1,7 @@ added file1
  added file1
  another line of text
 +<<<<<<<
--- a/tests/test-rawcommit1.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-rawcommit1.out	Wed Feb 01 19:18:15 2006 +0100
@@ -1,5 +1,6 @@
 05f9e54f4c9b86b09099803d8b49a50edcb4eaab 644 a
 54837d97f2932a8194e69745a280a2c11e61ff9c 644 b
+(the rawcommit command is deprecated)
 05f9e54f4c9b86b09099803d8b49a50edcb4eaab 644 a
 54837d97f2932a8194e69745a280a2c11e61ff9c 644 b
 76d5e637cbec1bcc04a5a3fa4bcc7d13f6847c00 644 c
@@ -9,6 +10,7 @@
 date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     2
 
+(the rawcommit command is deprecated)
 05f9e54f4c9b86b09099803d8b49a50edcb4eaab 644 a
 76d5e637cbec1bcc04a5a3fa4bcc7d13f6847c00 644 c
 changeset:   3:142428fbbcc5
@@ -17,6 +19,7 @@
 date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     3
 
+(the rawcommit command is deprecated)
 d6e3c4976c13feb1728cd3ac851abaf7256a5c23 644 a
 76d5e637cbec1bcc04a5a3fa4bcc7d13f6847c00 644 c
 changeset:   4:4d450f9aa680
@@ -25,6 +28,7 @@
 date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     4
 
+(the rawcommit command is deprecated)
 05f9e54f4c9b86b09099803d8b49a50edcb4eaab 644 a
 54837d97f2932a8194e69745a280a2c11e61ff9c 644 b
 3570202ceac2b52517df64ebd0a062cb0d8fe33a 644 c
@@ -33,6 +37,7 @@
 date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     4
 
+(the rawcommit command is deprecated)
 d6e3c4976c13feb1728cd3ac851abaf7256a5c23 644 a
 76d5e637cbec1bcc04a5a3fa4bcc7d13f6847c00 644 c
 changeset:   6:b4b8b9afa8cc
@@ -43,6 +48,7 @@
 date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     6
 
+(the rawcommit command is deprecated)
 d6e3c4976c13feb1728cd3ac851abaf7256a5c23 644 a
 76d5e637cbec1bcc04a5a3fa4bcc7d13f6847c00 644 c
 changeset:   7:f84d0b1b024e
--- a/tests/test-remove.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-remove.out	Wed Feb 01 19:18:15 2006 +0100
@@ -11,11 +11,11 @@
 +a
 # HG changeset patch
 # User test
-# Node ID 1e555b9b85c52e1e9e8175446f1ede507b2d1ebb
+# Node ID 451c12a24e5a7336921b8d93e280837d7c2b4fc1
 # Parent  b51ca55c20354097ca299529d18b5cd356976ba2
 2
 
-diff -r b51ca55c2035 -r 1e555b9b85c5 foo
+diff -r b51ca55c2035 -r 451c12a24e5a foo
 --- a/foo	Thu Jan  1 00:00:00 1970 +0000
 +++ /dev/null	Thu Jan  1 00:00:00 1970 +0000
 @@ -1,1 +0,0 @@
@@ -32,13 +32,13 @@
 +a
 
 
-changeset:   1:1e555b9b85c5
+changeset:   1:451c12a24e5a
 tag:         tip
 user:        test
 date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     2
 
-diff -r b51ca55c2035 -r 1e555b9b85c5 foo
+diff -r b51ca55c2035 -r 451c12a24e5a foo
 --- a/foo	Thu Jan  1 00:00:00 1970 +0000
 +++ /dev/null	Thu Jan  1 00:00:00 1970 +0000
 @@ -1,1 +0,0 @@
--- a/tests/test-rename	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-rename	Wed Feb 01 19:18:15 2006 +0100
@@ -134,3 +134,27 @@
 hg rename d1/* d2/* d3
 hg status
 hg update -C
+
+echo "# move a whole subtree with \"hg rename .\""
+mkdir d3
+(cd d1; hg rename . ../d3)
+hg status
+hg update -C
+
+echo "# move a whole subtree with \"hg rename --after .\""
+mkdir d3
+mv d1/* d3
+(cd d1; hg rename --after . ../d3)
+hg status
+hg update -C
+
+echo "# move the parent tree with \"hg rename ..\""
+(cd d1/d11; hg rename .. ../../d3)
+hg status
+hg update -C
+
+echo "# skip removed files"
+hg remove d1/b
+hg rename d1 d3
+hg status
+hg update -C
--- a/tests/test-rename.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-rename.out	Wed Feb 01 19:18:15 2006 +0100
@@ -181,3 +181,68 @@
 R d1/b
 R d1/ba
 R d1/d11/a1
+# move a whole subtree with "hg rename ."
+copying a to ../d3/d1/a
+copying b to ../d3/d1/b
+copying ba to ../d3/d1/ba
+copying d11/a1 to ../d3/d1/d11/a1
+removing a
+removing b
+removing ba
+removing d11/a1
+A d3/d1/a
+A d3/d1/b
+A d3/d1/ba
+A d3/d1/d11/a1
+R d1/a
+R d1/b
+R d1/ba
+R d1/d11/a1
+# move a whole subtree with "hg rename --after ."
+copying a to ../d3/a
+copying b to ../d3/b
+copying ba to ../d3/ba
+copying d11/a1 to ../d3/d11/a1
+removing a
+removing b
+removing ba
+removing d11/a1
+A d3/a
+A d3/b
+A d3/ba
+A d3/d11/a1
+R d1/a
+R d1/b
+R d1/ba
+R d1/d11/a1
+# move the parent tree with "hg rename .."
+copying ../a to ../../d3/a
+copying ../b to ../../d3/b
+copying ../ba to ../../d3/ba
+copying a1 to ../../d3/d11/a1
+removing ../a
+removing ../b
+removing ../ba
+removing a1
+A d3/a
+A d3/b
+A d3/ba
+A d3/d11/a1
+R d1/a
+R d1/b
+R d1/ba
+R d1/d11/a1
+# skip removed files
+copying d1/a to d3/a
+copying d1/ba to d3/ba
+copying d1/d11/a1 to d3/d11/a1
+removing d1/a
+removing d1/ba
+removing d1/d11/a1
+A d3/a
+A d3/ba
+A d3/d11/a1
+R d1/a
+R d1/b
+R d1/ba
+R d1/d11/a1
--- a/tests/test-revert-unknown.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-revert-unknown.out	Wed Feb 01 19:18:15 2006 +0100
@@ -1,7 +1,7 @@
 %% Should show unknown
 ? unknown
 %% Should show unknown and b removed
-R b
+! b
 ? unknown
 %% Should show a and unknown
 a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-status	Wed Feb 01 19:18:15 2006 +0100
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+hg init repo1
+cd repo1
+mkdir a b a/1 b/1 b/2
+touch in_root a/in_a b/in_b a/1/in_a_1 b/1/in_b_1 b/2/in_b_2
+echo "hg status in repo root:"
+hg status
+echo "hg status . in repo root:"
+hg status .
+for dir in a b a/1 b/1 b/2; do
+    echo "hg status in $dir:"
+    hg status --cwd "$dir"
+    echo "hg status . in $dir:"
+    hg status --cwd "$dir" .
+    echo "hg status .. in $dir:"
+    hg status --cwd "$dir" ..
+done
+cd ..
+
+hg init repo2
+cd repo2
+touch modified removed deleted ignored
+echo "ignored" > .hgignore
+hg ci -A -m 'initial checkin' -d "0 0"
+sleep 1 # make sure mtime is changed
+touch modified added unknown ignored
+hg add added
+hg remove removed
+rm deleted
+echo "hg status:"
+hg status
+echo "hg status modified added removed deleted unknown never-existed ignored:"
+hg status modified added removed deleted unknown never-existed ignored
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-status.out	Wed Feb 01 19:18:15 2006 +0100
@@ -0,0 +1,103 @@
+hg status in repo root:
+? a/1/in_a_1
+? a/in_a
+? b/1/in_b_1
+? b/2/in_b_2
+? b/in_b
+? in_root
+hg status . in repo root:
+? a/1/in_a_1
+? a/in_a
+? b/1/in_b_1
+? b/2/in_b_2
+? b/in_b
+? in_root
+hg status in a:
+? a/1/in_a_1
+? a/in_a
+? b/1/in_b_1
+? b/2/in_b_2
+? b/in_b
+? in_root
+hg status . in a:
+? 1/in_a_1
+? in_a
+hg status .. in a:
+? 1/in_a_1
+? in_a
+? ../b/1/in_b_1
+? ../b/2/in_b_2
+? ../b/in_b
+? ../in_root
+hg status in b:
+? a/1/in_a_1
+? a/in_a
+? b/1/in_b_1
+? b/2/in_b_2
+? b/in_b
+? in_root
+hg status . in b:
+? 1/in_b_1
+? 2/in_b_2
+? in_b
+hg status .. in b:
+? ../a/1/in_a_1
+? ../a/in_a
+? 1/in_b_1
+? 2/in_b_2
+? in_b
+? ../in_root
+hg status in a/1:
+? a/1/in_a_1
+? a/in_a
+? b/1/in_b_1
+? b/2/in_b_2
+? b/in_b
+? in_root
+hg status . in a/1:
+? in_a_1
+hg status .. in a/1:
+? in_a_1
+? ../in_a
+hg status in b/1:
+? a/1/in_a_1
+? a/in_a
+? b/1/in_b_1
+? b/2/in_b_2
+? b/in_b
+? in_root
+hg status . in b/1:
+? in_b_1
+hg status .. in b/1:
+? in_b_1
+? ../2/in_b_2
+? ../in_b
+hg status in b/2:
+? a/1/in_a_1
+? a/in_a
+? b/1/in_b_1
+? b/2/in_b_2
+? b/in_b
+? in_root
+hg status . in b/2:
+? in_b_2
+hg status .. in b/2:
+? ../1/in_b_1
+? in_b_2
+? ../in_b
+adding .hgignore
+adding deleted
+adding modified
+adding removed
+hg status:
+A added
+R removed
+! deleted
+? unknown
+hg status modified added removed deleted unknown never-existed ignored:
+never-existed: No such file or directory
+A added
+R removed
+! deleted
+? ignored
+? unknown
--- a/tests/test-symlinks	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-symlinks	Wed Feb 01 19:18:15 2006 +0100
@@ -37,6 +37,6 @@
 mkdir dir/a.o
 ln -sf nonexist dir/b.o
 mkfifo a.c
-# it should show a.c, dir/a.o and dir/b.o removed
+# it should show a.c, dir/a.o and dir/b.o deleted
 hg status
 hg status a.c
--- a/tests/test-symlinks.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-symlinks.out	Wed Feb 01 19:18:15 2006 +0100
@@ -3,9 +3,9 @@
 adding a.c
 adding dir/a.o
 adding dir/b.o
-R a.c
-R dir/a.o
-R dir/b.o
+! a.c
+! dir/a.o
+! dir/b.o
 ? .hgignore
 a.c: unsupported file type (type is fifo)
-R a.c
+! a.c
--- a/tests/test-tag	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-tag	Wed Feb 01 19:18:15 2006 +0100
@@ -10,6 +10,14 @@
 
 echo foo >> .hgtags
 hg tag -d "0 0" "bleah2" || echo "failed"
+hg tag -d "0 0" -r 0 "bleah2" 1 || echo "failed"
+
+hg revert .hgtags
+hg tag -d "0 0" -r 0 "bleah0"
+hg tag -l -d "0 0" "bleah1" 1
+
+cat .hgtags
+cat .hg/localtags
 
 hg tag -l 'xx
 newline'
--- a/tests/test-tag.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-tag.out	Wed Feb 01 19:18:15 2006 +0100
@@ -18,5 +18,12 @@
 
 abort: working copy of .hgtags is changed (please commit .hgtags manually)
 failed
+use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
+abort: use only one form to specify the revision
+failed
+use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
+acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
+acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
+863197ef03781c4fc00276d83eb66c4cb9cd91df bleah1
 abort: '\n' cannot be used in a tag name
 abort: ':' cannot be used in a tag name
--- a/tests/test-up-local-change	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-up-local-change	Wed Feb 01 19:18:15 2006 +0100
@@ -24,11 +24,34 @@
 cd ../r2
 hg -q pull ../r1
 hg status
+hg parents
 hg --debug up
+hg parents
+hg --debug up 0
+hg parents
 hg --debug up -m || echo failed
-hg --debug up -f -m
+hg parents
+hg --debug up
 hg parents
 hg -v history
 hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
               -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
 
+# create a second head
+cd ../r1
+hg up 0
+echo b2 > b
+echo a3 > a
+hg addremove
+hg commit -m "3" -d "0 0"
+
+cd ../r2
+hg -q pull ../r1
+hg status
+hg parents
+hg --debug up || echo failed
+hg --debug up -m || echo failed
+hg --debug up -f -m
+hg parents
+hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- a/tests/test-up-local-change.out	Thu Dec 15 18:04:39 2005 +0100
+++ b/tests/test-up-local-change.out	Wed Feb 01 19:18:15 2006 +0100
@@ -2,11 +2,16 @@
 diff -r c19d34741b0a a
 --- a/a
 +++ b/a
-@@ -1,1 +1,1 @@
+@@ -1,1 +1,1 @@ a
 -a
 +abc
 adding b
 M a
+changeset:   0:c19d34741b0a
+user:        test
+date:        Thu Jan  1 00:00:00 1970 +0000
+summary:     1
+
 resolving manifests
  force None allow None moddirstate True linear True
  ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
@@ -16,11 +21,38 @@
 merging a
 resolving a
 file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
-abort: outstanding uncommited changes
-failed
+changeset:   1:1e71731e6fbb
+tag:         tip
+user:        test
+date:        Thu Jan  1 00:00:00 1970 +0000
+summary:     2
+
 resolving manifests
- force None allow 1 moddirstate True linear True
- ancestor 1165e8bd193e local 1165e8bd193e remote 1165e8bd193e
+ force None allow None moddirstate True linear True
+ ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c
+remote deleted b
+removing b
+changeset:   0:c19d34741b0a
+user:        test
+date:        Thu Jan  1 00:00:00 1970 +0000
+summary:     1
+
+abort: there is nothing to merge, just use 'hg update'
+failed
+changeset:   0:c19d34741b0a
+user:        test
+date:        Thu Jan  1 00:00:00 1970 +0000
+summary:     1
+
+resolving manifests
+ force None allow None moddirstate True linear True
+ ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
+ a versions differ, resolve
+remote created b
+getting b
+merging a
+resolving a
+file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
 changeset:   1:1e71731e6fbb
 tag:         tip
 user:        test
@@ -47,6 +79,55 @@
 diff -r 1e71731e6fbb a
 --- a/a
 +++ b/a
-@@ -1,1 +1,1 @@
+@@ -1,1 +1,1 @@ a2
 -a2
 +abc
+adding b
+M a
+changeset:   1:1e71731e6fbb
+user:        test
+date:        Thu Jan  1 00:00:00 1970 +0000
+summary:     2
+
+resolving manifests
+ force None allow None moddirstate True linear False
+ ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
+ a versions differ, resolve
+ b versions differ, resolve
+this update spans a branch affecting the following files:
+ a (resolve)
+ b (resolve)
+aborting update spanning branches!
+(use update -m to merge across branches or -C to lose changes)
+failed
+abort: outstanding uncommited changes
+failed
+resolving manifests
+ force None allow 1 moddirstate True linear False
+ ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
+ a versions differ, resolve
+ b versions differ, resolve
+merging a
+resolving a
+file a: my d730145abbf9 other 13e0d5f949fa ancestor b789fdd96dc2
+merging b
+resolving b
+file b: my 1e88685f5dde other 61de8c7723ca ancestor 000000000000
+changeset:   1:1e71731e6fbb
+user:        test
+date:        Thu Jan  1 00:00:00 1970 +0000
+summary:     2
+
+changeset:   2:83c51d0caff4
+tag:         tip
+parent:      0:c19d34741b0a
+user:        test
+date:        Thu Jan  1 00:00:00 1970 +0000
+summary:     3
+
+diff -r 1e71731e6fbb a
+--- a/a
++++ b/a
+@@ -1,1 +1,1 @@ a2
+-a2
++abc