changeset 3460:afb106e08cda

merge with mpm
author Josef "Jeff" Sipek <jeffpc@josefsipek.net>
date Sat, 21 Oct 2006 15:22:08 -0400
parents a75d609ded05 (current diff) dba3cadef789 (diff)
children ad4b5ef8a051
files templates/changelog-gitweb.tmpl templates/changelog-rss.tmpl templates/changelogentry-gitweb.tmpl templates/changelogentry-rss.tmpl templates/changeset-gitweb.tmpl templates/changeset-raw.tmpl templates/error-gitweb.tmpl templates/fileannotate-gitweb.tmpl templates/fileannotate-raw.tmpl templates/filediff-raw.tmpl templates/filelog-gitweb.tmpl templates/filelog-rss.tmpl templates/filelogentry-rss.tmpl templates/filerevision-gitweb.tmpl templates/footer-gitweb.tmpl templates/gitweb/changelog.tmpl templates/gitweb/changeset.tmpl templates/gitweb/error.tmpl templates/gitweb/fileannotate.tmpl templates/gitweb/filelog.tmpl templates/gitweb/filerevision.tmpl templates/gitweb/manifest.tmpl templates/gitweb/map templates/gitweb/search.tmpl templates/gitweb/shortlog.tmpl templates/gitweb/summary.tmpl templates/gitweb/tags.tmpl templates/header-gitweb.tmpl templates/header-raw.tmpl templates/header-rss.tmpl templates/manifest-gitweb.tmpl templates/map-gitweb templates/map-raw templates/map-rss templates/old/changelog.tmpl templates/old/changelogentry.tmpl templates/old/changeset.tmpl templates/old/fileannotate.tmpl templates/old/filediff.tmpl templates/old/filelog.tmpl templates/old/filelogentry.tmpl templates/old/filerevision.tmpl templates/old/manifest.tmpl templates/old/map templates/old/search.tmpl templates/old/shortlog.tmpl templates/old/tags.tmpl templates/raw/map templates/rss/filelogentry.tmpl templates/rss/map templates/search-gitweb.tmpl templates/shortlog-gitweb.tmpl templates/summary-gitweb.tmpl templates/tagentry-rss.tmpl templates/tags-gitweb.tmpl templates/tags-rss.tmpl
diffstat 302 files changed, 11665 insertions(+), 3562 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sat Sep 02 22:58:02 2006 -0400
+++ b/.hgignore	Sat Oct 21 15:22:08 2006 -0400
@@ -21,6 +21,7 @@
 MANIFEST
 patches
 mercurial/__version__.py
+.DS_Store
 
 syntax: regexp
 ^\.pc/
--- a/CONTRIBUTORS	Sat Sep 02 22:58:02 2006 -0400
+++ b/CONTRIBUTORS	Sat Oct 21 15:22:08 2006 -0400
@@ -4,6 +4,7 @@
 Muli Ben-Yehuda <mulix at mulix.org>
 Mikael Berthe <mikael at lilotux.net>
 Benoit Boissinot <bboissin at gmail.com>
+Brendan Cully <brendan at kublai.com>
 Vincent Danjean <vdanjean.ml at free.fr>
 Jake Edge <jake at edge2.net>
 Michael Fetterman <michael.fetterman at intel.com>
--- a/MANIFEST.in	Sat Sep 02 22:58:02 2006 -0400
+++ b/MANIFEST.in	Sat Oct 21 15:22:08 2006 -0400
@@ -2,13 +2,11 @@
 recursive-include mercurial *.py
 include hgweb.cgi hgwebdir.cgi
 include hgeditor rewrite-log
-include tests/README tests/*.py tests/test-*[a-z0-9] tests/*.out
+include tests/README tests/*.py tests/test-*[a-z0-9] tests/*.out tests/*.bin
 prune tests/*.err
 include *.txt
-include templates/map templates/map-*[a-z0-9]
-include templates/*.tmpl
-include templates/static/*
 include doc/README doc/Makefile doc/gendoc.py doc/*.txt doc/*.html doc/*.[0-9]
+recursive-include templates *
 recursive-include contrib *
 recursive-include hgext *
 include README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/churn.py	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,179 @@
+# churn.py - create a graph showing who changed the most lines
+#
+# Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+#
+#
+# Aliases map file format is simple one alias per line in the following
+# format:
+#
+# <alias email> <actual email>
+
+from mercurial.demandload import *
+from mercurial.i18n import gettext as _
+demandload(globals(), 'time sys signal os')
+demandload(globals(), 'mercurial:hg,mdiff,fancyopts,cmdutil,ui,util,templater,node')
+
+def __gather(ui, repo, node1, node2):
+    def dirtywork(f, mmap1, mmap2):
+        lines = 0
+
+        to = mmap1 and repo.file(f).read(mmap1[f]) or None
+        tn = mmap2 and repo.file(f).read(mmap2[f]) or None
+
+        diff = mdiff.unidiff(to, "", tn, "", f).split("\n")
+
+        for line in diff:
+            if not line:
+                continue # skip EOF
+            if line.startswith(" "):
+                continue # context line
+            if line.startswith("--- ") or line.startswith("+++ "):
+                continue # begining of diff
+            if line.startswith("@@ "):
+                continue # info line
+
+            # changed lines
+            lines += 1
+
+        return lines
+
+    ##
+
+    lines = 0
+
+    changes = repo.status(node1, node2, None, util.always)[:5]
+
+    modified, added, removed, deleted, unknown = changes
+
+    who = repo.changelog.read(node2)[1]
+    who = templater.email(who) # get the email of the person
+
+    mmap1 = repo.manifest.read(repo.changelog.read(node1)[0])
+    mmap2 = repo.manifest.read(repo.changelog.read(node2)[0])
+    for f in modified:
+        lines += dirtywork(f, mmap1, mmap2)
+
+    for f in added:
+        lines += dirtywork(f, None, mmap2)
+
+    for f in removed:
+        lines += dirtywork(f, mmap1, None)
+
+    for f in deleted:
+        lines += dirtywork(f, mmap1, mmap2)
+
+    for f in unknown:
+        lines += dirtywork(f, mmap1, mmap2)
+
+    return (who, lines)
+
+def gather_stats(ui, repo, amap, revs=None, progress=False):
+    stats = {}
+
+    cl    = repo.changelog
+
+    if not revs:
+        revs = range(0, cl.count())
+
+    nr_revs = len(revs)
+    cur_rev = 0
+
+    for rev in revs:
+        cur_rev += 1 # next revision
+
+        node2    = cl.node(rev)
+        node1    = cl.parents(node2)[0]
+
+        if cl.parents(node2)[1] != node.nullid:
+            ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
+            continue
+
+        who, lines = __gather(ui, repo, node1, node2)
+
+        # remap the owner if possible
+        if amap.has_key(who):
+            ui.note("using '%s' alias for '%s'\n" % (amap[who], who))
+            who = amap[who]
+
+        if not stats.has_key(who):
+            stats[who] = 0
+        stats[who] += lines
+
+        ui.note("rev %d: %d lines by %s\n" % (rev, lines, who))
+
+        if progress:
+            if int(100.0*(cur_rev - 1)/nr_revs) < int(100.0*cur_rev/nr_revs):
+                ui.write("%d%%.." % (int(100.0*cur_rev/nr_revs),))
+                sys.stdout.flush()
+
+    if progress:
+        ui.write("done\n")
+        sys.stdout.flush()
+
+    return stats
+
+def churn(ui, repo, **opts):
+    "Graphs the number of lines changed"
+
+    def pad(s, l):
+        if len(s) < l:
+            return s + " " * (l-len(s))
+        return s[0:l]
+
+    def graph(n, maximum, width, char):
+        n = int(n * width / float(maximum))
+
+        return char * (n)
+
+    def get_aliases(f):
+        aliases = {}
+
+        for l in f.readlines():
+            l = l.strip()
+            alias, actual = l.split(" ")
+            aliases[alias] = actual
+
+        return aliases
+
+    amap = {}
+    aliases = opts.get('aliases')
+    if aliases:
+        try:
+            f = open(aliases,"r")
+        except OSError, e:
+            print "Error: " + e
+            return
+
+        amap = get_aliases(f)
+        f.close()
+
+    revs = [int(r) for r in cmdutil.revrange(ui, repo, opts['rev'])]
+    revs.sort()
+    stats = gather_stats(ui, repo, amap, revs, opts.get('progress'))
+
+    # make a list of tuples (name, lines) and sort it in descending order
+    ordered = stats.items()
+    ordered.sort(lambda x, y: cmp(y[1], x[1]))
+
+    maximum = ordered[0][1]
+
+    ui.note("Assuming 80 character terminal\n")
+    width = 80 - 1
+
+    for i in ordered:
+        person = i[0]
+        lines = i[1]
+        print "%s %6d %s" % (pad(person, 20), lines,
+                graph(lines, maximum, width - 20 - 1 - 6 - 2 - 2, '*'))
+
+cmdtable = {
+    "churn":
+    (churn,
+     [('r', 'rev', [], _('limit statistics to the specified revisions')),
+      ('', 'aliases', '', _('file with email aliases')),
+      ('', 'progress', None, _('show progress'))],
+    'hg churn [-r revision range] [-a file] [--progress]'),
+}
--- a/contrib/hgdiff	Sat Sep 02 22:58:02 2006 -0400
+++ b/contrib/hgdiff	Sat Oct 21 15:22:08 2006 -0400
@@ -5,9 +5,9 @@
 import re
 from optparse import OptionParser
 from mercurial.bdiff import bdiff, blocks
-from mercurial.mdiff import bunidiff
+from mercurial.mdiff import bunidiff, diffopts
 
-VERSION="0.2"
+VERSION="0.3"
 usage = "usage: %prog [options] file1 file2"
 parser = OptionParser(usage=usage)
 
@@ -57,9 +57,10 @@
         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)
+            l = bunidiff(t1, t2, l1, l2, file1, file2,
+                         diffopts(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"
--- a/contrib/hgk	Sat Sep 02 22:58:02 2006 -0400
+++ b/contrib/hgk	Sat Oct 21 15:22:08 2006 -0400
@@ -30,15 +30,29 @@
     set startmsecs [clock clicks -milliseconds]
     set nextupdate [expr $startmsecs + 100]
     set ncmupdate 1
+    set limit 0
+    set revargs {}
+    for {set i 0} {$i < [llength $rargs]} {incr i} {
+	set opt [lindex $rargs $i]
+	if {$opt == "--limit"} {
+	    incr i
+	    set limit [lindex $rargs $i]
+	} else {
+	    lappend revargs $opt
+	}
+    }
     if [catch {
-	set parse_args [concat --default HEAD $rargs]
+	set parse_args [concat --default HEAD $revargs]
 	set parsed_args [split [eval exec hg debug-rev-parse $parse_args] "\n"]
-    }] {
+    } err] {
 	# if git-rev-parse failed for some reason...
 	if {$rargs == {}} {
-	    set rargs HEAD
+	    set revargs HEAD
 	}
-	set parsed_args $rargs
+	set parsed_args $revargs
+    }
+    if {$limit > 0} {
+	set parsed_args [concat -n $limit $parsed_args]
     }
     if [catch {
 	set commfd [open "|hg debug-rev-list --header --topo-order --parents $parsed_args" r]
@@ -100,7 +114,7 @@
 	    set ids [string range $cmit 0 [expr {$j - 1}]]
 	    set ok 1
 	    foreach id $ids {
-		if {![regexp {^[0-9a-f]{40}$} $id]} {
+		if {![regexp {^[0-9a-f]{12}$} $id]} {
 		    set ok 0
 		    break
 		}
@@ -176,6 +190,7 @@
     set audate {}
     set comname {}
     set comdate {}
+    set rev {}
     if {![info exists nchildren($id)]} {
 	set children($id) {}
 	set nchildren($id) 0
@@ -209,6 +224,8 @@
 		    set x [expr {[llength $line] - 2}]
 		    set comdate [lindex $line $x]
 		    set comname [join [lrange $line 1 [expr {$x - 1}]]]
+		} elseif {$tag == "revision"} {
+		    set rev [lindex $line 1]
 		}
 	    }
 	} else {
@@ -233,7 +250,7 @@
 	set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"]
     }
     set commitinfo($id) [list $headline $auname $audate \
-			     $comname $comdate $comment]
+			     $comname $comdate $comment $rev]
 }
 
 proc readrefs {} {
@@ -261,7 +278,7 @@
 	catch {
 	    set fd [open $f r]
 	    set line [read $fd 40]
-	    if {[regexp {^[0-9a-f]{40}} $line id]} {
+	    if {[regexp {^[0-9a-f]{12}} $line id]} {
 		set name "$dname[file tail $f]"
 		set otherrefids($name) $id
 		lappend idotherrefs($id) $name
@@ -1743,7 +1760,7 @@
 	}
 	return
     }
-    if {![regexp {^[0-9a-f]{40}} $line id]} {
+    if {![regexp {^[0-9a-f]{12}} $line id]} {
 	error_popup "Can't parse git-diff-tree output: $line"
 	stopfindproc
 	return
@@ -1856,7 +1873,7 @@
 	}
 	return
     }
-    if {[regexp {^([0-9a-f]{40}) \(from ([0-9a-f]{40})\)} $line match id p]} {
+    if {[regexp {^([0-9a-f]{12}) \(from ([0-9a-f]{12})\)} $line match id p]} {
 	# start of a new string of diffs
 	donefilediff
 	set fdiffids [list $id $p]
@@ -2002,8 +2019,9 @@
     set l "..."
     if {[info exists commitinfo($p)]} {
 	set l [lindex $commitinfo($p) 0]
+	set r [lindex $commitinfo($p) 6]
     }
-    return "$p ($l)"
+    return "$r:$p ($l)"
 }
 
 # append some text to the ctext widget, and make any SHA1 ID
@@ -2014,7 +2032,7 @@
     set start [$ctext index "end - 1c"]
     $ctext insert end $text
     $ctext insert end "\n"
-    set links [regexp -indices -all -inline {[0-9a-f]{40}} $text]
+    set links [regexp -indices -all -inline {[0-9a-f]{12}} $text]
     foreach l $links {
 	set s [lindex $l 0]
 	set e [lindex $l 1]
@@ -2107,6 +2125,7 @@
     $ctext mark set fmark.0 0.0
     $ctext mark gravity fmark.0 left
     set info $commitinfo($id)
+    $ctext insert end "Revision: [lindex $info 6]\n"
     $ctext insert end "Author: [lindex $info 1]  [lindex $info 2]\n"
     $ctext insert end "Committer: [lindex $info 3]  [lindex $info 4]\n"
     if {[info exists idtags($id)]} {
--- a/contrib/macosx/Readme.html	Sat Sep 02 22:58:02 2006 -0400
+++ b/contrib/macosx/Readme.html	Sat Oct 21 15:22:08 2006 -0400
@@ -25,7 +25,7 @@
 <p class="p2"><br></p>
 <p class="p1"><b>After you install</b></p>
 <p class="p2"><br></p>
-<p class="p3">This package installs the <span class="s2">hg</span> executable in <span class="s2">/usr/local/bin</span>. This directory may not be in your shell's search path. Don't forget to check.</p>
+<p class="p3">This package installs the <span class="s2">hg</span> executable in <span class="s2">/Library/Frameworks/Python.framework/Versions/Current/bin</span>. This directory may not be in your shell's search path. The MacPython installer will have created an entry in <span class="s2">.profile</span> for it but if your shell doesn't use <span class="s2">.profile</span> you'll need configure it yourself or create a symlink from a directory already in your path.</p>
 <p class="p2"><br></p>
 <p class="p1"><b>Reporting problems</b></p>
 <p class="p2"><br></p>
--- a/contrib/mercurial.el	Sat Sep 02 22:58:02 2006 -0400
+++ b/contrib/mercurial.el	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
 ;;; mercurial.el --- Emacs support for the Mercurial distributed SCM
 
-;; Copyright (C) 2005 Bryan O'Sullivan
+;; Copyright (C) 2005, 2006 Bryan O'Sullivan
 
 ;; Author: Bryan O'Sullivan <bos@serpentine.com>
 
@@ -289,7 +289,7 @@
 
 (defsubst hg-chomp (str)
   "Strip trailing newlines from a string."
-  (hg-replace-in-string str "[\r\n]+\'" ""))
+  (hg-replace-in-string str "[\r\n]+\\'" ""))
 
 (defun hg-run-command (command &rest args)
   "Run the shell command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT).
@@ -502,6 +502,43 @@
 			     (or default "tip")))
 	rev))))
 
+(defun hg-parents-for-mode-line (root)
+  "Format the parents of the working directory for the mode line."
+  (let ((parents (split-string (hg-chomp
+				(hg-run0 "--cwd" root "parents" "--template"
+					 "{rev}\n")) "\n")))
+    (mapconcat 'identity parents "+")))
+
+(defun hg-buffers-visiting-repo (&optional path)
+  "Return a list of buffers visiting the repository containing PATH."
+  (let ((root-name (hg-root (or path (buffer-file-name))))
+	bufs)
+    (save-excursion
+      (dolist (buf (buffer-list) bufs)
+	(set-buffer buf)
+	(let ((name (buffer-file-name)))
+	  (when (and hg-status name (equal (hg-root name) root-name))
+	    (setq bufs (cons buf bufs))))))))
+
+(defun hg-update-mode-lines (path)
+  "Update the mode lines of all buffers visiting the same repository as PATH."
+  (let* ((root (hg-root path))
+	 (parents (hg-parents-for-mode-line root)))
+    (save-excursion
+      (dolist (info (hg-path-status
+		     root
+		     (mapcar
+		      (function
+		       (lambda (buf)
+			 (substring (buffer-file-name buf) (length root))))
+		      (hg-buffers-visiting-repo root))))
+	(let* ((name (car info))
+	       (status (cdr info))
+	       (buf (find-buffer-visiting (concat root name))))
+	  (when buf
+	    (set-buffer buf)
+	    (hg-mode-line-internal status parents)))))))
+  
 (defmacro hg-do-across-repo (path &rest body)
   (let ((root-name (gensym "root-"))
 	(buf-name (gensym "buf-")))
@@ -548,13 +585,31 @@
 			    '(("M " . modified)
 			      ("A " . added)
 			      ("R " . removed)
+			      ("! " . deleted)
 			      ("? " . nil)))))
 	  (if state
 	      (cdr state)
 	    'normal)))))
 
-(defun hg-tip ()
-  (split-string (hg-chomp (hg-run0 "-q" "tip")) ":"))
+(defun hg-path-status (root paths)
+  "Return status of PATHS in repo ROOT as an alist.
+Each entry is a pair (FILE-NAME . STATUS)."
+  (let ((s (apply 'hg-run "--cwd" root "status" "-marduc" paths))
+	result)
+    (dolist (entry (split-string (hg-chomp (cdr s)) "\n") (nreverse result))
+      (let (state name)
+	(if (equal (substring entry 1 2) " ")
+	    (setq state (cdr (assoc (substring entry 0 2)
+				    '(("M " . modified)
+				      ("A " . added)
+				      ("R " . removed)
+				      ("! " . deleted)
+				      ("C " . normal)
+				      ("I " . ignored)
+				      ("? " . nil))))
+		  name (substring entry 2))
+	  (setq name (substring entry 0 (search ": " entry :from-end t))))
+	(setq result (cons (cons name state) result))))))
 
 (defmacro hg-view-output (args &rest body)
   "Execute BODY in a clean buffer, then quickly display that buffer.
@@ -589,7 +644,7 @@
 
 (put 'hg-view-output 'lisp-indent-function 1)
 
-;;; Context save and restore across revert.
+;;; Context save and restore across revert and other operations.
 
 (defun hg-position-context (pos)
   "Return information to help find the given position again."
@@ -631,22 +686,28 @@
 
 ;;; Hooks.
 
+(defun hg-mode-line-internal (status parents)
+  (setq hg-status status
+	hg-mode (and status (concat " Hg:"
+				    parents
+				    (cdr (assq status
+					       '((normal . "")
+						 (removed . "r")
+						 (added . "a")
+						 (deleted . "!")
+						 (modified . "m"))))))))
+  
 (defun hg-mode-line (&optional force)
   "Update the modeline with the current status of a file.
 An update occurs if optional argument FORCE is non-nil,
 hg-update-modeline is non-nil, or we have not yet checked the state of
 the file."
-  (when (and (hg-root) (or force hg-update-modeline (not hg-mode)))
-    (let ((status (hg-file-status buffer-file-name)))
-      (setq hg-status status
-	    hg-mode (and status (concat " Hg:"
-					(car (hg-tip))
-					(cdr (assq status
-						   '((normal . "")
-						     (removed . "r")
-						     (added . "a")
-						     (modified . "m")))))))
-      status)))
+  (let ((root (hg-root)))
+    (when (and root (or force hg-update-modeline (not hg-mode)))
+      (let ((status (hg-file-status buffer-file-name))
+	    (parents (hg-parents-for-mode-line root)))
+	(hg-mode-line-internal status parents)
+	status))))
 
 (defun hg-mode (&optional toggle)
   "Minor mode for Mercurial distributed SCM integration.
@@ -722,7 +783,14 @@
       (if (not hg-root-dir)
 	  (error "error: %s: directory is not part of a Mercurial repository."
 		 default-directory)
-	(cd (hg-root))))))
+	(cd hg-root-dir)))))
+
+(defun hg-fix-paths ()
+  "Fix paths reported by some Mercurial commands."
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward " \\.\\.." nil t)
+      (replace-match " " nil nil))))
 
 (defun hg-add (path)
   "Add PATH to the Mercurial repository on the next commit.
@@ -732,9 +800,8 @@
 	(update (equal buffer-file-name path)))
     (hg-view-output (hg-output-buffer-name)
       (apply 'call-process (hg-binary) nil t nil (list "add" path))
-      ;; "hg add" shows pathes relative NOT TO ROOT BUT TO REPOSITORY
-      (replace-regexp " \\.\\.." " " nil 0 (buffer-size))
-      (goto-char 0)
+      (hg-fix-paths)
+      (goto-char (point-min))
       (cd (hg-root path)))
     (when update
       (unless vc-make-backup-files
@@ -820,8 +887,7 @@
       (let ((buf hg-prev-buffer))
 	(kill-buffer nil)
 	(switch-to-buffer buf))
-      (hg-do-across-repo root
-	(hg-mode-line)))))
+      (hg-update-mode-lines root))))
 
 (defun hg-commit-mode ()
   "Mode for describing a commit of changes to a Mercurial repository.
@@ -973,8 +1039,8 @@
     (hg-view-output (hg-output-buffer-name)
       (apply 'call-process (hg-binary) nil t nil (list "forget" path))
       ;; "hg forget" shows pathes relative NOT TO ROOT BUT TO REPOSITORY
-      (replace-regexp " \\.\\.." " " nil 0 (buffer-size))
-      (goto-char 0)
+      (hg-fix-paths)
+      (goto-char (point-min))
       (cd (hg-root path)))
     (when update
       (with-current-buffer buf
@@ -1148,6 +1214,21 @@
 	root)
     hg-root))
 
+(defun hg-cwd (&optional path)
+  "Return the current directory of PATH within the repository."
+  (do ((stack nil (cons (file-name-nondirectory
+			 (directory-file-name dir))
+			stack))
+       (prev nil dir)
+       (dir (file-name-directory (or path buffer-file-name
+				     (expand-file-name default-directory)))
+	    (file-name-directory (directory-file-name dir))))
+      ((equal prev dir))
+    (when (file-directory-p (concat dir ".hg"))
+      (let ((cwd (mapconcat 'identity stack "/")))
+	(unless (equal cwd "")
+	  (return (file-name-as-directory cwd)))))))
+
 (defun hg-status (path)
   "Print revision control status of a file or directory.
 With prefix argument, prompt for the path to give status for.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/mq.el	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,327 @@
+;;; mq.el --- Emacs support for Mercurial Queues
+
+;; Copyright (C) 2006 Bryan O'Sullivan
+
+;; Author: Bryan O'Sullivan <bos@serpentine.com>
+
+;; mq.el is free software; you can redistribute it and/or modify it
+;; under the terms of version 2 of the GNU General Public License as
+;; published by the Free Software Foundation.
+
+;; mq.el is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with mq.el, GNU Emacs, or XEmacs; see the file COPYING (`C-h
+;; C-l').  If not, write to the Free Software Foundation, Inc., 59
+;; Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+(require 'mercurial)
+
+
+(defcustom mq-mode-hook nil
+  "Hook run when a buffer enters mq-mode."
+  :type 'sexp
+  :group 'mercurial)
+
+(defcustom mq-global-prefix "\C-cq"
+  "The global prefix for Mercurial Queues keymap bindings."
+  :type 'sexp
+  :group 'mercurial)
+
+(defcustom mq-edit-mode-hook nil
+  "Hook run after a buffer is populated to edit a patch description."
+  :type 'sexp
+  :group 'mercurial)
+
+
+;;; Internal variables.
+
+(defvar mq-mode nil
+  "Is this file managed by MQ?")
+(make-variable-buffer-local 'mq-mode)
+(put 'mq-mode 'permanent-local t)
+
+(defvar mq-patch-history nil)
+
+(defvar mq-top-patch '(nil))
+
+(defvar mq-prev-buffer nil)
+(make-variable-buffer-local 'mq-prev-buffer)
+(put 'mq-prev-buffer 'permanent-local t)
+
+
+;;; Global keymap.
+
+(defvar mq-global-map (make-sparse-keymap))
+(fset 'mq-global-map mq-global-map)
+(global-set-key mq-global-prefix 'mq-global-map)
+(define-key mq-global-map "." 'mq-push)
+(define-key mq-global-map ">" 'mq-push-all)
+(define-key mq-global-map "," 'mq-pop)
+(define-key mq-global-map "<" 'mq-pop-all)
+(define-key mq-global-map "r" 'mq-refresh)
+(define-key mq-global-map "e" 'mq-refresh-edit)
+(define-key mq-global-map "n" 'mq-next)
+(define-key mq-global-map "p" 'mq-previous)
+(define-key mq-global-map "t" 'mq-top)
+
+(add-minor-mode 'mq-mode 'mq-mode)
+
+
+;;; Refresh edit mode keymap.
+
+(defvar mq-edit-mode-map (make-sparse-keymap))
+(define-key mq-edit-mode-map "\C-c\C-c" 'mq-edit-finish)
+(define-key mq-edit-mode-map "\C-c\C-k" 'mq-edit-kill)
+
+
+;;; Helper functions.
+
+(defun mq-read-patch-name (&optional source prompt)
+  "Read a patch name to use with a command.
+May return nil, meaning \"use the default\"."
+  (let ((patches (split-string
+		  (hg-chomp (hg-run0 (or source "qseries"))) "\n")))
+    (when current-prefix-arg
+      (completing-read (format "Patch%s: " (or prompt ""))
+		       (map 'list 'cons patches patches)
+		       nil
+		       nil
+		       nil
+		       'mq-patch-history))))
+
+(defun mq-refresh-buffers (root)
+  (save-excursion
+    (dolist (buf (hg-buffers-visiting-repo root))
+      (when (not (verify-visited-file-modtime buf))
+	(set-buffer buf)
+	(let ((ctx (hg-buffer-context)))
+	  (message "Refreshing %s..." (buffer-name))
+	  (revert-buffer t t t)
+	  (hg-restore-context ctx)
+	  (message "Refreshing %s...done" (buffer-name))))))
+  (hg-update-mode-lines root)
+  (mq-update-mode-lines root))
+
+(defun mq-last-line ()
+  (goto-char (point-max))
+  (beginning-of-line)
+  (when (looking-at "^$")
+    (forward-line -1))
+  (let ((bol (point)))
+    (end-of-line)
+    (let ((line (buffer-substring bol (point))))
+      (when (> (length line) 0)
+	line))))
+  
+(defun mq-push (&optional patch)
+  "Push patches until PATCH is reached.
+If PATCH is nil, push at most one patch."
+  (interactive (list (mq-read-patch-name "qunapplied" " to push")))
+  (let ((root (hg-root))
+	(prev-buf (current-buffer))
+	last-line ok)
+    (unless root
+      (error "Cannot push outside a repository!"))
+    (hg-sync-buffers root)
+    (let ((buf-name (format "MQ: Push %s" (or patch "next patch"))))
+      (kill-buffer (get-buffer-create buf-name))
+      (split-window-vertically)
+      (other-window 1)
+      (switch-to-buffer (get-buffer-create buf-name))
+      (cd root)
+      (message "Pushing...")
+      (setq ok (= 0 (apply 'call-process (hg-binary) nil t t "qpush"
+			   (if patch (list patch))))
+	    last-line (mq-last-line))
+      (let ((lines (count-lines (point-min) (point-max))))
+	(if (and (equal lines 2) (string-match "Now at:" last-line))
+	    (progn
+	      (kill-buffer (current-buffer))
+	      (delete-window))
+	  (hg-view-mode prev-buf))))
+    (mq-refresh-buffers root)
+    (sit-for 0)
+    (when last-line
+      (if ok
+	  (message "Pushing... %s" last-line)
+	(error "Pushing... %s" last-line)))))
+  
+(defun mq-push-all ()
+  "Push patches until all are applied."
+  (interactive)
+  (mq-push "-a"))
+
+(defun mq-pop (&optional patch)
+  "Pop patches until PATCH is reached.
+If PATCH is nil, pop at most one patch."
+  (interactive (list (mq-read-patch-name "qapplied" " to pop to")))
+  (let ((root (hg-root))
+	last-line ok)
+    (unless root
+      (error "Cannot pop outside a repository!"))
+    (hg-sync-buffers root)
+    (set-buffer (generate-new-buffer "qpop"))
+    (cd root)
+    (message "Popping...")
+    (setq ok (= 0 (apply 'call-process (hg-binary) nil t t "qpop"
+			 (if patch (list patch))))
+	  last-line (mq-last-line))
+    (kill-buffer (current-buffer))
+    (mq-refresh-buffers root)
+    (sit-for 0)
+    (when last-line
+      (if ok
+	  (message "Popping... %s" last-line)
+	(error "Popping... %s" last-line)))))
+  
+(defun mq-pop-all ()
+  "Push patches until none are applied."
+  (interactive)
+  (mq-pop "-a"))
+
+(defun mq-refresh-internal (root &rest args)
+  (hg-sync-buffers root)
+  (let ((patch (mq-patch-info "qtop")))
+    (message "Refreshing %s..." patch)
+    (let ((ret (apply 'hg-run "qrefresh" args)))
+      (if (equal (car ret) 0)
+	  (message "Refreshing %s... done." patch)
+	(error "Refreshing %s... %s" patch (hg-chomp (cdr ret)))))))
+
+(defun mq-refresh ()
+  "Refresh the topmost applied patch."
+  (interactive)
+  (let ((root (hg-root)))
+    (unless root
+      (error "Cannot refresh outside of a repository!"))
+  (mq-refresh-internal root)))
+
+(defun mq-patch-info (cmd &optional msg)
+  (let* ((ret (hg-run cmd))
+	 (info (hg-chomp (cdr ret))))
+    (if (equal (car ret) 0)
+	(if msg
+	    (message "%s patch: %s" msg info)
+	  info)
+      (error "%s" info))))
+
+(defun mq-top ()
+  "Print the name of the topmost applied patch."
+  (interactive)
+  (mq-patch-info "qtop" "Top"))
+
+(defun mq-next ()
+  "Print the name of the next patch to be pushed."
+  (interactive)
+  (mq-patch-info "qnext" "Next"))
+
+(defun mq-previous ()
+  "Print the name of the first patch below the topmost applied patch.
+This would become the active patch if popped to."
+  (interactive)
+  (mq-patch-info "qprev" "Previous"))
+
+(defun mq-edit-finish ()
+  "Finish editing the description of this patch, and refresh the patch."
+  (interactive)
+  (unless (equal (mq-patch-info "qtop") mq-top)
+    (error "Topmost patch has changed!"))
+  (hg-sync-buffers hg-root)
+  (mq-refresh-internal hg-root "-m" (buffer-substring (point-min) (point-max)))
+  (let ((buf mq-prev-buffer))
+    (kill-buffer nil)
+    (switch-to-buffer buf)))
+  
+(defun mq-edit-kill ()
+  "Kill the edit currently being prepared."
+  (interactive)
+  (when (or (not (buffer-modified-p)) (y-or-n-p "Really kill this edit? "))
+    (let ((buf mq-prev-buffer))
+      (kill-buffer nil)
+      (switch-to-buffer buf))))
+
+(defun mq-get-top (root)
+  (let ((entry (assoc root mq-top-patch)))
+    (if entry
+        (cdr entry))))
+
+(defun mq-set-top (root patch)
+  (let ((entry (assoc root mq-top-patch)))
+    (if entry
+        (if patch
+            (setcdr entry patch)
+          (setq mq-top-patch (delq entry mq-top-patch)))
+      (setq mq-top-patch (cons (cons root patch) mq-top-patch)))))
+
+(defun mq-update-mode-lines (root)
+  (let ((cwd default-directory))
+    (cd root)
+    (condition-case nil
+        (mq-set-top root (mq-patch-info "qtop"))
+      (error (mq-set-top root nil)))
+    (cd cwd))
+  (let ((patch (mq-get-top root)))
+    (save-excursion
+      (dolist (buf (hg-buffers-visiting-repo root))
+        (set-buffer buf)
+        (if mq-mode
+            (setq mq-mode (or (and patch (concat " MQ:" patch)) " MQ")))))))
+	
+(defun mq-mode (&optional arg)
+  "Minor mode for Mercurial repositories with an MQ patch queue"
+  (interactive "i")
+  (cond ((hg-root)
+         (setq mq-mode (if (null arg) (not mq-mode)
+                         arg))
+         (mq-update-mode-lines (hg-root))))
+  (run-hooks 'mq-mode-hook))
+
+(defun mq-edit-mode ()
+  "Mode for editing the description of a patch.
+
+Key bindings
+------------
+\\[mq-edit-finish]	use this description
+\\[mq-edit-kill]	abandon this description"
+  (interactive)
+  (use-local-map mq-edit-mode-map)
+  (set-syntax-table text-mode-syntax-table)
+  (setq local-abbrev-table text-mode-abbrev-table
+	major-mode 'mq-edit-mode
+	mode-name "MQ-Edit")
+  (set-buffer-modified-p nil)
+  (setq buffer-undo-list nil)
+  (run-hooks 'text-mode-hook 'mq-edit-mode-hook))
+  
+(defun mq-refresh-edit ()
+  "Refresh the topmost applied patch, editing the patch description."
+  (interactive)
+  (while mq-prev-buffer
+    (set-buffer mq-prev-buffer))
+  (let ((root (hg-root))
+	(prev-buffer (current-buffer))
+	(patch (mq-patch-info "qtop")))
+    (hg-sync-buffers root)
+    (let ((buf-name (format "*MQ: Edit description of %s*" patch)))
+      (switch-to-buffer (get-buffer-create buf-name))
+      (when (= (point-min) (point-max))
+	(set (make-local-variable 'hg-root) root)
+	(set (make-local-variable 'mq-top) patch)
+	(setq mq-prev-buffer prev-buffer)
+	(insert (hg-run0 "qheader"))
+	(goto-char (point-min)))
+      (mq-edit-mode)
+      (cd root)))
+  (message "Type `C-c C-c' to finish editing and refresh the patch."))
+
+
+(provide 'mq)
+
+
+;;; Local Variables:
+;;; prompt-to-byte-compile: nil
+;;; end:
--- a/contrib/win32/ReadMe.html	Sat Sep 02 22:58:02 2006 -0400
+++ b/contrib/win32/ReadMe.html	Sat Oct 21 15:22:08 2006 -0400
@@ -46,7 +46,7 @@
       other Mercurial commands should work fine for you.</p>
 
     <h1>Configuration notes</h1>
-    <p>The default editor for commit messages is 'vi'. You can set the EDITOR
+    <p>The default editor for commit messages is 'notepad'. You can set the EDITOR
     (or HGEDITOR) environment variable to specify your preference or set it in
     mercurial.ini:</p>
     <pre>
--- a/contrib/win32/mercurial.ini	Sat Sep 02 22:58:02 2006 -0400
+++ b/contrib/win32/mercurial.ini	Sat Oct 21 15:22:08 2006 -0400
@@ -3,6 +3,9 @@
 ; USERNAME is your Windows user name:
 ;   C:\Documents and Settings\USERNAME\Mercurial.ini
 
+[ui] 
+editor = notepad
+
 ; By default, we try to encode and decode all files that do not
 ; contain ASCII NUL characters.  What this means is that we try to set
 ; line endings to Windows style on update, and to Unix style on
--- a/doc/Makefile	Sat Sep 02 22:58:02 2006 -0400
+++ b/doc/Makefile	Sat Oct 21 15:22:08 2006 -0400
@@ -28,7 +28,7 @@
 
 install: man
 	for i in $(MAN) ; do \
-	  subdir=`echo $$i | sed -n 's/.\+\(\.[0-9]\)$$/man\1/p'` ; \
+	  subdir=`echo $$i | sed -n 's/..*\.\([0-9]\)$$/man\1/p'` ; \
 	  mkdir -p $(MANDIR)/$$subdir ; \
 	  $(INSTALL) $$i $(MANDIR)/$$subdir ; \
 	done
--- a/doc/hg.1.txt	Sat Sep 02 22:58:02 2006 -0400
+++ b/doc/hg.1.txt	Sat Oct 21 15:22:08 2006 -0400
@@ -127,6 +127,42 @@
     A range acts as a closed interval.  This means that a range of 3:5
     gives 3, 4 and 5.  Similarly, a range of 4:2 gives 4, 3, and 2.
 
+DATE FORMATS
+------------
+
+    Some commands (backout, commit, tag) allow the user to specify a date.
+    Possible formats for dates are:
+
+YYYY-mm-dd \HH:MM[:SS] [(+|-)NNNN]::
+    This is a subset of ISO 8601, allowing just the recommended notations
+    for date and time. The last part represents the timezone; if omitted,
+    local time is assumed. Examples:
+
+    "2005-08-22 03:27 -0700"
+
+    "2006-04-19 21:39:51"
+
+aaa bbb dd HH:MM:SS YYYY [(+|-)NNNN]::
+    This is the date format used by the C library. Here, aaa stands for
+    abbreviated weekday name and bbb for abbreviated month name. The last
+    part represents the timezone; if omitted, local time is assumed.
+    Examples:
+
+    "Mon Aug 22 03:27:00 2005 -0700"
+
+    "Wed Apr 19 21:39:51 2006"
+
+unixtime offset::
+    This is the internal representation format for dates. unixtime is
+    the number of seconds since the epoch (1970-01-01 00:00 UTC). offset
+    is the offset of the local timezone, in seconds west of UTC (negative
+    if the timezone is east of UTC).
+    Examples:
+
+    "1124706420 25200" (2005-08-22 03:27:00 -0700)
+
+    "1145475591 -7200" (2006-04-19 21:39:51 +0200)
+
 ENVIRONMENT VARIABLES
 ---------------------
 
@@ -193,6 +229,10 @@
     global /etc/mercurial/hgrc configuration.  See hgrc(5) for details of
     the contents and format of these files.
 
+Some commands (e.g. revert) produce backup files ending in .orig, if
+the .orig file already exists and is not tracked by Mercurial, it
+will be overwritten.
+
 BUGS
 ----
 Probably lots, please post them to the mailing list (See Resources below)
@@ -216,6 +256,6 @@
 
 COPYING
 -------
-Copyright \(C) 2005 Matt Mackall.
+Copyright \(C) 2005, 2006 Matt Mackall.
 Free use of this software is granted under the terms of the GNU General
 Public License (GPL).
--- a/doc/hgmerge.1.txt	Sat Sep 02 22:58:02 2006 -0400
+++ b/doc/hgmerge.1.txt	Sat Oct 21 15:22:08 2006 -0400
@@ -30,6 +30,6 @@
 
 COPYING
 -------
-Copyright \(C) 2005 Matt Mackall.
+Copyright \(C) 2005, 2006 Matt Mackall.
 Free use of this software is granted under the terms of the GNU General
 Public License (GPL).
--- a/doc/hgrc.5.txt	Sat Sep 02 22:58:02 2006 -0400
+++ b/doc/hgrc.5.txt	Sat Oct 21 15:22:08 2006 -0400
@@ -133,6 +133,21 @@
     # them to the working dir
     **.txt = tempfile: unix2dos -n INFILE OUTFILE
 
+defaults::
+  Use the [defaults] section to define command defaults, i.e. the 
+  default options/arguments to pass to the specified commands.
+  
+  The following example makes 'hg log' run in verbose mode, and
+  'hg status' show only the modified files, by default.
+  
+    [defaults]
+    log = -v
+    status = -m
+  
+  The actual commands, instead of their aliases, must be used when 
+  defining command defaults. The command defaults will also be
+  applied to the aliases of the commands defined.
+
 email::
   Settings for extensions that send email messages.
   from;;
@@ -306,7 +321,7 @@
 smtp::
   Configuration for extensions that need to send email messages.
   host;;
-    Optional.  Host name of mail server.  Default: "mail".
+    Host name of mail server, e.g. "mail.example.com".
   port;;
     Optional.  Port to connect to on mail server.  Default: 25.
   tls;;
@@ -377,6 +392,9 @@
     remote command to use for clone/push/pull operations. Default is 'hg'.
   ssh;;
     command to use for SSH connections. Default is 'ssh'.
+  strict;;
+    Require exact command names, instead of allowing unambiguous
+    abbreviations.  True or False.  Default is False.
   timeout;;
     The timeout used when a lock is held (in seconds), a negative value
     means no timeout. Default is 600.
--- a/doc/ja/hg.1.ja.txt	Sat Sep 02 22:58:02 2006 -0400
+++ b/doc/ja/hg.1.ja.txt	Sat Oct 21 15:22:08 2006 -0400
@@ -862,6 +862,6 @@
 
 著作権情報
 -----
-Copyright (C) 2005 Matt Mackall.
+Copyright (C) 2005, 2006 Matt Mackall.
 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
 認められます。
--- a/doc/ja/hgmerge.1.ja.txt	Sat Sep 02 22:58:02 2006 -0400
+++ b/doc/ja/hgmerge.1.ja.txt	Sat Oct 21 15:22:08 2006 -0400
@@ -32,6 +32,6 @@
 
 著作権情報
 ----
-Copyright (C) 2005 Matt Mackall.
+Copyright (C) 2005, 2006 Matt Mackall.
 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
 認められます。
--- a/hgeditor	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgeditor	Sat Oct 21 15:22:08 2006 -0400
@@ -41,13 +41,15 @@
 
 cat "$1" > "$HGTMP/msg"
 
-CHECKSUM=`md5sum "$HGTMP/msg"`
+MD5=$(which md5sum 2>/dev/null) || \
+    MD5=$(which md5 2>/dev/null) 
+[ -x "${MD5}" ] && CHECKSUM=`${MD5} "$HGTMP/msg"`
 if [ -s "$HGTMP/diff" ]; then
     $EDITOR "$HGTMP/msg" "$HGTMP/diff" || exit $?
 else
     $EDITOR "$HGTMP/msg" || exit $?
 fi
-echo "$CHECKSUM" | md5sum -c >/dev/null 2>&1 && exit 13
+[ -x "${MD5}" ] && (echo "$CHECKSUM" | ${MD5} -c >/dev/null 2>&1 && exit 13)
 
 mv "$HGTMP/msg" "$1"
 
--- a/hgext/acl.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/acl.py	Sat Oct 21 15:22:08 2006 -0400
@@ -60,8 +60,8 @@
             return None, False
 
         thisuser = self.getuser()
-        pats = [pat for pat, user in self.ui.configitems(key)
-                if user == thisuser]
+        pats = [pat for pat, users in self.ui.configitems(key)
+                if thisuser in users.replace(',', ' ').split()]
         self.ui.debug(_('acl: %s enabled, %d entries for user %s\n') %
                       (key, len(pats), thisuser))
         if pats:
@@ -80,7 +80,7 @@
         self.user = getpass.getuser()
         cfg = self.ui.config('acl', 'config')
         if cfg:
-            self.ui.readconfig(cfg)
+            self.ui.readsections(cfg, 'acl.allow', 'acl.deny')
         self.allow, self.allowable = self.buildmatch('acl.allow')
         self.deny, self.deniable = self.buildmatch('acl.deny')
 
--- a/hgext/bugzilla.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/bugzilla.py	Sat Oct 21 15:22:08 2006 -0400
@@ -74,7 +74,7 @@
         timeout = int(self.ui.config('bugzilla', 'timeout', 5))
         usermap = self.ui.config('bugzilla', 'usermap')
         if usermap:
-            self.ui.readconfig(usermap)
+            self.ui.readsections(usermap, 'usermap')
         self.ui.note(_('connecting to %s:%s as %s, password %s\n') %
                      (host, db, user, '*' * len(passwd)))
         self.conn = MySQLdb.connect(host=host, user=user, passwd=passwd,
--- a/hgext/extdiff.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/extdiff.py	Sat Oct 21 15:22:08 2006 -0400
@@ -5,37 +5,55 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 #
-# allow to use external programs to compare revisions, or revision
-# with working dir. program is called with two arguments: paths to
-# directories containing snapshots of files to compare.
+# The `extdiff' Mercurial extension allows you to use external programs
+# to compare revisions, or revision with working dir.  The external diff
+# programs are called with a configurable set of options and two
+# non-option arguments: paths to directories containing snapshots of
+# files to compare.
 #
-# to enable:
+# To enable this extension:
 #
 #   [extensions]
 #   hgext.extdiff =
 #
-# also allows to configure new diff commands, so you do not need to
-# type "hg extdiff -p kdiff3" always.
+# The `extdiff' extension also allows to configure new diff commands, so
+# you do not need to type "hg extdiff -p kdiff3" always.
 #
 #   [extdiff]
+#   # add new command that runs GNU diff(1) in 'context diff' mode
+#   cmd.cdiff = gdiff
+#   opts.cdiff = -Nprc5
+
 #   # add new command called vdiff, runs kdiff3
 #   cmd.vdiff = kdiff3
+
 #   # add new command called meld, runs meld (no need to name twice)
 #   cmd.meld =
+
 #   # add new command called vimdiff, runs gvimdiff with DirDiff plugin
 #   #(see http://www.vim.org/scripts/script.php?script_id=102)
-#   cmd.vimdiff = LC_ALL=C gvim -f '+bdel 1 2' '+ execute "DirDiff ".argv(0)." ".argv(1)'
+#   # Non english user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
+#   # your .vimrc
+#   cmd.vimdiff = gvim
+#   opts.vimdiff = -f '+next' '+execute "DirDiff" argv(0) argv(1)'
 #
-# you can use -I/-X and list of file or directory names like normal
-# "hg diff" command. extdiff makes snapshots of only needed files, so
-# compare program will be fast.
+# Each custom diff commands can have two parts: a `cmd' and an `opts'
+# part.  The cmd.xxx option defines the name of an executable program
+# that will be run, and opts.xxx defines a set of command-line options
+# which will be inserted to the command between the program name and
+# the files/directories to diff (i.e. the cdiff example above).
+#
+# You can use -I/-X and list of file or directory names like normal
+# "hg diff" command.  The `extdiff' extension makes snapshots of only
+# needed files, so running the external diff program will actually be
+# pretty fast (at least faster than having to compare the entire tree).
 
 from mercurial.demandload import demandload
 from mercurial.i18n import gettext as _
 from mercurial.node import *
-demandload(globals(), 'mercurial:commands,util os shutil tempfile')
+demandload(globals(), 'mercurial:cmdutil,util os shutil tempfile')
 
-def dodiff(ui, repo, diffcmd, pats, opts):
+def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
     def snapshot_node(files, node):
         '''snapshot files as of some revision'''
         changes = repo.changelog.read(node)
@@ -47,6 +65,9 @@
             ui.write_err(_('making snapshot of %d files from rev %s\n') %
                          (len(files), short(node)))
         for fn in files:
+            if not fn in mf:
+                # skipping new file after a merge ?
+                continue
             wfn = util.pconvert(fn)
             ui.note('  %s\n' % wfn)
             dest = os.path.join(base, wfn)
@@ -78,10 +99,10 @@
                 fp.write(chunk)
         return dirname
 
-    node1, node2 = commands.revpair(ui, repo, opts['rev'])
-    files, matchfn, anypats = commands.matchpats(repo, pats, opts)
-    modified, added, removed, deleted, unknown = repo.changes(
-        node1, node2, files, match=matchfn)
+    node1, node2 = cmdutil.revpair(ui, repo, opts['rev'])
+    files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
+    modified, added, removed, deleted, unknown = repo.status(
+        node1, node2, files, match=matchfn)[:5]
     if not (modified or added or removed):
         return 0
 
@@ -92,9 +113,11 @@
             dir2 = snapshot_node(modified + added, node2)
         else:
             dir2 = snapshot_wdir(modified + added)
-        util.system('%s %s "%s" "%s"' %
-                    (diffcmd, ' '.join(opts['option']), dir1, dir2),
-                    cwd=tmproot)
+        cmdline = ('%s %s %s %s' %
+                   (util.shellquote(diffcmd), ' '.join(diffopts),
+                    util.shellquote(dir1), util.shellquote(dir2)))
+        ui.debug('running %r in %s\n' % (cmdline, tmproot))
+        util.system(cmdline, cwd=tmproot)
         return 1
     finally:
         ui.note(_('cleaning up temp directory\n'))
@@ -104,7 +127,9 @@
     '''use external program to diff repository (or selected files)
 
     Show differences between revisions for the specified files, using
-    an external program.  The default program used is "diff -Npru".
+    an external program.  The default program used is diff, with
+    default options "-Npru".
+
     To select a different program, use the -p option.  The program
     will be passed the names of two directories to compare.  To pass
     additional options to the program, use the -o option.  These will
@@ -115,7 +140,12 @@
     specified then that revision is compared to the working
     directory, and, when no revisions are specified, the
     working directory files are compared to its parent.'''
-    return dodiff(ui, repo, opts['program'] or 'diff -Npru', pats, opts)
+    program = opts['program'] or 'diff'
+    if opts['program']:
+        option = opts['option']
+    else:
+        option = opts['option'] or ['-Npru']
+    return dodiff(ui, repo, program, option, pats, opts)
 
 cmdtable = {
     "extdiff":
@@ -133,21 +163,25 @@
         if not cmd.startswith('cmd.'): continue
         cmd = cmd[4:]
         if not path: path = cmd
-        def save(cmd, path):
+        diffopts = ui.config('extdiff', 'opts.' + cmd, '')
+        diffopts = diffopts and [diffopts] or []
+        def save(cmd, path, diffopts):
             '''use closure to save diff command to use'''
             def mydiff(ui, repo, *pats, **opts):
-                return dodiff(ui, repo, path, pats, opts)
-            mydiff.__doc__ = '''use %s to diff repository (or selected files)
+                return dodiff(ui, repo, path, diffopts, pats, opts)
+            mydiff.__doc__ = '''use %(path)r to diff repository (or selected files)
 
             Show differences between revisions for the specified
-            files, using the %s program.
+            files, using the %(path)r program.
 
             When two revision arguments are given, then changes are
             shown between those revisions. If only one revision is
             specified then that revision is compared to the working
             directory, and, when no revisions are specified, the
-            working directory files are compared to its parent.''' % (cmd, cmd)
+            working directory files are compared to its parent.''' % {
+                'path': path,
+                }
             return mydiff
-        cmdtable[cmd] = (save(cmd, path),
+        cmdtable[cmd] = (save(cmd, path, diffopts),
                          cmdtable['extdiff'][1][1:],
                          _('hg %s [OPT]... [FILE]...') % cmd)
--- a/hgext/fetch.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/fetch.py	Sat Oct 21 15:22:08 2006 -0400
@@ -24,13 +24,13 @@
         if modheads == 0:
             return 0
         if modheads == 1:
-            return hg.update(repo, repo.changelog.tip(), wlock=wlock)
+            return hg.clean(repo, repo.changelog.tip(), wlock=wlock)
         newheads = repo.heads(parent)
         newchildren = [n for n in repo.heads(parent) if n != parent]
         newparent = parent
         if newchildren:
             newparent = newchildren[0]
-            hg.update(repo, newparent, wlock=wlock)
+            hg.clean(repo, newparent, wlock=wlock)
         newheads = [n for n in repo.heads() if n != newparent]
         err = False
         if newheads:
@@ -63,7 +63,7 @@
             revs = [other.lookup(rev) for rev in opts['rev']]
         modheads = repo.pull(other, heads=revs, lock=lock)
         return postincoming(other, modheads)
-        
+
     parent, p2 = repo.dirstate.parents()
     if parent != repo.changelog.tip():
         raise util.Abort(_('working dir not at tip '
--- a/hgext/gpg.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/gpg.py	Sat Oct 21 15:22:08 2006 -0400
@@ -221,7 +221,7 @@
         repo.opener("localsigs", "ab").write(sigmessage)
         return
 
-    for x in repo.changes():
+    for x in repo.status()[:5]:
         if ".hgsigs" in x and not opts["force"]:
             raise util.Abort(_("working copy of .hgsigs is changed "
                                "(please commit .hgsigs manually "
--- a/hgext/hbisect.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/hbisect.py	Sat Oct 21 15:22:08 2006 -0400
@@ -23,10 +23,10 @@
     return parents.pop()
 
 def check_clean(ui, repo):
-        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)
+    modified, added, removed, deleted, unknown = repo.status()[:5]
+    if modified or added or removed:
+        ui.warn("Repository is not clean, please commit or revert\n")
+        sys.exit(1)
 
 class bisect(object):
     """dichotomic search in the DAG of changesets"""
--- a/hgext/hgk.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/hgk.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,95 +1,45 @@
 # Minimal support for git commands on an hg repository
 #
-# Copyright 2005 Chris Mason <mason@suse.com>
+# Copyright 2005, 2006 Chris Mason <mason@suse.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import time, sys, signal, os
-from mercurial import hg, mdiff, fancyopts, commands, ui, util
-
-def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
-           changes=None, text=False):
-    def date(c):
-        return time.asctime(time.gmtime(c[2][0]))
-
-    if not changes:
-        changes = repo.changes(node1, node2, files, match=match)
-    modified, added, removed, deleted, unknown = changes
-    if files:
-        modified, added, removed = map(lambda x: filterfiles(files, x),
-                                       (modified, added, removed))
-
-    if not modified and not added and not removed:
-        return
+from mercurial.demandload import *
+demandload(globals(), 'time sys signal os')
+demandload(globals(), 'mercurial:hg,fancyopts,commands,ui,util,patch,revlog')
 
-    if node2:
-        change = repo.changelog.read(node2)
-        mmap2 = repo.manifest.read(change[0])
-        date2 = date(change)
-        def read(f):
-            return repo.file(f).read(mmap2[f])
-    else:
-        date2 = time.asctime()
-        if not node1:
-            node1 = repo.dirstate.parents()[0]
-        def read(f):
-            return repo.wfile(f).read()
-
-    change = repo.changelog.read(node1)
-    mmap = repo.manifest.read(change[0])
-    date1 = date(change)
-
-    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 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 removed:
-        to = repo.file(f).read(mmap[f])
-        tn = None
-        fp.write("diff --git a/%s /dev/null\n" % (f))
-        fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
-
-def difftree(ui, repo, node1=None, node2=None, **opts):
+def difftree(ui, repo, node1=None, node2=None, *files, **opts):
     """diff trees from two commits"""
-    def __difftree(repo, node1, node2):
-        def date(c):
-            return time.asctime(time.gmtime(c[2][0]))
-
+    def __difftree(repo, node1, node2, files=[]):
         if node2:
             change = repo.changelog.read(node2)
             mmap2 = repo.manifest.read(change[0])
-            modified, added, removed, deleted, unknown = repo.changes(node1, node2)
-            def read(f): return repo.file(f).read(mmap2[f])
-            date2 = date(change)
+            status = repo.status(node1, node2, files=files)[:5]
+            modified, added, removed, deleted, unknown = status
         else:
-            date2 = time.asctime()
-            modified, added, removed, deleted, unknown = repo.changes(node1)
+            status = repo.status(node1, files=files)[:5]
+            modified, added, removed, deleted, unknown = status
             if not node1:
                 node1 = repo.dirstate.parents()[0]
-            def read(f): return file(os.path.join(repo.root, f)).read()
 
         change = repo.changelog.read(node1)
         mmap = repo.manifest.read(change[0])
-        date1 = date(change)
-        empty = "0" * 40;
+        empty = hg.short(hg.nullid)
 
         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)
+            print ":100664 100664 %s %s M\t%s\t%s" % (hg.short(mmap[f]),
+                                                      hg.short(mmap2[f]),
+                                                      f, f)
         for f in added:
-            print ":000000 100664 %s %s N\t%s\t%s" % (empty, hg.hex(mmap2[f]), f, f)
+            print ":000000 100664 %s %s N\t%s\t%s" % (empty,
+                                                      hg.short(mmap2[f]),
+                                                      f, f)
         for f in removed:
-            print ":100664 000000 %s %s D\t%s\t%s" % (hg.hex(mmap[f]), empty, f, f)
+            print ":100664 000000 %s %s D\t%s\t%s" % (hg.short(mmap[f]),
+                                                      empty,
+                                                      f, f)
     ##
 
     while True:
@@ -112,20 +62,22 @@
         if opts['patch']:
             if opts['pretty']:
                 catcommit(repo, node2, "")
-            dodiff(sys.stdout, ui, repo, node1, node2)
+            patch.diff(repo, node1, node2,
+                       files=files,
+                       opts=patch.diffopts(ui, {'git': True}))
         else:
-            __difftree(repo, node1, node2)
+            __difftree(repo, node1, node2, files=files)
         if not opts['stdin']:
             break
 
 def catcommit(repo, n, prefix, changes=None):
     nlprefix = '\n' + prefix;
     (p1, p2) = repo.changelog.parents(n)
-    (h, h1, h2) = map(hg.hex, (n, p1, p2))
+    (h, h1, h2) = map(hg.short, (n, p1, p2))
     (i1, i2) = map(repo.changelog.rev, (p1, p2))
     if not changes:
         changes = repo.changelog.read(n)
-    print "tree %s" % (hg.hex(changes[0]))
+    print "tree %s" % (hg.short(changes[0]))
     if i1 != -1: print "parent %s" % (h1)
     if i2 != -1: print "parent %s" % (h2)
     date_ar = changes[2]
@@ -138,6 +90,7 @@
 
     print "author %s %s %s" % (changes[1], date, date_ar[1])
     print "committer %s %s %s" % (committer, date, date_ar[1])
+    print "revision %d" % repo.changelog.rev(n)
     print ""
     if prefix != "":
         print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip())
@@ -151,7 +104,7 @@
     node1 = repo.lookup(node1)
     node2 = repo.lookup(node2)
     n = repo.changelog.ancestor(node1, node2)
-    print hg.hex(n)
+    print hg.short(n)
 
 def catfile(ui, repo, type=None, r=None, **opts):
     """cat a specific revision"""
@@ -264,7 +217,6 @@
 
     # walk the repository looking for commits that are in our
     # reachability graph
-    #for i in range(repo.changelog.count()-1, -1, -1):
     for i, changes in chlogwalk():
         n = repo.changelog.node(i)
         mask = is_reachable(want_sha1, reachable, n)
@@ -273,17 +225,17 @@
             if parents:
                 pp = repo.changelog.parents(n)
                 if pp[0] != hg.nullid:
-                    parentstr += " " + hg.hex(pp[0])
+                    parentstr += " " + hg.short(pp[0])
                 if pp[1] != hg.nullid:
-                    parentstr += " " + hg.hex(pp[1])
+                    parentstr += " " + hg.short(pp[1])
             if not full:
-                print hg.hex(n) + parentstr
-            elif full is "commit":
-                print hg.hex(n) + parentstr
+                print hg.short(n) + parentstr
+            elif full == "commit":
+                print hg.short(n) + parentstr
                 catcommit(repo, n, '    ', changes)
             else:
                 (p1, p2) = repo.changelog.parents(n)
-                (h, h1, h2) = map(hg.hex, (n, p1, p2))
+                (h, h1, h2) = map(hg.short, (n, p1, p2))
                 (i1, i2) = map(repo.changelog.rev, (p1, p2))
 
                 date = changes[2][0]
@@ -299,6 +251,19 @@
                 break
             count += 1
 
+def revparse(ui, repo, *revs, **opts):
+    """Parse given revisions"""
+    def revstr(rev):
+        if rev == 'HEAD':
+            rev = 'tip'
+        return revlog.hex(repo.lookup(rev))
+
+    for r in revs:
+        revrange = r.split(':', 1)
+        ui.write('%s\n' % revstr(revrange[0]))
+        if len(revrange) == 2:
+            ui.write('^%s\n' % revstr(revrange[1]))
+
 # git rev-list tries to order things by date, and has the ability to stop
 # at a given commit without walking the whole repo.  TODO add the stop
 # parameter
@@ -311,23 +276,31 @@
     copy = [x for x in revs]
     revtree(copy, repo, full, opts['max_count'], opts['parents'])
 
-def view(ui, repo, *etc):
+def view(ui, repo, *etc, **opts):
     "start interactive history viewer"
     os.chdir(repo.root)
-    os.system(ui.config("hgk", "path", "hgk") + " " + " ".join(etc))
+    optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
+    cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
+    ui.debug("running %s\n" % cmd)
+    os.system(cmd)
 
 cmdtable = {
-    "view": (view, [], 'hg view'),
+    "view": (view,
+             [('l', 'limit', '', 'limit number of changes displayed')],
+             'hg view [-l LIMIT] [REVRANGE]'),
     "debug-diff-tree": (difftree, [('p', 'patch', None, 'generate patch'),
                             ('r', 'recursive', None, 'recursive'),
                             ('P', 'pretty', None, 'pretty'),
                             ('s', 'stdin', None, 'stdin'),
                             ('C', 'copy', None, 'detect copies'),
                             ('S', 'search', "", 'search')],
-                            "hg git-diff-tree [options] node1 node2"),
+                            "hg git-diff-tree [options] node1 node2 [files...]"),
     "debug-cat-file": (catfile, [('s', 'stdin', None, 'stdin')],
                  "hg debug-cat-file [options] type file"),
     "debug-merge-base": (base, [], "hg debug-merge-base node node"),
+    'debug-rev-parse': (revparse,
+                        [('', 'default', '', 'ignored')],
+                        "hg debug-rev-parse rev"),
     "debug-rev-list": (revlist, [('H', 'header', None, 'header'),
                            ('t', 'topo-order', None, 'topo-order'),
                            ('p', 'parents', None, 'parents'),
--- a/hgext/mq.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/mq.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,7 +1,6 @@
-
 # queue.py - patch queues for mercurial
 #
-# Copyright 2005 Chris Mason <mason@suse.com>
+# Copyright 2005, 2006 Chris Mason <mason@suse.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -31,16 +30,17 @@
 '''
 
 from mercurial.demandload import *
+from mercurial.i18n import gettext as _
+from mercurial import commands
 demandload(globals(), "os sys re struct traceback errno bz2")
-from mercurial.i18n import gettext as _
-from mercurial import ui, hg, revlog, commands, util
+demandload(globals(), "mercurial:cmdutil,hg,patch,revlog,ui,util")
 
 commands.norepo += " qclone qversion"
 
 class statusentry:
     def __init__(self, rev, name=None):
         if not name:
-            fields = rev.split(':')
+            fields = rev.split(':', 1)
             if len(fields) == 2:
                 self.rev, self.name = fields
             else:
@@ -66,6 +66,7 @@
         self.guards_path = "guards"
         self.active_guards = None
         self.guards_dirty = False
+        self._diffopts = None
 
         if os.path.exists(self.join(self.series_path)):
             self.full_series = self.opener(self.series_path).read().splitlines()
@@ -75,6 +76,11 @@
             lines = self.opener(self.status_path).read().splitlines()
             self.applied = [statusentry(l) for l in lines]
 
+    def diffopts(self):
+        if self._diffopts is None:
+            self._diffopts = patch.diffopts(self.ui)
+        return self._diffopts
+
     def join(self, *p):
         return os.path.join(self.path, *p)
 
@@ -108,6 +114,9 @@
                 comment = l[h:]
             patch = patch.strip()
             if patch:
+                if patch in self.series:
+                    raise util.Abort(_('%s appears more than once in %s') %
+                                     (patch, self.join(self.series_path)))
                 self.series.append(patch)
                 self.series_guards.append(self.guard_re.findall(comment))
 
@@ -121,7 +130,7 @@
         for c in bad_chars:
             if c in guard:
                 return _('invalid character in guard %r: %r') % (guard, c)
-        
+
     def set_active(self, guards):
         for guard in guards:
             bad = self.check_guard(guard)
@@ -163,7 +172,7 @@
         self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
         self.parse_series()
         self.series_dirty = True
-        
+
     def pushable(self, idx):
         if isinstance(idx, str):
             idx = self.series.index(idx)
@@ -176,11 +185,11 @@
         if exactneg:
             return False, exactneg[0]
         pos = [g for g in patchguards if g[0] == '+']
-        nonpos = [g for g in pos if g[1:] not in guards]
+        exactpos = [g for g in pos if g[1:] in guards]
         if pos:
-            if not nonpos:
-                return True, ''
-            return False, nonpos
+            if exactpos:
+                return True, exactpos[0]
+            return False, pos
         return True, ''
 
     def explain_pushable(self, idx, all_patches=False):
@@ -247,6 +256,9 @@
 
         for line in file(pf):
             line = line.rstrip()
+            if line.startswith('diff --git'):
+                diffstart = 2
+                break
             if diffstart:
                 if line.startswith('+++ '):
                     diffstart = 2
@@ -292,6 +304,13 @@
             message.insert(0, subject)
         return (message, comments, user, date, diffstart > 1)
 
+    def printdiff(self, repo, node1, node2=None, files=None,
+                  fp=None, changes=None, opts={}):
+        fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts)
+
+        patch.diff(repo, node1, node2, fns, match=matchfn,
+                   fp=fp, changes=changes, opts=self.diffopts())
+
     def mergeone(self, repo, mergeq, head, patch, rev, wlock):
         # first try just applying the patch
         (err, n) = self.apply(repo, [ patch ], update_status=False,
@@ -325,7 +344,7 @@
         if comments:
             comments = "\n".join(comments) + '\n\n'
             patchf.write(comments)
-        commands.dodiff(patchf, self.ui, repo, head, n)
+        self.printdiff(repo, head, n, fp=patchf)
         patchf.close()
         return (0, n)
 
@@ -390,39 +409,15 @@
         '''Apply patchfile  to the working directory.
         patchfile: file name of patch'''
         try:
-            pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
-            f = os.popen("%s -d %s -p1 --no-backup-if-mismatch < %s" %
-                         (pp, util.shellquote(repo.root), util.shellquote(patchfile)))
-        except:
-            self.ui.warn("patch failed, unable to continue (try -v)\n")
-            return (None, [], False)
-        files = []
-        fuzz = False
-        for l in f:
-            l = l.rstrip('\r\n');
-            if self.ui.verbose:
-                self.ui.warn(l + "\n")
-            if l[:14] == 'patching file ':
-                pf = os.path.normpath(util.parse_patch_output(l))
-                if pf not in files:
-                    files.append(pf)
-                printed_file = False
-                file_str = l
-            elif l.find('with fuzz') >= 0:
-                if not printed_file:
-                    self.ui.warn(file_str + '\n')
-                    printed_file = True
-                self.ui.warn(l + '\n')
-                fuzz = True
-            elif l.find('saving rejects to file') >= 0:
-                self.ui.warn(l + '\n')
-            elif l.find('FAILED') >= 0:
-                if not printed_file:
-                    self.ui.warn(file_str + '\n')
-                    printed_file = True
-                self.ui.warn(l + '\n')
+            (files, fuzz) = patch.patch(patchfile, self.ui, strip=1,
+                                        cwd=repo.root)
+        except Exception, inst:
+            self.ui.note(str(inst) + '\n')
+            if not self.ui.verbose:
+                self.ui.warn("patch failed, unable to continue (try -v)\n")
+            return (False, [], False)
 
-        return (not f.close(), files, fuzz)
+        return (True, files, fuzz)
 
     def apply(self, repo, series, list=False, update_status=True,
               strict=False, patchdir=None, merge=None, wlock=None):
@@ -435,43 +430,37 @@
         lock = repo.lock()
         tr = repo.transaction()
         n = None
-        for patch in series:
-            pushable, reason = self.pushable(patch)
+        for patchname in series:
+            pushable, reason = self.pushable(patchname)
             if not pushable:
-                self.explain_pushable(patch, all_patches=True)
+                self.explain_pushable(patchname, all_patches=True)
                 continue
-            self.ui.warn("applying %s\n" % patch)
-            pf = os.path.join(patchdir, patch)
+            self.ui.warn("applying %s\n" % patchname)
+            pf = os.path.join(patchdir, patchname)
 
             try:
-                message, comments, user, date, patchfound = self.readheaders(patch)
+                message, comments, user, date, patchfound = self.readheaders(patchname)
             except:
-                self.ui.warn("Unable to read %s\n" % pf)
+                self.ui.warn("Unable to read %s\n" % patchname)
                 err = 1
                 break
 
             if not message:
-                message = "imported patch %s\n" % patch
+                message = "imported patch %s\n" % patchname
             else:
                 if list:
-                    message.append("\nimported patch %s" % patch)
+                    message.append("\nimported patch %s" % patchname)
                 message = '\n'.join(message)
 
             (patcherr, files, fuzz) = self.patch(repo, pf)
             patcherr = not patcherr
 
-            if merge and len(files) > 0:
+            if merge and files:
                 # Mark as merged and update dirstate parent info
-                repo.dirstate.update(repo.dirstate.filterfiles(files), 'm')
+                repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm')
                 p1, p2 = repo.dirstate.parents()
                 repo.dirstate.setparents(p1, merge)
-            if len(files) > 0:
-                cwd = repo.getcwd()
-                cfiles = files
-                if cwd:
-                    cfiles = [util.pathto(cwd, f) for f in files]
-                commands.addremove_lock(self.ui, repo, cfiles,
-                                        opts={}, wlock=wlock)
+            files = patch.updatedir(self.ui, repo, files, wlock=wlock)
             n = repo.commit(files, message, user, date, force=1, lock=lock,
                             wlock=wlock)
 
@@ -479,11 +468,11 @@
                 raise util.Abort(_("repo commit failed"))
 
             if update_status:
-                self.applied.append(statusentry(revlog.hex(n), patch))
+                self.applied.append(statusentry(revlog.hex(n), patchname))
 
             if patcherr:
                 if not patchfound:
-                    self.ui.warn("patch %s is empty\n" % patch)
+                    self.ui.warn("patch %s is empty\n" % patchname)
                     err = 0
                 else:
                     self.ui.warn("patch failed, rejects left in working dir\n")
@@ -497,21 +486,51 @@
         tr.close()
         return (err, n)
 
-    def delete(self, repo, patch, force=False):
-        patch = self.lookup(patch, strict=True)
-        info = self.isapplied(patch)
-        if info:
-            raise util.Abort(_("cannot delete applied patch %s") % patch)
-        if patch not in self.series:
-            raise util.Abort(_("patch %s not in series file") % patch)
-        if force:
+    def delete(self, repo, patches, opts):
+        realpatches = []
+        for patch in patches:
+            patch = self.lookup(patch, strict=True)
+            info = self.isapplied(patch)
+            if info:
+                raise util.Abort(_("cannot delete applied patch %s") % patch)
+            if patch not in self.series:
+                raise util.Abort(_("patch %s not in series file") % patch)
+            realpatches.append(patch)
+
+        appliedbase = 0
+        if opts.get('rev'):
+            if not self.applied:
+                raise util.Abort(_('no patches applied'))
+            revs = [int(r) for r in cmdutil.revrange(ui, repo, opts['rev'])]
+            if len(revs) > 1 and revs[0] > revs[1]:
+                revs.reverse()
+            for rev in revs:
+                if appliedbase >= len(self.applied):
+                    raise util.Abort(_("revision %d is not managed") % rev)
+
+                base = revlog.bin(self.applied[appliedbase].rev)
+                node = repo.changelog.node(rev)
+                if node != base:
+                    raise util.Abort(_("cannot delete revision %d above "
+                                       "applied patches") % rev)
+                realpatches.append(self.applied[appliedbase].name)
+                appliedbase += 1
+
+        if not opts.get('keep'):
             r = self.qrepo()
             if r:
-                r.remove([patch], True)
+                r.remove(realpatches, True)
             else:
-                os.unlink(self.join(patch))
-        i = self.find_series(patch)
-        del self.full_series[i]
+                for p in realpatches:
+                    os.unlink(self.join(p))
+
+        if appliedbase:
+            del self.applied[:appliedbase]
+            self.applied_dirty = 1
+        indices = [self.find_series(p) for p in realpatches]
+        indices.sort()
+        for i in indices[-1::-1]:
+            del self.full_series[i]
         self.parse_series()
         self.series_dirty = 1
 
@@ -523,19 +542,20 @@
                 raise util.Abort(_("queue top not at same revision as working directory"))
             return top
         return None
-    def check_localchanges(self, repo):
-        (c, a, r, d, u) = repo.changes(None, None)
-        if c or a or d or r:
-            raise util.Abort(_("local changes found, refresh first"))
+    def check_localchanges(self, repo, force=False, refresh=True):
+        m, a, r, d = repo.status()[:4]
+        if m or a or r or d:
+            if not force:
+                if refresh:
+                    raise util.Abort(_("local changes found, refresh first"))
+                else:
+                    raise util.Abort(_("local changes found"))
+        return m, a, r, d
     def new(self, repo, patch, msg=None, force=None):
         if os.path.exists(self.join(patch)):
             raise util.Abort(_('patch "%s" already exists') % patch)
-        commitfiles = []
-        (c, a, r, d, u) = repo.changes(None, None)
-        if c or a or d or r:
-            if not force:
-                raise util.Abort(_("local changes found, refresh first"))
-            commitfiles = c + a + r
+        m, a, r, d = self.check_localchanges(repo, force)
+        commitfiles = m + a + r
         self.check_toppatch(repo)
         wlock = repo.wlock()
         insert = self.full_series_end()
@@ -561,7 +581,7 @@
         r = self.qrepo()
         if r: r.add([patch])
         if commitfiles:
-            self.refresh(repo, msg=None, short=True)
+            self.refresh(repo, short=True)
 
     def strip(self, repo, rev, update=True, backup="all", wlock=None):
         def limitheads(chlog, stop):
@@ -649,9 +669,7 @@
         revnum = chlog.rev(rev)
 
         if update:
-            (c, a, r, d, u) = repo.changes(None, None)
-            if c or a or d or r:
-                raise util.Abort(_("local changes found"))
+            self.check_localchanges(repo, refresh=False)
             urev = self.qparents(repo, rev)
             hg.clean(repo, urev, wlock=wlock)
             repo.dirstate.write()
@@ -702,8 +720,8 @@
         stripall(rev, revnum)
 
         change = chlog.read(rev)
+        chlog.strip(revnum, revnum)
         repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
-        chlog.strip(revnum, revnum)
         if saveheads:
             self.ui.status("adding branch\n")
             commands.unbundle(self.ui, repo, chgrpfile, update=False)
@@ -718,13 +736,15 @@
                 return (i, a.rev, a.name)
         return None
 
-    # if the exact patch name does not exist, we try a few 
+    # if the exact patch name does not exist, we try a few
     # variations.  If strict is passed, we try only #1
     #
     # 1) a number to indicate an offset in the series file
     # 2) a unique substring of the patch name was given
     # 3) patchname[-+]num to indicate an offset in the series file
     def lookup(self, patch, strict=False):
+        patch = patch and str(patch)
+
         def partial_name(s):
             if s in self.series:
                 return s
@@ -763,25 +783,25 @@
                 # return any partial match made above
                 if res:
                     return res
-                minus = patch.rsplit('-', 1)
-                if len(minus) > 1:
-                    res = partial_name(minus[0])
+                minus = patch.rfind('-')
+                if minus >= 0:
+                    res = partial_name(patch[:minus])
                     if res:
                         i = self.series.index(res)
                         try:
-                            off = int(minus[1] or 1)
+                            off = int(patch[minus+1:] or 1)
                         except(ValueError, OverflowError):
                             pass
                         else:
                             if i - off >= 0:
                                 return self.series[i - off]
-                plus = patch.rsplit('+', 1)
-                if len(plus) > 1:
-                    res = partial_name(plus[0])
+                plus = patch.rfind('+')
+                if plus >= 0:
+                    res = partial_name(patch[:plus])
                     if res:
                         i = self.series.index(res)
                         try:
-                            off = int(plus[1] or 1)
+                            off = int(patch[plus+1:] or 1)
                         except(ValueError, OverflowError):
                             pass
                         else:
@@ -795,11 +815,9 @@
             wlock = repo.wlock()
         patch = self.lookup(patch)
         if patch and self.isapplied(patch):
-            self.ui.warn(_("patch %s is already applied\n") % patch)
-            sys.exit(1)
+            raise util.Abort(_("patch %s is already applied") % patch)
         if self.series_end() == len(self.series):
-            self.ui.warn(_("patch series fully applied\n"))
-            sys.exit(1)
+            raise util.Abort(_("patch series fully applied"))
         if not force:
             self.check_localchanges(repo)
 
@@ -849,8 +867,7 @@
             if not info:
                 raise util.Abort(_("patch %s is not applied") % patch)
         if len(self.applied) == 0:
-            self.ui.warn(_("no patches applied\n"))
-            sys.exit(1)
+            raise util.Abort(_("no patches applied"))
 
         if not update:
             parents = repo.dirstate.parents()
@@ -887,15 +904,15 @@
             qp = self.qparents(repo, rev)
             changes = repo.changelog.read(qp)
             mmap = repo.manifest.read(changes[0])
-            (c, a, r, d, u) = repo.changes(qp, top)
+            m, a, r, d, u = repo.status(qp, top)[:5]
             if d:
                 raise util.Abort("deletions found between repo revs")
-            for f in c:
+            for f in m:
                 getfile(f, mmap[f])
             for f in r:
                 getfile(f, mmap[f])
-                util.set_exec(repo.wjoin(f), mmap.execf[f])
-            repo.dirstate.update(c + r, 'n')
+                util.set_exec(repo.wjoin(f), mmap.execf(f))
+            repo.dirstate.update(m + r, 'n')
             for f in a:
                 try: os.unlink(repo.wjoin(f))
                 except: raise
@@ -911,28 +928,28 @@
         else:
             self.ui.write("Patch queue now empty\n")
 
-    def diff(self, repo, files):
+    def diff(self, repo, pats, opts):
         top = self.check_toppatch(repo)
         if not top:
             self.ui.write("No patches applied\n")
             return
         qp = self.qparents(repo, top)
-        commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
+        self.printdiff(repo, qp, files=pats, opts=opts)
 
-    def refresh(self, repo, msg=None, short=False):
+    def refresh(self, repo, pats=None, **opts):
         if len(self.applied) == 0:
             self.ui.write("No patches applied\n")
-            return
+            return 1
         wlock = repo.wlock()
         self.check_toppatch(repo)
-        (top, patch) = (self.applied[-1].rev, self.applied[-1].name)
+        (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
         top = revlog.bin(top)
         cparents = repo.changelog.parents(top)
         patchparent = self.qparents(repo, top)
-        message, comments, user, date, patchfound = self.readheaders(patch)
+        message, comments, user, date, patchfound = self.readheaders(patchfn)
 
-        patchf = self.opener(patch, "w")
-        msg = msg.rstrip()
+        patchf = self.opener(patchfn, "w")
+        msg = opts.get('msg', '').rstrip()
         if msg:
             if comments:
                 # Remove existing message.
@@ -946,6 +963,7 @@
             comments = "\n".join(comments) + '\n\n'
             patchf.write(comments)
 
+        fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
         tip = repo.changelog.tip()
         if top == tip:
             # if the top of our patch queue is also the tip, there is an
@@ -958,30 +976,30 @@
             # patch already
             #
             # this should really read:
-            #(cc, dd, aa, aa2, uu) = repo.changes(tip, patchparent)
+            #   mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
             # but we do it backwards to take advantage of manifest/chlog
-            # caching against the next repo.changes call
+            # caching against the next repo.status call
             #
-            (cc, aa, dd, aa2, uu) = repo.changes(patchparent, tip)
-            if short:
-                filelist = cc + aa + dd
+            mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
+            if opts.get('short'):
+                filelist = mm + aa + dd
             else:
                 filelist = None
-            (c, a, r, d, u) = repo.changes(None, None, filelist)
+            m, a, r, d, u = repo.status(files=filelist)[:5]
 
             # we might end up with files that were added between tip and
             # the dirstate parent, but then changed in the local dirstate.
             # in this case, we want them to only show up in the added section
-            for x in c:
+            for x in m:
                 if x not in aa:
-                    cc.append(x)
+                    mm.append(x)
             # we might end up with files added by the local dirstate that
             # were deleted by the patch.  In this case, they should only
             # show up in the changed section.
             for x in a:
                 if x in dd:
                     del dd[dd.index(x)]
-                    cc.append(x)
+                    mm.append(x)
                 else:
                     aa.append(x)
             # make sure any files deleted in the local dirstate
@@ -992,28 +1010,42 @@
                     del aa[aa.index(x)]
                     forget.append(x)
                     continue
-                elif x in cc:
-                    del cc[cc.index(x)]
+                elif x in mm:
+                    del mm[mm.index(x)]
                 dd.append(x)
 
-            c = list(util.unique(cc))
+            m = list(util.unique(mm))
             r = list(util.unique(dd))
             a = list(util.unique(aa))
-            filelist = list(util.unique(c + r + a ))
-            commands.dodiff(patchf, self.ui, repo, patchparent, None,
-                            filelist, changes=(c, a, r, [], u))
+            filelist = filter(matchfn, util.unique(m + r + a))
+            if opts.get('git'):
+                self.diffopts().git = True
+            patch.diff(repo, patchparent, files=filelist, match=matchfn,
+                       fp=patchf, changes=(m, a, r, [], u),
+                       opts=self.diffopts())
             patchf.close()
 
             changes = repo.changelog.read(tip)
             repo.dirstate.setparents(*cparents)
+            copies = [(f, repo.dirstate.copied(f)) for f in a]
             repo.dirstate.update(a, 'a')
+            for dst, src in copies:
+                repo.dirstate.copy(src, dst)
             repo.dirstate.update(r, 'r')
-            repo.dirstate.update(c, 'n')
+            # if the patch excludes a modified file, mark that file with mtime=0
+            # so status can see it.
+            mm = []
+            for i in range(len(m)-1, -1, -1):
+                if not matchfn(m[i]):
+                    mm.append(m[i])
+                    del m[i]
+            repo.dirstate.update(m, 'n')
+            repo.dirstate.update(mm, 'n', st_mtime=0)
             repo.dirstate.forget(forget)
 
             if not msg:
                 if not message:
-                    message = "patch queue: %s\n" % patch
+                    message = "patch queue: %s\n" % patchfn
                 else:
                     message = "\n".join(message)
             else:
@@ -1021,10 +1053,10 @@
 
             self.strip(repo, top, update=False, backup='strip', wlock=wlock)
             n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
-            self.applied[-1] = statusentry(revlog.hex(n), patch)
+            self.applied[-1] = statusentry(revlog.hex(n), patchfn)
             self.applied_dirty = 1
         else:
-            commands.dodiff(patchf, self.ui, repo, patchparent, None)
+            self.printdiff(repo, patchparent, fp=patchf)
             patchf.close()
             self.pop(repo, force=True, wlock=wlock)
             self.push(repo, force=True, wlock=wlock)
@@ -1051,25 +1083,38 @@
             self.explain_pushable(i)
         return unapplied
 
-    def qseries(self, repo, missing=None, summary=False):
-        start = self.series_end(all_patches=True)
+    def qseries(self, repo, missing=None, start=0, length=0, status=None,
+                summary=False):
+        def displayname(patchname):
+            if summary:
+                msg = self.readheaders(patchname)[0]
+                msg = msg and ': ' + msg[0] or ': '
+            else:
+                msg = ''
+            return '%s%s' % (patchname, msg)
+
+        def pname(i):
+            if status == 'A':
+                return self.applied[i].name
+            else:
+                return self.series[i]
+
+        unapplied = self.series_end(all_patches=True)
+        if not length:
+            length = len(self.series) - start
         if not missing:
-            for i in range(len(self.series)):
-                patch = self.series[i]
+            for i in range(start, start+length):
+                pfx = ''
+                patch = pname(i)
                 if self.ui.verbose:
-                    if i < start:
+                    if i < unapplied:
                         status = 'A'
                     elif self.pushable(i)[0]:
                         status = 'U'
                     else:
                         status = 'G'
-                    self.ui.write('%d %s ' % (i, status))
-                if summary:
-                    msg = self.readheaders(patch)[0]
-                    msg = msg and ': ' + msg[0] or ': '
-                else:
-                    msg = ''
-                self.ui.write('%s%s\n' % (patch, msg))
+                    pfx = '%d %s ' % (i, status)
+                self.ui.write('%s%s\n' % (pfx, displayname(patch)))
         else:
             msng_list = []
             for root, dirs, files in os.walk(self.path):
@@ -1082,9 +1127,8 @@
                         msng_list.append(fl)
             msng_list.sort()
             for x in msng_list:
-                if self.ui.verbose:
-                    self.ui.write("D ")
-                self.ui.write("%s\n" % x)
+                pfx = self.ui.verbose and ('D ') or ''
+                self.ui.write("%s%s\n" % (pfx, displayname(x)))
 
     def issaveline(self, l):
         if l.name == '.hg.patches.save.line':
@@ -1116,7 +1160,8 @@
                 file_ = se.name
                 if se.rev:
                     applied.append(se)
-                series.append(file_)
+                else:
+                    series.append(file_)
         if datastart == None:
             self.ui.warn("No saved patch data found\n")
             return 1
@@ -1207,116 +1252,174 @@
             return next(end + 1)
         return next(end)
 
-    def qapplied(self, repo, patch=None):
-        if patch and patch not in self.series:
-            raise util.Abort(_("patch %s is not in series file") % patch)
-        if not patch:
-            end = len(self.applied)
-        else:
-            end = self.series.index(patch) + 1
-        for x in xrange(end):
-            p = self.appliedname(x)
-            self.ui.write("%s\n" % p)
-
     def appliedname(self, index):
         pname = self.applied[index].name
         if not self.ui.verbose:
             p = pname
         else:
-            p = str(self.series.index(pname)) + " " + p
+            p = str(self.series.index(pname)) + " " + pname
         return p
 
-    def top(self, repo):
-        if len(self.applied):
-            p = self.appliedname(-1)
-            self.ui.write(p + '\n')
-        else:
-            self.ui.write("No patches applied\n")
+    def qimport(self, repo, files, patchname=None, rev=None, existing=None,
+                force=None):
+        def checkseries(patchname):
+            if patchname in self.series:
+                raise util.Abort(_('patch %s is already in the series file')
+                                 % patchname)
+        def checkfile(patchname):
+            if not force and os.path.exists(self.join(patchname)):
+                raise util.Abort(_('patch "%s" already exists')
+                                 % patchname)
 
-    def next(self, repo):
-        end = self.series_end()
-        if end == len(self.series):
-            self.ui.write("All patches applied\n")
-        else:
-            p = self.series[end]
-            if self.ui.verbose:
-                self.ui.write("%d " % self.series.index(p))
-            self.ui.write(p + '\n')
-
-    def prev(self, repo):
-        if len(self.applied) > 1:
-            p = self.appliedname(-2)
-            self.ui.write(p + '\n')
-        elif len(self.applied) == 1:
-            self.ui.write("Only one patch applied\n")
-        else:
-            self.ui.write("No patches applied\n")
-
-    def qimport(self, repo, files, patch=None, existing=None, force=None):
-        if len(files) > 1 and patch:
+        if rev:
+            if files:
+                raise util.Abort(_('option "-r" not valid when importing '
+                                   'files'))
+            rev = [int(r) for r in cmdutil.revrange(self.ui, repo, rev)]
+            rev.sort(lambda x, y: cmp(y, x))
+        if (len(files) > 1 or len(rev) > 1) and patchname:
             raise util.Abort(_('option "-n" not valid when importing multiple '
-                               'files'))
+                               'patches'))
         i = 0
         added = []
+        if rev:
+            # If mq patches are applied, we can only import revisions
+            # that form a linear path to qbase.
+            # Otherwise, they should form a linear path to a head.
+            heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
+            if len(heads) > 1:
+                raise util.Abort(_('revision %d is the root of more than one '
+                                   'branch') % rev[-1])
+            if self.applied:
+                base = revlog.hex(repo.changelog.node(rev[0]))
+                if base in [n.rev for n in self.applied]:
+                    raise util.Abort(_('revision %d is already managed')
+                                     % rev[0])
+                if heads != [revlog.bin(self.applied[-1].rev)]:
+                    raise util.Abort(_('revision %d is not the parent of '
+                                       'the queue') % rev[0])
+                base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
+                lastparent = repo.changelog.parentrevs(base)[0]
+            else:
+                if heads != [repo.changelog.node(rev[0])]:
+                    raise util.Abort(_('revision %d has unmanaged children')
+                                     % rev[0])
+                lastparent = None
+
+            for r in rev:
+                p1, p2 = repo.changelog.parentrevs(r)
+                n = repo.changelog.node(r)
+                if p2 != -1:
+                    raise util.Abort(_('cannot import merge revision %d') % r)
+                if lastparent and lastparent != r:
+                    raise util.Abort(_('revision %d is not the parent of %d')
+                                     % (r, lastparent))
+                lastparent = p1
+
+                if not patchname:
+                    patchname = '%d.diff' % r
+                checkseries(patchname)
+                checkfile(patchname)
+                self.full_series.insert(0, patchname)
+
+                patchf = self.opener(patchname, "w")
+                patch.export(repo, [n], fp=patchf, opts=self.diffopts())
+                patchf.close()
+
+                se = statusentry(revlog.hex(n), patchname)
+                self.applied.insert(0, se)
+
+                added.append(patchname)
+                patchname = None
+            self.parse_series()
+            self.applied_dirty = 1
+
         for filename in files:
             if existing:
-                if not patch:
-                    patch = filename
-                if not os.path.isfile(self.join(patch)):
-                    raise util.Abort(_("patch %s does not exist") % patch)
+                if not patchname:
+                    patchname = filename
+                if not os.path.isfile(self.join(patchname)):
+                    raise util.Abort(_("patch %s does not exist") % patchname)
             else:
                 try:
                     text = file(filename).read()
                 except IOError:
-                    raise util.Abort(_("unable to read %s") % patch)
-                if not patch:
-                    patch = os.path.split(filename)[1]
-                if not force and os.path.exists(self.join(patch)):
-                    raise util.Abort(_('patch "%s" already exists') % patch)
-                patchf = self.opener(patch, "w")
+                    raise util.Abort(_("unable to read %s") % patchname)
+                if not patchname:
+                    patchname = os.path.basename(filename)
+                checkfile(patchname)
+                patchf = self.opener(patchname, "w")
                 patchf.write(text)
-            if patch in self.series:
-                raise util.Abort(_('patch %s is already in the series file')
-                                 % patch)
+            checkseries(patchname)
             index = self.full_series_end() + i
-            self.full_series[index:index] = [patch]
+            self.full_series[index:index] = [patchname]
             self.parse_series()
-            self.ui.warn("adding %s to series file\n" % patch)
+            self.ui.warn("adding %s to series file\n" % patchname)
             i += 1
-            added.append(patch)
-            patch = None
+            added.append(patchname)
+            patchname = None
         self.series_dirty = 1
         qrepo = self.qrepo()
         if qrepo:
             qrepo.add(added)
 
-def delete(ui, repo, patch, **opts):
-    """remove a patch from the series file
+def delete(ui, repo, *patches, **opts):
+    """remove patches from queue
 
-    The patch must not be applied.
-    With -f, deletes the patch file as well as the series entry."""
+    With --rev, mq will stop managing the named revisions. The
+    patches must be applied and at the base of the stack. This option
+    is useful when the patches have been applied upstream.
+
+    Otherwise, the patches must not be applied.
+
+    With --keep, the patch files are preserved in the patch directory."""
     q = repo.mq
-    q.delete(repo, patch, force=opts.get('force'))
+    q.delete(repo, patches, opts)
     q.save_dirty()
     return 0
 
 def applied(ui, repo, patch=None, **opts):
     """print the patches already applied"""
-    repo.mq.qapplied(repo, patch)
-    return 0
+    q = repo.mq
+    if patch:
+        if patch not in q.series:
+            raise util.Abort(_("patch %s is not in series file") % patch)
+        end = q.series.index(patch) + 1
+    else:
+        end = len(q.applied)
+    if not end:
+        return
+
+    return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
 
 def unapplied(ui, repo, patch=None, **opts):
     """print the patches not yet applied"""
-    for i, p in repo.mq.unapplied(repo, patch):
-        if ui.verbose:
-            ui.write("%d " % i)
-        ui.write("%s\n" % p)
+    q = repo.mq
+    if patch:
+        if patch not in q.series:
+            raise util.Abort(_("patch %s is not in series file") % patch)
+        start = q.series.index(patch) + 1
+    else:
+        start = q.series_end()
+    q.qseries(repo, start=start, summary=opts.get('summary'))
 
 def qimport(ui, repo, *filename, **opts):
-    """import a patch"""
+    """import a patch
+
+    The patch will have the same name as its source file unless you
+    give it a new one with --name.
+
+    You can register an existing patch inside the patch directory
+    with the --existing flag.
+
+    With --force, an existing patch of the same name will be overwritten.
+
+    An existing changeset may be placed under mq control with --rev
+    (e.g. qimport --rev tip -n patch will place tip under mq control).
+    """
     q = repo.mq
-    q.qimport(repo, filename, patch=opts['name'],
-              existing=opts['existing'], force=opts['force'])
+    q.qimport(repo, filename, patchname=opts['name'],
+              existing=opts['existing'], force=opts['force'], rev=opts['rev'])
     q.save_dirty()
     return 0
 
@@ -1397,18 +1500,36 @@
 
 def top(ui, repo, **opts):
     """print the name of the current patch"""
-    repo.mq.top(repo)
-    return 0
+    q = repo.mq
+    t = len(q.applied)
+    if t:
+        return q.qseries(repo, start=t-1, length=1, status='A',
+                         summary=opts.get('summary'))
+    else:
+        ui.write("No patches applied\n")
+        return 1
 
 def next(ui, repo, **opts):
     """print the name of the next patch"""
-    repo.mq.next(repo)
-    return 0
+    q = repo.mq
+    end = q.series_end()
+    if end == len(q.series):
+        ui.write("All patches applied\n")
+        return 1
+    return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
 
 def prev(ui, repo, **opts):
     """print the name of the previous patch"""
-    repo.mq.prev(repo)
-    return 0
+    q = repo.mq
+    l = len(q.applied)
+    if l == 1:
+        ui.write("Only one patch applied\n")
+        return 1
+    if not l:
+        ui.write("No patches applied\n")
+        return 1
+    return q.qseries(repo, start=l-2, length=1, status='A',
+                     summary=opts.get('summary'))
 
 def new(ui, repo, patch, **opts):
     """create a new patch
@@ -1418,17 +1539,24 @@
     changes unless -f is specified, in which case the patch will
     be initialised with them.
 
-    -m or -l set the patch header as well as the commit message.
-    If neither is specified, the patch header is empty and the
+    -e, -m or -l set the patch header as well as the commit message.
+    If none is specified, the patch header is empty and the
     commit message is 'New patch: PATCH'"""
     q = repo.mq
     message = commands.logmessage(opts)
+    if opts['edit']:
+        message = ui.edit(message, ui.username())
     q.new(repo, patch, msg=message, force=opts['force'])
     q.save_dirty()
     return 0
 
-def refresh(ui, repo, **opts):
-    """update the current patch"""
+def refresh(ui, repo, *pats, **opts):
+    """update the current patch
+
+    If any file patterns are provided, the refreshed patch will contain only
+    the modifications that match those patterns; the remaining modifications
+    will remain in the working directory.
+    """
     q = repo.mq
     message = commands.logmessage(opts)
     if opts['edit']:
@@ -1437,14 +1565,13 @@
         patch = q.applied[-1].name
         (message, comment, user, date, hasdiff) = q.readheaders(patch)
         message = ui.edit('\n'.join(message), user or ui.username())
-    q.refresh(repo, msg=message, short=opts['short'])
+    ret = q.refresh(repo, pats, msg=message, **opts)
     q.save_dirty()
-    return 0
+    return ret
 
-def diff(ui, repo, *files, **opts):
+def diff(ui, repo, *pats, **opts):
     """diff of the current patch"""
-    # deep in the dirstate code, the walkhelper method wants a list, not a tuple
-    repo.mq.diff(repo, list(files))
+    repo.mq.diff(repo, pats, opts)
     return 0
 
 def fold(ui, repo, *files, **opts):
@@ -1454,7 +1581,7 @@
     applied to the current patch in the order given. If all the
     patches apply successfully, the current patch will be refreshed
     with the new cumulative patch, and the folded patches will
-    be deleted. With -f/--force, the folded patch files will
+    be deleted. With -k/--keep, the folded patch files will not
     be removed afterwards.
 
     The header for each folded patch will be concatenated with
@@ -1465,7 +1592,7 @@
     if not files:
         raise util.Abort(_('qfold requires at least one patch name'))
     if not q.check_toppatch(repo):
-        raise util.Abort(_('No patches applied\n'))
+        raise util.Abort(_('No patches applied'))
 
     message = commands.logmessage(opts)
     if opts['edit']:
@@ -1476,20 +1603,21 @@
     patches = []
     messages = []
     for f in files:
-        patch = q.lookup(f)
-        if patch in patches or patch == parent:
-            ui.warn(_('Skipping already folded patch %s') % patch)
-        if q.isapplied(patch):
-            raise util.Abort(_('qfold cannot fold already applied patch %s') % patch)
-        patches.append(patch)
+        p = q.lookup(f)
+        if p in patches or p == parent:
+            ui.warn(_('Skipping already folded patch %s') % p)
+        if q.isapplied(p):
+            raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
+        patches.append(p)
 
-    for patch in patches:
+    for p in patches:
         if not message:
-            messages.append(q.readheaders(patch)[0])
-        pf = q.join(patch)
+            messages.append(q.readheaders(p)[0])
+        pf = q.join(p)
         (patchsuccess, files, fuzz) = q.patch(repo, pf)
         if not patchsuccess:
-            raise util.Abort(_('Error folding patch %s') % patch)
+            raise util.Abort(_('Error folding patch %s') % p)
+        patch.updatedir(ui, repo, files)
 
     if not message:
         message, comments, user = q.readheaders(parent)[0:3]
@@ -1502,30 +1630,27 @@
         message = ui.edit(message, user or ui.username())
 
     q.refresh(repo, msg=message)
-
-    for patch in patches:
-        q.delete(repo, patch, force=opts['force'])
-
+    q.delete(repo, patches, opts)
     q.save_dirty()
 
 def guard(ui, repo, *args, **opts):
     '''set or print guards for a patch
 
-    guards control whether a patch can be pushed.  a patch with no
-    guards is aways pushed.  a patch with posative guard ("+foo") is
-    pushed only if qselect command enables guard "foo".  a patch with
-    nagative guard ("-foo") is never pushed if qselect command enables
-    guard "foo".
+    Guards control whether a patch can be pushed. A patch with no
+    guards is always pushed. A patch with a positive guard ("+foo") is
+    pushed only if the qselect command has activated it. A patch with
+    a negative guard ("-foo") is never pushed if the qselect command
+    has activated it.
 
-    with no arguments, default is to print current active guards.
-    with arguments, set active guards for patch.
+    With no arguments, print the currently active guards.
+    With arguments, set guards for the named patch.
 
-    to set nagative guard "-foo" on topmost patch ("--" is needed so
-    hg will not interpret "-foo" as argument):
+    To set a negative guard "-foo" on topmost patch ("--" is needed so
+    hg will not interpret "-foo" as an option):
       hg qguard -- -foo
 
-    to set guards on other patch:
-      hg qguard other.patch +2.6.17 -stable    
+    To set guards on another patch:
+      hg qguard other.patch +2.6.17 -stable
     '''
     def status(idx):
         guards = q.series_guards[idx] or ['unguarded']
@@ -1562,7 +1687,7 @@
     else:
         if not q.applied:
             ui.write('No patches applied\n')
-            return
+            return 1
         patch = q.lookup('qtip')
     message = repo.mq.readheaders(patch)[0]
 
@@ -1639,13 +1764,6 @@
         name = patch
         patch = None
 
-    if name in q.series:
-        raise util.Abort(_('A patch named %s already exists in the series file') % name)
-
-    absdest = q.join(name)
-    if os.path.exists(absdest):
-        raise util.Abort(_('%s already exists') % absdest)
-    
     if patch:
         patch = q.lookup(patch)
     else:
@@ -1653,6 +1771,15 @@
             ui.write(_('No patches applied\n'))
             return
         patch = q.lookup('qtip')
+    absdest = q.join(name)
+    if os.path.isdir(absdest):
+        name = os.path.join(name, os.path.basename(patch))
+        absdest = q.join(name)
+    if os.path.exists(absdest):
+        raise util.Abort(_('%s already exists') % absdest)
+
+    if name in q.series:
+        raise util.Abort(_('A patch named %s already exists in the series file') % name)
 
     if ui.verbose:
         ui.write('Renaming %s to %s\n' % (patch, name))
@@ -1724,44 +1851,64 @@
         backup = 'strip'
     elif opts['nobackup']:
         backup = 'none'
-    repo.mq.strip(repo, rev, backup=backup)
+    update = repo.dirstate.parents()[0] != revlog.nullid
+    repo.mq.strip(repo, rev, backup=backup, update=update)
     return 0
 
 def select(ui, repo, *args, **opts):
     '''set or print guarded patches to push
 
-    use qguard command to set or print guards on patch.  then use
-    qselect to tell mq which guards to use.  example:
+    Use the qguard command to set or print guards on patch, then use
+    qselect to tell mq which guards to use. A patch will be pushed if it
+    has no guards or any positive guards match the currently selected guard,
+    but will not be pushed if any negative guards match the current guard.
+    For example:
 
-        qguard foo.patch -stable    (nagative guard)
-        qguard bar.patch +stable    (posative guard)
+        qguard foo.patch -stable    (negative guard)
+        qguard bar.patch +stable    (positive guard)
         qselect stable
 
-    this sets "stable" guard.  mq will skip foo.patch (because it has
-    nagative match) but push bar.patch (because it has posative
-    match).  patch is pushed only if all posative guards match and no
-    nagative guards match.
+    This activates the "stable" guard. mq will skip foo.patch (because
+    it has a negative match) but push bar.patch (because it
+    has a positive match).
+
+    With no arguments, prints the currently active guards.
+    With one argument, sets the active guard.
 
-    with no arguments, default is to print current active guards.
-    with arguments, set active guards as given.
-    
-    use -n/--none to deactivate guards (no other arguments needed).
-    when no guards active, patches with posative guards are skipped,
-    patches with nagative guards are pushed.
+    Use -n/--none to deactivate guards (no other arguments needed).
+    When no guards are active, patches with positive guards are skipped
+    and patches with negative guards are pushed.
 
-    use -s/--series to print list of all guards in series file (no
-    other arguments needed).  use -v for more information.'''
+    qselect can change the guards on applied patches. It does not pop
+    guarded patches by default. Use --pop to pop back to the last applied
+    patch that is not guarded. Use --reapply (which implies --pop) to push
+    back to the current patch afterwards, but skip guarded patches.
+
+    Use -s/--series to print a list of all guards in the series file (no
+    other arguments needed). Use -v for more information.'''
 
     q = repo.mq
     guards = q.active()
     if args or opts['none']:
+        old_unapplied = q.unapplied(repo)
+        old_guarded = [i for i in xrange(len(q.applied)) if
+                       not q.pushable(i)[0]]
         q.set_active(args)
         q.save_dirty()
         if not args:
             ui.status(_('guards deactivated\n'))
-        if q.series:
-            ui.status(_('%d of %d unapplied patches active\n') %
-                      (len(q.unapplied(repo)), len(q.series)))
+        if not opts['pop'] and not opts['reapply']:
+            unapplied = q.unapplied(repo)
+            guarded = [i for i in xrange(len(q.applied))
+                       if not q.pushable(i)[0]]
+            if len(unapplied) != len(old_unapplied):
+                ui.status(_('number of unguarded, unapplied patches has '
+                            'changed from %d to %d\n') %
+                          (len(old_unapplied), len(unapplied)))
+            if len(guarded) != len(old_guarded):
+                ui.status(_('number of guarded, applied patches has changed '
+                            'from %d to %d\n') %
+                          (len(old_guarded), len(guarded)))
     elif opts['series']:
         guards = {}
         noguards = 0
@@ -1789,9 +1936,51 @@
                 ui.write(g, '\n')
         else:
             ui.write(_('no active guards\n'))
+    reapply = opts['reapply'] and q.applied and q.appliedname(-1)
+    popped = False
+    if opts['pop'] or opts['reapply']:
+        for i in xrange(len(q.applied)):
+            pushable, reason = q.pushable(i)
+            if not pushable:
+                ui.status(_('popping guarded patches\n'))
+                popped = True
+                if i == 0:
+                    q.pop(repo, all=True)
+                else:
+                    q.pop(repo, i-1)
+                break
+    if popped:
+        try:
+            if reapply:
+                ui.status(_('reapplying unguarded patches\n'))
+                q.push(repo, reapply)
+        finally:
+            q.save_dirty()
 
 def reposetup(ui, repo):
     class mqrepo(repo.__class__):
+        def abort_if_wdir_patched(self, errmsg, force=False):
+            if self.mq.applied and not force:
+                parent = revlog.hex(self.dirstate.parents()[0])
+                if parent in [s.rev for s in self.mq.applied]:
+                    raise util.Abort(errmsg)
+
+        def commit(self, *args, **opts):
+            if len(args) >= 6:
+                force = args[5]
+            else:
+                force = opts.get('force')
+            self.abort_if_wdir_patched(
+                _('cannot commit over an applied mq patch'),
+                force)
+
+            return super(mqrepo, self).commit(*args, **opts)
+
+        def push(self, remote, force=False, revs=None):
+            if self.mq.applied and not force:
+                raise util.Abort(_('source has mq patches applied'))
+            return super(mqrepo, self).push(remote, force, revs)
+
         def tags(self):
             if self.tagscache:
                 return self.tagscache
@@ -1813,11 +2002,14 @@
 
             return tagscache
 
-    repo.__class__ = mqrepo
-    repo.mq = queue(ui, repo.join(""))
+    if repo.local():
+        repo.__class__ = mqrepo
+        repo.mq = queue(ui, repo.join(""))
+
+seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
 
 cmdtable = {
-    "qapplied": (applied, [], 'hg qapplied [PATCH]'),
+    "qapplied": (applied, [] + seriesopts, 'hg qapplied [-s] [PATCH]'),
     "qclone": (clone,
                [('', 'pull', None, _('use pull protocol to copy metadata')),
                 ('U', 'noupdate', None, _('do not update the new working directories')),
@@ -1832,15 +2024,19 @@
         (commit,
          commands.table["^commit|ci"][1],
          'hg qcommit [OPTION]... [FILE]...'),
-    "^qdiff": (diff, [], 'hg qdiff [FILE]...'),
-    "qdelete":
+    "^qdiff": (diff,
+               [('I', 'include', [], _('include names matching the given patterns')),
+                ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+               'hg qdiff [-I] [-X] [FILE]...'),
+    "qdelete|qremove|qrm":
         (delete,
-         [('f', 'force', None, _('delete patch file'))],
-          'hg qdelete [-f] PATCH'),
+         [('k', 'keep', None, _('keep patch file')),
+          ('r', 'rev', [], _('stop managing a revision'))],
+          'hg qdelete [-k] [-r REV]... PATCH...'),
     'qfold':
         (fold,
          [('e', 'edit', None, _('edit patch header')),
-          ('f', 'force', None, _('delete folded patch files')),
+          ('k', 'keep', None, _('keep folded patch files')),
           ('m', 'message', '', _('set patch header to <text>')),
           ('l', 'logfile', '', _('set patch header to contents of <file>'))],
          'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
@@ -1853,20 +2049,22 @@
         (qimport,
          [('e', 'existing', None, 'import file in patch dir'),
           ('n', 'name', '', 'patch file name'),
-          ('f', 'force', None, 'overwrite existing files')],
-         'hg qimport [-e] [-n NAME] [-f] FILE...'),
+          ('f', 'force', None, 'overwrite existing files'),
+          ('r', 'rev', [], 'place existing revisions under mq control')],
+         'hg qimport [-e] [-n NAME] [-f] [-r REV]... FILE...'),
     "^qinit":
         (init,
          [('c', 'create-repo', None, 'create queue repository')],
          'hg qinit [-c]'),
     "qnew":
         (new,
-         [('m', 'message', '', _('use <text> as commit message')),
+         [('e', 'edit', None, _('edit commit message')),
+          ('m', 'message', '', _('use <text> as commit message')),
           ('l', 'logfile', '', _('read the commit message from <file>')),
           ('f', 'force', None, _('import uncommitted changes into patch'))],
-         'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'),
-    "qnext": (next, [], 'hg qnext'),
-    "qprev": (prev, [], 'hg qprev'),
+         'hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH'),
+    "qnext": (next, [] + seriesopts, 'hg qnext [-s]'),
+    "qprev": (prev, [] + seriesopts, 'hg qprev [-s]'),
     "^qpop":
         (pop,
          [('a', 'all', None, 'pop all patches'),
@@ -1886,8 +2084,11 @@
          [('e', 'edit', None, _('edit commit message')),
           ('m', 'message', '', _('change commit message with <text>')),
           ('l', 'logfile', '', _('change commit message with <file> content')),
-          ('s', 'short', None, 'short refresh')],
-         'hg qrefresh [-e] [-m TEXT] [-l FILE] [-s]'),
+          ('g', 'git', None, _('use git extended diff format')),
+          ('s', 'short', None, 'short refresh'),
+          ('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'),
     'qrename|qmv':
         (rename, [], 'hg qrename PATCH1 [PATCH2]'),
     "qrestore":
@@ -1906,20 +2107,21 @@
          'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
     "qselect": (select,
                 [('n', 'none', None, _('disable all guards')),
-                 ('s', 'series', None, _('list all guards in series file'))],
-                'hg qselect [GUARDS]'),
+                 ('s', 'series', None, _('list all guards in series file')),
+                 ('', 'pop', None,
+                  _('pop to before first guarded applied patch')),
+                 ('', 'reapply', None, _('pop, then reapply patches'))],
+                'hg qselect [OPTION...] [GUARD...]'),
     "qseries":
         (series,
-         [('m', 'missing', None, 'print patches not in series'),
-          ('s', 'summary', None, _('print first line of patch header'))],
-         'hg qseries [-m]'),
+         [('m', 'missing', None, 'print patches not in series')] + seriesopts,
+         'hg qseries [-ms]'),
     "^strip":
         (strip,
          [('f', 'force', None, 'force multi-head removal'),
           ('b', 'backup', None, 'bundle unrelated changesets'),
           ('n', 'nobackup', None, 'no backups')],
          'hg strip [-f] [-b] [-n] REV'),
-    "qtop": (top, [], 'hg qtop'),
-    "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
+    "qtop": (top, [] + seriesopts, 'hg qtop [-s]'),
+    "qunapplied": (unapplied, [] + seriesopts, 'hg qunapplied [-s] [PATCH]'),
 }
-
--- a/hgext/notify.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/notify.py	Sat Oct 21 15:22:08 2006 -0400
@@ -40,6 +40,7 @@
 #   changegroup = ...      # template when run as changegroup hook
 #   maxdiff = 300          # max lines of diffs to include (0=none, -1=all)
 #   maxsubject = 67        # truncate subject line longer than this
+#   diffstat = True        # add a diffstat before the diff content
 #   sources = serve        # notify if source of incoming changes in this list
 #                          # (serve == ssh or http, push, pull, bundle)
 #   [email]
@@ -67,8 +68,8 @@
 from mercurial.demandload import *
 from mercurial.i18n import gettext as _
 from mercurial.node import *
-demandload(globals(), 'email.Parser mercurial:commands,templater,util')
-demandload(globals(), 'fnmatch socket time')
+demandload(globals(), 'mercurial:commands,patch,templater,util,mail')
+demandload(globals(), 'email.Parser fnmatch socket time')
 
 # template for single changeset can include email headers.
 single_template = '''
@@ -101,7 +102,7 @@
         self.ui = ui
         cfg = self.ui.config('notify', 'config')
         if cfg:
-            self.ui.readconfig(cfg)
+            self.ui.readsections(cfg, 'usersubs', 'reposubs')
         self.repo = repo
         self.stripcount = int(self.ui.config('notify', 'strip', 0))
         self.root = self.strip(self.repo.root)
@@ -229,8 +230,8 @@
         else:
             self.ui.status(_('notify: sending %d subscribers %d changes\n') %
                              (len(self.subs), count))
-            mail = self.ui.sendmail()
-            mail.sendmail(templater.email(msg['From']), self.subs, msgtext)
+            mail.sendmail(self.ui, templater.email(msg['From']),
+                          self.subs, msgtext)
 
     def diff(self, node, ref):
         maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
@@ -238,8 +239,11 @@
             return
         fp = templater.stringio()
         prev = self.repo.changelog.parents(node)[0]
-        commands.dodiff(fp, self.ui, self.repo, prev, ref)
+        patch.diff(self.repo, prev, ref, fp=fp)
         difflines = fp.getvalue().splitlines(1)
+        if self.ui.configbool('notify', 'diffstat', True):
+            s = patch.diffstat(difflines)
+            self.sio.write('\ndiffstat:\n\n' + s)
         if maxdiff > 0 and len(difflines) > maxdiff:
             self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') %
                            (len(difflines), maxdiff))
--- a/hgext/patchbomb.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/hgext/patchbomb.py	Sat Oct 21 15:22:08 2006 -0400
@@ -23,26 +23,49 @@
 # 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 enable this extension:
 #
-# The "-m" (mbox) option will create an mbox file instead of sending
-# the messages directly. This can be reviewed e.g. with "mutt -R -f mbox",
-# and finally sent with "formail -s sendmail -bm -t < mbox".
+#   [extensions]
+#   hgext.patchbomb =
 #
 # To configure other defaults, add a section like this to your hgrc
 # file:
 #
-# [email]
-# from = My Name <my@email>
-# to = recipient1, recipient2, ...
-# cc = cc1, cc2, ...
-# bcc = bcc1, bcc2, ...
+#   [email]
+#   from = My Name <my@email>
+#   to = recipient1, recipient2, ...
+#   cc = cc1, cc2, ...
+#   bcc = bcc1, bcc2, ...
+#
+# Then you can use the "hg email" command to mail a series of changesets
+# as a patchbomb.
+#
+# To avoid sending patches prematurely, it is a good idea to first run
+# the "email" command with the "-n" option (test only).  You will be
+# prompted for an email recipient address, a subject an an introductory
+# message describing the patches of your patchbomb.  Then when all is
+# done, your pager will be fired up once for each patchbomb message, so
+# you can verify everything is alright.
+#
+# The "-m" (mbox) option is also very useful.  Instead of previewing
+# each patchbomb message in a pager or sending the messages directly,
+# it will create a UNIX mailbox file with the patch emails.  This
+# mailbox file can be previewed with any mail user agent which supports
+# UNIX mbox files, i.e. with mutt:
+#
+#   % mutt -R -f mbox
+#
+# When you are previewing the patchbomb messages, you can use `formail'
+# (a utility that is commonly installed as part of the procmail package),
+# to send each message out:
+#
+#  % formail -s sendmail -bm -t < mbox
+#
+# That should be all.  Now your patchbomb is on its way out.
 
 from mercurial.demandload import *
 demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
-                         mercurial:commands,hg,ui
+                         mercurial:cmdutil,commands,hg,mail,ui,patch
                          os errno popen2 socket sys tempfile time''')
 from mercurial.i18n import gettext as _
 from mercurial.node import *
@@ -53,27 +76,6 @@
     import readline
 except ImportError: pass
 
-def diffstat(patch):
-    fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
-    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
 
@@ -100,8 +102,8 @@
         if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'):
             raise ValueError
 
-    def cdiffstat(summary, patch):
-        s = diffstat(patch)
+    def cdiffstat(summary, patchlines):
+        s = patch.diffstat(patchlines)
         if s:
             if summary:
                 ui.write(summary, '\n')
@@ -117,7 +119,9 @@
             if line.startswith('#'):
                 if line.startswith('# Node ID'): node = line.split()[-1]
                 continue
-            if line.startswith('diff -r'): break
+            if (line.startswith('diff -r')
+                or line.startswith('diff --git')):
+                break
             desc.append(line)
         if not node: raise ValueError
 
@@ -142,10 +146,10 @@
             if patchname:
                 patchname = patchname[0]
             elif total > 1:
-                patchname = commands.make_filename(repo, '%b-%n.patch',
+                patchname = cmdutil.make_filename(repo, '%b-%n.patch',
                                                    binnode, idx, total)
             else:
-                patchname = commands.make_filename(repo, '%b.patch', binnode)
+                patchname = cmdutil.make_filename(repo, '%b.patch', binnode)
             p['Content-Disposition'] = 'inline; filename=' + patchname
             msg.attach(p)
         else:
@@ -154,7 +158,8 @@
         if total == 1:
             subj = '[PATCH] ' + desc[0].strip()
         else:
-            subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip())
+            tlen = len(str(total))
+            subj = '[PATCH %0*d of %d] %s' % (tlen, idx, total, desc[0].strip())
         if subj.endswith('.'): subj = subj[:-1]
         msg['Subject'] = subj
         msg['X-Mercurial-Node'] = node
@@ -182,7 +187,8 @@
 
     commands.export(ui, repo, *revs, **{'output': exportee(patches),
                                         'switch_parent': False,
-                                        'text': None})
+                                        'text': None,
+                                        'git': opts.get('git')})
 
     jumbo = []
     msgs = []
@@ -212,10 +218,14 @@
     if len(patches) > 1:
         ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
 
-        subj = '[PATCH 0 of %d] %s' % (
+        tlen = len(str(len(patches)))
+
+        subj = '[PATCH %0*d of %d] %s' % (
+            tlen, 0,
             len(patches),
             opts['subject'] or
-            prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches)))
+            prompt('Subject:', rest = ' [PATCH %0*d of %d] ' % (tlen, 0,
+                len(patches))))
 
         ui.write(_('Finish with ^D or a dot on a line by itself.\n\n'))
 
@@ -241,7 +251,7 @@
     ui.write('\n')
 
     if not opts['test'] and not opts['mbox']:
-        mail = ui.sendmail()
+        mailer = mail.connect(ui)
     parent = None
 
     # Calculate UTC offset
@@ -290,7 +300,7 @@
             ui.status('Sending ', m['Subject'], ' ...\n')
             # Exim does not remove the Bcc field
             del m['Bcc']
-            mail.sendmail(sender, to + bcc + cc, m.as_string(0))
+            mailer.sendmail(sender, to + bcc + cc, m.as_string(0))
 
 cmdtable = {
     'email':
@@ -299,6 +309,7 @@
       ('', 'bcc', [], 'email addresses of blind copy recipients'),
       ('c', 'cc', [], 'email addresses of copy recipients'),
       ('d', 'diffstat', None, 'add diffstat output to messages'),
+      ('g', 'git', None, _('use git extended diff format')),
       ('f', 'from', '', 'email address of sender'),
       ('', 'plain', None, 'omit hg patch header'),
       ('n', 'test', None, 'print messages that would be sent'),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/ancestor.py	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,83 @@
+# ancestor.py - generic DAG ancestor algorithm for mercurial
+#
+# Copyright 2006 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+import heapq
+
+def ancestor(a, b, pfunc):
+    """
+    return the least common ancestor of nodes a and b or None if there
+    is no such ancestor.
+
+    pfunc must return a list of parent vertices
+    """
+
+    if a == b:
+        return a
+
+    # find depth from root of all ancestors
+    visit = [a, b]
+    depth = {}
+    while visit:
+        vertex = visit[-1]
+        pl = pfunc(vertex)
+        if not pl:
+            depth[vertex] = 0
+            visit.pop()
+        else:
+            for p in pl:
+                if p == a or p == b: # did we find a or b as a parent?
+                    return p # we're done
+                if p not in depth:
+                    visit.append(p)
+            if visit[-1] == vertex:
+                depth[vertex] = min([depth[p] for p in pl]) - 1
+                visit.pop()
+
+    # traverse ancestors in order of decreasing distance from root
+    def ancestors(vertex):
+        h = [(depth[vertex], vertex)]
+        seen = {}
+        while h:
+            d, n = heapq.heappop(h)
+            if n not in seen:
+                seen[n] = 1
+                yield (d, n)
+                for p in pfunc(n):
+                    heapq.heappush(h, (depth[p], p))
+
+    def generations(vertex):
+        sg, s = None, {}
+        for g,v in ancestors(vertex):
+            if g != sg:
+                if sg:
+                    yield sg, s
+                sg, s = g, {v:1}
+            else:
+                s[v] = 1
+        yield sg, s
+
+    x = generations(a)
+    y = generations(b)
+    gx = x.next()
+    gy = y.next()
+
+    # increment each ancestor list until it is closer to root than
+    # the other, or they match
+    try:
+        while 1:
+            if gx[0] == gy[0]:
+                for v in gx[1]:
+                    if v in gy[1]:
+                        return v
+                gy = y.next()
+                gx = x.next()
+            elif gx[0] > gy[0]:
+                gy = y.next()
+            else:
+                gx = x.next()
+    except StopIteration:
+        return None
--- a/mercurial/archival.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/archival.py	Sat Oct 21 15:22:08 2006 -0400
@@ -163,11 +163,12 @@
     change = repo.changelog.read(node)
     mn = change[0]
     archiver = archivers[kind](dest, prefix, mtime or change[2][0])
-    mf = repo.manifest.read(mn).items()
-    mf.sort()
+    m = repo.manifest.read(mn)
+    items = m.items()
+    items.sort()
     write('.hg_archival.txt', 0644,
           'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node)))
-    for filename, filenode in mf:
-        write(filename, mf.execf(filename) and 0755 or 0644,
+    for filename, filenode in items:
+        write(filename, m.execf(filename) and 0755 or 0644,
               repo.file(filename).read(filenode))
     archiver.done()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/base85.c	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,155 @@
+/*
+ base85 codec
+
+ Copyright 2006 Brendan Cully <brendan@kublai.com>
+
+ This software may be used and distributed according to the terms of
+ the GNU General Public License, incorporated herein by reference.
+
+ Largely based on git's implementation
+*/
+
+#include <Python.h>
+
+static const char b85chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+	"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
+static char b85dec[256];
+
+static void
+b85prep(void)
+{
+	int i;
+
+	memset(b85dec, 0, sizeof(b85dec));
+	for (i = 0; i < sizeof(b85chars); i++)
+		b85dec[(int)(b85chars[i])] = i + 1;
+}
+
+static PyObject *
+b85encode(PyObject *self, PyObject *args)
+{
+	const unsigned char *text;
+	PyObject *out;
+	char *dst;
+	int len, olen, i;
+	unsigned int acc, val, ch;
+        int pad = 0;
+
+	if (!PyArg_ParseTuple(args, "s#|i", &text, &len, &pad))
+		return NULL;
+
+        if (pad)
+                olen = ((len + 3) / 4 * 5) - 3;
+        else {
+                olen = len % 4;
+                if (olen)
+                        olen++;
+                olen += len / 4 * 5;
+        }
+	if (!(out = PyString_FromStringAndSize(NULL, olen + 3)))
+		return NULL;
+
+	dst = PyString_AS_STRING(out);
+
+	while (len) {
+		acc = 0;
+		for (i = 24; i >= 0; i -= 8) {
+			ch = *text++;
+			acc |= ch << i;
+			if (--len == 0)
+				break;
+		}
+		for (i = 4; i >= 0; i--) {
+			val = acc % 85;
+			acc /= 85;
+			dst[i] = b85chars[val];
+		}
+		dst += 5;
+	}
+
+        if (!pad)
+                _PyString_Resize(&out, olen);
+
+	return out;
+}
+
+static PyObject *
+b85decode(PyObject *self, PyObject *args)
+{
+	PyObject *out;
+	const char *text;
+	char *dst;
+	int len, i, j, olen, c, cap;
+	unsigned int acc;
+
+	if (!PyArg_ParseTuple(args, "s#", &text, &len))
+		return NULL;
+
+	olen = len / 5 * 4;
+	i = len % 5;
+	if (i)
+		olen += i - 1;
+	if (!(out = PyString_FromStringAndSize(NULL, olen)))
+		return NULL;
+
+	dst = PyString_AS_STRING(out);
+
+	i = 0;
+	while (i < len)
+	{
+		acc = 0;
+		cap = len - i - 1;
+		if (cap > 4)
+			cap = 4;
+		for (j = 0; j < cap; i++, j++)
+		{
+			c = b85dec[(int)*text++] - 1;
+			if (c < 0)
+				return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i);
+			acc = acc * 85 + c;
+		}
+		if (i++ < len)
+		{
+			c = b85dec[(int)*text++] - 1;
+			if (c < 0)
+				return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i);
+			/* overflow detection: 0xffffffff == "|NsC0",
+			 * "|NsC" == 0x03030303 */
+			if (acc > 0x03030303 || (acc *= 85) > 0xffffffff - c)
+				return PyErr_Format(PyExc_ValueError, "Bad base85 sequence at position %d", i);
+			acc += c;
+		}
+
+		cap = olen < 4 ? olen : 4;
+		olen -= cap;
+		for (j = 0; j < 4 - cap; j++)
+			acc *= 85;
+		if (cap && cap < 4)
+			acc += 0xffffff >> (cap - 1) * 8;
+		for (j = 0; j < cap; j++)
+		{
+			acc = (acc << 8) | (acc >> 24);
+			*dst++ = acc;
+		}
+	}
+
+	return out;
+}
+
+static char base85_doc[] = "Base85 Data Encoding";
+
+static PyMethodDef methods[] = {
+	{"b85encode", b85encode, METH_VARARGS,
+         "Encode text in base85.\n\n"
+         "If the second parameter is true, pad the result to a multiple of "
+         "five characters.\n"},
+	{"b85decode", b85decode, METH_VARARGS, "Decode base85 text.\n"},
+	{NULL, NULL}
+};
+
+PyMODINIT_FUNC initbase85(void)
+{
+	Py_InitModule3("base85", methods, base85_doc);
+
+	b85prep();
+}
--- a/mercurial/bdiff.c	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/bdiff.c	Sat Oct 21 15:22:08 2006 -0400
@@ -1,7 +1,7 @@
 /*
  bdiff.c - efficient binary diff extension for Mercurial
 
- Copyright 2005 Matt Mackall <mpm@selenic.com>
+ Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
  This software may be used and distributed according to the terms of
  the GNU General Public License, incorporated herein by reference.
@@ -300,18 +300,19 @@
 
 static PyObject *bdiff(PyObject *self, PyObject *args)
 {
-	PyObject *sa, *sb, *result = NULL;
+	char *sa, *sb;
+	PyObject *result = NULL;
 	struct line *al, *bl;
 	struct hunklist l = {NULL, NULL};
 	struct hunk *h;
 	char encode[12], *rb;
-	int an, bn, len = 0, la = 0, lb = 0;
+	int an, bn, len = 0, la, lb;
 
-	if (!PyArg_ParseTuple(args, "SS:bdiff", &sa, &sb))
+	if (!PyArg_ParseTuple(args, "s#s#:bdiff", &sa, &la, &sb, &lb))
 		return NULL;
 
-	an = splitlines(PyString_AsString(sa), PyString_Size(sa), &al);
-	bn = splitlines(PyString_AsString(sb), PyString_Size(sb), &bl);
+	an = splitlines(sa, la, &al);
+	bn = splitlines(sb, lb, &bl);
 	if (!al || !bl)
 		goto nomem;
 
@@ -320,6 +321,7 @@
 		goto nomem;
 
 	/* calculate length of output */
+	la = lb = 0;
 	for (h = l.base; h != l.head; h++) {
 		if (h->a1 != la || h->b1 != lb)
 			len += 12 + bl[h->b1].l - bl[lb].l;
--- a/mercurial/bundlerepo.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/bundlerepo.py	Sat Oct 21 15:22:08 2006 -0400
@@ -233,10 +233,12 @@
         self.bundlefile.close()
 
     def __del__(self):
-        if not self.bundlefile.closed:
-            self.bundlefile.close()
-        if self.tempfile is not None:
-            os.unlink(self.tempfile)
+        bundlefile = getattr(self, 'bundlefile', None)
+        if bundlefile and not bundlefile.closed:
+            bundlefile.close()
+        tempfile = getattr(self, 'tempfile', None)
+        if tempfile is not None:
+            os.unlink(tempfile)
 
 def instance(ui, path, create):
     if create:
--- a/mercurial/changelog.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/changelog.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
 # changelog.py - changelog class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -10,38 +10,91 @@
 from demandload import demandload
 demandload(globals(), "os time util")
 
+def _string_escape(text):
+    """
+    >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
+    >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
+    >>> s
+    'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
+    >>> res = _string_escape(s)
+    >>> s == _string_unescape(res)
+    True
+    """
+    # subset of the string_escape codec
+    text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
+    return text.replace('\0', '\\0')
+
+def _string_unescape(text):
+    return text.decode('string_escape')
+
 class changelog(revlog):
     def __init__(self, opener, defversion=REVLOGV0):
         revlog.__init__(self, opener, "00changelog.i", "00changelog.d",
                         defversion)
 
+    def decode_extra(self, text):
+        extra = {}
+        for l in text.split('\0'):
+            if not l:
+                continue
+            k, v = _string_unescape(l).split(':', 1)
+            extra[k] = v
+        return extra
+
+    def encode_extra(self, d):
+        items = [_string_escape(":".join(t)) for t in d.iteritems()]
+        return "\0".join(items)
+
     def extract(self, text):
+        """
+        format used:
+        nodeid\n        : manifest node in ascii
+        user\n          : user, no \n or \r allowed
+        time tz extra\n : date (time is int or float, timezone is int)
+                        : extra is metadatas, encoded and separated by '\0'
+                        : older versions ignore it
+        files\n\n       : files modified by the cset, no \n or \r allowed
+        (.*)            : comment (free text, ideally utf-8)
+
+        changelog v0 doesn't use extra
+        """
         if not text:
-            return (nullid, "", (0, 0), [], "")
+            return (nullid, "", (0, 0), [], "", {})
         last = text.index("\n\n")
         desc = text[last + 2:]
-        l = text[:last].splitlines()
+        l = text[:last].split('\n')
         manifest = bin(l[0])
         user = l[1]
-        date = l[2].split(' ')
-        time = float(date.pop(0))
-        try:
-            # various tools did silly things with the time zone field.
-            timezone = int(date[0])
-        except:
-            timezone = 0
+
+        extra_data = l[2].split(' ', 2)
+        if len(extra_data) != 3:
+            time = float(extra_data.pop(0))
+            try:
+                # various tools did silly things with the time zone field.
+                timezone = int(extra_data[0])
+            except:
+                timezone = 0
+            extra = {}
+        else:
+            time, timezone, extra = extra_data
+            time, timezone = float(time), int(timezone)
+            extra = self.decode_extra(extra)
         files = l[3:]
-        return (manifest, user, (time, timezone), files, desc)
+        return (manifest, user, (time, timezone), files, desc, extra)
 
     def read(self, node):
         return self.extract(self.revision(node))
 
     def add(self, manifest, list, desc, transaction, p1=None, p2=None,
-                  user=None, date=None):
+                  user=None, date=None, extra={}):
+
         if date:
             parseddate = "%d %d" % util.parsedate(date)
         else:
             parseddate = "%d %d" % util.makedate()
+        if extra:
+            extra = self.encode_extra(extra)
+            parseddate = "%s %s" % (parseddate, extra)
         list.sort()
         l = [hex(manifest), user, parseddate] + list + ["", desc]
         text = "\n".join(l)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/cmdutil.py	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,215 @@
+# cmdutil.py - help for command processing in mercurial
+#
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from demandload import demandload
+from node import *
+from i18n import gettext as _
+demandload(globals(), 'mdiff util')
+demandload(globals(), 'os sys')
+
+revrangesep = ':'
+
+def revfix(repo, val, defval):
+    '''turn user-level id of changeset into rev number.
+    user-level id can be tag, changeset, rev number, or negative rev
+    number relative to number of revs (-1 is tip, etc).'''
+    if not val:
+        return defval
+    try:
+        num = int(val)
+        if str(num) != val:
+            raise ValueError
+        if num < 0:
+            num += repo.changelog.count()
+        if num < 0:
+            num = 0
+        elif num >= repo.changelog.count():
+            raise ValueError
+    except ValueError:
+        try:
+            num = repo.changelog.rev(repo.lookup(val))
+        except KeyError:
+            raise util.Abort(_('invalid revision identifier %s') % val)
+    return num
+
+def revpair(ui, repo, revs):
+    '''return pair of nodes, given list of revisions. second item can
+    be None, meaning use working dir.'''
+    if not revs:
+        return repo.dirstate.parents()[0], None
+    end = None
+    if len(revs) == 1:
+        start = revs[0]
+        if revrangesep in start:
+            start, end = start.split(revrangesep, 1)
+            start = revfix(repo, start, 0)
+            end = revfix(repo, end, repo.changelog.count() - 1)
+        else:
+            start = revfix(repo, start, None)
+    elif len(revs) == 2:
+        if revrangesep in revs[0] or revrangesep in revs[1]:
+            raise util.Abort(_('too many revisions specified'))
+        start = revfix(repo, revs[0], None)
+        end = revfix(repo, revs[1], None)
+    else:
+        raise util.Abort(_('too many revisions specified'))
+    if end is not None: end = repo.lookup(str(end))
+    return repo.lookup(str(start)), end
+
+def revrange(ui, repo, revs):
+    """Yield revision as strings from a list of revision specifications."""
+    seen = {}
+    for spec in revs:
+        if revrangesep in spec:
+            start, end = spec.split(revrangesep, 1)
+            start = revfix(repo, start, 0)
+            end = revfix(repo, end, repo.changelog.count() - 1)
+            step = start > end and -1 or 1
+            for rev in xrange(start, end+step, step):
+                if rev in seen:
+                    continue
+                seen[rev] = 1
+                yield str(rev)
+        else:
+            rev = revfix(repo, spec, None)
+            if rev in seen:
+                continue
+            seen[rev] = 1
+            yield str(rev)
+
+def make_filename(repo, pat, node,
+                  total=None, seqno=None, revwidth=None, pathname=None):
+    node_expander = {
+        'H': lambda: hex(node),
+        'R': lambda: str(repo.changelog.rev(node)),
+        'h': lambda: short(node),
+        }
+    expander = {
+        '%': lambda: '%',
+        'b': lambda: os.path.basename(repo.root),
+        }
+
+    try:
+        if node:
+            expander.update(node_expander)
+        if node and revwidth is not None:
+            expander['r'] = (lambda:
+                    str(repo.changelog.rev(node)).zfill(revwidth))
+        if total is not None:
+            expander['N'] = lambda: str(total)
+        if seqno is not None:
+            expander['n'] = lambda: str(seqno)
+        if total is not None and seqno is not None:
+            expander['n'] = lambda:str(seqno).zfill(len(str(total)))
+        if pathname is not None:
+            expander['s'] = lambda: os.path.basename(pathname)
+            expander['d'] = lambda: os.path.dirname(pathname) or '.'
+            expander['p'] = lambda: pathname
+
+        newname = []
+        patlen = len(pat)
+        i = 0
+        while i < patlen:
+            c = pat[i]
+            if c == '%':
+                i += 1
+                c = pat[i]
+                c = expander[c]()
+            newname.append(c)
+            i += 1
+        return ''.join(newname)
+    except KeyError, inst:
+        raise util.Abort(_("invalid format spec '%%%s' in output file name") %
+                         inst.args[0])
+
+def make_file(repo, pat, node=None,
+              total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
+    if not pat or pat == '-':
+        return 'w' in mode and sys.stdout or sys.stdin
+    if hasattr(pat, 'write') and 'w' in mode:
+        return pat
+    if hasattr(pat, 'read') and 'r' in mode:
+        return pat
+    return open(make_filename(repo, pat, node, total, seqno, revwidth,
+                              pathname),
+                mode)
+
+def matchpats(repo, pats=[], opts={}, head=''):
+    cwd = repo.getcwd()
+    if not pats and cwd:
+        opts['include'] = [os.path.join(cwd, i)
+                           for i in opts.get('include', [])]
+        opts['exclude'] = [os.path.join(cwd, x)
+                           for x in opts.get('exclude', [])]
+        cwd = ''
+    return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
+                           opts.get('exclude'), head)
+
+def makewalk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
+    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,
+                                 badmatch=badmatch):
+            yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
+    return files, matchfn, walk()
+
+def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
+    files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
+    for r in results:
+        yield r
+
+def findrenames(repo, added=None, removed=None, threshold=0.5):
+    if added is None or removed is None:
+        added, removed = repo.status()[1:3]
+    changes = repo.changelog.read(repo.dirstate.parents()[0])
+    mf = repo.manifest.read(changes[0])
+    for a in added:
+        aa = repo.wread(a)
+        bestscore, bestname = None, None
+        for r in removed:
+            rr = repo.file(r).read(mf[r])
+            delta = mdiff.textdiff(aa, rr)
+            if len(delta) < len(aa):
+                myscore = 1.0 - (float(len(delta)) / len(aa))
+                if bestscore is None or myscore > bestscore:
+                    bestscore, bestname = myscore, r
+        if bestname and bestscore >= threshold:
+            yield bestname, a, bestscore
+
+def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
+              similarity=None):
+    if dry_run is None:
+        dry_run = opts.get('dry_run')
+    if similarity is None:
+        similarity = float(opts.get('similarity') or 0)
+    add, remove = [], []
+    mapping = {}
+    for src, abs, rel, exact in walk(repo, pats, opts):
+        if src == 'f' and repo.dirstate.state(abs) == '?':
+            add.append(abs)
+            mapping[abs] = rel, exact
+            if repo.ui.verbose or not exact:
+                repo.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)
+            mapping[abs] = rel, exact
+            if repo.ui.verbose or not exact:
+                repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
+    if not dry_run:
+        repo.add(add, wlock=wlock)
+        repo.remove(remove, wlock=wlock)
+    if similarity > 0:
+        for old, new, score in findrenames(repo, add, remove, similarity):
+            oldrel, oldexact = mapping[old]
+            newrel, newexact = mapping[new]
+            if repo.ui.verbose or not oldexact or not newexact:
+                repo.ui.status(_('recording removal of %s as rename to %s '
+                                 '(%d%% similar)\n') %
+                               (oldrel, newrel, score * 100))
+            if not dry_run:
+                repo.copy(old, new, wlock=wlock)
--- a/mercurial/commands.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/commands.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
 # commands.py - command processing for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -8,12 +8,12 @@
 from demandload import demandload
 from node import *
 from i18n import gettext as _
-demandload(globals(), "os re sys signal shutil imp urllib pdb")
+demandload(globals(), "os re sys signal shutil imp urllib pdb shlex")
 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
-demandload(globals(), "fnmatch mdiff random signal tempfile time")
+demandload(globals(), "fnmatch difflib patch random signal tempfile time")
 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
-demandload(globals(), "archival cStringIO changegroup email.Parser")
-demandload(globals(), "hgweb.server sshserver")
+demandload(globals(), "archival cStringIO changegroup")
+demandload(globals(), "cmdutil hgweb.server sshserver")
 
 class UnknownCommand(Exception):
     """Exception raised if command is not in the command table."""
@@ -21,19 +21,10 @@
     """Exception raised if command shortcut matches more than one command."""
 
 def bail_if_changed(repo):
-    modified, added, removed, deleted, unknown = repo.changes()
+    modified, added, removed, deleted = repo.status()[:4]
     if modified or added or removed or deleted:
         raise util.Abort(_("outstanding uncommitted changes"))
 
-def filterfiles(filters, files):
-    l = [x for x in files if x in filters]
-
-    for t in filters:
-        if t and t[-1] != "/":
-            t += "/"
-        l += [x for x in files if x.startswith(t)]
-    return l
-
 def relpath(repo, args):
     cwd = repo.getcwd()
     if cwd:
@@ -59,29 +50,6 @@
                              (logfile, inst.strerror))
     return message
 
-def matchpats(repo, pats=[], opts={}, head=''):
-    cwd = repo.getcwd()
-    if not pats and cwd:
-        opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
-        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)
-
-def makewalk(repo, pats, opts, node=None, head='', badmatch=None):
-    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,
-                                 badmatch=badmatch):
-            yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
-    return files, matchfn, walk()
-
-def walk(repo, pats, opts, node=None, head='', badmatch=None):
-    files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
-    for r in results:
-        yield r
-
 def walkchangerevs(ui, repo, pats, opts):
     '''Iterate over files and the revs they changed in.
 
@@ -124,23 +92,17 @@
                     windowsize *= 2
 
 
-    files, matchfn, anypats = matchpats(repo, pats, opts)
+    files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
     follow = opts.get('follow') or opts.get('follow_first')
 
     if repo.changelog.count() == 0:
         return [], False, matchfn
 
     if follow:
-        p = repo.dirstate.parents()[0]
-        if p == nullid:
-            ui.warn(_('No working directory revision; defaulting to tip\n'))
-            start = 'tip'
-        else:
-            start = repo.changelog.rev(p)
-        defrange = '%s:0' % start
+        defrange = '%s:0' % repo.changectx().rev()
     else:
         defrange = 'tip:0'
-    revs = map(int, revrange(ui, repo, opts['rev'] or [defrange]))
+    revs = map(int, cmdutil.revrange(ui, repo, opts['rev'] or [defrange]))
     wanted = {}
     slowpath = anypats
     fncache = {}
@@ -215,49 +177,59 @@
                 fncache[rev] = matches
                 wanted[rev] = 1
 
-    def iterate():
-        class followfilter:
-            def __init__(self, onlyfirst=False):
-                self.startrev = -1
-                self.roots = []
-                self.onlyfirst = onlyfirst
-
-            def match(self, rev):
-                def realparents(rev):
-                    if self.onlyfirst:
-                        return repo.changelog.parentrevs(rev)[0:1]
-                    else:
-                        return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
-
-                if self.startrev == -1:
-                    self.startrev = rev
+    class followfilter:
+        def __init__(self, onlyfirst=False):
+            self.startrev = -1
+            self.roots = []
+            self.onlyfirst = onlyfirst
+
+        def match(self, rev):
+            def realparents(rev):
+                if self.onlyfirst:
+                    return repo.changelog.parentrevs(rev)[0:1]
+                else:
+                    return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
+
+            if self.startrev == -1:
+                self.startrev = rev
+                return True
+
+            if rev > self.startrev:
+                # forward: all descendants
+                if not self.roots:
+                    self.roots.append(self.startrev)
+                for parent in realparents(rev):
+                    if parent in self.roots:
+                        self.roots.append(rev)
+                        return True
+            else:
+                # backwards: all parents
+                if not self.roots:
+                    self.roots.extend(realparents(self.startrev))
+                if rev in self.roots:
+                    self.roots.remove(rev)
+                    self.roots.extend(realparents(rev))
                     return True
 
-                if rev > self.startrev:
-                    # forward: all descendants
-                    if not self.roots:
-                        self.roots.append(self.startrev)
-                    for parent in realparents(rev):
-                        if parent in self.roots:
-                            self.roots.append(rev)
-                            return True
-                else:
-                    # backwards: all parents
-                    if not self.roots:
-                        self.roots.extend(realparents(self.startrev))
-                    if rev in self.roots:
-                        self.roots.remove(rev)
-                        self.roots.extend(realparents(rev))
-                        return True
-
-                return False
-
+            return False
+
+    # it might be worthwhile to do this in the iterator if the rev range
+    # is descending and the prune args are all within that range
+    for rev in opts.get('prune', ()):
+        rev = repo.changelog.rev(repo.lookup(rev))
+        ff = followfilter()
+        stop = min(revs[0], revs[-1])
+        for x in range(rev, stop-1, -1):
+            if ff.match(x) and wanted.has_key(x):
+                del wanted[x]
+
+    def iterate():
         if follow and not files:
             ff = followfilter(onlyfirst=opts.get('follow_first'))
             def want(rev):
-                if rev not in wanted:
-                    return False
-                return ff.match(rev)
+                if ff.match(rev) and rev in wanted:
+                    return True
+                return False
         else:
             def want(rev):
                 return rev in wanted
@@ -274,133 +246,6 @@
                 yield 'iter', rev, None
     return iterate(), getchange, matchfn
 
-revrangesep = ':'
-
-def revfix(repo, val, defval):
-    '''turn user-level id of changeset into rev number.
-    user-level id can be tag, changeset, rev number, or negative rev
-    number relative to number of revs (-1 is tip, etc).'''
-    if not val:
-        return defval
-    try:
-        num = int(val)
-        if str(num) != val:
-            raise ValueError
-        if num < 0:
-            num += repo.changelog.count()
-        if num < 0:
-            num = 0
-        elif num >= repo.changelog.count():
-            raise ValueError
-    except ValueError:
-        try:
-            num = repo.changelog.rev(repo.lookup(val))
-        except KeyError:
-            raise util.Abort(_('invalid revision identifier %s'), val)
-    return num
-
-def revpair(ui, repo, revs):
-    '''return pair of nodes, given list of revisions. second item can
-    be None, meaning use working dir.'''
-    if not revs:
-        return repo.dirstate.parents()[0], None
-    end = None
-    if len(revs) == 1:
-        start = revs[0]
-        if revrangesep in start:
-            start, end = start.split(revrangesep, 1)
-            start = revfix(repo, start, 0)
-            end = revfix(repo, end, repo.changelog.count() - 1)
-        else:
-            start = revfix(repo, start, None)
-    elif len(revs) == 2:
-        if revrangesep in revs[0] or revrangesep in revs[1]:
-            raise util.Abort(_('too many revisions specified'))
-        start = revfix(repo, revs[0], None)
-        end = revfix(repo, revs[1], None)
-    else:
-        raise util.Abort(_('too many revisions specified'))
-    if end is not None: end = repo.lookup(str(end))
-    return repo.lookup(str(start)), end
-
-def revrange(ui, repo, revs):
-    """Yield revision as strings from a list of revision specifications."""
-    seen = {}
-    for spec in revs:
-        if revrangesep in spec:
-            start, end = spec.split(revrangesep, 1)
-            start = revfix(repo, start, 0)
-            end = revfix(repo, end, repo.changelog.count() - 1)
-            step = start > end and -1 or 1
-            for rev in xrange(start, end+step, step):
-                if rev in seen:
-                    continue
-                seen[rev] = 1
-                yield str(rev)
-        else:
-            rev = revfix(repo, spec, None)
-            if rev in seen:
-                continue
-            seen[rev] = 1
-            yield str(rev)
-
-def make_filename(repo, pat, node,
-                  total=None, seqno=None, revwidth=None, pathname=None):
-    node_expander = {
-        'H': lambda: hex(node),
-        'R': lambda: str(repo.changelog.rev(node)),
-        'h': lambda: short(node),
-        }
-    expander = {
-        '%': lambda: '%',
-        'b': lambda: os.path.basename(repo.root),
-        }
-
-    try:
-        if node:
-            expander.update(node_expander)
-        if node and revwidth is not None:
-            expander['r'] = (lambda:
-                    str(repo.changelog.rev(node)).zfill(revwidth))
-        if total is not None:
-            expander['N'] = lambda: str(total)
-        if seqno is not None:
-            expander['n'] = lambda: str(seqno)
-        if total is not None and seqno is not None:
-            expander['n'] = lambda:str(seqno).zfill(len(str(total)))
-        if pathname is not None:
-            expander['s'] = lambda: os.path.basename(pathname)
-            expander['d'] = lambda: os.path.dirname(pathname) or '.'
-            expander['p'] = lambda: pathname
-
-        newname = []
-        patlen = len(pat)
-        i = 0
-        while i < patlen:
-            c = pat[i]
-            if c == '%':
-                i += 1
-                c = pat[i]
-                c = expander[c]()
-            newname.append(c)
-            i += 1
-        return ''.join(newname)
-    except KeyError, inst:
-        raise util.Abort(_("invalid format spec '%%%s' in output file name"),
-                    inst.args[0])
-
-def make_file(repo, pat, node=None,
-              total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
-    if not pat or pat == '-':
-        return 'w' in mode and sys.stdout or sys.stdin
-    if hasattr(pat, 'write') and 'w' in mode:
-        return pat
-    if hasattr(pat, 'read') and 'r' in mode:
-        return pat
-    return open(make_filename(repo, pat, node, total, seqno, revwidth,
-                              pathname),
-                mode)
-
 def write_bundle(cg, filename=None, compress=True):
     """Write a bundle file and return its filename.
 
@@ -420,7 +265,7 @@
     try:
         if filename:
             if os.path.exists(filename):
-                raise util.Abort(_("file '%s' already exists"), filename)
+                raise util.Abort(_("file '%s' already exists") % filename)
             fh = open(filename, "wb")
         else:
             fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
@@ -453,74 +298,6 @@
         if cleanup is not None:
             os.unlink(cleanup)
 
-def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
-           changes=None, text=False, opts={}):
-    if not node1:
-        node1 = repo.dirstate.parents()[0]
-    # reading the data for node1 early allows it to play nicely
-    # with repo.changes and the revlog cache.
-    change = repo.changelog.read(node1)
-    mmap = repo.manifest.read(change[0])
-    date1 = util.datestr(change[2])
-
-    if not changes:
-        changes = repo.changes(node1, node2, files, match=match)
-    modified, added, removed, deleted, unknown = changes
-    if files:
-        modified, added, removed = map(lambda x: filterfiles(files, x),
-                                       (modified, added, removed))
-
-    if not modified and not added and not removed:
-        return
-
-    if node2:
-        change = repo.changelog.read(node2)
-        mmap2 = repo.manifest.read(change[0])
-        _date2 = util.datestr(change[2])
-        def date2(f):
-            return _date2
-        def read(f):
-            return repo.file(f).read(mmap2[f])
-    else:
-        tz = util.makedate()[1]
-        _date2 = util.datestr()
-        def date2(f):
-            try:
-                return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
-            except OSError, err:
-                if err.errno != errno.ENOENT: raise
-                return _date2
-        def read(f):
-            return repo.wread(f)
-
-    if ui.quiet:
-        r = None
-    else:
-        hexfunc = ui.verbose and hex or short
-        r = [hexfunc(node) for node in [node1, node2] if node]
-
-    diffopts = ui.diffopts()
-    showfunc = opts.get('show_function') or diffopts['showfunc']
-    ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
-    ignorewsamount = opts.get('ignore_space_change') or \
-                     diffopts['ignorewsamount']
-    ignoreblanklines = opts.get('ignore_blank_lines') or \
-                     diffopts['ignoreblanklines']
-
-    all = modified + added + removed
-    all.sort()
-    for f in all:
-        to = None
-        tn = None
-        if f in mmap:
-            to = repo.file(f).read(mmap[f])
-        if f not in removed:
-            tn = read(f)
-        fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
-                               showfunc=showfunc, ignorews=ignorews,
-                               ignorewsamount=ignorewsamount,
-                               ignoreblanklines=ignoreblanklines))
-
 def trimuser(ui, name, rev, revcache):
     """trim the name of the user who committed a change"""
     user = revcache.get(rev)
@@ -535,7 +312,7 @@
         self.ui = ui
         self.repo = repo
 
-    def show(self, rev=0, changenode=None, brinfo=None):
+    def show(self, rev=0, changenode=None, brinfo=None, copies=None):
         '''show a single changeset or file revision'''
         log = self.repo.changelog
         if changenode is None:
@@ -549,19 +326,20 @@
 
         changes = log.read(changenode)
         date = util.datestr(changes[2])
-
-        parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p))
-                   for p in log.parents(changenode)
+        branch = changes[5].get("branch")
+
+        hexfunc = self.ui.debugflag and hex or short
+
+        parents = [(log.rev(p), hexfunc(p)) for p in log.parents(changenode)
                    if self.ui.debugflag or p != nullid]
         if (not self.ui.debugflag and len(parents) == 1 and
             parents[0][0] == rev-1):
             parents = []
 
-        if self.ui.verbose:
-            self.ui.write(_("changeset:   %d:%s\n") % (rev, hex(changenode)))
-        else:
-            self.ui.write(_("changeset:   %d:%s\n") % (rev, short(changenode)))
-
+        self.ui.write(_("changeset:   %d:%s\n") % (rev, hexfunc(changenode)))
+
+        if branch:
+            self.ui.status(_("branch:      %s\n") % branch)
         for tag in self.repo.nodetags(changenode):
             self.ui.status(_("tag:         %s\n") % tag)
         for parent in parents:
@@ -577,13 +355,16 @@
         self.ui.status(_("date:        %s\n") % date)
 
         if self.ui.debugflag:
-            files = self.repo.changes(log.parents(changenode)[0], changenode)
+            files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
             for key, value in zip([_("files:"), _("files+:"), _("files-:")],
                                   files):
                 if value:
                     self.ui.note("%-12s %s\n" % (key, " ".join(value)))
         else:
             self.ui.note(_("files:       %s\n") % " ".join(changes[3]))
+        if copies:
+            copies = ['%s (%s)' % c for c in copies]
+            self.ui.note(_("copies:      %s\n") % ' '.join(copies))
 
         description = changes[4].strip()
         if description:
@@ -597,21 +378,36 @@
         self.ui.status("\n")
 
 def show_changeset(ui, repo, opts):
-    '''show one changeset.  uses template or regular display.  caller
-    can pass in 'style' and 'template' options in opts.'''
-
+    """show one changeset using template or regular display.
+
+    Display format will be the first non-empty hit of:
+    1. option 'template'
+    2. option 'style'
+    3. [ui] setting 'logtemplate'
+    4. [ui] setting 'style'
+    If all of these values are either the unset or the empty string,
+    regular display via changeset_printer() is done.
+    """
+    # options
     tmpl = opts.get('template')
+    mapfile = None
     if tmpl:
         tmpl = templater.parsestring(tmpl, quoted=False)
     else:
-        tmpl = ui.config('ui', 'logtemplate')
-        if tmpl: tmpl = templater.parsestring(tmpl)
-    mapfile = opts.get('style') or ui.config('ui', 'style')
+        mapfile = opts.get('style')
+        # ui settings
+        if not mapfile:
+            tmpl = ui.config('ui', 'logtemplate')
+            if tmpl:
+                tmpl = templater.parsestring(tmpl)
+            else:
+                mapfile = ui.config('ui', 'style')
+
     if tmpl or mapfile:
         if mapfile:
-            if not os.path.isfile(mapfile):
-                mapname = templater.templatepath('map-cmdline.' + mapfile)
-                if not mapname: mapname = templater.templatepath(mapfile)
+            if not os.path.split(mapfile)[0]:
+                mapname = (templater.templatepath('map-cmdline.' + mapfile)
+                           or templater.templatepath(mapfile))
                 if mapname: mapfile = mapname
         try:
             t = templater.changeset_templater(ui, repo, mapfile)
@@ -633,7 +429,7 @@
     ui.write(_("Mercurial Distributed SCM (version %s)\n")
              % version.get_version())
     ui.status(_(
-        "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
+        "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
         "This is free software; see the source for copying conditions. "
         "There is NO\nwarranty; "
         "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
@@ -654,7 +450,7 @@
         if with_version:
             show_version(ui)
             ui.write('\n')
-        aliases, i = findcmd(name)
+        aliases, i = findcmd(ui, name)
         # synopsis
         ui.write("%s\n\n" % i[2])
 
@@ -787,7 +583,7 @@
     """
 
     names = []
-    for src, abs, rel, exact in walk(repo, pats, opts):
+    for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
         if exact:
             if ui.verbose:
                 ui.status(_('adding %s\n') % rel)
@@ -799,35 +595,23 @@
         repo.add(names)
 
 def addremove(ui, repo, *pats, **opts):
-    """add all new files, delete all missing files (DEPRECATED)
-
-    (DEPRECATED)
+    """add all new files, delete all missing files
+
     Add all new files and remove all missing files from the repository.
 
     New files are ignored if they match any of the patterns in .hgignore. As
     with add, these changes take effect at the next commit.
 
-    This command is now deprecated and will be removed in a future
-    release. Please use add and remove --after instead.
+    Use the -s option to detect renamed files.  With a parameter > 0,
+    this compares every removed file with every added file and records
+    those similar enough as renames.  This option takes a percentage
+    between 0 (disabled) and 100 (files must be identical) as its
+    parameter.  Detecting renamed files this way can be expensive.
     """
-    ui.warn(_('(the addremove command is deprecated; use add and remove '
-              '--after instead)\n'))
-    return addremove_lock(ui, repo, pats, opts)
-
-def addremove_lock(ui, repo, pats, opts, wlock=None):
-    add, remove = [], []
-    for src, abs, rel, exact in walk(repo, pats, opts):
-        if src == 'f' and repo.dirstate.state(abs) == '?':
-            add.append(abs)
-            if ui.verbose or not exact:
-                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') % ((pats and rel) or abs))
-    if not opts.get('dry_run'):
-        repo.add(add, wlock=wlock)
-        repo.remove(remove, wlock=wlock)
+    sim = float(opts.get('similarity') or 0)
+    if sim < 0 or sim > 100:
+        raise util.Abort(_('similarity must be between 0 and 100'))
+    return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
 
 def annotate(ui, repo, *pats, **opts):
     """show changeset information per file line
@@ -841,42 +625,29 @@
     detects as binary. With -a, annotate will generate an annotation
     anyway, probably with undesirable results.
     """
-    def getnode(rev):
-        return short(repo.changelog.node(rev))
-
-    ucache = {}
-    def getname(rev):
-        try:
-            return ucache[rev]
-        except:
-            u = trimuser(ui, repo.changectx(rev).user(), rev, ucache)
-            ucache[rev] = u
-            return u
-
-    dcache = {}
-    def getdate(rev):
-        datestr = dcache.get(rev)
-        if datestr is None:
-            datestr = dcache[rev] = util.datestr(repo.changectx(rev).date())
-        return datestr
+    getdate = util.cachefunc(lambda x: util.datestr(x.date()))
 
     if not pats:
         raise util.Abort(_('at least one file name or pattern required'))
 
-    opmap = [['user', getname], ['number', str], ['changeset', getnode],
-             ['date', getdate]]
-    if not opts['user'] and not opts['changeset'] and not opts['date']:
+    opmap = [['user', lambda x: ui.shortuser(x.user())],
+             ['number', lambda x: str(x.rev())],
+             ['changeset', lambda x: short(x.node())],
+             ['date', getdate], ['follow', lambda x: x.path()]]
+    if (not opts['user'] and not opts['changeset'] and not opts['date']
+        and not opts['follow']):
         opts['number'] = 1
 
-    ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
-
-    for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()):
+    ctx = repo.changectx(opts['rev'])
+
+    for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
+                                             node=ctx.node()):
         fctx = ctx.filectx(abs)
         if not opts['text'] and util.binary(fctx.data()):
             ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
             continue
 
-        lines = fctx.annotate()
+        lines = fctx.annotate(follow=opts.get('follow'))
         pieces = []
 
         for o, f in opmap:
@@ -914,18 +685,11 @@
     The default is the basename of the archive, with suffixes removed.
     '''
 
-    if opts['rev']:
-        node = repo.lookup(opts['rev'])
-    else:
-        node, p2 = repo.dirstate.parents()
-        if p2 != nullid:
-            raise util.Abort(_('uncommitted merge - please provide a '
-                               'specific revision'))
-
-    dest = make_filename(repo, dest, node)
+    node = repo.changectx(opts['rev']).node()
+    dest = cmdutil.make_filename(repo, dest, node)
     if os.path.realpath(dest) == repo.root:
         raise util.Abort(_('repository root cannot be destination'))
-    dummy, matchfn, dummy = matchpats(repo, [], opts)
+    dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
     kind = opts.get('type') or 'files'
     prefix = opts['prefix']
     if dest == '-':
@@ -933,7 +697,7 @@
             raise util.Abort(_('cannot archive plain files to stdout'))
         dest = sys.stdout
         if not prefix: prefix = os.path.basename(repo.root) + '-%h'
-    prefix = make_filename(repo, prefix, node)
+    prefix = cmdutil.make_filename(repo, prefix, node)
     archival.archive(repo, dest, node, kind, not opts['no_decode'],
                      matchfn, prefix)
 
@@ -978,6 +742,7 @@
         parent = p1
     hg.clean(repo, node, show_stats=False)
     revert_opts = opts.copy()
+    revert_opts['all'] = True
     revert_opts['rev'] = hex(parent)
     revert(ui, repo, **revert_opts)
     commit_opts = opts.copy()
@@ -1004,9 +769,12 @@
 def bundle(ui, repo, fname, dest=None, **opts):
     """create a changegroup file
 
-    Generate a compressed changegroup file collecting all changesets
+    Generate a compressed changegroup file collecting changesets.
     not found in the other repository.
 
+    If no destination repository is specified the destination is
+    assumed to have all the node specified by --base.
+
     This file can then be transferred using conventional means and
     applied to another repository with the unbundle command. This is
     useful when native push and pull are not available or when
@@ -1016,17 +784,51 @@
     Unlike import/export, this exactly preserves all changeset
     contents including permissions, rename data, and revision history.
     """
-    dest = ui.expandpath(dest or 'default-push', dest or 'default')
-    other = hg.repository(ui, dest)
-    o = repo.findoutgoing(other, force=opts['force'])
-    cg = repo.changegroup(o, 'bundle')
+    revs = opts.get('rev') or None
+    if revs:
+        revs = [repo.lookup(rev) for rev in revs]
+    base = opts.get('base')
+    if base:
+        if dest:
+            raise util.Abort(_("--base is incompatible with specifiying "
+                               "a destination"))
+        base = [repo.lookup(rev) for rev in base]
+        # create the right base
+        # XXX: nodesbetween / changegroup* should be "fixed" instead
+        o = []
+        has_set = sets.Set(base)
+        for n in base:
+            has_set.update(repo.changelog.reachable(n))
+        if revs:
+            visit = list(revs)
+        else:
+            visit = repo.changelog.heads()
+        while visit:
+            n = visit.pop(0)
+            parents = [p for p in repo.changelog.parents(n)
+                       if p != nullid and p not in has_set]
+            if len(parents) == 0:
+                o.insert(0, n)
+            else:
+                visit.extend(parents)
+    else:
+        setremoteconfig(ui, opts)
+        dest = ui.expandpath(dest or 'default-push', dest or 'default')
+        other = hg.repository(ui, dest)
+        o = repo.findoutgoing(other, force=opts['force'])
+
+    if revs:
+        cg = repo.changegroupsubset(o, revs, 'bundle')
+    else:
+        cg = repo.changegroup(o, 'bundle')
     write_bundle(cg, fname)
 
 def cat(ui, repo, file1, *pats, **opts):
     """output the latest or given revisions of files
 
     Print the specified files as they were at the given revision.
-    If no revision is given then the tip is used.
+    If no revision is given then working dir parent is used, or tip
+    if no revision is checked out.
 
     Output may be to a file, in which case the name of the file is
     given using a format string.  The formatting rules are the same as
@@ -1036,9 +838,10 @@
     %d   dirname of file being printed, or '.' if in repo root
     %p   root-relative path name of file being printed
     """
-    ctx = repo.changectx(opts['rev'] or "-1")
-    for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()):
-        fp = make_file(repo, opts['output'], ctx.node(), pathname=abs)
+    ctx = repo.changectx(opts['rev'])
+    for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
+                                             ctx.node()):
+        fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
         fp.write(ctx.filectx(abs).data())
 
 def clone(ui, source, dest=None, **opts):
@@ -1100,11 +903,10 @@
     message = logmessage(opts)
 
     if opts['addremove']:
-        addremove_lock(ui, repo, pats, opts)
-    fns, match, anypats = matchpats(repo, pats, opts)
+        cmdutil.addremove(repo, pats, opts)
+    fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
     if pats:
-        modified, added, removed, deleted, unknown = (
-            repo.changes(files=fns, match=match))
+        modified, added, removed = repo.status(files=fns, match=match)[:3]
         files = modified + added + removed
     else:
         files = []
@@ -1259,7 +1061,7 @@
     copylist = []
     for pat in pats:
         srcs = []
-        for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
+        for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
             origsrc = okaytocopy(abssrc, relsrc, exact)
             if origsrc:
                 srcs.append((origsrc, abssrc, relsrc, exact))
@@ -1311,7 +1113,7 @@
         options = []
         otables = [globalopts]
         if cmd:
-            aliases, entry = findcmd(cmd)
+            aliases, entry = findcmd(ui, cmd)
             otables.append(entry[1])
         for t in otables:
             for o in t:
@@ -1321,7 +1123,7 @@
         ui.write("%s\n" % "\n".join(options))
         return
 
-    clist = findpossible(cmd).keys()
+    clist = findpossible(ui, cmd).keys()
     clist.sort()
     ui.write("%s\n" % "\n".join(clist))
 
@@ -1370,7 +1172,7 @@
         error = _(".hg/dirstate inconsistent with current parent's manifest")
         raise util.Abort(error)
 
-def debugconfig(ui, repo, *values):
+def showconfig(ui, repo, *values):
     """show combined config settings from all hgrc files
 
     With no args, print names and values of all config items.
@@ -1418,8 +1220,8 @@
                  % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
                     time.strftime("%x %X",
                                   time.localtime(dc[file_][3])), file_))
-    for f in repo.dirstate.copies:
-        ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
+    for f in repo.dirstate.copies():
+        ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
 
 def debugdata(ui, file_, rev):
     """dump the contents of an data file revision"""
@@ -1428,7 +1230,7 @@
     try:
         ui.write(r.revision(r.lookup(rev)))
     except KeyError:
-        raise util.Abort(_('invalid revision identifier %s'), rev)
+        raise util.Abort(_('invalid revision identifier %s') % rev)
 
 def debugindex(ui, file_):
     """dump the contents of an index file"""
@@ -1476,7 +1278,7 @@
 
 def debugwalk(ui, repo, *pats, **opts):
     """show how files match on given patterns"""
-    items = list(walk(repo, pats, opts))
+    items = list(cmdutil.walk(repo, pats, opts))
     if not items:
         return
     fmt = '%%s  %%-%ds  %%-%ds  %%s' % (
@@ -1503,39 +1305,12 @@
     it detects as binary. With -a, diff will generate a diff anyway,
     probably with undesirable results.
     """
-    node1, node2 = revpair(ui, repo, opts['rev'])
-
-    fns, matchfn, anypats = matchpats(repo, pats, opts)
-
-    dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
-           text=opts['text'], opts=opts)
-
-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)
-
-    fp = make_file(repo, opts['output'], node, total=total, seqno=seqno,
-                   revwidth=revwidth)
-    if fp != sys.stdout:
-        ui.note("%s\n" % fp.name)
-
-    fp.write("# HG changeset patch\n")
-    fp.write("# User %s\n" % change[1])
-    fp.write("# Date %d %d\n" % change[2])
-    fp.write("# Node ID %s\n" % hex(node))
-    fp.write("# Parent  %s\n" % hex(prev))
-    if len(parents) > 1:
-        fp.write("# Parent  %s\n" % hex(parents[1]))
-    fp.write(change[4].rstrip())
-    fp.write("\n\n")
-
-    dodiff(fp, ui, repo, prev, node, text=opts['text'])
-    if fp != sys.stdout:
-        fp.close()
+    node1, node2 = cmdutil.revpair(ui, repo, opts['rev'])
+
+    fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
+
+    patch.diff(repo, node1, node2, fns, match=matchfn,
+               opts=patch.diffopts(ui, opts))
 
 def export(ui, repo, *changesets, **opts):
     """dump the header and diffs for one or more changesets
@@ -1566,15 +1341,14 @@
     """
     if not changesets:
         raise util.Abort(_("export requires at least one changeset"))
-    seqno = 0
-    revs = list(revrange(ui, repo, changesets))
-    total = len(revs)
-    revwidth = max(map(len, revs))
-    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)
+    revs = list(cmdutil.revrange(ui, repo, changesets))
+    if len(revs) > 1:
+        ui.note(_('exporting patches:\n'))
+    else:
+        ui.note(_('exporting patch:\n'))
+    patch.export(repo, map(repo.lookup, revs), template=opts['output'],
+                 switch_parent=opts['switch_parent'],
+                 opts=patch.diffopts(ui, opts))
 
 def forget(ui, repo, *pats, **opts):
     """don't add the specified files on the next commit (DEPRECATED)
@@ -1587,7 +1361,7 @@
     """
     ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
     forget = []
-    for src, abs, rel, exact in walk(repo, pats, opts):
+    for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
         if repo.dirstate.state(abs) == 'a':
             forget.append(abs)
             if ui.verbose or not exact:
@@ -1644,42 +1418,56 @@
             self.linenum = linenum
             self.colstart = colstart
             self.colend = colend
+
         def __eq__(self, other):
             return self.line == other.line
-        def __hash__(self):
-            return hash(self.line)
 
     matches = {}
+    copies = {}
     def grepbody(fn, rev, body):
-        matches[rev].setdefault(fn, {})
+        matches[rev].setdefault(fn, [])
         m = matches[rev][fn]
         for lnum, cstart, cend, line in matchlines(body):
             s = linestate(line, lnum, cstart, cend)
-            m[s] = s
-
-    # FIXME: prev isn't used, why ?
+            m.append(s)
+
+    def difflinestates(a, b):
+        sm = difflib.SequenceMatcher(None, a, b)
+        for tag, alo, ahi, blo, bhi in sm.get_opcodes():
+            if tag == 'insert':
+                for i in range(blo, bhi):
+                    yield ('+', b[i])
+            elif tag == 'delete':
+                for i in range(alo, ahi):
+                    yield ('-', a[i])
+            elif tag == 'replace':
+                for i in range(alo, ahi):
+                    yield ('-', a[i])
+                for i in range(blo, bhi):
+                    yield ('+', b[i])
+
     prev = {}
     ucache = {}
     def display(fn, rev, states, prevstates):
-        diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
-        diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
         counts = {'-': 0, '+': 0}
         filerevmatches = {}
-        for l in diff:
+        if incrementing or not opts['all']:
+            a, b = prevstates, states
+        else:
+            a, b = states, prevstates
+        for change, l in difflinestates(a, b):
             if incrementing or not opts['all']:
-                change = ((l in prevstates) and '-') or '+'
                 r = rev
             else:
-                change = ((l in states) and '-') or '+'
                 r = prev[fn]
-            cols = [fn, str(rev)]
+            cols = [fn, str(r)]
             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))
+                cols.append(trimuser(ui, getchange(r)[1], rev,
+                                     ucache))
             if opts['files_with_matches']:
                 c = (fn, rev)
                 if c in filerevmatches:
@@ -1696,6 +1484,7 @@
     changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
     count = 0
     incrementing = False
+    follow = opts.get('follow')
     for st, rev, fns in changeiter:
         if st == 'window':
             incrementing = rev
@@ -1710,20 +1499,31 @@
                 fstate.setdefault(fn, {})
                 try:
                     grepbody(fn, rev, getfile(fn).read(mf[fn]))
+                    if follow:
+                        copied = getfile(fn).renamed(mf[fn])
+                        if copied:
+                            copies.setdefault(rev, {})[fn] = copied[0]
                 except KeyError:
                     pass
         elif st == 'iter':
             states = matches[rev].items()
             states.sort()
             for fn, m in states:
+                copy = copies.get(rev, {}).get(fn)
                 if fn in skip:
+                    if copy:
+                        skip[copy] = True
                     continue
                 if incrementing or not opts['all'] or fstate[fn]:
                     pos, neg = display(fn, rev, m, fstate[fn])
                     count += pos + neg
                     if pos and not opts['all']:
                         skip[fn] = True
+                        if copy:
+                            skip[copy] = True
                 fstate[fn] = m
+                if copy:
+                    fstate[copy] = m
                 prev[fn] = rev
 
     if not incrementing:
@@ -1732,7 +1532,8 @@
         for fn, state in fstate:
             if fn in skip:
                 continue
-            display(fn, rev, {}, state)
+            if fn not in copies.get(prev[fn], {}):
+                display(fn, rev, {}, state)
     return (count == 0 and 1) or 0
 
 def heads(ui, repo, **opts):
@@ -1769,13 +1570,18 @@
         ui.write(_("unknown\n"))
         return
 
-    hexfunc = ui.verbose and hex or short
-    modified, added, removed, deleted, unknown = repo.changes()
+    hexfunc = ui.debugflag and hex or short
+    modified, added, removed, deleted = repo.status()[:4]
     output = ["%s%s" %
               ('+'.join([hexfunc(parent) for parent in parents]),
               (modified or added or removed or deleted) and "+" or "")]
 
     if not ui.quiet:
+
+        branch = repo.workingctx().branch()
+        if branch:
+            output.append("(%s)" % branch)
+
         # multiple tags for a single parent separated by '/'
         parenttags = ['/'.join(tags)
                       for tags in map(repo.nodetags, parents) if tags]
@@ -1814,81 +1620,23 @@
     d = opts["base"]
     strip = opts["strip"]
 
-    mailre = re.compile(r'(?:From |[\w-]+:)')
-
-    # attempt to detect the start of a patch
-    # (this heuristic is borrowed from quilt)
-    diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
-                        'retrieving revision [0-9]+(\.[0-9]+)*$|' +
-                        '(---|\*\*\*)[ \t])', re.MULTILINE)
-
-    for patch in patches:
-        pf = os.path.join(d, patch)
-
-        message = None
-        user = None
-        date = None
-        hgpatch = False
-
-        p = email.Parser.Parser()
+    wlock = repo.wlock()
+    lock = repo.lock()
+
+    for p in patches:
+        pf = os.path.join(d, p)
+
         if pf == '-':
-            msg = p.parse(sys.stdin)
             ui.status(_("applying patch from stdin\n"))
+            tmpname, message, user, date = patch.extract(ui, sys.stdin)
         else:
-            msg = p.parse(file(pf))
-            ui.status(_("applying %s\n") % patch)
-
-        fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
-        tmpfp = os.fdopen(fd, 'w')
+            ui.status(_("applying %s\n") % p)
+            tmpname, message, user, date = patch.extract(ui, file(pf))
+
+        if tmpname is None:
+            raise util.Abort(_('no diffs found'))
+
         try:
-            message = msg['Subject']
-            if message:
-                message = message.replace('\n\t', ' ')
-                ui.debug('Subject: %s\n' % message)
-            user = msg['From']
-            if user:
-                ui.debug('From: %s\n' % user)
-            diffs_seen = 0
-            ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
-            for part in msg.walk():
-                content_type = part.get_content_type()
-                ui.debug('Content-Type: %s\n' % content_type)
-                if content_type not in ok_types:
-                    continue
-                payload = part.get_payload(decode=True)
-                m = diffre.search(payload)
-                if m:
-                    ui.debug(_('found patch at byte %d\n') % m.start(0))
-                    diffs_seen += 1
-                    hgpatch = False
-                    fp = cStringIO.StringIO()
-                    if message:
-                        fp.write(message)
-                        fp.write('\n')
-                    for line in payload[:m.start(0)].splitlines():
-                        if line.startswith('# HG changeset patch'):
-                            ui.debug(_('patch generated by hg export\n'))
-                            hgpatch = True
-                            # drop earlier commit message content
-                            fp.seek(0)
-                            fp.truncate()
-                        elif hgpatch:
-                            if line.startswith('# User '):
-                                user = line[7:]
-                                ui.debug('From: %s\n' % user)
-                            elif line.startswith("# Date "):
-                                date = line[7:]
-                        if not line.startswith('# '):
-                            fp.write(line)
-                            fp.write('\n')
-                    message = fp.getvalue()
-                    if tmpfp:
-                        tmpfp.write(payload)
-                        if not payload.endswith('\n'):
-                            tmpfp.write('\n')
-                elif not diffs_seen and message and content_type == 'text/plain':
-                    message += '\n' + payload
-
             if opts['message']:
                 # pickup the cmdline msg
                 message = opts['message']
@@ -1900,18 +1648,9 @@
                 message = None
             ui.debug(_('message:\n%s\n') % message)
 
-            tmpfp.close()
-            if not diffs_seen:
-                raise util.Abort(_('no diffs found'))
-
-            files = util.patch(strip, tmpname, ui, cwd=repo.root)
-            if len(files) > 0:
-                cfiles = files
-                cwd = repo.getcwd()
-                if cwd:
-                    cfiles = [util.pathto(cwd, f) for f in files]
-                addremove_lock(ui, repo, cfiles, {})
-            repo.commit(files, message, user, date)
+            files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
+            files = patch.updatedir(ui, repo, files, wlock=wlock)
+            repo.commit(files, message, user, date, wlock=wlock, lock=lock)
         finally:
             os.unlink(tmpname)
 
@@ -1964,7 +1703,7 @@
             displayer.show(changenode=n)
             if opts['patch']:
                 prev = (parents and parents[0]) or nullid
-                dodiff(ui, ui, other, prev, n)
+                patch.diff(other, prev, n, fp=repo.ui)
                 ui.write("\n")
     finally:
         if hasattr(other, 'close'):
@@ -2012,8 +1751,8 @@
     else:
         node = None
 
-    for src, abs, rel, exact in walk(repo, pats, opts, node=node,
-                                     head='(?:.*/|)'):
+    for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
+                                             head='(?:.*/|)'):
         if not node and repo.dirstate.state(abs) == '?':
             continue
         if opts['fullpath']:
@@ -2081,6 +1820,43 @@
         limit = sys.maxint
     count = 0
 
+    if opts['copies'] and opts['rev']:
+        endrev = max([int(i)
+                      for i in cmdutil.revrange(ui, repo, opts['rev'])]) + 1
+    else:
+        endrev = repo.changelog.count()
+    rcache = {}
+    ncache = {}
+    dcache = []
+    def getrenamed(fn, rev, man):
+        '''looks up all renames for a file (up to endrev) the first
+        time the file is given. It indexes on the changerev and only
+        parses the manifest if linkrev != changerev.
+        Returns rename info for fn at changerev rev.'''
+        if fn not in rcache:
+            rcache[fn] = {}
+            ncache[fn] = {}
+            fl = repo.file(fn)
+            for i in xrange(fl.count()):
+                node = fl.node(i)
+                lr = fl.linkrev(node)
+                renamed = fl.renamed(node)
+                rcache[fn][lr] = renamed
+                if renamed:
+                    ncache[fn][node] = renamed
+                if lr >= endrev:
+                    break
+        if rev in rcache[fn]:
+            return rcache[fn][rev]
+        mr = repo.manifest.rev(man)
+        if repo.manifest.parentrevs(mr) != (mr - 1, -1):
+            return ncache[fn].get(repo.manifest.find(man, fn)[0])
+        if not dcache or dcache[0] != man:
+            dcache[:] = [man, repo.manifest.readdelta(man)]
+        if fn in dcache[1]:
+            return ncache[fn].get(dcache[1][fn])
+        return None
+
     displayer = show_changeset(ui, repo, opts)
     for st, rev, fns in changeiter:
         if st == 'window':
@@ -2112,10 +1888,17 @@
             if opts['branches']:
                 br = repo.branchlookup([repo.changelog.node(rev)])
 
-            displayer.show(rev, brinfo=br)
+            copies = []
+            if opts.get('copies') and rev:
+                mf = getchange(rev)[0]
+                for fn in getchange(rev)[3]:
+                    rename = getrenamed(fn, rev, mf)
+                    if rename:
+                        copies.append((fn, rename[0]))
+            displayer.show(rev, brinfo=br, copies=copies)
             if opts['patch']:
                 prev = (parents and parents[0]) or nullid
-                dodiff(du, du, repo, prev, changenode, match=matchfn)
+                patch.diff(repo, prev, changenode, match=matchfn, fp=du)
                 du.write("\n\n")
         elif st == 'iter':
             if count == limit: break
@@ -2160,9 +1943,29 @@
     requested revision. Files that changed between either parent are
     marked as changed for the next commit and a commit must be
     performed before any further updates are allowed.
+
+    If no revision is specified, the working directory's parent is a
+    head revision, and the repository contains exactly one other head,
+    the other head is merged with by default.  Otherwise, an explicit
+    revision to merge with must be provided.
     """
 
-    node = _lookup(repo, node, branch)
+    if node or branch:
+        node = _lookup(repo, node, branch)
+    else:
+        heads = repo.heads()
+        if len(heads) > 2:
+            raise util.Abort(_('repo has %d heads - '
+                               'please merge with an explicit rev') %
+                             len(heads))
+        if len(heads) == 1:
+            raise util.Abort(_('there is nothing to merge - '
+                               'use "hg update" instead'))
+        parent = repo.dirstate.parents()[0]
+        if parent not in heads:
+            raise util.Abort(_('working dir not at a head rev - '
+                               'use "hg update" or merge with an explicit rev'))
+        node = parent == heads[0] and heads[-1] or heads[0]
     return hg.merge(repo, node, force=force)
 
 def outgoing(ui, repo, dest=None, **opts):
@@ -2196,7 +1999,7 @@
         displayer.show(changenode=n)
         if opts['patch']:
             prev = (parents and parents[0]) or nullid
-            dodiff(ui, ui, repo, prev, n)
+            patch.diff(repo, prev, n)
             ui.write("\n")
 
 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
@@ -2302,10 +2105,12 @@
     other = hg.repository(ui, source)
     ui.status(_('pulling from %s\n') % (source))
     revs = None
-    if opts['rev'] and not other.local():
-        raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
-    elif opts['rev']:
-        revs = [other.lookup(rev) for rev in opts['rev']]
+    if opts['rev']:
+        if 'lookup' in other.capabilities:
+            revs = [other.lookup(rev) for rev in opts['rev']]
+        else:
+            error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
+            raise util.Abort(error)
     modheads = repo.pull(other, heads=revs, force=opts['force'])
     return postincoming(ui, repo, modheads, opts['update'])
 
@@ -2409,12 +2214,12 @@
     names = []
     if not opts['after'] and not pats:
         raise util.Abort(_('no files specified'))
-    files, matchfn, anypats = matchpats(repo, pats, opts)
+    files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
     exact = dict.fromkeys(files)
-    mardu = map(dict.fromkeys, repo.changes(files=files, match=matchfn))
+    mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
     modified, added, removed, deleted, unknown = mardu
     remove, forget = [], []
-    for src, abs, rel, exact in walk(repo, pats, opts):
+    for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
         reason = None
         if abs not in deleted and opts['after']:
             reason = _('is still present')
@@ -2479,8 +2284,8 @@
     Modified files are saved with a .orig suffix before reverting.
     To disable these backups, use --no-backup.
 
-    Using the -r option, revert the given files or directories to
-    their contents as of a specific revision.  This can be helpful to"roll
+    Using the -r option, revert the given files or directories to their
+    contents as of a specific 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
@@ -2494,16 +2299,18 @@
 
     If names are given, all files matching the names are reverted.
 
-    If no arguments are given, all files in the repository are reverted.
+    If no arguments are given, no files are reverted.
     """
+
+    if not pats and not opts['all']:
+        raise util.Abort(_('no files or directories specified; '
+                           'use --all to revert the whole repo'))
+
     parent, p2 = repo.dirstate.parents()
-    if opts['rev']:
-        node = repo.lookup(opts['rev'])
-    elif p2 != nullid:
-        raise util.Abort(_('working dir has two parents; '
-                           'you must specify the revision to revert to'))
-    else:
-        node = parent
+    if not opts['rev'] and p2 != nullid:
+        raise util.Abort(_('uncommitted merge - please provide a '
+                           'specific revision'))
+    node = repo.changectx(opts['rev']).node()
     mf = repo.manifest.read(repo.changelog.read(node)[0])
     if node == parent:
         pmf = mf
@@ -2521,20 +2328,21 @@
 
     # walk dirstate.
 
-    for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
+    for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
+                                             badmatch=mf.has_key):
         names[abs] = (rel, exact)
         if src == 'b':
             target_only[abs] = True
 
     # walk target manifest.
 
-    for src, abs, rel, exact in walk(repo, pats, opts, node=node,
-                                     badmatch=names.has_key):
+    for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
+                                             badmatch=names.has_key):
         if abs in names: continue
         names[abs] = (rel, exact)
         target_only[abs] = True
 
-    changes = repo.changes(match=names.has_key, wlock=wlock)
+    changes = repo.status(match=names.has_key, wlock=wlock)[:5]
     modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
 
     revert = ([], _('reverting %s\n'))
@@ -2659,7 +2467,8 @@
 
     if opts["stdio"]:
         if repo is None:
-            raise hg.RepoError(_('no repo found'))
+            raise hg.RepoError(_("There is no Mercurial repository here"
+                                 " (.hg not found)"))
         s = sshserver.sshserver(ui, repo)
         s.serve_forever()
 
@@ -2667,10 +2476,11 @@
                " accesslog errorlog webdir_conf")
     for o in optlist.split():
         if opts[o]:
-            ui.setconfig("web", o, opts[o])
+            ui.setconfig("web", o, str(opts[o]))
 
     if repo is None and not ui.config("web", "webdir_conf"):
-        raise hg.RepoError(_('no repo found'))
+        raise hg.RepoError(_("There is no Mercurial repository here"
+                             " (.hg not found)"))
 
     if opts['daemon'] and not opts['daemon_pipefds']:
         rfd, wfd = os.pipe()
@@ -2685,7 +2495,7 @@
     try:
         httpd = hgweb.server.create_server(ui, repo)
     except socket.error, inst:
-        raise util.Abort(_('cannot start server: ') + inst.args[1])
+        raise util.Abort(_('cannot start server: %s') % inst.args[1])
 
     if ui.verbose:
         addr, port = httpd.socket.getsockname()
@@ -2740,8 +2550,8 @@
     """
 
     all = opts['all']
-    
-    files, matchfn, anypats = matchpats(repo, pats, opts)
+
+    files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
     cwd = (pats and repo.getcwd()) or ''
     modified, added, removed, deleted, unknown, ignored, clean = [
         [util.pathto(cwd, x) for x in n]
@@ -2770,9 +2580,10 @@
 
         for f in changes:
             ui.write(format % f)
-            if ((all or opts.get('copies')) and not opts.get('no_status')
-                and opt == 'added' and repo.dirstate.copies.has_key(f)):
-                ui.write('  %s%s' % (repo.dirstate.copies[f], end))
+            if ((all or opts.get('copies')) and not opts.get('no_status')):
+                copied = repo.dirstate.copied(f)
+                if copied:
+                    ui.write('  %s%s' % (copied, end))
 
 def tag(ui, repo, name, rev_=None, **opts):
     """add a tag for the current tip or a given revision
@@ -2800,18 +2611,16 @@
             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:
-        p1, p2 = repo.dirstate.parents()
-        if p1 == nullid:
-            raise util.Abort(_('no revision to tag'))
-        if p2 != nullid:
-            raise util.Abort(_('outstanding uncommitted merges'))
-        r = hex(p1)
-
-    repo.tag(name, r, opts['local'], opts['message'], opts['user'],
-             opts['date'])
+    if not rev_ and repo.dirstate.parents()[1] != nullid:
+        raise util.Abort(_('uncommitted merge - please provide a '
+                           'specific revision'))
+    r = repo.changectx(rev_).node()
+
+    message = opts['message']
+    if not message:
+        message = _('Added tag %s for changeset %s') % (name, short(r))
+
+    repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
 
 def tags(ui, repo):
     """list repository tags
@@ -2823,9 +2632,10 @@
 
     l = repo.tagslist()
     l.reverse()
+    hexfunc = ui.debugflag and hex or short
     for t, n in l:
         try:
-            r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
+            r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
         except KeyError:
             r = "    ?:?"
         if ui.quiet:
@@ -2844,7 +2654,7 @@
         br = repo.branchlookup([n])
     show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
     if opts['patch']:
-        dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
+        patch.diff(repo, repo.changelog.parents(n)[0], n)
 
 def unbundle(ui, repo, fname, **opts):
     """apply a changegroup file
@@ -2931,7 +2741,7 @@
             repo.ui.warn(_("Using head %s for branch %s\n")
                          % (short(node), branch))
         else:
-            raise util.Abort(_("branch %s not found\n") % (branch))
+            raise util.Abort(_("branch %s not found") % branch)
     else:
         node = node and repo.lookup(node) or repo.changelog.tip()
     return node
@@ -2950,29 +2760,59 @@
 
 # Command options and aliases are listed here, alphabetically
 
+globalopts = [
+    ('R', 'repository', '',
+     _('repository root directory or symbolic path name')),
+    ('', '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')),
+    ('', 'config', [], _('set/override config option')),
+    ('', 'debug', None, _('enable debugging output')),
+    ('', 'debugger', None, _('start debugger')),
+    ('', 'lsprof', None, _('print improved command execution profile')),
+    ('', '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')),
+]
+
+dryrunopts = [('n', 'dry-run', None,
+               _('do not perform actions, just print output'))]
+
+remoteopts = [
+    ('e', 'ssh', '', _('specify ssh command to use')),
+    ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
+]
+
+walkopts = [
+    ('I', 'include', [], _('include names matching the given patterns')),
+    ('X', 'exclude', [], _('exclude names matching the given patterns')),
+]
+
 table = {
     "^add":
         (add,
-         [('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns')),
-          ('n', 'dry-run', None, _('do not perform actions, just print output'))],
+         walkopts + dryrunopts,
          _('hg add [OPTION]... [FILE]...')),
-    "debugaddremove|addremove":
+    "addremove":
         (addremove,
-         [('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns')),
-          ('n', 'dry-run', None, _('do not perform actions, just print output'))],
+         [('s', 'similarity', '',
+           _('guess renamed files by similarity (0<=s<=100)')),
+         ] + walkopts + dryrunopts,
          _('hg addremove [OPTION]... [FILE]...')),
     "^annotate":
         (annotate,
          [('r', 'rev', '', _('annotate the specified revision')),
+          ('f', 'follow', None, _('follow file copies and renames')),
           ('a', 'text', None, _('treat all files as text')),
           ('u', 'user', None, _('list the author')),
           ('d', 'date', None, _('list the date')),
           ('n', 'number', None, _('list the revision number (default)')),
           ('c', 'changeset', None, _('list the changeset')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         ] + walkopts,
          _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
     "archive":
         (archive,
@@ -2980,8 +2820,7 @@
           ('p', 'prefix', '', _('directory prefix for files in archive')),
           ('r', 'rev', '', _('revision to distribute')),
           ('t', 'type', '', _('type of distribution to create')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         ] + walkopts,
          _('hg archive [OPTION]... DEST')),
     "backout":
         (backout,
@@ -2992,20 +2831,23 @@
           ('d', 'date', '', _('record datecode as commit date')),
           ('', 'parent', '', _('parent to choose when backing out merge')),
           ('u', 'user', '', _('record user as committer')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         ] + walkopts,
          _('hg backout [OPTION]... REV')),
     "bundle":
         (bundle,
          [('f', 'force', None,
-           _('run even when remote repository is unrelated'))],
-         _('hg bundle FILE DEST')),
+           _('run even when remote repository is unrelated')),
+          ('r', 'rev', [],
+           _('a changeset you would like to bundle')),
+          ('', 'base', [],
+           _('a base changeset to specify instead of a destination')),
+         ] + remoteopts,
+         _('hg bundle [--base REV]... [--rev REV]... FILE [DEST]')),
     "cat":
         (cat,
          [('o', 'output', '', _('print output to file with formatted name')),
           ('r', 'rev', '', _('print the given revision')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         ] + walkopts,
          _('hg cat [OPTION]... FILE...')),
     "^clone":
         (clone,
@@ -3015,9 +2857,7 @@
           ('', 'pull', None, _('use pull protocol to copy metadata')),
           ('', 'uncompressed', None,
            _('use uncompressed transfer (fast over LAN)')),
-          ('e', 'ssh', '', _('specify ssh command to use')),
-          ('', 'remotecmd', '',
-           _('specify hg command to run on the remote side'))],
+         ] + remoteopts,
          _('hg clone [OPTION]... SOURCE [DEST]')),
     "^commit|ci":
         (commit,
@@ -3027,17 +2867,14 @@
           ('l', 'logfile', '', _('read the commit message from <file>')),
           ('d', 'date', '', _('record datecode as commit date')),
           ('u', 'user', '', _('record user as commiter')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         ] + walkopts,
          _('hg commit [OPTION]... [FILE]...')),
     "copy|cp":
         (copy,
          [('A', 'after', None, _('record a copy that has already occurred')),
           ('f', 'force', None,
            _('forcibly copy over an existing managed file')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns')),
-          ('n', 'dry-run', None, _('do not perform actions, just print output'))],
+         ] + walkopts + dryrunopts,
          _('hg copy [OPTION]... [SOURCE]... DEST')),
     "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
     "debugcomplete":
@@ -3049,7 +2886,6 @@
          [('r', 'rev', '', _('revision to rebuild to'))],
          _('debugrebuildstate [-r REV] [REV]')),
     "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
-    "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
     "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
     "debugstate": (debugstate, [], _('debugstate')),
     "debugdata": (debugdata, [], _('debugdata FILE REV')),
@@ -3057,48 +2893,46 @@
     "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
     "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
     "debugwalk":
-        (debugwalk,
-         [('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
-         _('debugwalk [OPTION]... [FILE]...')),
+        (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
     "^diff":
         (diff,
          [('r', 'rev', [], _('revision')),
           ('a', 'text', None, _('treat all files as text')),
           ('p', 'show-function', None,
            _('show which function each change is in')),
+          ('g', 'git', None, _('use git extended diff format')),
+          ('', 'nodates', None, _("don't include dates in diff headers")),
           ('w', 'ignore-all-space', None,
            _('ignore white space when comparing lines')),
           ('b', 'ignore-space-change', None,
            _('ignore changes in the amount of white space')),
           ('B', 'ignore-blank-lines', None,
            _('ignore changes whose lines are all blank')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         ] + walkopts,
          _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
     "^export":
         (export,
          [('o', 'output', '', _('print output to file with formatted name')),
           ('a', 'text', None, _('treat all files as text')),
+          ('g', 'git', None, _('use git extended diff format')),
+          ('', 'nodates', None, _("don't include dates in diff headers")),
           ('', 'switch-parent', None, _('diff against the second parent'))],
          _('hg export [-a] [-o OUTFILESPEC] REV...')),
     "debugforget|forget":
-        (forget,
-         [('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
-         _('hg forget [OPTION]... FILE...')),
+        (forget, walkopts, _('hg forget [OPTION]... FILE...')),
     "grep":
         (grep,
          [('0', 'print0', None, _('end fields with NUL')),
           ('', 'all', None, _('print all revisions that match')),
+          ('f', 'follow', None,
+           _('follow changeset history, or file history across copies and renames')),
           ('i', 'ignore-case', None, _('ignore case when matching')),
           ('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')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         ] + walkopts,
          _('hg grep [OPTION]... PATTERN [FILE]...')),
     "heads":
         (heads,
@@ -3127,19 +2961,13 @@
           ('n', 'newest-first', None, _('show newest record first')),
           ('', 'bundle', '', _('file to store the bundles into')),
           ('p', 'patch', None, _('show patch')),
-          ('r', 'rev', [], _('a specific revision you would like to pull')),
+          ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
           ('', 'template', '', _('display with template')),
-          ('e', 'ssh', '', _('specify ssh command to use')),
-          ('', 'remotecmd', '',
-           _('specify hg command to run on the remote side'))],
+         ] + remoteopts,
          _('hg incoming [-p] [-n] [-M] [-r REV]...'
            ' [--bundle FILENAME] [SOURCE]')),
     "^init":
-        (init,
-         [('e', 'ssh', '', _('specify ssh command to use')),
-          ('', 'remotecmd', '',
-           _('specify hg command to run on the remote side'))],
-         _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
+        (init, remoteopts, _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
     "locate":
         (locate,
          [('r', 'rev', '', _('search the repository as it stood at rev')),
@@ -3147,8 +2975,7 @@
            _('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'))],
+         ] + walkopts,
          _('hg locate [OPTION]... [PATTERN]...')),
     "^log|history":
         (log,
@@ -3157,6 +2984,7 @@
            _('follow changeset history, or file history across copies and renames')),
           ('', 'follow-first', None,
            _('only follow the first parent of merge changesets')),
+          ('C', 'copies', None, _('show copied files')),
           ('k', 'keyword', [], _('search for a keyword')),
           ('l', 'limit', '', _('limit number of changes displayed')),
           ('r', 'rev', [], _('show the specified revision or range')),
@@ -3164,9 +2992,9 @@
           ('', 'style', '', _('display using template map file')),
           ('m', 'only-merges', None, _('show only merges')),
           ('p', 'patch', None, _('show patch')),
+          ('P', 'prune', [], _('do not display revision or any of its ancestors')),
           ('', 'template', '', _('display with template')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         ] + walkopts,
          _('hg log [OPTION]... [FILE]')),
     "manifest": (manifest, [], _('hg manifest [REV]')),
     "merge":
@@ -3183,9 +3011,7 @@
           ('r', 'rev', [], _('a specific revision you would like to push')),
           ('n', 'newest-first', None, _('show newest record first')),
           ('', 'template', '', _('display with template')),
-          ('e', 'ssh', '', _('specify ssh command to use')),
-          ('', 'remotecmd', '',
-           _('specify hg command to run on the remote side'))],
+         ] + remoteopts,
          _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
     "^parents":
         (parents,
@@ -3198,21 +3024,17 @@
     "^pull":
         (pull,
          [('u', 'update', None,
-           _('update the working directory to tip after pull')),
-          ('e', 'ssh', '', _('specify ssh command to use')),
+           _('update to new tip if changesets were pulled')),
           ('f', 'force', None,
            _('run even when remote repository is unrelated')),
-          ('r', 'rev', [], _('a specific revision you would like to pull')),
-          ('', 'remotecmd', '',
-           _('specify hg command to run on the remote side'))],
+          ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
+         ] + remoteopts,
          _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
     "^push":
         (push,
          [('f', 'force', None, _('force push')),
-          ('e', 'ssh', '', _('specify ssh command to use')),
           ('r', 'rev', [], _('a specific revision you would like to push')),
-          ('', 'remotecmd', '',
-           _('specify hg command to run on the remote side'))],
+         ] + remoteopts,
          _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
     "debugrawcommit|rawcommit":
         (rawcommit,
@@ -3228,28 +3050,25 @@
         (remove,
          [('A', 'after', None, _('record remove that has already occurred')),
           ('f', 'force', None, _('remove file even if modified')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         ] + walkopts,
          _('hg remove [OPTION]... FILE...')),
     "rename|mv":
         (rename,
          [('A', 'after', None, _('record a rename that has already occurred')),
           ('f', 'force', None,
            _('forcibly copy over an existing managed file')),
-          ('I', 'include', [], _('include names matching the given patterns')),
-          ('X', 'exclude', [], _('exclude names matching the given patterns')),
-          ('n', 'dry-run', None, _('do not perform actions, just print output'))],
+         ] + walkopts + dryrunopts,
          _('hg rename [OPTION]... SOURCE... DEST')),
     "^revert":
         (revert,
-         [('r', 'rev', '', _('revision to revert to')),
+         [('a', 'all', None, _('revert all changes when no arguments given')),
+          ('r', 'rev', '', _('revision to revert to')),
           ('', 'no-backup', None, _('do not save backup copies of files')),
-          ('I', 'include', [], _('include names matching given patterns')),
-          ('X', 'exclude', [], _('exclude names matching given patterns')),
-          ('n', 'dry-run', None, _('do not perform actions, just print output'))],
+         ] + walkopts + dryrunopts,
          _('hg revert [-r REV] [NAME]...')),
     "rollback": (rollback, [], _('hg rollback')),
     "root": (root, [], _('hg root')),
+    "showconfig|debugconfig": (showconfig, [], _('showconfig [NAME]...')),
     "^serve":
         (serve,
          [('A', 'accesslog', '', _('name of access log file to write to')),
@@ -3282,8 +3101,7 @@
           ('C', 'copies', None, _('show source of copied files')),
           ('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'))],
+         ] + walkopts,
          _('hg status [OPTION]... [FILE]...')),
     "tag":
         (tag,
@@ -3304,7 +3122,7 @@
     "unbundle":
         (unbundle,
          [('u', 'update', None,
-           _('update the working directory to tip after unbundle'))],
+           _('update to new tip if changesets were unbundled'))],
          _('hg unbundle [-u] FILE')),
     "debugundo|undo": (undo, [], _('hg undo')),
     "^update|up|checkout|co":
@@ -3318,30 +3136,11 @@
     "version": (show_version, [], _('hg version')),
 }
 
-globalopts = [
-    ('R', 'repository', '',
-     _('repository root directory or symbolic path name')),
-    ('', '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')),
-    ('', 'config', [], _('set/override config option')),
-    ('', 'debug', None, _('enable debugging output')),
-    ('', 'debugger', None, _('start debugger')),
-    ('', 'lsprof', None, _('print improved command execution profile')),
-    ('', '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 debugcomplete debugdata"
           " debugindex debugindexdot")
-optionalrepo = ("paths serve debugconfig")
-
-def findpossible(cmd):
+optionalrepo = ("paths serve showconfig")
+
+def findpossible(ui, cmd):
     """
     Return cmd -> (aliases, command table entry)
     for each matching command.
@@ -3354,13 +3153,13 @@
         found = None
         if cmd in aliases:
             found = cmd
-        else:
+        elif not ui.config("ui", "strict"):
             for a in aliases:
                 if a.startswith(cmd):
                     found = a
                     break
         if found is not None:
-            if aliases[0].startswith("debug"):
+            if aliases[0].startswith("debug") or found.startswith("debug"):
                 debugchoice[found] = (aliases, table[e])
             else:
                 choice[found] = (aliases, table[e])
@@ -3370,9 +3169,9 @@
 
     return choice
 
-def findcmd(cmd):
+def findcmd(ui, cmd):
     """Return (aliases, command table entry) for command string."""
-    choice = findpossible(cmd)
+    choice = findpossible(ui, cmd)
 
     if choice.has_key(cmd):
         return choice[cmd]
@@ -3407,11 +3206,11 @@
 
     if args:
         cmd, args = args[0], args[1:]
-        aliases, i = findcmd(cmd)
+        aliases, i = findcmd(ui, cmd)
         cmd = aliases[0]
         defaults = ui.config("defaults", cmd)
         if defaults:
-            args = defaults.split() + args
+            args = shlex.split(defaults) + args
         c = list(i[1])
     else:
         cmd = None
@@ -3446,18 +3245,11 @@
                 return sys.modules[v]
         raise KeyError(name)
 
-def dispatch(args):
-    for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
-        num = getattr(signal, name, None)
-        if num: signal.signal(num, catchterm)
-
-    try:
-        u = ui.ui(traceback='--traceback' in sys.argv[1:])
-    except util.Abort, inst:
-        sys.stderr.write(_("abort: %s\n") % inst)
-        return -1
-
-    for ext_name, load_from_name in u.extensions():
+def load_extensions(ui):
+    added = []
+    for ext_name, load_from_name in ui.extensions():
+        if ext_name in external:
+            continue
         try:
             if load_from_name:
                 # the module will be loaded in sys.modules
@@ -3477,24 +3269,53 @@
                 except ImportError:
                     mod = importh(ext_name)
             external[ext_name] = mod.__name__
+            added.append((mod, ext_name))
         except (util.SignalInterrupt, KeyboardInterrupt):
             raise
         except Exception, inst:
-            u.warn(_("*** failed to import extension %s: %s\n") % (ext_name, inst))
-            if u.print_exc():
+            ui.warn(_("*** failed to import extension %s: %s\n") %
+                    (ext_name, inst))
+            if ui.print_exc():
                 return 1
 
-    for name in external.itervalues():
-        mod = sys.modules[name]
+    for mod, name in added:
         uisetup = getattr(mod, 'uisetup', None)
         if uisetup:
-            uisetup(u)
+            uisetup(ui)
         cmdtable = getattr(mod, 'cmdtable', {})
         for t in cmdtable:
             if t in table:
-                u.warn(_("module %s overrides %s\n") % (name, t))
+                ui.warn(_("module %s overrides %s\n") % (name, t))
         table.update(cmdtable)
 
+def parseconfig(config):
+    """parse the --config options from the command line"""
+    parsed = []
+    for cfg in config:
+        try:
+            name, value = cfg.split('=', 1)
+            section, name = name.split('.', 1)
+            if not section or not name:
+                raise IndexError
+            parsed.append((section, name, value))
+        except (IndexError, ValueError):
+            raise util.Abort(_('malformed --config option: %s') % cfg)
+    return parsed
+
+def dispatch(args):
+    for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
+        num = getattr(signal, name, None)
+        if num: signal.signal(num, catchterm)
+
+    try:
+        u = ui.ui(traceback='--traceback' in sys.argv[1:])
+    except util.Abort, inst:
+        sys.stderr.write(_("abort: %s\n") % inst)
+        return -1
+
+    load_extensions(u)
+    u.addreadhook(load_extensions)
+
     try:
         cmd, func, args, options, cmdoptions = parse(u, args)
         if options["time"]:
@@ -3510,10 +3331,6 @@
                     (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
             atexit.register(print_time)
 
-        u.updateopts(options["verbose"], options["debug"], options["quiet"],
-                     not options["noninteractive"], options["traceback"],
-                     options["config"])
-
         # enter the debugger before command execution
         if options['debugger']:
             pdb.set_trace()
@@ -3526,8 +3343,14 @@
                     raise util.Abort('%s: %s' %
                                      (options['cwd'], inst.strerror))
 
+            u.updateopts(options["verbose"], options["debug"], options["quiet"],
+                         not options["noninteractive"], options["traceback"],
+                         parseconfig(options["config"]))
+
             path = u.expandpath(options["repository"]) or ""
             repo = path and hg.repository(u, path=path) or None
+            if repo and not repo.local():
+                raise util.Abort(_("repository '%s' is not local") % path)
 
             if options['help']:
                 return help_(u, cmd, options['version'])
@@ -3545,6 +3368,7 @@
                         mod = sys.modules[name]
                         if hasattr(mod, 'reposetup'):
                             mod.reposetup(u, repo)
+                            hg.repo_setup_hooks.append(mod.reposetup)
                 except hg.RepoError:
                     if cmd not in optionalrepo.split():
                         raise
@@ -3552,11 +3376,6 @@
             else:
                 d = lambda: func(u, *args, **cmdoptions)
 
-            # reupdate the options, repo/.hg/hgrc may have changed them
-            u.updateopts(options["verbose"], options["debug"], options["quiet"],
-                         not options["noninteractive"], options["traceback"],
-                         options["config"])
-
             try:
                 if options['profile']:
                     import hotshot, hotshot.stats
@@ -3628,7 +3447,7 @@
         u.warn(_("abort: could not lock %s: %s\n") %
                (inst.desc or inst.filename, inst.strerror))
     except revlog.RevlogError, inst:
-        u.warn(_("abort: "), inst, "!\n")
+        u.warn(_("abort: %s!\n") % inst)
     except util.SignalInterrupt:
         u.warn(_("killed!\n"))
     except KeyboardInterrupt:
@@ -3650,18 +3469,18 @@
                 u.warn(_("broken pipe\n"))
         elif getattr(inst, "strerror", None):
             if getattr(inst, "filename", None):
-                u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
+                u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
             else:
                 u.warn(_("abort: %s\n") % inst.strerror)
         else:
             raise
     except OSError, inst:
-        if hasattr(inst, "filename"):
+        if getattr(inst, "filename", None):
             u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
         else:
             u.warn(_("abort: %s\n") % inst.strerror)
     except util.Abort, inst:
-        u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
+        u.warn(_("abort: %s\n") % inst)
     except TypeError, inst:
         # was this an argument error?
         tb = traceback.extract_tb(sys.exc_info()[2])
--- a/mercurial/context.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/context.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,40 +1,70 @@
 # context.py - changeset and file context objects for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
+from node import *
+from i18n import gettext as _
+from demandload import demandload
+demandload(globals(), "ancestor bdiff repo revlog util os")
+
 class changectx(object):
     """A changecontext object makes access to data related to a particular
     changeset convenient."""
-    def __init__(self, repo, changeid):
+    def __init__(self, repo, changeid=None):
         """changeid is a revision number, node, or tag"""
         self._repo = repo
 
+        if not changeid and changeid != 0:
+            p1, p2 = self._repo.dirstate.parents()
+            self._rev = self._repo.changelog.rev(p1)
+            if self._rev == -1:
+                changeid = 'tip'
+            else:
+                self._node = p1
+                return
+
         self._node = self._repo.lookup(changeid)
         self._rev = self._repo.changelog.rev(self._node)
 
-    def changeset(self):
-        try:
-            return self._changeset
-        except AttributeError:
+    def __str__(self):
+        return short(self.node())
+
+    def __repr__(self):
+        return "<changectx %s>" % str(self)
+
+    def __eq__(self, other):
+        return self._rev == other._rev
+
+    def __nonzero__(self):
+        return self._rev != -1
+
+    def __getattr__(self, name):
+        if name == '_changeset':
             self._changeset = self._repo.changelog.read(self.node())
             return self._changeset
-
-    def manifest(self):
-        try:
+        elif name == '_manifest':
+            self._manifest = self._repo.manifest.read(self._changeset[0])
             return self._manifest
-        except AttributeError:
-            self._manifest = self._repo.manifest.read(self.changeset()[0])
-            return self._manifest
+        elif name == '_manifestdelta':
+            md = self._repo.manifest.readdelta(self._changeset[0])
+            self._manifestdelta = md
+            return self._manifestdelta
+        else:
+            raise AttributeError, name
+
+    def changeset(self): return self._changeset
+    def manifest(self): return self._manifest
 
     def rev(self): return self._rev
     def node(self): return self._node
-    def user(self): return self.changeset()[1]
-    def date(self): return self.changeset()[2]
-    def changedfiles(self): return self.changeset()[3]
-    def description(self): return self.changeset()[4]
+    def user(self): return self._changeset[1]
+    def date(self): return self._changeset[2]
+    def files(self): return self._changeset[3]
+    def description(self): return self._changeset[4]
+    def branch(self): return self._changeset[5].get("branch", "")
 
     def parents(self):
         """return contexts for each parent changeset"""
@@ -47,14 +77,25 @@
         return [ changectx(self._repo, x) for x in c ]
 
     def filenode(self, path):
-        node, flag = self._repo.manifest.find(self.changeset()[0], path)
+        if '_manifest' in self.__dict__:
+            try:
+                return self._manifest[path]
+            except KeyError:
+                raise repo.LookupError(_("'%s' not found in manifest") % path)
+        if '_manifestdelta' in self.__dict__ or path in self.files():
+            if path in self._manifestdelta:
+                return self._manifestdelta[path]
+        node, flag = self._repo.manifest.find(self._changeset[0], path)
+        if not node:
+            raise repo.LookupError(_("'%s' not found in manifest") % path)
+
         return node
 
     def filectx(self, path, fileid=None):
         """get a file context from this changeset"""
         if fileid is None:
             fileid = self.filenode(path)
-        return filectx(self._repo, path, fileid=fileid)
+        return filectx(self._repo, path, fileid=fileid, changectx=self)
 
     def filectxs(self):
         """generate a file context for each file in this changeset's
@@ -65,62 +106,389 @@
         for f in m:
             yield self.filectx(f, fileid=mf[f])
 
+    def ancestor(self, c2):
+        """
+        return the ancestor context of self and c2
+        """
+        n = self._repo.changelog.ancestor(self._node, c2._node)
+        return changectx(self._repo, n)
+
 class filectx(object):
     """A filecontext object makes access to data related to a particular
        filerevision convenient."""
-    def __init__(self, repo, path, changeid=None, fileid=None):
+    def __init__(self, repo, path, changeid=None, fileid=None,
+                 filelog=None, changectx=None):
         """changeid can be a changeset revision, node, or tag.
            fileid can be a file revision or node."""
         self._repo = repo
         self._path = path
 
-        assert changeid or fileid
+        assert changeid is not None or fileid is not None
 
-        if not fileid:
-            # if given a changeset id, go ahead and look up the file
+        if filelog:
+            self._filelog = filelog
+        if changectx:
+            self._changectx = changectx
+            self._changeid = changectx.node()
+
+        if fileid is None:
             self._changeid = changeid
-            self._changectx = self.changectx()
-            self._filelog = self._repo.file(self._path)
-            self._filenode = self._changectx.filenode(self._path)
         else:
-            # else be lazy
-            self._filelog = self._repo.file(self._path)
-            self._filenode = self._filelog.lookup(fileid)
-            self._changeid = self._filelog.linkrev(self._filenode)
-        self._filerev = self._filelog.rev(self._filenode)
+            self._fileid = fileid
 
-    def changectx(self):
-        try:
-            return self._changectx
-        except AttributeError:
+    def __getattr__(self, name):
+        if name == '_changectx':
             self._changectx = changectx(self._repo, self._changeid)
             return self._changectx
+        elif name == '_filelog':
+            self._filelog = self._repo.file(self._path)
+            return self._filelog
+        elif name == '_changeid':
+            self._changeid = self._filelog.linkrev(self._filenode)
+            return self._changeid
+        elif name == '_filenode':
+            try:
+                if '_fileid' in self.__dict__:
+                    self._filenode = self._filelog.lookup(self._fileid)
+                else:
+                    self._filenode = self._changectx.filenode(self._path)
+            except revlog.RevlogError, inst:
+                raise repo.LookupError(str(inst))
+            return self._filenode
+        elif name == '_filerev':
+            self._filerev = self._filelog.rev(self._filenode)
+            return self._filerev
+        else:
+            raise AttributeError, name
+
+    def __nonzero__(self):
+        return self._filerev != nullid
+
+    def __str__(self):
+        return "%s@%s" % (self.path(), short(self.node()))
+
+    def __repr__(self):
+        return "<filectx %s>" % str(self)
+
+    def __eq__(self, other):
+        return self._path == other._path and self._changeid == other._changeid
+
+    def filectx(self, fileid):
+        '''opens an arbitrary revision of the file without
+        opening a new filelog'''
+        return filectx(self._repo, self._path, fileid=fileid,
+                       filelog=self._filelog)
 
     def filerev(self): return self._filerev
     def filenode(self): return self._filenode
     def filelog(self): return self._filelog
 
-    def rev(self): return self.changectx().rev()
-    def node(self): return self.changectx().node()
-    def user(self): return self.changectx().user()
-    def date(self): return self.changectx().date()
-    def files(self): return self.changectx().files()
-    def description(self): return self.changectx().description()
-    def manifest(self): return self.changectx().manifest()
+    def rev(self):
+        if '_changectx' in self.__dict__:
+            return self._changectx.rev()
+        return self._filelog.linkrev(self._filenode)
+
+    def node(self): return self._changectx.node()
+    def user(self): return self._changectx.user()
+    def date(self): return self._changectx.date()
+    def files(self): return self._changectx.files()
+    def description(self): return self._changectx.description()
+    def branch(self): return self._changectx.branch()
+    def manifest(self): return self._changectx.manifest()
+    def changectx(self): return self._changectx
 
     def data(self): return self._filelog.read(self._filenode)
-    def metadata(self): return self._filelog.readmeta(self._filenode)
     def renamed(self): return self._filelog.renamed(self._filenode)
+    def path(self): return self._path
+    def size(self): return self._filelog.size(self._filerev)
+
+    def cmp(self, text): return self._filelog.cmp(self._filenode, text)
 
     def parents(self):
-        # need to fix for renames
-        p = self._filelog.parents(self._filenode)
-        return [ filectx(self._repo, self._path, fileid=x) for x in p ]
+        p = self._path
+        fl = self._filelog
+        pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
+
+        r = self.renamed()
+        if r:
+            pl[0] = (r[0], r[1], None)
+
+        return [ filectx(self._repo, p, fileid=n, filelog=l)
+                 for p,n,l in pl if n != nullid ]
 
     def children(self):
         # hard for renames
         c = self._filelog.children(self._filenode)
-        return [ filectx(self._repo, self._path, fileid=x) for x in c ]
+        return [ filectx(self._repo, self._path, fileid=x,
+                         filelog=self._filelog) for x in c ]
+
+    def annotate(self, follow=False):
+        '''returns a list of tuples of (ctx, line) for each line
+        in the file, where ctx is the filectx of the node where
+        that line was last changed'''
+
+        def decorate(text, rev):
+            return ([rev] * len(text.splitlines()), text)
+
+        def pair(parent, child):
+            for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
+                child[0][b1:b2] = parent[0][a1:a2]
+            return child
+
+        getlog = util.cachefunc(lambda x: self._repo.file(x))
+        def getctx(path, fileid):
+            log = path == self._path and self._filelog or getlog(path)
+            return filectx(self._repo, path, fileid=fileid, filelog=log)
+        getctx = util.cachefunc(getctx)
+
+        def parents(f):
+            # we want to reuse filectx objects as much as possible
+            p = f._path
+            if f._filerev is None: # working dir
+                pl = [ (n.path(), n.filerev()) for n in f.parents() ]
+            else:
+                pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ]
+
+            if follow:
+                r = f.renamed()
+                if r:
+                    pl[0] = (r[0], getlog(r[0]).rev(r[1]))
+
+            return [ getctx(p, n) for p, n in pl if n != -1 ]
+
+        # use linkrev to find the first changeset where self appeared
+        if self.rev() != self._filelog.linkrev(self._filenode):
+            base = self.filectx(self.filerev())
+        else:
+            base = self
+
+        # find all ancestors
+        needed = {base: 1}
+        visit = [base]
+        files = [base._path]
+        while visit:
+            f = visit.pop(0)
+            for p in parents(f):
+                if p not in needed:
+                    needed[p] = 1
+                    visit.append(p)
+                    if p._path not in files:
+                        files.append(p._path)
+                else:
+                    # count how many times we'll use this
+                    needed[p] += 1
+
+        # sort by revision (per file) which is a topological order
+        visit = []
+        files.reverse()
+        for f in files:
+            fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
+            fn.sort()
+            visit.extend(fn)
+        hist = {}
+
+        for r, f in visit:
+            curr = decorate(f.data(), f)
+            for p in parents(f):
+                if p != nullid:
+                    curr = pair(hist[p], curr)
+                    # trim the history of unneeded revs
+                    needed[p] -= 1
+                    if not needed[p]:
+                        del hist[p]
+            hist[f] = curr
+
+        return zip(hist[f][0], hist[f][1].splitlines(1))
+
+    def ancestor(self, fc2):
+        """
+        find the common ancestor file context, if any, of self, and fc2
+        """
+
+        acache = {}
+
+        # prime the ancestor cache for the working directory
+        for c in (self, fc2):
+            if c._filerev == None:
+                pl = [ (n.path(), n.filenode()) for n in c.parents() ]
+                acache[(c._path, None)] = pl
+
+        flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
+        def parents(vertex):
+            if vertex in acache:
+                return acache[vertex]
+            f, n = vertex
+            if f not in flcache:
+                flcache[f] = self._repo.file(f)
+            fl = flcache[f]
+            pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
+            re = fl.renamed(n)
+            if re:
+                pl.append(re)
+            acache[vertex]=pl
+            return pl
+
+        a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
+        v = ancestor.ancestor(a, b, parents)
+        if v:
+            f,n = v
+            return filectx(self._repo, f, fileid=n, filelog=flcache[f])
+
+        return None
+
+class workingctx(changectx):
+    """A workingctx object makes access to data related to
+    the current working directory convenient."""
+    def __init__(self, repo):
+        self._repo = repo
+        self._rev = None
+        self._node = None
+
+    def __str__(self):
+        return str(self._parents[0]) + "+"
+
+    def __nonzero__(self):
+        return True
 
-    def annotate(self):
-        return self._filelog.annotate(self._filenode)
+    def __getattr__(self, name):
+        if name == '_parents':
+            self._parents = self._repo.parents()
+            return self._parents
+        if name == '_status':
+            self._status = self._repo.status()
+            return self._status
+        if name == '_manifest':
+            self._buildmanifest()
+            return self._manifest
+        else:
+            raise AttributeError, name
+
+    def _buildmanifest(self):
+        """generate a manifest corresponding to the working directory"""
+
+        man = self._parents[0].manifest().copy()
+        copied = self._repo.dirstate.copies()
+        modified, added, removed, deleted, unknown = self._status[:5]
+        for i,l in (("a", added), ("m", modified), ("u", unknown)):
+            for f in l:
+                man[f] = man.get(copied.get(f, f), nullid) + i
+                man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
+
+        for f in deleted + removed:
+            if f in man:
+                del man[f]
+
+        self._manifest = man
+
+    def manifest(self): return self._manifest
+
+    def user(self): return self._repo.ui.username()
+    def date(self): return util.makedate()
+    def description(self): return ""
+    def files(self):
+        f = self.modified() + self.added() + self.removed()
+        f.sort()
+        return f
+
+    def modified(self): return self._status[0]
+    def added(self): return self._status[1]
+    def removed(self): return self._status[2]
+    def deleted(self): return self._status[3]
+    def unknown(self): return self._status[4]
+    def clean(self): return self._status[5]
+    def branch(self):
+        try:
+            return self._repo.opener("branch").read().strip()
+        except IOError:
+            return ""
+
+    def parents(self):
+        """return contexts for each parent changeset"""
+        return self._parents
+
+    def children(self):
+        return []
+
+    def filectx(self, path):
+        """get a file context from the working directory"""
+        return workingfilectx(self._repo, path, workingctx=self)
+
+    def ancestor(self, c2):
+        """return the ancestor context of self and c2"""
+        return self._parents[0].ancestor(c2) # punt on two parents for now
+
+class workingfilectx(filectx):
+    """A workingfilectx object makes access to data related to a particular
+       file in the working directory convenient."""
+    def __init__(self, repo, path, filelog=None, workingctx=None):
+        """changeid can be a changeset revision, node, or tag.
+           fileid can be a file revision or node."""
+        self._repo = repo
+        self._path = path
+        self._changeid = None
+        self._filerev = self._filenode = None
+
+        if filelog:
+            self._filelog = filelog
+        if workingctx:
+            self._changectx = workingctx
+
+    def __getattr__(self, name):
+        if name == '_changectx':
+            self._changectx = workingctx(repo)
+            return self._changectx
+        elif name == '_repopath':
+            self._repopath = (self._repo.dirstate.copied(self._path)
+                              or self._path)
+            return self._repopath
+        elif name == '_filelog':
+            self._filelog = self._repo.file(self._repopath)
+            return self._filelog
+        else:
+            raise AttributeError, name
+
+    def __nonzero__(self):
+        return True
+
+    def __str__(self):
+        return "%s@%s" % (self.path(), self._changectx)
+
+    def filectx(self, fileid):
+        '''opens an arbitrary revision of the file without
+        opening a new filelog'''
+        return filectx(self._repo, self._repopath, fileid=fileid,
+                       filelog=self._filelog)
+
+    def rev(self):
+        if '_changectx' in self.__dict__:
+            return self._changectx.rev()
+        return self._filelog.linkrev(self._filenode)
+
+    def data(self): return self._repo.wread(self._path)
+    def renamed(self):
+        rp = self._repopath
+        if rp == self._path:
+            return None
+        return rp, self._workingctx._parents._manifest.get(rp, nullid)
+
+    def parents(self):
+        '''return parent filectxs, following copies if necessary'''
+        p = self._path
+        rp = self._repopath
+        pcl = self._changectx._parents
+        fl = self._filelog
+        pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ]
+        if len(pcl) > 1:
+            if rp != p:
+                fl = None
+            pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
+
+        return [ filectx(self._repo, p, fileid=n, filelog=l)
+                 for p,n,l in pl if n != nullid ]
+
+    def children(self):
+        return []
+
+    def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
+
+    def cmp(self, text): return self._repo.wread(self._path) == text
--- a/mercurial/demandload.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/demandload.py	Sat Oct 21 15:22:08 2006 -0400
@@ -109,9 +109,9 @@
             mod = mod[:col]
         else:
             fromlist = []
-        as = None
+        as_ = None
         if '@' in mod:
-            mod, as = mod.split("@")
+            mod, as_ = mod.split("@")
         importer = _importer(scope, mod, fromlist)
         if fromlist:
             for name in fromlist:
@@ -130,6 +130,6 @@
                     continue
             else:
                 basemod = mod
-            if not as:
-                as = basemod
-            scope[as] = _replacer(importer, as)
+            if not as_:
+                as_ = basemod
+            scope[as_] = _replacer(importer, as_)
--- a/mercurial/dirstate.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/dirstate.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,7 +1,7 @@
 """
 dirstate.py - working directory tracking for mercurial
 
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
@@ -10,7 +10,7 @@
 from node import *
 from i18n import gettext as _
 from demandload import *
-demandload(globals(), "struct os time bisect stat util re errno")
+demandload(globals(), "struct os time bisect stat strutil util re errno")
 
 class dirstate(object):
     format = ">cllll"
@@ -22,7 +22,8 @@
         self.ui = ui
         self.map = None
         self.pl = None
-        self.copies = {}
+        self.dirs = None
+        self.copymap = {}
         self.ignorefunc = None
         self.blockignore = False
 
@@ -159,7 +160,7 @@
 
         # deref fields so they will be local in loop
         map = self.map
-        copies = self.copies
+        copymap = self.copymap
         format = self.format
         unpack = struct.unpack
 
@@ -175,7 +176,7 @@
             f = st[pos:newpos]
             if '\0' in f:
                 f, c = f.split('\0')
-                copies[f] = c
+                copymap[f] = c
             map[f] = e[:4]
             pos = newpos
 
@@ -192,10 +193,45 @@
     def copy(self, source, dest):
         self.lazyread()
         self.markdirty()
-        self.copies[dest] = source
+        self.copymap[dest] = source
 
     def copied(self, file):
-        return self.copies.get(file, None)
+        return self.copymap.get(file, None)
+
+    def copies(self):
+        return self.copymap
+
+    def initdirs(self):
+        if self.dirs is None:
+            self.dirs = {}
+            for f in self.map:
+                self.updatedirs(f, 1)
+
+    def updatedirs(self, path, delta):
+        if self.dirs is not None:
+            for c in strutil.findall(path, '/'):
+                pc = path[:c]
+                self.dirs.setdefault(pc, 0)
+                self.dirs[pc] += delta
+
+    def checkshadows(self, files):
+        def prefixes(f):
+            for c in strutil.rfindall(f, '/'):
+                yield f[:c]
+        self.lazyread()
+        self.initdirs()
+        seendirs = {}
+        for f in files:
+            if self.dirs.get(f):
+                raise util.Abort(_('directory named %r already in dirstate') %
+                                 f)
+            for d in prefixes(f):
+                if d in seendirs:
+                    break
+                if d in self.map:
+                    raise util.Abort(_('file named %r already in dirstate') %
+                                     d)
+                seendirs[d] = True
 
     def update(self, files, state, **kw):
         ''' current states:
@@ -207,31 +243,40 @@
         if not files: return
         self.lazyread()
         self.markdirty()
+        if state == "a":
+            self.initdirs()
+            self.checkshadows(files)
         for f in files:
             if state == "r":
                 self.map[f] = ('r', 0, 0, 0)
+                self.updatedirs(f, -1)
             else:
+                if state == "a":
+                    self.updatedirs(f, 1)
                 s = os.lstat(self.wjoin(f))
                 st_size = kw.get('st_size', s.st_size)
                 st_mtime = kw.get('st_mtime', s.st_mtime)
                 self.map[f] = (state, s.st_mode, st_size, st_mtime)
-            if self.copies.has_key(f):
-                del self.copies[f]
+            if self.copymap.has_key(f):
+                del self.copymap[f]
 
     def forget(self, files):
         if not files: return
         self.lazyread()
         self.markdirty()
+        self.initdirs()
         for f in files:
             try:
                 del self.map[f]
+                self.updatedirs(f, -1)
             except KeyError:
                 self.ui.warn(_("not in dirstate: %s!\n") % f)
                 pass
 
     def clear(self):
         self.map = {}
-        self.copies = {}
+        self.copymap = {}
+        self.dirs = None
         self.markdirty()
 
     def rebuild(self, parent, files):
@@ -476,7 +521,7 @@
                 if size >= 0 and (size != st.st_size
                                   or (mode ^ st.st_mode) & 0100):
                     modified.append(fn)
-                elif time != st.st_mtime:
+                elif time != int(st.st_mtime):
                     lookup.append(fn)
                 elif list_clean:
                     clean.append(fn)
--- a/mercurial/filelog.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/filelog.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,13 +1,13 @@
 # filelog.py - file history class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
 from revlog import *
 from demandload import *
-demandload(globals(), "bdiff os")
+demandload(globals(), "os")
 
 class filelog(revlog):
     def __init__(self, opener, path, defversion=REVLOG_DEFAULT_VERSION):
@@ -37,7 +37,7 @@
         s = t.index('\1\n', 2)
         return t[s+2:]
 
-    def readmeta(self, node):
+    def _readmeta(self, node):
         t = self.revision(node)
         if not t.startswith('\1\n'):
             return {}
@@ -60,48 +60,27 @@
     def renamed(self, node):
         if self.parents(node)[0] != nullid:
             return False
-        m = self.readmeta(node)
+        m = self._readmeta(node)
         if m and m.has_key("copy"):
             return (m["copy"], bin(m["copyrev"]))
         return False
 
-    def annotate(self, node):
-
-        def decorate(text, rev):
-            return ([rev] * len(text.splitlines()), text)
+    def size(self, rev):
+        """return the size of a given revision"""
 
-        def pair(parent, child):
-            for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
-                child[0][b1:b2] = parent[0][a1:a2]
-            return child
+        # for revisions with renames, we have to go the slow way
+        node = self.node(rev)
+        if self.renamed(node):
+            return len(self.read(node))
+
+        return revlog.size(self, rev)
 
-        # find all ancestors
-        needed = {node:1}
-        visit = [node]
-        while visit:
-            n = visit.pop(0)
-            for p in self.parents(n):
-                if p not in needed:
-                    needed[p] = 1
-                    visit.append(p)
-                else:
-                    # count how many times we'll use this
-                    needed[p] += 1
+    def cmp(self, node, text):
+        """compare text with a given file revision"""
 
-        # sort by revision which is a topological order
-        visit = [ (self.rev(n), n) for n in needed.keys() ]
-        visit.sort()
-        hist = {}
+        # for renames, we have to go the slow way
+        if self.renamed(node):
+            t2 = self.read(node)
+            return t2 != text
 
-        for r,n in visit:
-            curr = decorate(self.read(n), self.linkrev(n))
-            for p in self.parents(n):
-                if p != nullid:
-                    curr = pair(hist[p], curr)
-                    # trim the history of unneeded revs
-                    needed[p] -= 1
-                    if not needed[p]:
-                        del hist[p]
-            hist[n] = curr
-
-        return zip(hist[n][0], hist[n][1].splitlines(1))
+        return revlog.cmp(self, node, text)
--- a/mercurial/hg.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/hg.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,7 @@
 # hg.py - repository classes for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -13,7 +14,7 @@
 demandload(globals(), "errno lock os shutil util merge@_merge verify@_verify")
 
 def _local(path):
-    return (os.path.isfile(path and util.drop_scheme('file', path)) and
+    return (os.path.isfile(util.drop_scheme('file', path)) and
             bundlerepo or localrepo)
 
 schemes = {
@@ -48,9 +49,14 @@
             return False
     return repo.local()
 
-def repository(ui, path=None, create=False):
+repo_setup_hooks = []
+
+def repository(ui, path='', create=False):
     """return a repository object for the specified path"""
-    return _lookup(path).instance(ui, path, create)
+    repo = _lookup(path).instance(ui, path, create)
+    for hook in repo_setup_hooks:
+        hook(ui, repo)
+    return repo
 
 def defaultdest(source):
     '''return default destination of clone if none is given'''
@@ -109,7 +115,7 @@
     source = localpath(source)
 
     if os.path.exists(dest):
-        raise util.Abort(_("destination '%s' already exists"), dest)
+        raise util.Abort(_("destination '%s' already exists") % dest)
 
     class DirCleanup(object):
         def __init__(self, dir_):
@@ -121,12 +127,7 @@
             if self.dir_:
                 self.rmtree(self.dir_, True)
 
-    dest_repo = None
-    try:
-        dest_repo = repository(ui, dest)
-        raise util.Abort(_("destination '%s' already exists." % dest))
-    except RepoError:
-        dest_repo = repository(ui, dest, create=True)
+    dest_repo = repository(ui, dest, create=True)
 
     dest_path = None
     dir_cleanup = None
@@ -175,9 +176,10 @@
     else:
         revs = None
         if rev:
-            if not src_repo.local():
-                raise util.Abort(_("clone by revision not supported yet "
-                                   "for remote repositories"))
+            if 'lookup' not in src_repo.capabilities:
+                raise util.Abort(_("src repository does not support revision "
+                                   "lookup and so doesn't support clone by "
+                                   "revision"))
             revs = [src_repo.lookup(r) for r in rev]
 
         if dest_repo.local():
@@ -200,30 +202,55 @@
             dest_lock.release()
 
         if update:
-            _merge.update(dest_repo, dest_repo.changelog.tip())
+            _update(dest_repo, dest_repo.changelog.tip())
     if dir_cleanup:
         dir_cleanup.close()
 
     return src_repo, dest_repo
 
+def _showstats(repo, stats):
+    stats = ((stats[0], _("updated")),
+             (stats[1], _("merged")),
+             (stats[2], _("removed")),
+             (stats[3], _("unresolved")))
+    note = ", ".join([_("%d files %s") % s for s in stats])
+    repo.ui.status("%s\n" % note)
+
+def _update(repo, node): return update(repo, node)
+
 def update(repo, node):
     """update the working directory to node, merging linear changes"""
-    return _merge.update(repo, node)
+    stats = _merge.update(repo, node, False, False, None, None)
+    _showstats(repo, stats)
+    if stats[3]:
+        repo.ui.status(_("There are unresolved merges with"
+                         " locally modified files.\n"))
+    return stats[3]
 
 def clean(repo, node, wlock=None, show_stats=True):
     """forcibly switch the working directory to node, clobbering changes"""
-    return _merge.update(repo, node, force=True, wlock=wlock,
-                         show_stats=show_stats)
+    stats = _merge.update(repo, node, False, True, None, wlock)
+    if show_stats: _showstats(repo, stats)
+    return stats[3]
 
 def merge(repo, node, force=None, remind=True, wlock=None):
     """branch merge with node, resolving changes"""
-    return _merge.update(repo, node, branchmerge=True, force=force,
-                         remind=remind, wlock=wlock)
+    stats = _merge.update(repo, node, True, force, False, wlock)
+    _showstats(repo, stats)
+    if stats[3]:
+        pl = repo.parents()
+        repo.ui.status(_("There are unresolved merges,"
+                         " you can redo the full merge using:\n"
+                         "  hg update -C %s\n"
+                         "  hg merge %s\n"
+                         % (pl[0].rev(), pl[1].rev())))
+    elif remind:
+        repo.ui.status(_("(branch merge, don't forget to commit)\n"))
+    return stats[3]
 
 def revert(repo, node, choose, wlock):
     """revert changes to revision in node without updating dirstate"""
-    return _merge.update(repo, node, force=True, partial=choose,
-                         show_stats=False, wlock=wlock)
+    return _merge.update(repo, node, False, True, choose, wlock)[3]
 
 def verify(repo):
     """verify the consistency of a repository"""
--- a/mercurial/hgweb/common.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/hgweb/common.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,7 +1,7 @@
 # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -38,7 +38,24 @@
         ct = mimetypes.guess_type(path)[0] or "text/plain"
         req.header([('Content-type', ct),
                     ('Content-length', os.path.getsize(path))])
-        return file(path).read()
+        return file(path, 'rb').read()
     except (TypeError, OSError):
         # illegal fname or unreadable file
         return ""
+
+def style_map(templatepath, style):
+    """Return path to mapfile for a given style.
+
+    Searches mapfile in the following locations:
+    1. templatepath/style/map
+    2. templatepath/map-style
+    3. templatepath/map
+    """
+    locations = style and [os.path.join(style, "map"), "map-"+style] or []
+    locations.append("map")
+    for location in locations:
+        mapfile = os.path.join(templatepath, location)
+        if os.path.isfile(mapfile):
+            return mapfile
+    raise RuntimeError("No hgweb templates found in %r" % templatepath)
+
--- a/mercurial/hgweb/hgweb_mod.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/hgweb/hgweb_mod.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,7 +1,7 @@
 # hgweb/hgweb_mod.py - Web interface for a repository.
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -11,9 +11,10 @@
 import mimetypes
 from mercurial.demandload import demandload
 demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
-demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone")
-demandload(globals(), "mercurial:templater")
-demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile")
+demandload(globals(), 'urllib')
+demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch")
+demandload(globals(), "mercurial:revlog,templater")
+demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
 from mercurial.node import *
 from mercurial.i18n import gettext as _
 
@@ -27,6 +28,44 @@
         return "/"
     return up + "/"
 
+def revnavgen(pos, pagelen, limit, nodefunc):
+    def seq(factor, limit=None):
+        if limit:
+            yield limit
+            if limit >= 20 and limit <= 40:
+                yield 50
+        else:
+            yield 1 * factor
+            yield 3 * factor
+        for f in seq(factor * 10):
+            yield f
+
+    def nav(**map):
+        l = []
+        last = 0
+        for f in seq(1, pagelen):
+            if f < pagelen or f <= last:
+                continue
+            if f > limit:
+                break
+            last = f
+            if pos + f < limit:
+                l.append(("+%d" % f, hex(nodefunc(pos + f).node())))
+            if pos - f >= 0:
+                l.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node())))
+
+        try:
+            yield {"label": "(0)", "node": hex(nodefunc('0').node())}
+
+            for label, node in l:
+                yield {"label": label, "node": node}
+
+            yield {"label": "tip", "node": "tip"}
+        except hg.RepoError:
+            pass
+
+    return nav
+
 class hgweb(object):
     def __init__(self, repo, name=None):
         if type(repo) == type(""):
@@ -54,15 +93,9 @@
 
     def archivelist(self, nodeid):
         allowed = self.repo.ui.configlist("web", "allow_archive")
-        for i in self.archives:
+        for i, spec in self.archive_specs.iteritems():
             if i in allowed or self.repo.ui.configbool("web", "allow" + i):
-                yield {"type" : i, "node" : nodeid, "url": ""}
-
-    def listfiles(self, files, mf):
-        for f in files[:self.maxfiles]:
-            yield self.t("filenodelink", node=hex(mf[f]), file=f)
-        if len(files) > self.maxfiles:
-            yield self.t("fileellipses")
+                yield {"type" : i, "extension" : spec[2], "node" : nodeid}
 
     def listfilediffs(self, files, changeset):
         for f in files[:self.maxfiles]:
@@ -70,14 +103,16 @@
         if len(files) > self.maxfiles:
             yield self.t("fileellipses")
 
-    def siblings(self, siblings=[], rev=None, hiderev=None, **args):
-        if not rev:
-            rev = lambda x: ""
-        siblings = [s for s in siblings if s != nullid]
-        if len(siblings) == 1 and rev(siblings[0]) == hiderev:
+    def siblings(self, siblings=[], hiderev=None, **args):
+        siblings = [s for s in siblings if s.node() != nullid]
+        if len(siblings) == 1 and siblings[0].rev() == hiderev:
             return
         for s in siblings:
-            yield dict(node=hex(s), rev=rev(s), **args)
+            d = {'node': hex(s.node()), 'rev': s.rev()}
+            if hasattr(s, 'path'):
+                d['file'] = s.path()
+            d.update(args)
+            yield d
 
     def renamelink(self, fl, node):
         r = fl.renamed(node)
@@ -129,95 +164,47 @@
         date1 = util.datestr(change1[2])
         date2 = util.datestr(change2[2])
 
-        modified, added, removed, deleted, unknown = r.changes(node1, node2)
+        modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
         if files:
             modified, added, removed = map(lambda x: filterfiles(files, x),
                                            (modified, added, removed))
 
-        diffopts = self.repo.ui.diffopts()
-        showfunc = diffopts['showfunc']
-        ignorews = diffopts['ignorews']
-        ignorewsamount = diffopts['ignorewsamount']
-        ignoreblanklines = diffopts['ignoreblanklines']
+        diffopts = patch.diffopts(self.repo.ui)
         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,
-                            showfunc=showfunc, ignorews=ignorews,
-                            ignorewsamount=ignorewsamount,
-                            ignoreblanklines=ignoreblanklines), f, tn)
+                                          opts=diffopts), f, tn)
         for f in added:
             to = None
             tn = r.file(f).read(mmap2[f])
             yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
-                            showfunc=showfunc, ignorews=ignorews,
-                            ignorewsamount=ignorewsamount,
-                            ignoreblanklines=ignoreblanklines), f, tn)
+                                          opts=diffopts), f, tn)
         for f in removed:
             to = r.file(f).read(mmap1[f])
             tn = None
             yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
-                            showfunc=showfunc, ignorews=ignorews,
-                            ignorewsamount=ignorewsamount,
-                            ignoreblanklines=ignoreblanklines), f, tn)
-
-    def changelog(self, pos, shortlog=False):
-        def changenav(**map):
-            def seq(factor, maxchanges=None):
-                if maxchanges:
-                    yield maxchanges
-                    if maxchanges >= 20 and maxchanges <= 40:
-                        yield 50
-                else:
-                    yield 1 * factor
-                    yield 3 * factor
-                for f in seq(factor * 10):
-                    yield f
+                                          opts=diffopts), f, tn)
 
-            l = []
-            last = 0
-            maxchanges = shortlog and self.maxshortchanges or self.maxchanges
-            for f in seq(1, maxchanges):
-                if f < maxchanges or f <= last:
-                    continue
-                if f > count:
-                    break
-                last = f
-                r = "%d" % f
-                if pos + f < count:
-                    l.append(("+" + r, pos + f))
-                if pos - f >= 0:
-                    l.insert(0, ("-" + r, pos - f))
-
-            yield {"rev": 0, "label": "(0)"}
-
-            for label, rev in l:
-                yield {"label": label, "rev": rev}
-
-            yield {"label": "tip", "rev": "tip"}
-
+    def changelog(self, ctx, shortlog=False):
         def changelist(**map):
             parity = (start - end) & 1
             cl = self.repo.changelog
             l = [] # build a list in forward order for efficiency
             for i in range(start, end):
-                n = cl.node(i)
-                changes = cl.read(n)
-                hn = hex(n)
+                ctx = self.repo.changectx(i)
+                n = ctx.node()
 
                 l.insert(0, {"parity": parity,
-                             "author": changes[1],
-                             "parent": self.siblings(cl.parents(n), cl.rev,
-                                                     cl.rev(n) - 1),
-                             "child": self.siblings(cl.children(n), cl.rev,
-                                                    cl.rev(n) + 1),
+                             "author": ctx.user(),
+                             "parent": self.siblings(ctx.parents(), i - 1),
+                             "child": self.siblings(ctx.children(), i + 1),
                              "changelogtag": self.showtag("changelogtag",n),
-                             "manifest": hex(changes[0]),
-                             "desc": changes[4],
-                             "date": changes[2],
-                             "files": self.listfilediffs(changes[3], n),
+                             "desc": ctx.description(),
+                             "date": ctx.date(),
+                             "files": self.listfilediffs(ctx.files(), n),
                              "rev": i,
-                             "node": hn})
+                             "node": hex(n)})
                 parity = 1 - parity
 
             for e in l:
@@ -225,15 +212,17 @@
 
         maxchanges = shortlog and self.maxshortchanges or self.maxchanges
         cl = self.repo.changelog
-        mf = cl.read(cl.tip())[0]
         count = cl.count()
+        pos = ctx.rev()
         start = max(0, pos - maxchanges + 1)
         end = min(count, start + maxchanges)
         pos = end - 1
 
+        changenav = revnavgen(pos, maxchanges, count, self.repo.changectx)
+
         yield self.t(shortlog and 'shortlog' or 'changelog',
                      changenav=changenav,
-                     manifest=hex(mf),
+                     node=hex(cl.tip()),
                      rev=pos, changesets=count, entries=changelist,
                      archives=self.archivelist("tip"))
 
@@ -248,127 +237,120 @@
                 for i in range(cl.count() - 1, 0, -100):
                     l = []
                     for j in range(max(0, i - 100), i):
-                        n = cl.node(j)
-                        changes = cl.read(n)
-                        l.append((n, j, changes))
+                        ctx = self.repo.changectx(j)
+                        l.append(ctx)
                     l.reverse()
                     for e in l:
                         yield e
 
-            for n, i, changes in revgen():
+            for ctx in revgen():
                 miss = 0
                 for q in qw:
-                    if not (q in changes[1].lower() or
-                            q in changes[4].lower() or
-                            q in " ".join(changes[3][:20]).lower()):
+                    if not (q in ctx.user().lower() or
+                            q in ctx.description().lower() or
+                            q in " ".join(ctx.files()[:20]).lower()):
                         miss = 1
                         break
                 if miss:
                     continue
 
                 count += 1
-                hn = hex(n)
+                n = ctx.node()
 
                 yield self.t('searchentry',
                              parity=self.stripes(count),
-                             author=changes[1],
-                             parent=self.siblings(cl.parents(n), cl.rev),
-                             child=self.siblings(cl.children(n), cl.rev),
+                             author=ctx.user(),
+                             parent=self.siblings(ctx.parents()),
+                             child=self.siblings(ctx.children()),
                              changelogtag=self.showtag("changelogtag",n),
-                             manifest=hex(changes[0]),
-                             desc=changes[4],
-                             date=changes[2],
-                             files=self.listfilediffs(changes[3], n),
-                             rev=i,
-                             node=hn)
+                             desc=ctx.description(),
+                             date=ctx.date(),
+                             files=self.listfilediffs(ctx.files(), n),
+                             rev=ctx.rev(),
+                             node=hex(n))
 
                 if count >= self.maxchanges:
                     break
 
         cl = self.repo.changelog
-        mf = cl.read(cl.tip())[0]
 
         yield self.t('search',
                      query=query,
-                     manifest=hex(mf),
+                     node=hex(cl.tip()),
                      entries=changelist)
 
-    def changeset(self, nodeid):
-        cl = self.repo.changelog
-        n = self.repo.lookup(nodeid)
-        nodeid = hex(n)
-        changes = cl.read(n)
-        p1 = cl.parents(n)[0]
+    def changeset(self, ctx):
+        n = ctx.node()
+        parents = ctx.parents()
+        p1 = parents[0].node()
 
         files = []
-        mf = self.repo.manifest.read(changes[0])
-        for f in changes[3]:
+        parity = 0
+        for f in ctx.files():
             files.append(self.t("filenodelink",
-                                filenode=hex(mf.get(f, nullid)), file=f))
+                                node=hex(n), file=f,
+                                parity=parity))
+            parity = 1 - parity
 
         def diff(**map):
             yield self.diff(p1, n, None)
 
         yield self.t('changeset',
                      diff=diff,
-                     rev=cl.rev(n),
-                     node=nodeid,
-                     parent=self.siblings(cl.parents(n), cl.rev),
-                     child=self.siblings(cl.children(n), cl.rev),
+                     rev=ctx.rev(),
+                     node=hex(n),
+                     parent=self.siblings(parents),
+                     child=self.siblings(ctx.children()),
                      changesettag=self.showtag("changesettag",n),
-                     manifest=hex(changes[0]),
-                     author=changes[1],
-                     desc=changes[4],
-                     date=changes[2],
+                     author=ctx.user(),
+                     desc=ctx.description(),
+                     date=ctx.date(),
                      files=files,
-                     archives=self.archivelist(nodeid))
+                     archives=self.archivelist(hex(n)))
 
-    def filelog(self, f, filenode):
-        cl = self.repo.changelog
-        fl = self.repo.file(f)
-        filenode = hex(fl.lookup(filenode))
+    def filelog(self, fctx):
+        f = fctx.path()
+        fl = fctx.filelog()
         count = fl.count()
+        pagelen = self.maxshortchanges
+        pos = fctx.filerev()
+        start = max(0, pos - pagelen + 1) 
+        end = min(count, start + pagelen)
+        pos = end - 1
 
         def entries(**map):
             l = []
             parity = (count - 1) & 1
 
-            for i in range(count):
+            for i in range(start, end):
+                ctx = fctx.filectx(i)
                 n = fl.node(i)
-                lr = fl.linkrev(n)
-                cn = cl.node(lr)
-                cs = cl.read(cl.node(lr))
 
                 l.insert(0, {"parity": parity,
-                             "filenode": hex(n),
                              "filerev": i,
                              "file": f,
-                             "node": hex(cn),
-                             "author": cs[1],
-                             "date": cs[2],
+                             "node": hex(ctx.node()),
+                             "author": ctx.user(),
+                             "date": ctx.date(),
                              "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]})
+                             "parent": self.siblings(fctx.parents()),
+                             "child": self.siblings(fctx.children()),
+                             "desc": ctx.description()})
                 parity = 1 - parity
 
             for e in l:
                 yield e
 
-        yield self.t("filelog", file=f, filenode=filenode, entries=entries)
+        nodefunc = lambda x: fctx.filectx(fileid=x)
+        nav = revnavgen(pos, pagelen, count, nodefunc)
+        yield self.t("filelog", file=f, node=hex(fctx.node()), nav=nav,
+                     entries=entries)
 
-    def filerevision(self, f, node):
-        fl = self.repo.file(f)
-        n = fl.lookup(node)
-        node = hex(n)
-        text = fl.read(n)
-        changerev = fl.linkrev(n)
-        cl = self.repo.changelog
-        cn = cl.node(changerev)
-        cs = cl.read(cn)
-        mfn = cs[0]
+    def filerevision(self, fctx):
+        f = fctx.path()
+        text = fctx.data()
+        fl = fctx.filelog()
+        n = fctx.filenode()
 
         mt = mimetypes.guess_type(f)[0]
         rawtext = text
@@ -385,83 +367,60 @@
 
         yield self.t("filerevision",
                      file=f,
-                     filenode=node,
                      path=_up(f),
                      text=lines(),
                      raw=rawtext,
                      mimetype=mt,
-                     rev=changerev,
-                     node=hex(cn),
-                     manifest=hex(mfn),
-                     author=cs[1],
-                     date=cs[2],
-                     parent=self.siblings(fl.parents(n), fl.rev, file=f),
-                     child=self.siblings(fl.children(n), fl.rev, file=f),
+                     rev=fctx.rev(),
+                     node=hex(fctx.node()),
+                     author=fctx.user(),
+                     date=fctx.date(),
+                     desc=fctx.description(),
+                     parent=self.siblings(fctx.parents()),
+                     child=self.siblings(fctx.children()),
                      rename=self.renamelink(fl, n),
-                     permissions=self.repo.manifest.read(mfn).execf[f])
+                     permissions=fctx.manifest().execf(f))
 
-    def fileannotate(self, f, node):
-        bcache = {}
-        ncache = {}
-        fl = self.repo.file(f)
-        n = fl.lookup(node)
-        node = hex(n)
-        changerev = fl.linkrev(n)
-
-        cl = self.repo.changelog
-        cn = cl.node(changerev)
-        cs = cl.read(cn)
-        mfn = cs[0]
+    def fileannotate(self, fctx):
+        f = fctx.path()
+        n = fctx.filenode()
+        fl = fctx.filelog()
 
         def annotate(**map):
             parity = 0
             last = None
-            for r, l in fl.annotate(n):
-                try:
-                    cnode = ncache[r]
-                except KeyError:
-                    cnode = ncache[r] = self.repo.changelog.node(r)
+            for f, l in fctx.annotate(follow=True):
+                fnode = f.filenode()
+                name = self.repo.ui.shortuser(f.user())
 
-                try:
-                    name = bcache[r]
-                except KeyError:
-                    cl = self.repo.changelog.read(cnode)
-                    bcache[r] = name = self.repo.ui.shortuser(cl[1])
-
-                if last != cnode:
+                if last != fnode:
                     parity = 1 - parity
-                    last = cnode
+                    last = fnode
 
                 yield {"parity": parity,
-                       "node": hex(cnode),
-                       "rev": r,
+                       "node": hex(f.node()),
+                       "rev": f.rev(),
                        "author": name,
-                       "file": f,
+                       "file": f.path(),
                        "line": l}
 
         yield self.t("fileannotate",
                      file=f,
-                     filenode=node,
                      annotate=annotate,
                      path=_up(f),
-                     rev=changerev,
-                     node=hex(cn),
-                     manifest=hex(mfn),
-                     author=cs[1],
-                     date=cs[2],
+                     rev=fctx.rev(),
+                     node=hex(fctx.node()),
+                     author=fctx.user(),
+                     date=fctx.date(),
+                     desc=fctx.description(),
                      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.read(mfn).execf[f])
+                     parent=self.siblings(fctx.parents()),
+                     child=self.siblings(fctx.children()),
+                     permissions=fctx.manifest().execf(f))
 
-    def manifest(self, mnode, path):
-        man = self.repo.manifest
-        mn = man.lookup(mnode)
-        mnode = hex(mn)
-        mf = man.read(mn)
-        rev = man.rev(mn)
-        changerev = man.linkrev(mn)
-        node = self.repo.changelog.node(changerev)
+    def manifest(self, ctx, path):
+        mf = ctx.manifest()
+        node = ctx.node()
 
         files = {}
 
@@ -491,11 +450,10 @@
                     continue
 
                 yield {"file": full,
-                       "manifest": mnode,
-                       "filenode": hex(fnode),
                        "parity": self.stripes(parity),
                        "basename": f,
-                       "permissions": mf.execf[full]}
+                       "size": ctx.filectx(full).size(),
+                       "permissions": mf.execf(full)}
                 parity += 1
 
         def dirlist(**map):
@@ -509,13 +467,11 @@
 
                 yield {"parity": self.stripes(parity),
                        "path": os.path.join(path, f),
-                       "manifest": mnode,
                        "basename": f[:-1]}
                 parity += 1
 
         yield self.t("manifest",
-                     manifest=mnode,
-                     rev=rev,
+                     rev=ctx.rev(),
                      node=hex(node),
                      path=path,
                      up=_up(path),
@@ -525,7 +481,6 @@
 
     def tags(self):
         cl = self.repo.changelog
-        mf = cl.read(cl.tip())[0]
 
         i = self.repo.tagslist()
         i.reverse()
@@ -536,19 +491,17 @@
                 if notip and k == "tip": continue
                 yield {"parity": self.stripes(parity),
                        "tag": k,
-                       "tagmanifest": hex(cl.read(n)[0]),
                        "date": cl.read(n)[2],
                        "node": hex(n)}
                 parity += 1
 
         yield self.t("tags",
-                     manifest=hex(mf),
+                     node=hex(self.repo.changelog.tip()),
                      entries=lambda **x: entries(False, **x),
                      entriesnotip=lambda **x: entries(True, **x))
 
     def summary(self):
         cl = self.repo.changelog
-        mf = cl.read(cl.tip())[0]
 
         i = self.repo.tagslist()
         i.reverse()
@@ -565,15 +518,13 @@
                     break;
 
                 c = cl.read(n)
-                m = c[0]
                 t = c[2]
 
                 yield self.t("tagentry",
                              parity = self.stripes(parity),
                              tag = k,
                              node = hex(n),
-                             date = t,
-                             tagmanifest = hex(m))
+                             date = t)
                 parity += 1
 
         def changelist(**map):
@@ -590,7 +541,6 @@
                     'shortlogentry',
                     parity = parity,
                     author = changes[1],
-                    manifest = hex(changes[0]),
                     desc = changes[4],
                     date = t,
                     rev = i,
@@ -599,8 +549,6 @@
 
             yield l
 
-        cl = self.repo.changelog
-        mf = cl.read(cl.tip())[0]
         count = cl.count()
         start = max(0, count - self.maxchanges)
         end = min(count, start + self.maxchanges)
@@ -610,30 +558,27 @@
                  owner = (self.repo.ui.config("ui", "username") or # preferred
                           self.repo.ui.config("web", "contact") or # deprecated
                           self.repo.ui.config("web", "author", "unknown")), # also
-                 lastchange = (0, 0), # FIXME
-                 manifest = hex(mf),
+                 lastchange = cl.read(cl.tip())[2],
                  tags = tagentries,
                  shortlog = changelist,
+                 node = hex(cl.tip()),
                  archives=self.archivelist("tip"))
 
-    def filediff(self, file, changeset):
-        cl = self.repo.changelog
-        n = self.repo.lookup(changeset)
-        changeset = hex(n)
-        p1 = cl.parents(n)[0]
-        cs = cl.read(n)
-        mf = self.repo.manifest.read(cs[0])
+    def filediff(self, fctx):
+        n = fctx.node()
+        path = fctx.path()
+        parents = fctx.parents()
+        p1 = parents and parents[0].node() or nullid
 
         def diff(**map):
-            yield self.diff(p1, n, [file])
+            yield self.diff(p1, n, [path])
 
         yield self.t("filediff",
-                     file=file,
-                     filenode=hex(mf.get(file, nullid)),
-                     node=changeset,
-                     rev=self.repo.changelog.rev(n),
-                     parent=self.siblings(cl.parents(n), cl.rev),
-                     child=self.siblings(cl.children(n), cl.rev),
+                     file=path,
+                     node=hex(n),
+                     rev=fctx.rev(),
+                     parent=self.siblings(parents),
+                     child=self.siblings(fctx.children()),
                      diff=diff)
 
     archive_specs = {
@@ -659,10 +604,7 @@
     # find tag, changeset, file
 
     def cleanpath(self, path):
-        p = util.normpath(path)
-        if p[:2] == "..":
-            raise Exception("suspicious path")
-        return p
+        return util.canonpath(self.repo.root, '', path)
 
     def run(self):
         if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
@@ -715,36 +657,113 @@
                         form[name] = value
                     del form[k]
 
+        def rewrite_request(req):
+            '''translate new web interface to traditional format'''
+
+            def spliturl(req):
+                def firstitem(query):
+                    return query.split('&', 1)[0].split(';', 1)[0]
+
+                def normurl(url):
+                    inner = '/'.join([x for x in url.split('/') if x])
+                    tl = len(url) > 1 and url.endswith('/') and '/' or ''
+
+                    return '%s%s%s' % (url.startswith('/') and '/' or '',
+                                       inner, tl)
+
+                root = normurl(req.env.get('REQUEST_URI', '').split('?', 1)[0])
+                pi = normurl(req.env.get('PATH_INFO', ''))
+                if pi:
+                    # strip leading /
+                    pi = pi[1:]
+                    if pi:
+                        root = root[:-len(pi)]
+                    if req.env.has_key('REPO_NAME'):
+                        rn = req.env['REPO_NAME'] + '/'
+                        root += rn
+                        query = pi[len(rn):]
+                    else:
+                        query = pi
+                else:
+                    root += '?'
+                    query = firstitem(req.env['QUERY_STRING'])
+
+                return (root, query)
+
+            req.url, query = spliturl(req)
+
+            if req.form.has_key('cmd'):
+                # old style
+                return
+
+            args = query.split('/', 2)
+            if not args or not args[0]:
+                return
+
+            cmd = args.pop(0)
+            style = cmd.rfind('-')
+            if style != -1:
+                req.form['style'] = [cmd[:style]]
+                cmd = cmd[style+1:]
+            # avoid accepting e.g. style parameter as command
+            if hasattr(self, 'do_' + cmd):
+                req.form['cmd'] = [cmd]
+
+            if args and args[0]:
+                node = args.pop(0)
+                req.form['node'] = [node]
+            if args:
+                req.form['file'] = args
+
+            if cmd == 'static':
+                req.form['file'] = req.form['node']
+            elif cmd == 'archive':
+                fn = req.form['node'][0]
+                for type_, spec in self.archive_specs.iteritems():
+                    ext = spec[2]
+                    if fn.endswith(ext):
+                        req.form['node'] = [fn[:-len(ext)]]
+                        req.form['type'] = [type_]
+
+        def sessionvars(**map):
+            fields = []
+            if req.form.has_key('style'):
+                style = req.form['style'][0]
+                if style != self.repo.ui.config('web', 'style', ''):
+                    fields.append(('style', style))
+
+            separator = req.url[-1] == '?' and ';' or '?'
+            for name, value in fields:
+                yield dict(name=name, value=value, separator=separator)
+                separator = ';'
+
         self.refresh()
 
         expand_form(req.form)
+        rewrite_request(req)
 
-        m = os.path.join(self.templatepath, "map")
         style = self.repo.ui.config("web", "style", "")
         if req.form.has_key('style'):
             style = req.form['style'][0]
-        if style:
-            b = os.path.basename("map-" + style)
-            p = os.path.join(self.templatepath, b)
-            if os.path.isfile(p):
-                m = p
+        mapfile = style_map(self.templatepath, style)
 
         port = req.env["SERVER_PORT"]
         port = port != "80" and (":" + port) or ""
-        uri = req.env["REQUEST_URI"]
-        if "?" in uri:
-            uri = uri.split("?")[0]
-        url = "http://%s%s%s" % (req.env["SERVER_NAME"], port, uri)
+        urlbase = 'http://%s%s' % (req.env['SERVER_NAME'], port)
+
         if not self.reponame:
             self.reponame = (self.repo.ui.config("web", "name")
-                             or uri.strip('/') or self.repo.root)
+                             or req.env.get('REPO_NAME')
+                             or req.url.strip('/') or self.repo.root)
 
-        self.t = templater.templater(m, templater.common_filters,
-                                     defaults={"url": url,
+        self.t = templater.templater(mapfile, templater.common_filters,
+                                     defaults={"url": req.url,
+                                               "urlbase": urlbase,
                                                "repo": self.reponame,
                                                "header": header,
                                                "footer": footer,
                                                "rawfileheader": rawfileheader,
+                                               "sessionvars": sessionvars
                                                })
 
         if not req.form.has_key('cmd'):
@@ -754,9 +773,43 @@
 
         method = getattr(self, 'do_' + cmd, None)
         if method:
-            method(req)
+            try:
+                method(req)
+            except (hg.RepoError, revlog.RevlogError), inst:
+                req.write(self.t("error", error=str(inst)))
+        else:
+            req.write(self.t("error", error='No such method: ' + cmd))
+
+    def changectx(self, req):
+        if req.form.has_key('node'):
+            changeid = req.form['node'][0]
+        elif req.form.has_key('manifest'):
+            changeid = req.form['manifest'][0]
         else:
-            req.write(self.t("error"))
+            changeid = self.repo.changelog.count() - 1
+
+        try:
+            ctx = self.repo.changectx(changeid)
+        except hg.RepoError:
+            man = self.repo.manifest
+            mn = man.lookup(changeid)
+            ctx = self.repo.changectx(man.linkrev(mn))
+
+        return ctx
+
+    def filectx(self, req):
+        path = self.cleanpath(req.form['file'][0])
+        if req.form.has_key('node'):
+            changeid = req.form['node'][0]
+        else:
+            changeid = req.form['filenode'][0]
+        try:
+            ctx = self.repo.changectx(changeid)
+            fctx = ctx.filectx(path)
+        except hg.RepoError:
+            fctx = self.repo.filectx(path, fileid=changeid)
+
+        return fctx
 
     def stripes(self, parity):
         "make horizontal stripes for easier reading"
@@ -765,35 +818,54 @@
         else:
             return 0
 
-    def do_changelog(self, req):
-        hi = self.repo.changelog.count() - 1
-        if req.form.has_key('rev'):
-            hi = req.form['rev'][0]
+    def do_log(self, req):
+        if req.form.has_key('file') and req.form['file'][0]:
+            self.do_filelog(req)
+        else:
+            self.do_changelog(req)
+
+    def do_rev(self, req):
+        self.do_changeset(req)
+
+    def do_file(self, req):
+        path = req.form.get('file', [''])[0]
+        if path:
             try:
-                hi = self.repo.changelog.rev(self.repo.lookup(hi))
+                req.write(self.filerevision(self.filectx(req)))
+                return
+            except hg.RepoError:
+                pass
+            path = self.cleanpath(path)
+
+        req.write(self.manifest(self.changectx(req), '/' + path))
+
+    def do_diff(self, req):
+        self.do_filediff(req)
+
+    def do_changelog(self, req, shortlog = False):
+        if req.form.has_key('node'):
+            ctx = self.changectx(req)
+        else:
+            if req.form.has_key('rev'):
+                hi = req.form['rev'][0]
+            else:
+                hi = self.repo.changelog.count() - 1
+            try:
+                ctx = self.repo.changectx(hi)
             except hg.RepoError:
                 req.write(self.search(hi)) # XXX redirect to 404 page?
                 return
 
-        req.write(self.changelog(hi))
+        req.write(self.changelog(ctx, shortlog = shortlog))
 
     def do_shortlog(self, req):
-        hi = self.repo.changelog.count() - 1
-        if req.form.has_key('rev'):
-            hi = req.form['rev'][0]
-            try:
-                hi = self.repo.changelog.rev(self.repo.lookup(hi))
-            except hg.RepoError:
-                req.write(self.search(hi)) # XXX redirect to 404 page?
-                return
-
-        req.write(self.changelog(hi, shortlog = True))
+        self.do_changelog(req, shortlog = True)
 
     def do_changeset(self, req):
-        req.write(self.changeset(req.form['node'][0]))
+        req.write(self.changeset(self.changectx(req)))
 
     def do_manifest(self, req):
-        req.write(self.manifest(req.form['manifest'][0],
+        req.write(self.manifest(self.changectx(req),
                                 self.cleanpath(req.form['path'][0])))
 
     def do_tags(self, req):
@@ -803,20 +875,24 @@
         req.write(self.summary())
 
     def do_filediff(self, req):
-        req.write(self.filediff(self.cleanpath(req.form['file'][0]),
-                                req.form['node'][0]))
-
-    def do_file(self, req):
-        req.write(self.filerevision(self.cleanpath(req.form['file'][0]),
-                                    req.form['filenode'][0]))
+        req.write(self.filediff(self.filectx(req)))
 
     def do_annotate(self, req):
-        req.write(self.fileannotate(self.cleanpath(req.form['file'][0]),
-                                    req.form['filenode'][0]))
+        req.write(self.fileannotate(self.filectx(req)))
 
     def do_filelog(self, req):
-        req.write(self.filelog(self.cleanpath(req.form['file'][0]),
-                               req.form['filenode'][0]))
+        req.write(self.filelog(self.filectx(req)))
+
+    def do_lookup(self, req):
+        try:
+            r = hex(self.repo.lookup(req.form['key'][0]))
+            success = 1
+        except Exception,inst:
+            r = str(inst)
+            success = 0
+        resp = "%s %s\n" % (success, r)
+        req.httphdr("application/mercurial-0.1", length=len(resp))
+        req.write(resp)
 
     def do_heads(self, req):
         resp = " ".join(map(hex, self.repo.heads())) + "\n"
@@ -835,7 +911,6 @@
         req.write(resp)
 
     def do_between(self, req):
-        nodes = []
         if req.form.has_key('pairs'):
             pairs = [map(bin, p.split("-"))
                      for p in req.form['pairs'][0].split(" ")]
@@ -865,6 +940,28 @@
 
         req.write(z.flush())
 
+    def do_changegroupsubset(self, req):
+        req.httphdr("application/mercurial-0.1")
+        bases = []
+        heads = []
+        if not self.allowpull:
+            return
+
+        if req.form.has_key('bases'):
+            bases = [bin(x) for x in req.form['bases'][0].split(' ')]
+        if req.form.has_key('heads'):
+            heads = [bin(x) for x in req.form['heads'][0].split(' ')]
+
+        z = zlib.compressobj()
+        f = self.repo.changegroupsubset(bases, heads, 'serve')
+        while 1:
+            chunk = f.read(4096)
+            if not chunk:
+                break
+            req.write(z.compress(chunk))
+
+        req.write(z.flush())
+
     def do_archive(self, req):
         changeset = self.repo.lookup(req.form['node'][0])
         type_ = req.form['type'][0]
@@ -885,7 +982,7 @@
                   or self.t("error", error="%r not found" % fname))
 
     def do_capabilities(self, req):
-        caps = ['unbundle']
+        caps = ['unbundle', 'lookup', 'changegroupsubset']
         if self.repo.ui.configbool('server', 'uncompressed'):
             caps.append('stream=%d' % self.repo.revlogversion)
         resp = ' '.join(caps)
--- a/mercurial/hgweb/hgwebdir_mod.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/hgweb/hgwebdir_mod.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,17 +1,17 @@
 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
 import os
 from mercurial.demandload import demandload
-demandload(globals(), "ConfigParser mimetools cStringIO")
+demandload(globals(), "mimetools cStringIO")
 demandload(globals(), "mercurial:ui,hg,util,templater")
 demandload(globals(), "mercurial.hgweb.hgweb_mod:hgweb")
-demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile")
+demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
 from mercurial.i18n import gettext as _
 
 # This is a stopgap
@@ -21,6 +21,7 @@
             return [(name.strip(os.sep), path) for name, path in items]
 
         self.motd = ""
+        self.style = ""
         self.repos_sorted = ('name', False)
         if isinstance(config, (list, tuple)):
             self.repos = cleannames(config)
@@ -29,11 +30,14 @@
             self.repos = cleannames(config.items())
             self.repos.sort()
         else:
-            cp = ConfigParser.SafeConfigParser()
+            cp = util.configparser()
             cp.read(config)
             self.repos = []
-            if cp.has_section('web') and cp.has_option('web', 'motd'):
-                self.motd = cp.get('web', 'motd')
+            if cp.has_section('web'):
+                if cp.has_option('web', 'motd'):
+                    self.motd = cp.get('web', 'motd')
+                if cp.has_option('web', 'style'):
+                    self.style = cp.get('web', 'style')
             if cp.has_section('paths'):
                 self.repos.extend(cleannames(cp.items('paths')))
             if cp.has_section('collections'):
@@ -65,18 +69,39 @@
         def footer(**map):
             yield tmpl("footer", motd=self.motd, **map)
 
-        m = os.path.join(templater.templatepath(), "map")
-        tmpl = templater.templater(m, templater.common_filters,
+        url = req.env['REQUEST_URI'].split('?')[0]
+        if not url.endswith('/'):
+            url += '/'
+
+        style = self.style
+        if req.form.has_key('style'):
+            style = req.form['style'][0]
+        mapfile = style_map(templater.templatepath(), style)
+        tmpl = templater.templater(mapfile, templater.common_filters,
                                    defaults={"header": header,
-                                             "footer": footer})
+                                             "footer": footer,
+                                             "url": url})
 
         def archivelist(ui, nodeid, url):
             allowed = ui.configlist("web", "allow_archive")
-            for i in ['zip', 'gz', 'bz2']:
-                if i in allowed or ui.configbool("web", "allow" + i):
-                    yield {"type" : i, "node": nodeid, "url": url}
+            for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
+                if i[0] in allowed or ui.configbool("web", "allow" + i[0]):
+                    yield {"type" : i[0], "extension": i[1],
+                           "node": nodeid, "url": url}
 
         def entries(sortcolumn="", descending=False, **map):
+            def sessionvars(**map):
+                fields = []
+                if req.form.has_key('style'):
+                    style = req.form['style'][0]
+                    if style != get('web', 'style', ''):
+                        fields.append(('style', style))
+
+                separator = url[-1] == '?' and ';' or '?'
+                for name, value in fields:
+                    yield dict(name=name, value=value, separator=separator)
+                    separator = ';'
+
             rows = []
             parity = 0
             for name, path in self.repos:
@@ -88,7 +113,7 @@
                 get = u.config
 
                 url = ('/'.join([req.env["REQUEST_URI"].split('?')[0], name])
-                       .replace("//", "/"))
+                       .replace("//", "/")) + '/'
 
                 # update time with local timezone
                 try:
@@ -110,6 +135,7 @@
                            description_sort=description.upper() or "unknown",
                            lastchange=d,
                            lastchange_sort=d[1]-d[0],
+                           sessionvars=sessionvars,
                            archives=archivelist(u, "tip", url))
                 if (not sortcolumn
                     or (sortcolumn, descending) == self.repos_sorted):
@@ -129,9 +155,22 @@
                     yield row
 
         virtual = req.env.get("PATH_INFO", "").strip('/')
-        if virtual:
-            real = dict(self.repos).get(virtual)
+        if virtual.startswith('static/'):
+            static = os.path.join(templater.templatepath(), 'static')
+            fname = virtual[7:]
+            req.write(staticfile(static, fname, req) or
+                      tmpl('error', error='%r not found' % fname))
+        elif virtual:
+            while virtual:
+                real = dict(self.repos).get(virtual)
+                if real:
+                    break
+                up = virtual.rfind('/')
+                if up < 0:
+                    break
+                virtual = virtual[:up]
             if real:
+                req.env['REPO_NAME'] = virtual
                 try:
                     hgweb(real).run_wsgi(req)
                 except IOError, inst:
--- a/mercurial/hgweb/request.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/hgweb/request.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,7 +1,7 @@
 # hgweb/request.py - An http request from either CGI or the standalone server.
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/server.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/hgweb/server.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,7 +1,7 @@
 # hgweb/server.py - The standalone hg web server.
 #
 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -30,9 +30,9 @@
         self.handler = handler
     def flush(self):
         pass
-    def write(str):
+    def write(self, str):
         self.writelines(str.split('\n'))
-    def writelines(seq):
+    def writelines(self, seq):
         for msg in seq:
             self.handler.log_error("HG error:  %s", msg)
 
@@ -71,7 +71,7 @@
         env['REQUEST_METHOD'] = self.command
         env['SERVER_NAME'] = self.server.server_name
         env['SERVER_PORT'] = str(self.server.server_port)
-        env['REQUEST_URI'] = "/"
+        env['REQUEST_URI'] = self.path
         env['PATH_INFO'] = path_info
         if query:
             env['QUERY_STRING'] = query
@@ -207,7 +207,8 @@
                 hgwebobj = self.repoviewmaker(repo.__class__(repo.ui,
                                                              repo.origroot))
             else:
-                raise hg.RepoError(_('no repo found'))
+                raise hg.RepoError(_("There is no Mercurial repository here"
+                                     " (.hg not found)"))
             return hgwebobj
 
     class IPv6HTTPServer(MercurialHTTPServer):
--- a/mercurial/httprangereader.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/httprangereader.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
 # httprangereader.py - just what it says
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/httprepo.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/httprepo.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,7 @@
 # httprepo.py - HTTP repository proxy classes for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -130,7 +131,7 @@
         self.ui = ui
 
         proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
-        proxyauthinfo = None
+        # XXX proxyauthinfo = None
         handler = httphandler()
 
         if proxyurl:
@@ -164,7 +165,8 @@
                                                proxyuser, proxypasswd or ''),
                     proxypath, proxyquery, proxyfrag))
                 handler = urllib2.ProxyHandler({scheme: proxyurl})
-                ui.debug(_('proxying through %s\n') % proxyurl)
+                ui.debug(_('proxying through http://%s:%s\n') %
+                          (proxyhost, proxyport))
 
         # urllib2 takes proxy values from the environment and those
         # will take precedence if found, so drop them
@@ -228,6 +230,9 @@
             self.ui.debug(_('http error while sending %s command\n') % cmd)
             self.ui.print_exc()
             raise IOError(None, inst)
+        except IndexError:
+            # this only happens with Python 2.3, later versions raise URLError
+            raise util.Abort(_('http error, possibly caused by proxy setting'))
         try:
             proto = resp.getheader('content-type')
         except AttributeError:
@@ -256,6 +261,13 @@
             # if using keepalive, allow connection to be reused
             fp.close()
 
+    def lookup(self, key):
+        d = self.do_cmd("lookup", key = key).read()
+        success, data = d[:-1].split(' ', 1)
+        if int(success):
+            return bin(data)
+        raise hg.RepoError(data)
+
     def heads(self):
         d = self.do_read("heads")
         try:
@@ -287,7 +299,6 @@
     def changegroup(self, nodes, kind):
         n = " ".join(map(hex, nodes))
         f = self.do_cmd("changegroup", roots=n)
-        bytes = 0
 
         def zgenerator(f):
             zd = zlib.decompressobj()
@@ -300,6 +311,22 @@
 
         return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
 
+    def changegroupsubset(self, bases, heads, source):
+        baselst = " ".join([hex(n) for n in bases])
+        headlst = " ".join([hex(n) for n in heads])
+        f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
+
+        def zgenerator(f):
+            zd = zlib.decompressobj()
+            try:
+                for chnk in f:
+                    yield zd.decompress(chnk)
+            except httplib.HTTPException:
+                raise IOError(None, _('connection ended unexpectedly'))
+            yield zd.flush()
+
+        return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
+
     def unbundle(self, cg, heads, source):
         # have to stream bundle to a temp file because we do not have
         # http 1.1 chunked transfer.
@@ -324,7 +351,7 @@
                     rfp.close()
             except socket.error, err:
                 if err[0] in (errno.ECONNRESET, errno.EPIPE):
-                    raise util.Abort(_('push failed: %s'), err[1])
+                    raise util.Abort(_('push failed: %s') % err[1])
                 raise util.Abort(err[1])
         finally:
             fp.close()
--- a/mercurial/i18n.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/i18n.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,7 +1,7 @@
 """
 i18n.py - internationalization support for mercurial
 
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/localrepo.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/localrepo.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
 # localrepo.py - read/write repository class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -15,7 +15,7 @@
 demandload(globals(), "os revlog time util")
 
 class localrepository(repo.repository):
-    capabilities = ()
+    capabilities = ('lookup', 'changegroupsubset')
 
     def __del__(self):
         self.transhandle = None
@@ -27,12 +27,21 @@
                 oldp = p
                 p = os.path.dirname(p)
                 if p == oldp:
-                    raise repo.RepoError(_("no repo found"))
+                    raise repo.RepoError(_("There is no Mercurial repository"
+                                           " here (.hg not found)"))
             path = p
         self.path = os.path.join(path, ".hg")
 
-        if not create and not os.path.isdir(self.path):
-            raise repo.RepoError(_("repository %s not found") % path)
+        if not os.path.isdir(self.path):
+            if create:
+                if not os.path.exists(path):
+                    os.mkdir(path)
+                os.mkdir(self.path)
+                os.mkdir(self.join("data"))
+            else:
+                raise repo.RepoError(_("repository %s not found") % path)
+        elif create:
+            raise repo.RepoError(_("repository %s already exists") % path)
 
         self.root = os.path.abspath(path)
         self.origroot = path
@@ -45,7 +54,7 @@
         except IOError:
             pass
 
-        v = self.ui.revlogopts
+        v = self.ui.configrevlog()
         self.revlogversion = int(v.get('format', revlog.REVLOG_DEFAULT_FORMAT))
         self.revlogv1 = self.revlogversion != revlog.REVLOGV0
         fl = v.get('flags', None)
@@ -70,17 +79,12 @@
         self.revlogversion = v
 
         self.tagscache = None
+        self.branchcache = None
         self.nodetagscache = None
         self.encodepats = None
         self.decodepats = None
         self.transhandle = None
 
-        if create:
-            if not os.path.exists(path):
-                os.mkdir(path)
-            os.mkdir(self.path)
-            os.mkdir(self.join("data"))
-
         self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
 
     def url(self):
@@ -131,7 +135,7 @@
             except Exception, exc:
                 if isinstance(exc, util.Abort):
                     self.ui.warn(_('error: %s hook failed: %s\n') %
-                                 (hname, exc.args[0] % exc.args[1:]))
+                                 (hname, exc.args[0]))
                 else:
                     self.ui.warn(_('error: %s hook raised an exception: '
                                    '%s\n') % (hname, exc))
@@ -169,7 +173,7 @@
 
     tag_disallowed = ':\r\n'
 
-    def tag(self, name, node, local=False, message=None, user=None, date=None):
+    def tag(self, name, node, message, local, user, date):
         '''tag a revision with a symbolic name.
 
         if local is True, the tag is stored in a per-repository file.
@@ -191,27 +195,24 @@
             if c in name:
                 raise util.Abort(_('%r cannot be used in a tag name') % c)
 
-        self.hook('pretag', throw=True, node=node, tag=name, local=local)
+        self.hook('pretag', throw=True, node=hex(node), tag=name, local=local)
 
         if local:
-            self.opener('localtags', 'a').write('%s %s\n' % (node, name))
-            self.hook('tag', node=node, tag=name, local=local)
+            self.opener('localtags', 'a').write('%s %s\n' % (hex(node), name))
+            self.hook('tag', node=hex(node), tag=name, local=local)
             return
 
-        for x in self.changes():
+        for x in self.status()[:5]:
             if '.hgtags' in x:
                 raise util.Abort(_('working copy of .hgtags is changed '
                                    '(please commit .hgtags manually)'))
 
-        self.wfile('.hgtags', 'ab').write('%s %s\n' % (node, name))
+        self.wfile('.hgtags', 'ab').write('%s %s\n' % (hex(node), name))
         if self.dirstate.state('.hgtags') == '?':
             self.add(['.hgtags'])
 
-        if not message:
-            message = _('Added tag %s for changeset %s') % (name, node)
-
         self.commit(['.hgtags'], message, user, date)
-        self.hook('tag', node=node, tag=name, local=local)
+        self.hook('tag', node=hex(node), tag=name, local=local)
 
     def tags(self):
         '''return a mapping of tag to node'''
@@ -288,18 +289,64 @@
                 self.nodetagscache.setdefault(n, []).append(t)
         return self.nodetagscache.get(node, [])
 
+    def branchtags(self):
+        if self.branchcache != None:
+            return self.branchcache
+
+        self.branchcache = {} # avoid recursion in changectx
+
+        try:
+            f = self.opener("branches.cache")
+            last, lrev = f.readline().rstrip().split(" ", 1)
+            last, lrev = bin(last), int(lrev)
+            if (lrev < self.changelog.count() and
+                self.changelog.node(lrev) == last): # sanity check
+                for l in f:
+                    node, label = l.rstrip().split(" ", 1)
+                    self.branchcache[label] = bin(node)
+            else: # invalidate the cache
+                last, lrev = nullid, -1
+            f.close()
+        except IOError:
+            last, lrev = nullid, -1
+
+        tip = self.changelog.count() - 1
+        if lrev != tip:
+            for r in xrange(lrev + 1, tip + 1):
+                c = self.changectx(r)
+                b = c.branch()
+                if b:
+                    self.branchcache[b] = c.node()
+            self._writebranchcache()
+
+        return self.branchcache
+
+    def _writebranchcache(self):
+        try:
+            f = self.opener("branches.cache", "w")
+            t = self.changelog.tip()
+            f.write("%s %s\n" % (hex(t), self.changelog.count() - 1))
+            for label, node in self.branchcache.iteritems():
+                f.write("%s %s\n" % (hex(node), label))
+        except IOError:
+            pass
+
     def lookup(self, key):
-        try:
+        if key == '.':
+            key = self.dirstate.parents()[0]
+            if key == nullid:
+                raise repo.RepoError(_("no revision checked out"))
+        n = self.changelog._match(key)
+        if n:
+            return n
+        if key in self.tags():
             return self.tags()[key]
-        except KeyError:
-            if key == '.':
-                key = self.dirstate.parents()[0]
-                if key == nullid:
-                    raise repo.RepoError(_("no revision checked out"))
-            try:
-                return self.changelog.lookup(key)
-            except:
-                raise repo.RepoError(_("unknown revision '%s'") % key)
+        if key in self.branchtags():
+            return self.branchtags()[key]
+        n = self.changelog._partialmatch(key)
+        if n:
+            return n
+        raise repo.RepoError(_("unknown revision '%s'") % key)
 
     def dev(self):
         return os.lstat(self.path).st_dev
@@ -318,9 +365,25 @@
             f = f[1:]
         return filelog.filelog(self.opener, f, self.revlogversion)
 
-    def changectx(self, changeid):
+    def changectx(self, changeid=None):
         return context.changectx(self, changeid)
 
+    def workingctx(self):
+        return context.workingctx(self)
+
+    def parents(self, changeid=None):
+        '''
+        get list of changectxs for parents of changeid or working directory
+        '''
+        if changeid is None:
+            pl = self.dirstate.parents()
+        else:
+            n = self.changelog.lookup(changeid)
+            pl = self.changelog.parents(n)
+        if pl[1] == nullid:
+            return [self.changectx(pl[0])]
+        return [self.changectx(pl[0]), self.changectx(pl[1])]
+
     def filectx(self, path, changeid=None, fileid=None):
         """changeid can be a changeset revision, node, or tag.
            fileid can be a file revision or node."""
@@ -445,24 +508,45 @@
                             self.wreload,
                             desc=_('working directory of %s') % self.origroot)
 
-    def checkfilemerge(self, filename, text, filelog, manifest1, manifest2):
-        "determine whether a new filenode is needed"
-        fp1 = manifest1.get(filename, nullid)
-        fp2 = manifest2.get(filename, nullid)
+    def filecommit(self, fn, manifest1, manifest2, linkrev, transaction, changelist):
+        """
+        commit an individual file as part of a larger transaction
+        """
+
+        t = self.wread(fn)
+        fl = self.file(fn)
+        fp1 = manifest1.get(fn, nullid)
+        fp2 = manifest2.get(fn, nullid)
 
-        if fp2 != nullid:
+        meta = {}
+        cp = self.dirstate.copied(fn)
+        if cp:
+            meta["copy"] = cp
+            if not manifest2: # not a branch merge
+                meta["copyrev"] = hex(manifest1.get(cp, nullid))
+                fp2 = nullid
+            elif fp2 != nullid: # copied on remote side
+                meta["copyrev"] = hex(manifest1.get(cp, nullid))
+            else: # copied on local side, reversed
+                meta["copyrev"] = hex(manifest2.get(cp))
+                fp2 = nullid
+            self.ui.debug(_(" %s: copy %s:%s\n") %
+                          (fn, cp, meta["copyrev"]))
+            fp1 = nullid
+        elif fp2 != nullid:
             # is one parent an ancestor of the other?
-            fpa = filelog.ancestor(fp1, fp2)
+            fpa = fl.ancestor(fp1, fp2)
             if fpa == fp1:
                 fp1, fp2 = fp2, nullid
             elif fpa == fp2:
                 fp2 = nullid
 
             # is the file unmodified from the parent? report existing entry
-            if fp2 == nullid and text == filelog.read(fp1):
-                return (fp1, None, None)
+            if fp2 == nullid and not fl.cmp(fp1, t):
+                return fp1
 
-        return (None, fp1, fp2)
+        changelist.append(fn)
+        return fl.add(t, meta, transaction, linkrev, fp1, fp2)
 
     def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None):
         orig_parent = self.dirstate.parents()[0] or nullid
@@ -473,6 +557,7 @@
         m1 = self.manifest.read(c1[0]).copy()
         m2 = self.manifest.read(c2[0])
         changed = []
+        removed = []
 
         if orig_parent == p1:
             update_dirstate = 1
@@ -486,32 +571,22 @@
         linkrev = self.changelog.count()
         for f in files:
             try:
-                t = self.wread(f)
+                m1[f] = self.filecommit(f, m1, m2, linkrev, tr, changed)
                 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
-                r = self.file(f)
-
-                (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
-                if entry:
-                    m1[f] = entry
-                    continue
-
-                m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
-                changed.append(f)
-                if update_dirstate:
-                    self.dirstate.update([f], "n")
             except IOError:
                 try:
                     del m1[f]
-                    del m1[f]
                     if update_dirstate:
                         self.dirstate.forget([f])
+                    removed.append(f)
                 except:
                     # deleted from p2?
                     pass
 
         mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0])
         user = user or self.ui.username()
-        n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
+        n = self.changelog.add(mnode, changed + removed, text,
+                               tr, p1, p2, user, date)
         tr.close()
         if update_dirstate:
             self.dirstate.setparents(n, nullid)
@@ -533,7 +608,7 @@
                 else:
                     self.ui.warn(_("%s not tracked!\n") % f)
         else:
-            modified, added, removed, deleted, unknown = self.changes(match=match)
+            modified, added, removed, deleted, unknown = self.status(match=match)[:5]
             commit = modified + added
             remove = removed
 
@@ -543,7 +618,11 @@
         m1 = self.manifest.read(c1[0]).copy()
         m2 = self.manifest.read(c2[0])
 
-        if not commit and not remove and not force and p2 == nullid:
+        branchname = self.workingctx().branch()
+        oldname = c1[5].get("branch", "")
+
+        if not commit and not remove and not force and p2 == nullid and \
+               branchname == oldname:
             self.ui.status(_("nothing changed\n"))
             return None
 
@@ -566,39 +645,18 @@
         for f in commit:
             self.ui.note(f + "\n")
             try:
+                new[f] = self.filecommit(f, m1, m2, linkrev, tr, changed)
                 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
-                t = self.wread(f)
             except IOError:
                 self.ui.warn(_("trouble committing %s!\n") % f)
                 raise
 
-            r = self.file(f)
-
-            meta = {}
-            cp = self.dirstate.copied(f)
-            if cp:
-                meta["copy"] = cp
-                meta["copyrev"] = hex(m1.get(cp, m2.get(cp, nullid)))
-                self.ui.debug(_(" %s: copy %s:%s\n") % (f, cp, meta["copyrev"]))
-                fp1, fp2 = nullid, nullid
-            else:
-                entry, fp1, fp2 = self.checkfilemerge(f, t, r, m1, m2)
-                if entry:
-                    new[f] = entry
-                    continue
-
-            new[f] = r.add(t, meta, tr, linkrev, fp1, fp2)
-            # remember what we've added so that we can later calculate
-            # the files to pull from a set of changesets
-            changed.append(f)
-
         # update manifest
         m1.update(new)
         for f in remove:
             if f in m1:
                 del m1[f]
-        mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0],
-                               (new, remove))
+        mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0], (new, remove))
 
         # add changeset
         new = new.keys()
@@ -629,7 +687,11 @@
         if not lines:
             return None
         text = '\n'.join(lines)
-        n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date)
+        extra = {}
+        if branchname:
+            extra["branch"] = branchname
+        n = self.changelog.add(mn, changed + remove, text, tr, p1, p2,
+                               user, date, extra)
         self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
                   parent2=xp2)
         tr.close()
@@ -645,7 +707,11 @@
         if node:
             fdict = dict.fromkeys(files)
             for fn in self.manifest.read(self.changelog.read(node)[0]):
-                fdict.pop(fn, None)
+                for ffn in fdict:
+                    # match if the file is the exact name or a directory
+                    if ffn == fn or fn.startswith("%s/" % ffn):
+                        del fdict[ffn]
+                        break
                 if match(fn):
                     yield 'm', fn
             for fn in fdict:
@@ -669,12 +735,11 @@
 
         def fcmp(fn, mf):
             t1 = self.wread(fn)
-            t2 = self.file(fn).read(mf.get(fn, nullid))
-            return cmp(t1, t2)
+            return self.file(fn).cmp(mf.get(fn, nullid), t1)
 
         def mfmatches(node):
             change = self.changelog.read(node)
-            mf = dict(self.manifest.read(change[0]))
+            mf = self.manifest.read(change[0]).copy()
             for fn in mf.keys():
                 if not match(fn):
                     del mf[fn]
@@ -712,14 +777,18 @@
                     for f in lookup:
                         if fcmp(f, mf2):
                             modified.append(f)
-                        elif wlock is not None:
-                            self.dirstate.update([f], "n")
+                        else:
+                            clean.append(f)
+                            if wlock is not None:
+                                self.dirstate.update([f], "n")
             else:
                 # we are comparing working dir against non-parent
                 # generate a pseudo-manifest for the working dir
+                # XXX: create it in dirstate.py ?
                 mf2 = mfmatches(self.dirstate.parents()[0])
                 for f in lookup + modified + added:
                     mf2[f] = ""
+                    mf2.set(f, execf=util.is_exec(self.wjoin(f), mf2.execf(f)))
                 for f in removed:
                     if f in mf2:
                         del mf2[f]
@@ -737,7 +806,8 @@
             mf2keys.sort()
             for fn in mf2keys:
                 if mf1.has_key(fn):
-                    if mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1)):
+                    if mf1.flags(fn) != mf2.flags(fn) or \
+                       (mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1))):
                         modified.append(fn)
                     elif list_clean:
                         clean.append(fn)
@@ -752,16 +822,6 @@
             l.sort()
         return (modified, added, removed, deleted, unknown, ignored, clean)
 
-    def changes(self, node1=None, node2=None, files=[], match=util.always,
-                wlock=None, list_ignored=False, list_clean=False):
-        '''DEPRECATED - use status instead'''
-        marduit = self.status(node1, node2, files, match, wlock,
-                              list_ignored, list_clean)
-        if list_ignored:
-            return marduit[:-1]
-        else:
-            return marduit[:-2]
-
     def add(self, list, wlock=None):
         if not wlock:
             wlock = self.wlock()
@@ -1115,7 +1175,7 @@
             else:
                 raise util.Abort(_("repository is unrelated"))
 
-        self.ui.note(_("found new changesets starting at ") +
+        self.ui.debug(_("found new changesets starting at ") +
                      " ".join([short(f) for f in fetch]) + "\n")
 
         self.ui.debug(_("%d total queries\n") % reqcnt)
@@ -1188,6 +1248,8 @@
             if heads is None:
                 cg = remote.changegroup(fetch, 'pull')
             else:
+                if 'changegroupsubset' not in remote.capabilities:
+                    raise util.Abort(_("Partial pull cannot be done because other repository doesn't support changegroupsubset."))
                 cg = remote.changegroupsubset(fetch, heads, 'pull')
             return self.addchangegroup(cg, 'pull', remote.url())
         finally:
@@ -1753,6 +1815,6 @@
 
 def instance(ui, path, create):
     return localrepository(ui, util.drop_scheme('file', path), create)
-    
+
 def islocal(path):
     return True
--- a/mercurial/lock.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/lock.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
 # lock.py - simple locking scheme for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/mail.py	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,68 @@
+# mail.py - mail sending bits for mercurial
+#
+# Copyright 2006 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from i18n import gettext as _
+from demandload import *
+demandload(globals(), "os re smtplib templater util")
+
+def _smtp(ui):
+    '''send mail using smtp.'''
+
+    local_hostname = ui.config('smtp', 'local_hostname')
+    s = smtplib.SMTP(local_hostname=local_hostname)
+    mailhost = ui.config('smtp', 'host')
+    if not mailhost:
+        raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
+    mailport = int(ui.config('smtp', 'port', 25))
+    ui.note(_('sending mail: smtp host %s, port %s\n') %
+            (mailhost, mailport))
+    s.connect(host=mailhost, port=mailport)
+    if ui.configbool('smtp', 'tls'):
+        ui.note(_('(using tls)\n'))
+        s.ehlo()
+        s.starttls()
+        s.ehlo()
+    username = ui.config('smtp', 'username')
+    password = ui.config('smtp', 'password')
+    if username and password:
+        ui.note(_('(authenticating to mail server as %s)\n') %
+                  (username))
+        s.login(username, password)
+    return s
+
+class _sendmail(object):
+    '''send mail using sendmail.'''
+
+    def __init__(self, ui, program):
+        self.ui = ui
+        self.program = program
+
+    def sendmail(self, sender, recipients, msg):
+        cmdline = '%s -f %s %s' % (
+            self.program, templater.email(sender),
+            ' '.join(map(templater.email, recipients)))
+        self.ui.note(_('sending mail: %s\n') % cmdline)
+        fp = os.popen(cmdline, 'w')
+        fp.write(msg)
+        ret = fp.close()
+        if ret:
+            raise util.Abort('%s %s' % (
+                os.path.basename(self.program.split(None, 1)[0]),
+                util.explain_exit(ret)[0]))
+
+def connect(ui):
+    '''make a mail connection. object returned has one method, sendmail.
+    call as sendmail(sender, list-of-recipients, msg).'''
+
+    method = ui.config('email', 'method', 'smtp')
+    if method == 'smtp':
+        return _smtp(ui)
+
+    return _sendmail(ui, method)
+
+def sendmail(ui, sender, recipients, msg):
+    return connect(ui).sendmail(sender, recipients, msg)
--- a/mercurial/manifest.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/manifest.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
 # manifest.py - manifest revision class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -9,9 +9,12 @@
 from i18n import gettext as _
 from demandload import *
 demandload(globals(), "array bisect struct")
+demandload(globals(), "mdiff")
 
 class manifestdict(dict):
-    def __init__(self, mapping={}, flags={}):
+    def __init__(self, mapping=None, flags=None):
+        if mapping is None: mapping = {}
+        if flags is None: flags = {}
         dict.__init__(self, mapping)
         self._flags = flags
     def flags(self, f):
@@ -27,8 +30,9 @@
         fl = entry[40:-1]
         if fl: self._flags[f] = fl
     def set(self, f, execf=False, linkf=False):
-        if execf: self._flags[f] = "x"
-        if linkf: self._flags[f] = "x"
+        if linkf: self._flags[f] = "l"
+        elif execf: self._flags[f] = "x"
+        else: self._flags[f] = ""
     def copy(self):
         return manifestdict(dict.copy(self), dict.copy(self._flags))
 
@@ -39,23 +43,29 @@
         revlog.__init__(self, opener, "00manifest.i", "00manifest.d",
                         defversion)
 
+    def parselines(self, lines):
+        for l in lines.splitlines(1):
+            yield l.split('\0')
+
+    def readdelta(self, node):
+        delta = mdiff.patchtext(self.delta(node))
+        deltamap = manifestdict()
+        for f, n in self.parselines(delta):
+            deltamap.rawset(f, n)
+        return deltamap
+
     def read(self, node):
         if node == nullid: return manifestdict() # don't upset local cache
         if self.mapcache and self.mapcache[0] == node:
             return self.mapcache[1]
         text = self.revision(node)
         self.listcache = array.array('c', text)
-        lines = text.splitlines(1)
         mapping = manifestdict()
-        for l in lines:
-            (f, n) = l.split('\0')
+        for f, n in self.parselines(text):
             mapping.rawset(f, n)
         self.mapcache = (node, mapping)
         return mapping
 
-    def diff(self, a, b):
-        return mdiff.textdiff(str(a), str(b))
-
     def _search(self, m, s, lo=0, hi=None):
         '''return a tuple (start, end) that says where to find s within m.
 
@@ -169,7 +179,7 @@
                 if start == end and w[1] == 1:
                     # item we want to delete was not found, error out
                     raise AssertionError(
-                            _("failed to remove %s from manifest\n") % f)
+                            _("failed to remove %s from manifest") % f)
                 if dstart != None and dstart <= start and dend >= start:
                     if dend < end:
                         dend = end
--- a/mercurial/mdiff.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/mdiff.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
 # mdiff.py - diff and patch routines for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -19,44 +19,73 @@
             lines[-1] = lines[-1][:-1]
     return lines
 
-def unidiff(a, ad, b, bd, fn, r=None, text=False,
-            showfunc=False, ignorews=False, ignorewsamount=False,
-            ignoreblanklines=False):
+class diffopts(object):
+    '''context is the number of context lines
+    text treats all files as text
+    showfunc enables diff -p output
+    git enables the git extended patch format
+    nodates removes dates from diff headers
+    ignorews ignores all whitespace changes in the diff
+    ignorewsamount ignores changes in the amount of whitespace
+    ignoreblanklines ignores changes whose lines are all blank'''
+
+    defaults = {
+        'context': 3,
+        'text': False,
+        'showfunc': True,
+        'git': False,
+        'nodates': False,
+        'ignorews': False,
+        'ignorewsamount': False,
+        'ignoreblanklines': False,
+        }
+
+    __slots__ = defaults.keys()
+
+    def __init__(self, **opts):
+        for k in self.__slots__:
+            v = opts.get(k)
+            if v is None:
+                v = self.defaults[k]
+            setattr(self, k, v)
+
+defaultopts = diffopts()
+
+def unidiff(a, ad, b, bd, fn, r=None, opts=defaultopts):
+    def datetag(date):
+        return (opts.git or opts.nodates) and '\n' or '\t%s\n' % date
 
     if not a and not b: return ""
     epoch = util.datestr((0, 0))
 
-    if not text and (util.binary(a) or util.binary(b)):
+    if not opts.text and (util.binary(a) or util.binary(b)):
         l = ['Binary file %s has changed\n' % fn]
     elif not a:
         b = splitnewlines(b)
         if a is None:
-            l1 = "--- %s\t%s\n" % ("/dev/null", epoch)
+            l1 = '--- /dev/null%s' % datetag(epoch)
         else:
-            l1 = "--- %s\t%s\n" % ("a/" + fn, ad)
-        l2 = "+++ %s\t%s\n" % ("b/" + fn, bd)
+            l1 = "--- %s%s" % ("a/" + fn, datetag(ad))
+        l2 = "+++ %s%s" % ("b/" + fn, datetag(bd))
         l3 = "@@ -0,0 +1,%d @@\n" % len(b)
         l = [l1, l2, l3] + ["+" + e for e in b]
     elif not b:
         a = splitnewlines(a)
-        l1 = "--- %s\t%s\n" % ("a/" + fn, ad)
+        l1 = "--- %s%s" % ("a/" + fn, datetag(ad))
         if b is None:
-            l2 = "+++ %s\t%s\n" % ("/dev/null", epoch)
+            l2 = '+++ /dev/null%s' % datetag(epoch)
         else:
-            l2 = "+++ %s\t%s\n" % ("b/" + fn, bd)
+            l2 = "+++ %s%s" % ("b/" + fn, datetag(bd))
         l3 = "@@ -1,%d +0,0 @@\n" % len(a)
         l = [l1, l2, l3] + ["-" + e for e in a]
     else:
         al = splitnewlines(a)
         bl = splitnewlines(b)
-        l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn,
-                          showfunc=showfunc, ignorews=ignorews,
-                          ignorewsamount=ignorewsamount,
-                          ignoreblanklines=ignoreblanklines))
+        l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, opts=opts))
         if not l: return ""
         # difflib uses a space, rather than a tab
-        l[0] = "%s\t%s\n" % (l[0][:-2], ad)
-        l[1] = "%s\t%s\n" % (l[1][:-2], bd)
+        l[0] = "%s%s" % (l[0][:-2], datetag(ad))
+        l[1] = "%s%s" % (l[1][:-2], datetag(bd))
 
     for ln in xrange(len(l)):
         if l[ln][-1] != '\n':
@@ -72,21 +101,15 @@
 # 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
-# ignorewsamount ignores changes in the amount of whitespace
-# ignoreblanklines ignores changes whose lines are all blank
-def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False,
-             ignorews=False, ignorewsamount=False, ignoreblanklines=False):
+def bunidiff(t1, t2, l1, l2, header1, header2, opts=defaultopts):
     def contextend(l, len):
-        ret = l + context
+        ret = l + opts.context
         if ret > len:
             ret = len
         return ret
 
     def contextstart(l):
-        ret = l - context
+        ret = l - opts.context
         if ret < 0:
             return 0
         return ret
@@ -101,7 +124,7 @@
         blen = b2 - bstart + aend - a2
 
         func = ""
-        if showfunc:
+        if opts.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):
@@ -119,14 +142,14 @@
 
     header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ]
 
-    if showfunc:
+    if opts.showfunc:
         funcre = re.compile('\w')
-    if ignorewsamount:
+    if opts.ignorewsamount:
         wsamountre = re.compile('[ \t]+')
         wsappendedre = re.compile(' \n')
-    if ignoreblanklines:
+    if opts.ignoreblanklines:
         wsblanklinesre = re.compile('\n')
-    if ignorews:
+    if opts.ignorews:
         wsre = re.compile('[ \t]')
 
     # bdiff.blocks gives us the matching sequences in the files.  The loop
@@ -159,13 +182,13 @@
         if not old and not new:
             continue
 
-        if ignoreblanklines:
+        if opts.ignoreblanklines:
             wsold = wsblanklinesre.sub('', "".join(old))
             wsnew = wsblanklinesre.sub('', "".join(new))
             if wsold == wsnew:
                 continue
 
-        if ignorewsamount:
+        if opts.ignorewsamount:
             wsold = wsamountre.sub(' ', "".join(old))
             wsold = wsappendedre.sub('\n', wsold)
             wsnew = wsamountre.sub(' ', "".join(new))
@@ -173,7 +196,7 @@
             if wsold == wsnew:
                 continue
 
-        if ignorews:
+        if opts.ignorews:
             wsold = wsre.sub('', "".join(old))
             wsnew = wsre.sub('', "".join(new))
             if wsold == wsnew:
@@ -184,7 +207,7 @@
         prev = None
         if hunk:
             # join with the previous hunk if it falls inside the context
-            if astart < hunk[1] + context + 1:
+            if astart < hunk[1] + opts.context + 1:
                 prev = hunk
                 astart = hunk[1]
                 bstart = hunk[3]
--- a/mercurial/merge.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/merge.py	Sat Oct 21 15:22:08 2006 -0400
@@ -8,327 +8,411 @@
 from node import *
 from i18n import gettext as _
 from demandload import *
-demandload(globals(), "util os tempfile")
+demandload(globals(), "errno util os tempfile")
+
+def filemerge(repo, fw, fo, wctx, mctx):
+    """perform a 3-way merge in the working directory
 
-def merge3(repo, fn, my, other, p1, p2):
-    """perform a 3-way merge in the working directory"""
+    fw = filename in the working directory
+    fo = filename in other parent
+    wctx, mctx = working and merge changecontexts
+    """
 
-    def temp(prefix, node):
-        pre = "%s~%s." % (os.path.basename(fn), prefix)
+    def temp(prefix, ctx):
+        pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
         (fd, name) = tempfile.mkstemp(prefix=pre)
         f = os.fdopen(fd, "wb")
-        repo.wwrite(fn, fl.read(node), f)
+        repo.wwrite(ctx.path(), ctx.data(), f)
         f.close()
         return name
 
-    fl = repo.file(fn)
-    base = fl.ancestor(my, other)
-    a = repo.wjoin(fn)
-    b = temp("base", base)
-    c = temp("other", other)
+    fcm = wctx.filectx(fw)
+    fco = mctx.filectx(fo)
+
+    if not fco.cmp(fcm.data()): # files identical?
+        return None
 
-    repo.ui.note(_("resolving %s\n") % fn)
-    repo.ui.debug(_("file %s: my %s other %s ancestor %s\n") %
-                          (fn, short(my), short(other), short(base)))
+    fca = fcm.ancestor(fco)
+    if not fca:
+        fca = repo.filectx(fw, fileid=-1)
+    a = repo.wjoin(fw)
+    b = temp("base", fca)
+    c = temp("other", fco)
+
+    if fw != fo:
+        repo.ui.status(_("merging %s and %s\n") % (fw, fo))
+    else:
+        repo.ui.status(_("merging %s\n") % fw)
+
+    repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca))
 
     cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge")
            or "hgmerge")
     r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root,
-                    environ={'HG_FILE': fn,
-                             'HG_MY_NODE': p1,
-                             'HG_OTHER_NODE': p2,
-                             'HG_FILE_MY_NODE': hex(my),
-                             'HG_FILE_OTHER_NODE': hex(other),
-                             'HG_FILE_BASE_NODE': hex(base)})
+                    environ={'HG_FILE': fw,
+                             'HG_MY_NODE': str(wctx.parents()[0]),
+                             'HG_OTHER_NODE': str(mctx)})
     if r:
-        repo.ui.warn(_("merging %s failed!\n") % fn)
+        repo.ui.warn(_("merging %s failed!\n") % fw)
 
     os.unlink(b)
     os.unlink(c)
     return r
 
-def update(repo, node, branchmerge=False, force=False, partial=None,
-           wlock=None, show_stats=True, remind=True):
+def checkunknown(wctx, mctx):
+    "check for collisions between unknown files and files in mctx"
+    man = mctx.manifest()
+    for f in wctx.unknown():
+        if f in man:
+            if mctx.filectx(f).cmp(wctx.filectx(f).data()):
+                raise util.Abort(_("'%s' already exists in the working"
+                                   " dir and differs from remote") % f)
 
-    overwrite = force and not branchmerge
-    forcemerge = force and branchmerge
-
-    if not wlock:
-        wlock = repo.wlock()
+def forgetremoved(wctx, mctx):
+    """
+    Forget removed files
 
-    ### check phase
+    If we're jumping between revisions (as opposed to merging), and if
+    neither the working directory nor the target rev has the file,
+    then we need to remove it from the dirstate, to prevent the
+    dirstate from listing the file when it is no longer in the
+    manifest.
+    """
 
-    pl = repo.dirstate.parents()
-    if not overwrite and pl[1] != nullid:
-        raise util.Abort(_("outstanding uncommitted merges"))
+    action = []
+    man = mctx.manifest()
+    for f in wctx.deleted() + wctx.removed():
+        if f not in man:
+            action.append((f, "f"))
 
-    p1, p2 = pl[0], node
-    pa = repo.changelog.ancestor(p1, p2)
+    return action
+
+def nonoverlap(d1, d2, d3):
+    "Return list of elements in d1 not in d2 or d3"
 
-    # is there a linear path from p1 to p2?
-    linear_path = (pa == p1 or pa == p2)
-    if branchmerge and linear_path:
-        raise util.Abort(_("there is nothing to merge, just use "
-                           "'hg update' or look at 'hg heads'"))
+    l = []
+    for d in d1:
+        if d not in d3 and d not in d2:
+            l.append(d)
 
-    if not overwrite and not linear_path and not branchmerge:
-        raise util.Abort(_("update spans branches, use 'hg merge' "
-                           "or 'hg update -C' to lose changes"))
+    l.sort()
+    return l
+
+def findold(fctx, limit):
+    "find files that path was copied from, back to linkrev limit"
 
-    modified, added, removed, deleted, unknown = repo.changes()
-    if branchmerge and not forcemerge:
-        if modified or added or removed:
-            raise util.Abort(_("outstanding uncommitted changes"))
+    old = {}
+    orig = fctx.path()
+    visit = [fctx]
+    while visit:
+        fc = visit.pop()
+        if fc.rev() < limit:
+            continue
+        if fc.path() != orig and fc.path() not in old:
+            old[fc.path()] = 1
+        visit += fc.parents()
 
-    m1n = repo.changelog.read(p1)[0]
-    m2n = repo.changelog.read(p2)[0]
-    man = repo.manifest.ancestor(m1n, m2n)
-    m1 = repo.manifest.read(m1n)
-    m2 = repo.manifest.read(m2n).copy()
-    ma = repo.manifest.read(man)
+    old = old.keys()
+    old.sort()
+    return old
+
+def findcopies(repo, m1, m2, ma, limit):
+    """
+    Find moves and copies between m1 and m2 back to limit linkrev
+    """
+
+    if not repo.ui.configbool("merge", "followcopies", True):
+        return {}
 
-    if not forcemerge and not overwrite:
-        for f in unknown:
-            if f in m2:
-                t1 = repo.wread(f)
-                t2 = repo.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)
+    # avoid silly behavior for update from empty dir
+    if not m1:
+        return {}
+
+    dcopies = repo.dirstate.copies()
+    copy = {}
+    match = {}
+    u1 = nonoverlap(m1, m2, ma)
+    u2 = nonoverlap(m2, m1, ma)
+    ctx = util.cachefunc(lambda f,n: repo.filectx(f, fileid=n[:20]))
 
-    # resolve the manifest to determine which files
-    # we care about merging
-    repo.ui.note(_("resolving manifests\n"))
-    repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") %
-                  (overwrite, branchmerge, partial and True or False, linear_path))
-    repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
-                  (short(man), short(m1n), short(m2n)))
+    def checkpair(c, f2, man):
+        ''' check if an apparent pair actually matches '''
+        c2 = ctx(f2, man[f2])
+        ca = c.ancestor(c2)
+        if ca and ca.path() == c.path() or ca.path() == c2.path():
+            copy[c.path()] = f2
+            copy[f2] = c.path()
+
+    for f in u1:
+        c = ctx(dcopies.get(f, f), m1[f])
+        for of in findold(c, limit):
+            if of in m2:
+                checkpair(c, of, m2)
+            else:
+                match.setdefault(of, []).append(f)
+
+    for f in u2:
+        c = ctx(f, m2[f])
+        for of in findold(c, limit):
+            if of in m1:
+                checkpair(c, of, m1)
+            elif of in match:
+                for mf in match[of]:
+                    checkpair(c, mf, m1)
 
-    merge = {}
-    get = {}
-    remove = []
+    return copy
+
+def manifestmerge(repo, p1, p2, pa, overwrite, partial):
+    """
+    Merge p1 and p2 with ancestor ma and generate merge action list
 
-    # construct a working dir manifest
-    mw = m1.copy()
-    umap = dict.fromkeys(unknown)
+    overwrite = whether we clobber working files
+    partial = function to filter file lists
+    """
 
-    for f in added + modified + unknown:
-        mw[f] = ""
-        mw.set(f, util.is_exec(repo.wjoin(f), mw.execf(f)))
+    repo.ui.note(_("resolving manifests\n"))
+    repo.ui.debug(_(" overwrite %s partial %s\n") % (overwrite, bool(partial)))
+    repo.ui.debug(_(" ancestor %s local %s remote %s\n") % (pa, p1, p2))
 
-    for f in deleted + removed:
-        if f in mw:
-            del mw[f]
+    m1 = p1.manifest()
+    m2 = p2.manifest()
+    ma = pa.manifest()
+    backwards = (pa == p2)
+    action = []
+    copy = {}
 
-        # If we're jumping between revisions (as opposed to merging),
-        # and if neither the working directory nor the target rev has
-        # the file, then we need to remove it from the dirstate, to
-        # prevent the dirstate from listing the file when it is no
-        # longer in the manifest.
-        if not partial and linear_path and f not in m2:
-            repo.dirstate.forget((f,))
+    def fmerge(f, f2=None, fa=None):
+        """merge executable flags"""
+        if not f2:
+            f2 = f
+            fa = f
+        a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2)
+        return ((a^b) | (a^c)) ^ a
+
+    def act(msg, m, f, *args):
+        repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
+        action.append((f, m) + args)
+
+    if not (backwards or overwrite):
+        copy = findcopies(repo, m1, m2, ma, pa.rev())
 
     # Compare manifests
-    for f, n in mw.iteritems():
+    for f, n in m1.iteritems():
         if partial and not partial(f):
             continue
         if f in m2:
-            s = 0
-
-            # is the wfile new since m1, and match m2?
-            if f not in m1:
-                t1 = repo.wread(f)
-                t2 = repo.file(f).read(m2[f])
-                if cmp(t1, t2) == 0:
-                    n = m2[f]
-                del t1, t2
-
             # are files different?
             if n != m2[f]:
                 a = ma.get(f, nullid)
                 # are both different from the ancestor?
-                if n != a and m2[f] != a:
-                    repo.ui.debug(_(" %s versions differ, resolve\n") % f)
-                    # merge executable bits
-                    # "if we changed or they changed, change in merge"
-                    a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
-                    mode = ((a^b) | (a^c)) ^ a
-                    merge[f] = (mode, m1.get(f, nullid), m2[f])
-                    s = 1
+                if not overwrite and n != a and m2[f] != a:
+                    act("versions differ", "m", f, f, f, fmerge(f), False)
                 # are we clobbering?
                 # is remote's version newer?
-                # or are we going back in time?
-                elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
-                    repo.ui.debug(_(" remote %s is newer, get\n") % f)
-                    get[f] = (m2.execf(f), m2[f])
-                    s = 1
-            elif f in umap or f in added:
-                # this unknown file is the same as the checkout
-                # we need to reset the dirstate if the file was added
-                get[f] = (m2.execf(f), m2[f])
-
-            if not s and mw.execf(f) != m2.execf(f):
-                if overwrite:
-                    repo.ui.debug(_(" updating permissions for %s\n") % f)
-                    util.set_exec(repo.wjoin(f), m2.execf(f))
-                else:
-                    a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
-                    mode = ((a^b) | (a^c)) ^ a
-                    if mode != b:
-                        repo.ui.debug(_(" updating permissions for %s\n")
-                                      % f)
-                        util.set_exec(repo.wjoin(f), mode)
-            del m2[f]
+                # or are we going back in time and clean?
+                elif overwrite or m2[f] != a or (backwards and not n[20:]):
+                    act("remote is newer", "g", f, m2.execf(f))
+                # local is newer, not overwrite, check mode bits
+                elif fmerge(f) != m1.execf(f):
+                    act("update permissions", "e", f, m2.execf(f))
+            # contents same, check mode bits
+            elif m1.execf(f) != m2.execf(f):
+                if overwrite or fmerge(f) != m1.execf(f):
+                    act("update permissions", "e", f, m2.execf(f))
+        elif f in copy:
+            f2 = copy[f]
+            if f in ma: # case 3,20 A/B/A
+                act("remote moved", "m", f, f2, f2, fmerge(f, f2, f), True)
+            else:
+                if f2 in m1: # case 2 A,B/B/B
+                    act("local copied", "m",
+                        f, f2, f, fmerge(f, f2, f2), False)
+                else: # case 4,21 A/B/B
+                    act("local moved", "m",
+                        f, f2, f, fmerge(f, f2, f2), False)
         elif f in ma:
-            if n != ma[f]:
-                r = _("d")
-                if not overwrite and (linear_path or branchmerge):
-                    r = repo.ui.prompt(
-                        (_(" local changed %s which remote deleted\n") % f) +
-                         _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
-                if r == _("d"):
-                    remove.append(f)
+            if n != ma[f] and not overwrite:
+                if repo.ui.prompt(
+                    (_(" local changed %s which remote deleted\n") % f) +
+                    _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("d"):
+                    act("prompt delete", "r", f)
             else:
-                repo.ui.debug(_("other deleted %s\n") % f)
-                remove.append(f) # other deleted it
+                act("other deleted", "r", f)
         else:
             # file is created on branch or in working directory
-            if overwrite and f not in umap:
-                repo.ui.debug(_("remote deleted %s, clobbering\n") % f)
-                remove.append(f)
-            elif n == m1.get(f, nullid): # same as parent
-                if p2 == pa: # going backwards?
-                    repo.ui.debug(_("remote deleted %s\n") % f)
-                    remove.append(f)
-                else:
-                    repo.ui.debug(_("local modified %s, keeping\n") % f)
-            else:
-                repo.ui.debug(_("working dir created %s, keeping\n") % f)
+            if (overwrite and n[20:] != "u") or (backwards and not n[20:]):
+                act("remote deleted", "r", f)
 
     for f, n in m2.iteritems():
         if partial and not partial(f):
             continue
+        if f in m1:
+            continue
+        if f in copy:
+            f2 = copy[f]
+            if f2 not in m2: # already seen
+                continue
+            # rename case 1, A/A,B/A
+            act("remote copied", "m", f2, f, f, fmerge(f2, f, f2), False)
+        elif f in ma:
+            if overwrite or backwards:
+                act("recreating", "g", f, m2.execf(f))
+            elif n != ma[f]:
+                if repo.ui.prompt(
+                    (_("remote changed %s which local deleted\n") % f) +
+                    _("(k)eep or (d)elete?"), _("[kd]"), _("k")) == _("k"):
+                    act("prompt recreating", "g", f, m2.execf(f))
+        else:
+            act("remote created", "g", f, m2.execf(f))
+
+    return action
+
+def applyupdates(repo, action, wctx, mctx):
+    "apply the merge action list to the working directory"
+
+    updated, merged, removed, unresolved = 0, 0, 0, 0
+    action.sort()
+    for a in action:
+        f, m = a[:2]
         if f[0] == "/":
             continue
-        if f in ma and n != ma[f]:
-            r = _("k")
-            if not overwrite and (linear_path or branchmerge):
-                r = repo.ui.prompt(
-                    (_("remote changed %s which local deleted\n") % f) +
-                     _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
-            if r == _("k"):
-                get[f] = (m2.execf(f), n)
-        elif f not in ma:
-            repo.ui.debug(_("remote created %s\n") % f)
-            get[f] = (m2.execf(f), n)
-        else:
-            if overwrite or p2 == pa: # going backwards?
-                repo.ui.debug(_("local deleted %s, recreating\n") % f)
-                get[f] = (m2.execf(f), n)
+        if m == "r": # remove
+            repo.ui.note(_("removing %s\n") % f)
+            util.audit_path(f)
+            try:
+                util.unlink(repo.wjoin(f))
+            except OSError, inst:
+                if inst.errno != errno.ENOENT:
+                    repo.ui.warn(_("update failed to remove %s: %s!\n") %
+                                 (f, inst.strerror))
+            removed +=1
+        elif m == "m": # merge
+            f2, fd, flag, move = a[2:]
+            r = filemerge(repo, f, f2, wctx, mctx)
+            if r > 0:
+                unresolved += 1
             else:
-                repo.ui.debug(_("local deleted %s\n") % f)
-
-    del mw, m1, m2, ma
+                if r is None:
+                    updated += 1
+                else:
+                    merged += 1
+                if f != fd:
+                    repo.ui.debug(_("copying %s to %s\n") % (f, fd))
+                    repo.wwrite(fd, repo.wread(f))
+                    if move:
+                        repo.ui.debug(_("removing %s\n") % f)
+                        os.unlink(repo.wjoin(f))
+            util.set_exec(repo.wjoin(fd), flag)
+        elif m == "g": # get
+            flag = a[2]
+            repo.ui.note(_("getting %s\n") % f)
+            t = mctx.filectx(f).data()
+            repo.wwrite(f, t)
+            util.set_exec(repo.wjoin(f), flag)
+            updated += 1
+        elif m == "e": # exec
+            flag = a[2]
+            util.set_exec(repo.wjoin(f), flag)
 
-    if overwrite:
-        for f in merge:
-            get[f] = merge[f][:2]
-        merge = {}
+    return updated, merged, removed, unresolved
 
-    if linear_path or overwrite:
-        # we don't need to do any magic, just jump to the new rev
-        p1, p2 = p2, nullid
-
-    xp1 = hex(p1)
-    xp2 = hex(p2)
-    if p2 == nullid: xxp2 = ''
-    else: xxp2 = xp2
+def recordupdates(repo, action, branchmerge):
+    "record merge actions to the dirstate"
 
-    repo.hook('preupdate', throw=True, parent1=xp1, parent2=xxp2)
-
-    # get the files we don't need to change
-    files = get.keys()
-    files.sort()
-    for f in files:
-        flag, node = get[f]
-        if f[0] == "/":
-            continue
-        repo.ui.note(_("getting %s\n") % f)
-        t = repo.file(f).read(node)
-        repo.wwrite(f, t)
-        util.set_exec(repo.wjoin(f), flag)
-        if not partial:
+    for a in action:
+        f, m = a[:2]
+        if m == "r": # remove
+            if branchmerge:
+                repo.dirstate.update([f], 'r')
+            else:
+                repo.dirstate.forget([f])
+        elif m == "f": # forget
+            repo.dirstate.forget([f])
+        elif m == "g": # get
             if branchmerge:
                 repo.dirstate.update([f], 'n', st_mtime=-1)
             else:
                 repo.dirstate.update([f], 'n')
-
-    # merge the tricky bits
-    unresolved = []
-    files = merge.keys()
-    files.sort()
-    for f in files:
-        repo.ui.status(_("merging %s\n") % f)
-        flag, my, other = merge[f]
-        ret = merge3(repo, f, my, other, xp1, xp2)
-        if ret:
-            unresolved.append(f)
-        util.set_exec(repo.wjoin(f), flag)
-        if not partial:
+        elif m == "m": # merge
+            f2, fd, flag, move = a[2:]
             if branchmerge:
                 # We've done a branch merge, mark this file as merged
                 # so that we properly record the merger later
-                repo.dirstate.update([f], 'm')
+                repo.dirstate.update([fd], 'm')
+                if f != f2: # copy/rename
+                    if move:
+                        repo.dirstate.update([f], 'r')
+                    if f != fd:
+                        repo.dirstate.copy(f, fd)
+                    else:
+                        repo.dirstate.copy(f2, fd)
             else:
                 # We've update-merged a locally modified file, so
                 # we set the dirstate to emulate a normal checkout
                 # of that file some time in the past. Thus our
                 # merge will appear as a normal local file
                 # modification.
-                f_len = len(repo.file(f).read(other))
-                repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
+                repo.dirstate.update([fd], 'n', st_size=-1, st_mtime=-1)
+                if move:
+                    repo.dirstate.forget([f])
+
+def update(repo, node, branchmerge, force, partial, wlock):
+    """
+    Perform a merge between the working directory and the given node
+
+    branchmerge = whether to merge between branches
+    force = whether to force branch merging or file overwriting
+    partial = a function to filter file lists (dirstate not updated)
+    wlock = working dir lock, if already held
+    """
+
+    if not wlock:
+        wlock = repo.wlock()
+
+    overwrite = force and not branchmerge
+    forcemerge = force and branchmerge
+    wc = repo.workingctx()
+    pl = wc.parents()
+    p1, p2 = pl[0], repo.changectx(node)
+    pa = p1.ancestor(p2)
+    fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
 
-    remove.sort()
-    for f in remove:
-        repo.ui.note(_("removing %s\n") % f)
-        util.audit_path(f)
-        try:
-            util.unlink(repo.wjoin(f))
-        except OSError, inst:
-            if inst.errno != errno.ENOENT:
-                repo.ui.warn(_("update failed to remove %s: %s!\n") %
-                             (f, inst.strerror))
+    ### check phase
+    if not overwrite and len(pl) > 1:
+        raise util.Abort(_("outstanding uncommitted merges"))
+    if pa == p1 or pa == p2: # is there a linear path from p1 to p2?
+        if branchmerge:
+            raise util.Abort(_("there is nothing to merge, just use "
+                               "'hg update' or look at 'hg heads'"))
+    elif not (overwrite or branchmerge):
+        raise util.Abort(_("update spans branches, use 'hg merge' "
+                           "or 'hg update -C' to lose changes"))
+    if branchmerge and not forcemerge:
+        if wc.modified() or wc.added() or wc.removed():
+            raise util.Abort(_("outstanding uncommitted changes"))
+
+    ### calculate phase
+    action = []
+    if not force:
+        checkunknown(wc, p2)
+    if not branchmerge:
+        action += forgetremoved(wc, p2)
+    action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
+
+    ### apply phase
+    if not branchmerge: # just jump to the new rev
+        fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
     if not partial:
-        if branchmerge:
-            repo.dirstate.update(remove, 'r')
-        else:
-            repo.dirstate.forget(remove)
+        repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
+
+    stats = applyupdates(repo, action, wc, p2)
 
     if not partial:
-        repo.dirstate.setparents(p1, p2)
+        recordupdates(repo, action, branchmerge)
+        repo.dirstate.setparents(fp1, fp2)
+        repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
+        if not branchmerge:
+            repo.opener("branch", "w").write(p2.branch() + "\n")
 
-    if show_stats:
-        stats = ((len(get), _("updated")),
-                 (len(merge) - len(unresolved), _("merged")),
-                 (len(remove), _("removed")),
-                 (len(unresolved), _("unresolved")))
-        note = ", ".join([_("%d files %s") % s for s in stats])
-        repo.ui.status("%s\n" % note)
-    if not partial:
-        if branchmerge:
-            if unresolved:
-                repo.ui.status(_("There are unresolved merges,"
-                                " you can redo the full merge using:\n"
-                                "  hg update -C %s\n"
-                                "  hg merge %s\n"
-                                % (repo.changelog.rev(p1),
-                                    repo.changelog.rev(p2))))
-            elif remind:
-                repo.ui.status(_("(branch merge, don't forget to commit)\n"))
-        elif unresolved:
-            repo.ui.status(_("There are unresolved merges with"
-                             " locally modified files.\n"))
+    return stats
 
-    repo.hook('update', parent1=xp1, parent2=xxp2, error=len(unresolved))
-    return len(unresolved)
-
--- a/mercurial/mpatch.c	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/mpatch.c	Sat Oct 21 15:22:08 2006 -0400
@@ -14,7 +14,7 @@
  allocation of intermediate Python objects. Working memory is about 2x
  the total number of hunks.
 
- Copyright 2005 Matt Mackall <mpm@selenic.com>
+ Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
  This software may be used and distributed according to the terms
  of the GNU General Public License, incorporated herein by reference.
@@ -62,6 +62,9 @@
 {
 	struct flist *a = NULL;
 
+	if (size < 1)
+		size = 1;
+
 	a = (struct flist *)malloc(sizeof(struct flist));
 	if (a) {
 		a->base = (struct frag *)malloc(sizeof(struct frag) * size);
--- a/mercurial/node.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/node.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,7 +1,7 @@
 """
 node.py - basic nodeid manipulation for mercurial
 
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/packagescan.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/packagescan.py	Sat Oct 21 15:22:08 2006 -0400
@@ -2,7 +2,7 @@
 # Used for the py2exe distutil.
 # This module must be the first mercurial module imported in setup.py
 #
-# Copyright 2005 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
+# Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -26,6 +26,7 @@
         foo            import foo
         foo bar        import foo, bar
         foo.bar        import foo.bar
+        foo@bar        import foo as bar
         foo:bar        from foo import bar
         foo:bar,quux   from foo import bar, quux
         foo.bar:quux   from foo.bar import quux"""
@@ -38,6 +39,9 @@
         except:
             module = m
             fromlist = []
+        as_ = None
+        if '@' in module:
+            module, as_ = module.split('@')
         mod = __import__(module, scope, scope, fromlist)
         if fromlist == []:
             # mod is only the top package, but we need all packages
@@ -46,7 +50,9 @@
             mn = comp[0]
             while True:
                 # mn and mod.__name__ might not be the same
-                scope[mn] = mod
+                if not as_:
+                    as_ = mn
+                scope[as_] = mod
                 requiredmodules[mod.__name__] = 1
                 if len(comp) == i: break
                 mod = getattr(mod,comp[i])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/patch.py	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,659 @@
+# patch.py - patch file parsing routines
+#
+# Copyright 2006 Brendan Cully <brendan@kublai.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from demandload import demandload
+from i18n import gettext as _
+from node import *
+demandload(globals(), "base85 cmdutil mdiff util")
+demandload(globals(), "cStringIO email.Parser errno os popen2 re shutil sha")
+demandload(globals(), "sys tempfile zlib")
+
+# helper functions
+
+def copyfile(src, dst, basedir=None):
+    if not basedir:
+        basedir = os.getcwd()
+
+    abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)]
+    if os.path.exists(absdst):
+        raise util.Abort(_("cannot create %s: destination already exists") %
+                         dst)
+
+    targetdir = os.path.dirname(absdst)
+    if not os.path.isdir(targetdir):
+        os.makedirs(targetdir)
+    try:
+        shutil.copyfile(abssrc, absdst)
+        shutil.copymode(abssrc, absdst)
+    except shutil.Error, inst:
+        raise util.Abort(str(inst))
+
+# public functions
+
+def extract(ui, fileobj):
+    '''extract patch from data read from fileobj.
+
+    patch can be normal patch or contained in email message.
+
+    return tuple (filename, message, user, date). any item in returned
+    tuple can be None.  if filename is None, fileobj did not contain
+    patch. caller must unlink filename when done.'''
+
+    # attempt to detect the start of a patch
+    # (this heuristic is borrowed from quilt)
+    diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
+                        'retrieving revision [0-9]+(\.[0-9]+)*$|' +
+                        '(---|\*\*\*)[ \t])', re.MULTILINE)
+
+    fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
+    tmpfp = os.fdopen(fd, 'w')
+    try:
+        hgpatch = False
+
+        msg = email.Parser.Parser().parse(fileobj)
+
+        message = msg['Subject']
+        user = msg['From']
+        # should try to parse msg['Date']
+        date = None
+
+        if message:
+            message = message.replace('\n\t', ' ')
+            ui.debug('Subject: %s\n' % message)
+        if user:
+            ui.debug('From: %s\n' % user)
+        diffs_seen = 0
+        ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
+
+        for part in msg.walk():
+            content_type = part.get_content_type()
+            ui.debug('Content-Type: %s\n' % content_type)
+            if content_type not in ok_types:
+                continue
+            payload = part.get_payload(decode=True)
+            m = diffre.search(payload)
+            if m:
+                ui.debug(_('found patch at byte %d\n') % m.start(0))
+                diffs_seen += 1
+                cfp = cStringIO.StringIO()
+                if message:
+                    cfp.write(message)
+                    cfp.write('\n')
+                for line in payload[:m.start(0)].splitlines():
+                    if line.startswith('# HG changeset patch'):
+                        ui.debug(_('patch generated by hg export\n'))
+                        hgpatch = True
+                        # drop earlier commit message content
+                        cfp.seek(0)
+                        cfp.truncate()
+                    elif hgpatch:
+                        if line.startswith('# User '):
+                            user = line[7:]
+                            ui.debug('From: %s\n' % user)
+                        elif line.startswith("# Date "):
+                            date = line[7:]
+                    if not line.startswith('# '):
+                        cfp.write(line)
+                        cfp.write('\n')
+                message = cfp.getvalue()
+                if tmpfp:
+                    tmpfp.write(payload)
+                    if not payload.endswith('\n'):
+                        tmpfp.write('\n')
+            elif not diffs_seen and message and content_type == 'text/plain':
+                message += '\n' + payload
+    except:
+        tmpfp.close()
+        os.unlink(tmpname)
+        raise
+
+    tmpfp.close()
+    if not diffs_seen:
+        os.unlink(tmpname)
+        return None, message, user, date
+    return tmpname, message, user, date
+
+def readgitpatch(patchname):
+    """extract git-style metadata about patches from <patchname>"""
+    class gitpatch:
+        "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
+        def __init__(self, path):
+            self.path = path
+            self.oldpath = None
+            self.mode = None
+            self.op = 'MODIFY'
+            self.copymod = False
+            self.lineno = 0
+            self.binary = False
+
+    # Filter patch for git information
+    gitre = re.compile('diff --git a/(.*) b/(.*)')
+    pf = file(patchname)
+    gp = None
+    gitpatches = []
+    # Can have a git patch with only metadata, causing patch to complain
+    dopatch = False
+
+    lineno = 0
+    for line in pf:
+        lineno += 1
+        if line.startswith('diff --git'):
+            m = gitre.match(line)
+            if m:
+                if gp:
+                    gitpatches.append(gp)
+                src, dst = m.group(1,2)
+                gp = gitpatch(dst)
+                gp.lineno = lineno
+        elif gp:
+            if line.startswith('--- '):
+                if gp.op in ('COPY', 'RENAME'):
+                    gp.copymod = True
+                    dopatch = 'filter'
+                gitpatches.append(gp)
+                gp = None
+                if not dopatch:
+                    dopatch = True
+                continue
+            if line.startswith('rename from '):
+                gp.op = 'RENAME'
+                gp.oldpath = line[12:].rstrip()
+            elif line.startswith('rename to '):
+                gp.path = line[10:].rstrip()
+            elif line.startswith('copy from '):
+                gp.op = 'COPY'
+                gp.oldpath = line[10:].rstrip()
+            elif line.startswith('copy to '):
+                gp.path = line[8:].rstrip()
+            elif line.startswith('deleted file'):
+                gp.op = 'DELETE'
+            elif line.startswith('new file mode '):
+                gp.op = 'ADD'
+                gp.mode = int(line.rstrip()[-3:], 8)
+            elif line.startswith('new mode '):
+                gp.mode = int(line.rstrip()[-3:], 8)
+            elif line.startswith('GIT binary patch'):
+                if not dopatch:
+                    dopatch = 'binary'
+                gp.binary = True
+    if gp:
+        gitpatches.append(gp)
+
+    if not gitpatches:
+        dopatch = True
+
+    return (dopatch, gitpatches)
+
+def dogitpatch(patchname, gitpatches, cwd=None):
+    """Preprocess git patch so that vanilla patch can handle it"""
+    def extractbin(fp):
+        line = fp.readline().rstrip()
+        while line and not line.startswith('literal '):
+            line = fp.readline().rstrip()
+        if not line:
+            return
+        size = int(line[8:])
+        dec = []
+        line = fp.readline().rstrip()
+        while line:
+            l = line[0]
+            if l <= 'Z' and l >= 'A':
+                l = ord(l) - ord('A') + 1
+            else:
+                l = ord(l) - ord('a') + 27
+            dec.append(base85.b85decode(line[1:])[:l])
+            line = fp.readline().rstrip()
+        text = zlib.decompress(''.join(dec))
+        if len(text) != size:
+            raise util.Abort(_('binary patch is %d bytes, not %d') %
+                             (len(text), size))
+        return text
+
+    pf = file(patchname)
+    pfline = 1
+
+    fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
+    tmpfp = os.fdopen(fd, 'w')
+
+    try:
+        for i in range(len(gitpatches)):
+            p = gitpatches[i]
+            if not p.copymod and not p.binary:
+                continue
+
+            # rewrite patch hunk
+            while pfline < p.lineno:
+                tmpfp.write(pf.readline())
+                pfline += 1
+
+            if p.binary:
+                text = extractbin(pf)
+                if not text:
+                    raise util.Abort(_('binary patch extraction failed'))
+                if not cwd:
+                    cwd = os.getcwd()
+                absdst = os.path.join(cwd, p.path)
+                basedir = os.path.dirname(absdst)
+                if not os.path.isdir(basedir):
+                    os.makedirs(basedir)
+                out = file(absdst, 'wb')
+                out.write(text)
+                out.close()
+            elif p.copymod:
+                copyfile(p.oldpath, p.path, basedir=cwd)
+                tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
+                line = pf.readline()
+                pfline += 1
+                while not line.startswith('--- a/'):
+                    tmpfp.write(line)
+                    line = pf.readline()
+                    pfline += 1
+                tmpfp.write('--- a/%s\n' % p.path)
+
+        line = pf.readline()
+        while line:
+            tmpfp.write(line)
+            line = pf.readline()
+    except:
+        tmpfp.close()
+        os.unlink(patchname)
+        raise
+
+    tmpfp.close()
+    return patchname
+
+def patch(patchname, ui, strip=1, cwd=None):
+    """apply the patch <patchname> to the working directory.
+    a list of patched files is returned"""
+
+    # helper function
+    def __patch(patchname):
+        """patch and updates the files and fuzz variables"""
+        files = {}
+        fuzz = False
+
+        patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''),
+                                    'patch')
+        args = []
+        if cwd:
+            args.append('-d %s' % util.shellquote(cwd))
+        fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
+                                           util.shellquote(patchname)))
+
+        for line in fp:
+            line = line.rstrip()
+            ui.note(line + '\n')
+            if line.startswith('patching file '):
+                pf = util.parse_patch_output(line)
+                printed_file = False
+                files.setdefault(pf, (None, None))
+            elif line.find('with fuzz') >= 0:
+                fuzz = True
+                if not printed_file:
+                    ui.warn(pf + '\n')
+                    printed_file = True
+                ui.warn(line + '\n')
+            elif line.find('saving rejects to file') >= 0:
+                ui.warn(line + '\n')
+            elif line.find('FAILED') >= 0:
+                if not printed_file:
+                    ui.warn(pf + '\n')
+                    printed_file = True
+                ui.warn(line + '\n')
+        code = fp.close()
+        if code:
+            raise util.Abort(_("patch command failed: %s") %
+                             util.explain_exit(code)[0])
+        return files, fuzz
+
+    (dopatch, gitpatches) = readgitpatch(patchname)
+
+    files, fuzz = {}, False
+    if dopatch:
+        if dopatch in ('filter', 'binary'):
+            patchname = dogitpatch(patchname, gitpatches, cwd=cwd)
+        try:
+            if dopatch != 'binary':
+                files, fuzz = __patch(patchname)
+        finally:
+            if dopatch == 'filter':
+                os.unlink(patchname)
+
+    for gp in gitpatches:
+        files[gp.path] = (gp.op, gp)
+
+    return (files, fuzz)
+
+def diffopts(ui, opts={}):
+    return mdiff.diffopts(
+        text=opts.get('text'),
+        git=(opts.get('git') or
+                  ui.configbool('diff', 'git', None)),
+        nodates=(opts.get('nodates') or
+                  ui.configbool('diff', 'nodates', None)),
+        showfunc=(opts.get('show_function') or
+                  ui.configbool('diff', 'showfunc', None)),
+        ignorews=(opts.get('ignore_all_space') or
+                  ui.configbool('diff', 'ignorews', None)),
+        ignorewsamount=(opts.get('ignore_space_change') or
+                        ui.configbool('diff', 'ignorewsamount', None)),
+        ignoreblanklines=(opts.get('ignore_blank_lines') or
+                          ui.configbool('diff', 'ignoreblanklines', None)))
+
+def updatedir(ui, repo, patches, wlock=None):
+    '''Update dirstate after patch application according to metadata'''
+    if not patches:
+        return
+    copies = []
+    removes = []
+    cfiles = patches.keys()
+    cwd = repo.getcwd()
+    if cwd:
+        cfiles = [util.pathto(cwd, f) for f in patches.keys()]
+    for f in patches:
+        ctype, gp = patches[f]
+        if ctype == 'RENAME':
+            copies.append((gp.oldpath, gp.path, gp.copymod))
+            removes.append(gp.oldpath)
+        elif ctype == 'COPY':
+            copies.append((gp.oldpath, gp.path, gp.copymod))
+        elif ctype == 'DELETE':
+            removes.append(gp.path)
+    for src, dst, after in copies:
+        if not after:
+            copyfile(src, dst, repo.root)
+        repo.copy(src, dst, wlock=wlock)
+    if removes:
+        repo.remove(removes, True, wlock=wlock)
+    for f in patches:
+        ctype, gp = patches[f]
+        if gp and gp.mode:
+            x = gp.mode & 0100 != 0
+            dst = os.path.join(repo.root, gp.path)
+            util.set_exec(dst, x)
+    cmdutil.addremove(repo, cfiles, wlock=wlock)
+    files = patches.keys()
+    files.extend([r for r in removes if r not in files])
+    files.sort()
+
+    return files
+
+def b85diff(fp, to, tn):
+    '''print base85-encoded binary diff'''
+    def gitindex(text):
+        if not text:
+            return '0' * 40
+        l = len(text)
+        s = sha.new('blob %d\0' % l)
+        s.update(text)
+        return s.hexdigest()
+
+    def fmtline(line):
+        l = len(line)
+        if l <= 26:
+            l = chr(ord('A') + l - 1)
+        else:
+            l = chr(l - 26 + ord('a') - 1)
+        return '%c%s\n' % (l, base85.b85encode(line, True))
+
+    def chunk(text, csize=52):
+        l = len(text)
+        i = 0
+        while i < l:
+            yield text[i:i+csize]
+            i += csize
+
+    # TODO: deltas
+    l = len(tn)
+    fp.write('index %s..%s\nGIT binary patch\nliteral %s\n' %
+             (gitindex(to), gitindex(tn), len(tn)))
+
+    tn = ''.join([fmtline(l) for l in chunk(zlib.compress(tn))])
+    fp.write(tn)
+    fp.write('\n')
+
+def diff(repo, node1=None, node2=None, files=None, match=util.always,
+         fp=None, changes=None, opts=None):
+    '''print diff of changes to files between two nodes, or node and
+    working directory.
+
+    if node1 is None, use first dirstate parent instead.
+    if node2 is None, compare node1 with working directory.'''
+
+    if opts is None:
+        opts = mdiff.defaultopts
+    if fp is None:
+        fp = repo.ui
+
+    if not node1:
+        node1 = repo.dirstate.parents()[0]
+
+    clcache = {}
+    def getchangelog(n):
+        if n not in clcache:
+            clcache[n] = repo.changelog.read(n)
+        return clcache[n]
+    mcache = {}
+    def getmanifest(n):
+        if n not in mcache:
+            mcache[n] = repo.manifest.read(n)
+        return mcache[n]
+    fcache = {}
+    def getfile(f):
+        if f not in fcache:
+            fcache[f] = repo.file(f)
+        return fcache[f]
+
+    # reading the data for node1 early allows it to play nicely
+    # with repo.status and the revlog cache.
+    change = getchangelog(node1)
+    mmap = getmanifest(change[0])
+    date1 = util.datestr(change[2])
+
+    if not changes:
+        changes = repo.status(node1, node2, files, match=match)[:5]
+    modified, added, removed, deleted, unknown = changes
+    if files:
+        def filterfiles(filters):
+            l = [x for x in filters if x in files]
+
+            for t in files:
+                if not t.endswith("/"):
+                    t += "/"
+                l += [x for x in filters if x.startswith(t)]
+            return l
+
+        modified, added, removed = map(filterfiles, (modified, added, removed))
+
+    if not modified and not added and not removed:
+        return
+
+    def renamedbetween(f, n1, n2):
+        r1, r2 = map(repo.changelog.rev, (n1, n2))
+        src = None
+        while r2 > r1:
+            cl = getchangelog(n2)[0]
+            m = getmanifest(cl)
+            try:
+                src = getfile(f).renamed(m[f])
+            except KeyError:
+                return None
+            if src:
+                f = src[0]
+            n2 = repo.changelog.parents(n2)[0]
+            r2 = repo.changelog.rev(n2)
+        return src
+
+    if node2:
+        change = getchangelog(node2)
+        mmap2 = getmanifest(change[0])
+        _date2 = util.datestr(change[2])
+        def date2(f):
+            return _date2
+        def read(f):
+            return getfile(f).read(mmap2[f])
+        def renamed(f):
+            return renamedbetween(f, node1, node2)
+    else:
+        tz = util.makedate()[1]
+        _date2 = util.datestr()
+        def date2(f):
+            try:
+                return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
+            except OSError, err:
+                if err.errno != errno.ENOENT: raise
+                return _date2
+        def read(f):
+            return repo.wread(f)
+        def renamed(f):
+            src = repo.dirstate.copied(f)
+            parent = repo.dirstate.parents()[0]
+            if src:
+                f = src[0]
+            of = renamedbetween(f, node1, parent)
+            if of:
+                return of
+            elif src:
+                cl = getchangelog(parent)[0]
+                return (src, getmanifest(cl)[src])
+            else:
+                return None
+
+    if repo.ui.quiet:
+        r = None
+    else:
+        hexfunc = repo.ui.debugflag and hex or short
+        r = [hexfunc(node) for node in [node1, node2] if node]
+
+    if opts.git:
+        copied = {}
+        for f in added:
+            src = renamed(f)
+            if src:
+                copied[f] = src
+        srcs = [x[1][0] for x in copied.items()]
+
+    all = modified + added + removed
+    all.sort()
+    for f in all:
+        to = None
+        tn = None
+        dodiff = True
+        header = []
+        if f in mmap:
+            to = getfile(f).read(mmap[f])
+        if f not in removed:
+            tn = read(f)
+        if opts.git:
+            def gitmode(x):
+                return x and '100755' or '100644'
+            def addmodehdr(header, omode, nmode):
+                if omode != nmode:
+                    header.append('old mode %s\n' % omode)
+                    header.append('new mode %s\n' % nmode)
+
+            a, b = f, f
+            if f in added:
+                if node2:
+                    mode = gitmode(mmap2.execf(f))
+                else:
+                    mode = gitmode(util.is_exec(repo.wjoin(f), None))
+                if f in copied:
+                    a, arev = copied[f]
+                    omode = gitmode(mmap.execf(a))
+                    addmodehdr(header, omode, mode)
+                    op = a in removed and 'rename' or 'copy'
+                    header.append('%s from %s\n' % (op, a))
+                    header.append('%s to %s\n' % (op, f))
+                    to = getfile(a).read(arev)
+                else:
+                    header.append('new file mode %s\n' % mode)
+                    if util.binary(tn):
+                        dodiff = 'binary'
+            elif f in removed:
+                if f in srcs:
+                    dodiff = False
+                else:
+                    mode = gitmode(mmap.execf(f))
+                    header.append('deleted file mode %s\n' % mode)
+            else:
+                omode = gitmode(mmap.execf(f))
+                if node2:
+                    nmode = gitmode(mmap2.execf(f))
+                else:
+                    nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f)))
+                addmodehdr(header, omode, nmode)
+                if util.binary(to) or util.binary(tn):
+                    dodiff = 'binary'
+            r = None
+            header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
+        if dodiff == 'binary':
+            fp.write(''.join(header))
+            b85diff(fp, to, tn)
+        elif dodiff:
+            text = mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts)
+            if text or len(header) > 1:
+                fp.write(''.join(header))
+            fp.write(text)
+
+def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
+           opts=None):
+    '''export changesets as hg patches.'''
+
+    total = len(revs)
+    revwidth = max(map(len, revs))
+
+    def single(node, seqno, fp):
+        parents = [p for p in repo.changelog.parents(node) if p != nullid]
+        if switch_parent:
+            parents.reverse()
+        prev = (parents and parents[0]) or nullid
+        change = repo.changelog.read(node)
+
+        if not fp:
+            fp = cmdutil.make_file(repo, template, node, total=total,
+                                   seqno=seqno, revwidth=revwidth)
+        if fp not in (sys.stdout, repo.ui):
+            repo.ui.note("%s\n" % fp.name)
+
+        fp.write("# HG changeset patch\n")
+        fp.write("# User %s\n" % change[1])
+        fp.write("# Date %d %d\n" % change[2])
+        fp.write("# Node ID %s\n" % hex(node))
+        fp.write("# Parent  %s\n" % hex(prev))
+        if len(parents) > 1:
+            fp.write("# Parent  %s\n" % hex(parents[1]))
+        fp.write(change[4].rstrip())
+        fp.write("\n\n")
+
+        diff(repo, prev, node, fp=fp, opts=opts)
+        if fp not in (sys.stdout, repo.ui):
+            fp.close()
+
+    for seqno, cset in enumerate(revs):
+        single(cset, seqno, fp)
+
+def diffstat(patchlines):
+    fd, name = tempfile.mkstemp(prefix="hg-patchbomb-", suffix=".txt")
+    try:
+        p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name)
+        try:
+            for line in patchlines: 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
--- a/mercurial/remoterepo.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/remoterepo.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
-# remoterepo - remote repositort proxy classes for mercurial
+# remoterepo - remote repository proxy classes for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/repo.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/repo.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,7 @@
 # repo.py - repository base classes for mercurial
 #
 # Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -8,6 +9,9 @@
 class RepoError(Exception):
     pass
 
+class LookupError(RepoError):
+    pass
+
 class repository(object):
     def capable(self, name):
         '''tell whether repo supports named capability.
--- a/mercurial/revlog.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/revlog.py	Sat Oct 21 15:22:08 2006 -0400
@@ -4,7 +4,7 @@
 This provides efficient delta storage with O(1) retrieve and append
 and O(changes) merge between branches
 
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
@@ -13,7 +13,7 @@
 from node import *
 from i18n import gettext as _
 from demandload import demandload
-demandload(globals(), "binascii changegroup errno heapq mdiff os")
+demandload(globals(), "binascii changegroup errno ancestor mdiff os")
 demandload(globals(), "sha struct util zlib")
 
 # revlog version strings
@@ -116,7 +116,6 @@
         which takes much less time.
         """
         if self.allmap: return
-        start = 0
         end = self.datasize
         self.allmap = 1
         cur = 0
@@ -139,6 +138,11 @@
         if self.all: return
         if data is None:
             self.dataf.seek(blockstart)
+            if blockstart + blocksize > self.datasize:
+                # the revlog may have grown since we've started running,
+                # but we don't have space in self.index for more entries.
+                # limit blocksize so that we don't get too much data.
+                blocksize = max(self.datasize - blockstart, 0)
             data = self.dataf.read(blocksize)
         lend = len(data) / self.s
         i = blockstart / self.s
@@ -595,12 +599,12 @@
             if not heads:
                 return nonodes
             ancestors = {}
-            # Start at the top and keep marking parents until we're done.
-            nodestotag = heads[:]
             # Turn heads into a dictionary so we can remove 'fake' heads.
             # Also, later we will be using it to filter out the heads we can't
             # find from roots.
             heads = dict.fromkeys(heads, 0)
+            # Start at the top and keep marking parents until we're done.
+            nodestotag = heads.keys()
             # Remember where the top was so we can use it as a limit later.
             highestrev = max([self.rev(n) for n in nodestotag])
             while nodestotag:
@@ -742,30 +746,81 @@
                     continue
         return c
 
-    def lookup(self, id):
-        """locate a node based on revision number or subset of hex nodeid"""
-        if type(id) == type(0):
+    def _match(self, id):
+        if isinstance(id, (long, int)):
+            # rev
             return self.node(id)
+        if len(id) == 20:
+            # possibly a binary node
+            # odds of a binary node being all hex in ASCII are 1 in 10**25
+            try:
+                node = id
+                r = self.rev(node) # quick search the index
+                return node
+            except RevlogError:
+                pass # may be partial hex id
         try:
+            # str(rev)
             rev = int(id)
             if str(rev) != id: raise ValueError
             if rev < 0: rev = self.count() + rev
             if rev < 0 or rev >= self.count(): raise ValueError
             return self.node(rev)
         except (ValueError, OverflowError):
-            c = []
-            for n in self.nodemap:
-                if hex(n).startswith(id):
-                    c.append(n)
-            if len(c) > 1: raise RevlogError(_("Ambiguous identifier"))
-            if len(c) == 1: return c[0]
+            pass
+        if len(id) == 40:
+            try:
+                # a full hex nodeid?
+                node = bin(id)
+                r = self.rev(node)
+                return node
+            except TypeError:
+                pass
 
-        # might need fixing if we change hash lengths
-        if len(id) == 20 and id in self.nodemap:
-            return id
+    def _partialmatch(self, id):
+        if len(id) < 40:
+            try:
+                # hex(node)[:...]
+                bin_id = bin(id[:len(id) & ~1]) # grab an even number of digits
+                node = None
+                for n in self.nodemap:
+                    if n.startswith(bin_id) and hex(n).startswith(id):
+                        if node is not None:
+                            raise RevlogError(_("Ambiguous identifier"))
+                        node = n
+                if node is not None:
+                    return node
+            except TypeError:
+                pass
+
+    def lookup(self, id):
+        """locate a node based on:
+            - revision number or str(revision number)
+            - nodeid or subset of hex nodeid
+        """
+
+        n = self._match(id)
+        if n is not None:
+            return n
+        n = self._partialmatch(id)
+        if n:
+            return n
 
         raise RevlogError(_("No match found"))
 
+    def cmp(self, node, text):
+        """compare text with a given file revision"""
+        p1, p2 = self.parents(node)
+        return hash(text, p1, p2) != node
+
+    def makenode(self, node, text):
+        """calculate a file nodeid for text, descended or possibly
+        unchanged from node"""
+
+        if self.cmp(node, text):
+            return hash(text, node, nullid)
+        return node
+
     def diff(self, a, b):
         """return a delta between two revisions"""
         return mdiff.textdiff(a, b)
@@ -921,6 +976,14 @@
         p1, p2 - the parent nodeids of the revision
         d - an optional precomputed delta
         """
+        if not self.inlinedata():
+            dfh = self.opener(self.datafile, "a")
+        else:
+            dfh = None
+        ifh = self.opener(self.indexfile, "a+")
+        return self._addrevision(text, transaction, link, p1, p2, d, ifh, dfh)
+
+    def _addrevision(self, text, transaction, link, p1, p2, d, ifh, dfh):
         if text is None: text = ""
         if p1 is None: p1 = self.tip()
         if p2 is None: p2 = nullid
@@ -939,7 +1002,7 @@
             end = self.end(t)
             if not d:
                 prev = self.revision(self.tip())
-                d = self.diff(prev, str(text))
+                d = self.diff(prev, text)
             data = compress(d)
             l = len(data[1]) + len(data[0])
             dist = end - start + l
@@ -970,28 +1033,25 @@
         if not self.inlinedata():
             transaction.add(self.datafile, offset)
             transaction.add(self.indexfile, n * len(entry))
-            f = self.opener(self.datafile, "a")
             if data[0]:
-                f.write(data[0])
-            f.write(data[1])
-            f.close()
-            f = self.opener(self.indexfile, "a")
+                dfh.write(data[0])
+            dfh.write(data[1])
+            dfh.flush()
         else:
-            f = self.opener(self.indexfile, "a+")
-            f.seek(0, 2)
-            transaction.add(self.indexfile, f.tell(), self.count() - 1)
+            ifh.seek(0, 2)
+            transaction.add(self.indexfile, ifh.tell(), self.count() - 1)
 
         if len(self.index) == 1 and self.version != REVLOGV0:
             l = struct.pack(versionformat, self.version)
-            f.write(l)
+            ifh.write(l)
             entry = entry[4:]
 
-        f.write(entry)
+        ifh.write(entry)
 
         if self.inlinedata():
-            f.write(data[0])
-            f.write(data[1])
-            self.checkinlinesize(transaction, f)
+            ifh.write(data[0])
+            ifh.write(data[1])
+            self.checkinlinesize(transaction, ifh)
 
         self.cache = (node, n, text)
         return node
@@ -999,78 +1059,14 @@
     def ancestor(self, a, b):
         """calculate the least common ancestor of nodes a and b"""
 
-        # start with some short cuts for the linear cases
-        if a == b:
-            return a
-        ra = self.rev(a)
-        rb = self.rev(b)
-        if ra < rb:
-            last = b
-            first = a
-        else:
-            last = a
-            first = b
-
-        # reachable won't include stop in the list, so we have to use a parent
-        reachable = self.reachable(last, stop=self.parents(first)[0])
-        if first in reachable:
-            return first
-
-        # calculate the distance of every node from root
-        dist = {nullid: 0}
-        for i in xrange(self.count()):
-            n = self.node(i)
-            p1, p2 = self.parents(n)
-            dist[n] = max(dist[p1], dist[p2]) + 1
+        def parents(rev):
+            return [p for p in self.parentrevs(rev) if p != -1]
 
-        # traverse ancestors in order of decreasing distance from root
-        def ancestors(node):
-            # we store negative distances because heap returns smallest member
-            h = [(-dist[node], node)]
-            seen = {}
-            while h:
-                d, n = heapq.heappop(h)
-                if n not in seen:
-                    seen[n] = 1
-                    yield (-d, n)
-                    for p in self.parents(n):
-                        heapq.heappush(h, (-dist[p], p))
-
-        def generations(node):
-            sg, s = None, {}
-            for g,n in ancestors(node):
-                if g != sg:
-                    if sg:
-                        yield sg, s
-                    sg, s = g, {n:1}
-                else:
-                    s[n] = 1
-            yield sg, s
+        c = ancestor.ancestor(self.rev(a), self.rev(b), parents)
+        if c is None:
+            return nullid
 
-        x = generations(a)
-        y = generations(b)
-        gx = x.next()
-        gy = y.next()
-
-        # increment each ancestor list until it is closer to root than
-        # the other, or they match
-        while 1:
-            #print "ancestor gen %s %s" % (gx[0], gy[0])
-            if gx[0] == gy[0]:
-                # find the intersection
-                i = [ n for n in gx[1] if n in gy[1] ]
-                if i:
-                    return i[0]
-                else:
-                    #print "next"
-                    gy = y.next()
-                    gx = x.next()
-            elif gx[0] < gy[0]:
-                #print "next y"
-                gy = y.next()
-            else:
-                #print "next x"
-                gx = x.next()
+        return self.node(c)
 
     def group(self, nodelist, lookup, infocollect=None):
         """calculate a delta group
@@ -1176,7 +1172,13 @@
                 ifh.flush()
                 text = self.revision(chain)
                 text = self.patches(text, [delta])
-                chk = self.addrevision(text, transaction, link, p1, p2)
+                chk = self._addrevision(text, transaction, link, p1, p2, None,
+                                        ifh, dfh)
+                if not dfh and not self.inlinedata():
+                    # addrevision switched from inline to conventional
+                    # reopen the index
+                    dfh = self.opener(self.datafile, "a")
+                    ifh = self.opener(self.indexfile, "a")
                 if chk != node:
                     raise RevlogError(_("consistency error adding group"))
                 textlen = len(text)
@@ -1196,11 +1198,6 @@
                         dfh = self.opener(self.datafile, "a")
                         ifh = self.opener(self.indexfile, "a")
                 else:
-                    if not dfh:
-                        # addrevision switched from inline to conventional
-                        # reopen the index
-                        dfh = self.opener(self.datafile, "a")
-                        ifh = self.opener(self.indexfile, "a")
                     dfh.write(cdelta)
                     ifh.write(struct.pack(self.indexformat, *e))
 
--- a/mercurial/sshrepo.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/sshrepo.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,6 @@
 # sshrepo.py - ssh repository proxy class for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -18,7 +18,7 @@
 
         m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path)
         if not m:
-            raise hg.RepoError(_("couldn't parse location %s") % path)
+            self.repoerror(_("couldn't parse location %s") % path)
 
         self.user = m.group(2)
         self.host = m.group(3)
@@ -32,19 +32,13 @@
         remotecmd = self.ui.config("ui", "remotecmd", "hg")
 
         if create:
-            try:
-                self.validate_repo(ui, sshcmd, args, remotecmd)
-                return # the repo is good, nothing more to do
-            except hg.RepoError:
-                pass
-
             cmd = '%s %s "%s init %s"'
             cmd = cmd % (sshcmd, args, remotecmd, self.path)
 
             ui.note('running %s\n' % cmd)
             res = os.system(cmd)
             if res != 0:
-                raise hg.RepoError(_("could not create remote repo"))
+                self.repoerror(_("could not create remote repo"))
 
         self.validate_repo(ui, sshcmd, args, remotecmd)
 
@@ -52,6 +46,9 @@
         return self._url
 
     def validate_repo(self, ui, sshcmd, args, remotecmd):
+        # cleanup up previous run
+        self.cleanup()
+
         cmd = '%s %s "%s -R %s serve --stdio"'
         cmd = cmd % (sshcmd, args, remotecmd, self.path)
 
@@ -73,7 +70,7 @@
             lines.append(l)
             max_noise -= 1
         else:
-            raise hg.RepoError(_("no response from remote hg"))
+            self.repoerror(_("no suitable response from remote hg"))
 
         self.capabilities = ()
         lines.reverse()
@@ -90,7 +87,11 @@
             if not l: break
             self.ui.status(_("remote: "), l)
 
-    def __del__(self):
+    def repoerror(self, msg):
+        self.cleanup()
+        raise hg.RepoError(msg)
+
+    def cleanup(self):
         try:
             self.pipeo.close()
             self.pipei.close()
@@ -101,6 +102,8 @@
         except:
             pass
 
+    __del__ = cleanup
+
     def do_cmd(self, cmd, **args):
         self.ui.debug(_("sending %s command\n") % cmd)
         self.pipeo.write("%s\n" % cmd)
@@ -118,7 +121,7 @@
         try:
             l = int(l)
         except:
-            raise hg.RepoError(_("unexpected response '%s'") % l)
+            self.repoerror(_("unexpected response '%s'") % l)
         return r.read(l)
 
     def lock(self):
@@ -128,12 +131,24 @@
     def unlock(self):
         self.call("unlock")
 
+    def lookup(self, key):
+        d = self.call("lookup", key=key)
+        success, data = d[:-1].split(" ", 1)
+        try:
+            if int(success):
+                return bin(data)
+            else:
+                raise data
+        except:
+            raise
+            raise hg.RepoError("unexpected response '%s'" % (d[:400] + "..."))
+
     def heads(self):
         d = self.call("heads")
         try:
             return map(bin, d[:-1].split(" "))
         except:
-            raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
+            self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
 
     def branches(self, nodes):
         n = " ".join(map(hex, nodes))
@@ -142,7 +157,7 @@
             br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
             return br
         except:
-            raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
+            self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
 
     def between(self, pairs):
         n = "\n".join(["-".join(map(hex, p)) for p in pairs])
@@ -151,16 +166,21 @@
             p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
             return p
         except:
-            raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
+            self.repoerror(_("unexpected response '%s'") % (d[:400] + "..."))
 
     def changegroup(self, nodes, kind):
         n = " ".join(map(hex, nodes))
         return self.do_cmd("changegroup", roots=n)
 
+    def changegroupsubset(self, bases, heads, kind):
+        bases = " ".join(map(hex, bases))
+        heads = " ".join(map(hex, heads))
+        return self.do_cmd("changegroupsubset", bases=bases, heads=heads)
+
     def unbundle(self, cg, heads, source):
         d = self.call("unbundle", heads=' '.join(map(hex, heads)))
         if d:
-            raise hg.RepoError(_("push refused: %s") % d)
+            self.repoerror(_("push refused: %s") % d)
 
         while 1:
             d = cg.read(4096)
@@ -186,7 +206,7 @@
     def addchangegroup(self, cg, source, url):
         d = self.call("addchangegroup")
         if d:
-            raise hg.RepoError(_("push refused: %s") % d)
+            self.repoerror(_("push refused: %s") % d)
         while 1:
             d = cg.read(4096)
             if not d: break
--- a/mercurial/sshserver.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/sshserver.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,7 @@
 # sshserver.py - ssh protocol server support for mercurial
 #
 # Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -47,6 +48,17 @@
             else: self.respond("")
         return cmd != ''
 
+    def do_lookup(self):
+        arg, key = self.getarg()
+        assert arg == 'key'
+        try:
+            r = hex(self.repo.lookup(key))
+            success = 1
+        except Exception,inst:
+            r = str(inst)
+            success = 0
+        self.respond("%s %s\n" % (success, r))
+
     def do_heads(self):
         h = self.repo.heads()
         self.respond(" ".join(map(hex, h)) + "\n")
@@ -60,7 +72,7 @@
         capabilities: space separated list of tokens
         '''
 
-        caps = ['unbundle']
+        caps = ['unbundle', 'lookup', 'changegroupsubset']
         if self.ui.configbool('server', 'uncompressed'):
             caps.append('stream=%d' % self.repo.revlogversion)
         self.respond("capabilities: %s\n" % (' '.join(caps),))
@@ -109,6 +121,22 @@
 
         self.fout.flush()
 
+    def do_changegroupsubset(self):
+        bases = []
+        heads = []
+        argmap = dict([self.getarg(), self.getarg()])
+        bases = [bin(n) for n in argmap['bases'].split(' ')]
+        heads = [bin(n) for n in argmap['heads'].split(' ')]
+
+        cg = self.repo.changegroupsubset(bases, heads, 'serve')
+        while True:
+            d = cg.read(4096)
+            if not d:
+                break
+            self.fout.write(d)
+
+        self.fout.flush()
+
     def do_addchangegroup(self):
         '''DEPRECATED'''
 
@@ -123,7 +151,7 @@
     def client_url(self):
         client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
         return 'remote:ssh:' + client
-        
+
     def do_unbundle(self):
         their_heads = self.getarg()[1].split()
 
--- a/mercurial/statichttprepo.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/statichttprepo.py	Sat Oct 21 15:22:08 2006 -0400
@@ -2,7 +2,7 @@
 #
 # This provides read-only repo access to repositories exported via static http
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/strutil.py	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,34 @@
+# strutil.py - string utilities for Mercurial
+#
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+def findall(haystack, needle, start=0, end=None):
+    if end is None:
+        end = len(haystack)
+    if end < 0:
+        end += len(haystack)
+    if start < 0:
+        start += len(haystack)
+    while start < end:
+        c = haystack.find(needle, start, end)
+        if c == -1:
+            break
+        yield c
+        start = c + 1
+
+def rfindall(haystack, needle, start=0, end=None):
+    if end is None:
+        end = len(haystack)
+    if end < 0:
+        end += len(haystack)
+    if start < 0:
+        start += len(haystack)
+    while end >= 0:
+        c = haystack.rfind(needle, start, end)
+        if c == -1:
+            break
+        yield c
+        end = c - 1
--- a/mercurial/templater.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/templater.py	Sat Oct 21 15:22:08 2006 -0400
@@ -135,7 +135,11 @@
                 fl = m.group(4)
 
                 if format:
-                    q = v.__iter__
+                    try:
+                        q = v.__iter__
+                    except AttributeError:
+                        raise SyntaxError(_("Error expanding '%s%s'")
+                                          % (key, format))
                     for i in q():
                         lm.update(i)
                         yield self(format[1:], **lm)
@@ -330,7 +334,8 @@
     def __init__(self, ui, repo, mapfile, dest=None):
         self.t = templater(mapfile, common_filters,
                            cache={'parent': '{rev}:{node|short} ',
-                                  'manifest': '{rev}:{node|short}'})
+                                  'manifest': '{rev}:{node|short}',
+                                  'filecopy': '{name} ({source})'})
         self.ui = ui
         self.dest = dest
         self.repo = repo
@@ -355,7 +360,7 @@
         self.write(thing, header=True)
 
     def show(self, rev=0, changenode=None, brinfo=None, changes=None,
-             **props):
+             copies=[], **props):
         '''show a single changeset or file revision'''
         log = self.repo.changelog
         if changenode is None:
@@ -459,7 +464,7 @@
                 yield x
 
         if self.ui.debugflag:
-            files = self.repo.changes(log.parents(changenode)[0], changenode)
+            files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
             def showfiles(**args):
                 for x in showlist('file', files[0], **args): yield x
             def showadds(**args):
@@ -472,6 +477,13 @@
             showadds = ''
             showdels = ''
 
+        copies = [{'name': x[0], 'source': x[1]}
+                  for x in copies]
+        def showcopies(**args):
+            for x in showlist('file_copy', copies, plural='file_copies',
+                              **args):
+                yield x
+
         defprops = {
             'author': changes[1],
             'branches': showbranches,
@@ -480,6 +492,7 @@
             'file_adds': showadds,
             'file_dels': showdels,
             'files': showfiles,
+            'file_copies': showcopies,
             'manifest': showmanifest,
             'node': hex(changenode),
             'parents': showparents,
--- a/mercurial/transaction.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/transaction.py	Sat Oct 21 15:22:08 2006 -0400
@@ -6,7 +6,7 @@
 # effectively log-structured, this should amount to simply truncating
 # anything that isn't referenced in the changelog.
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/ui.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/ui.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,68 +1,86 @@
 # ui.py - user interface bits for mercurial
 #
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
 from i18n import gettext as _
 from demandload import *
-demandload(globals(), "errno getpass os re smtplib socket sys tempfile")
-demandload(globals(), "ConfigParser templater traceback util")
+demandload(globals(), "errno getpass os re socket sys tempfile")
+demandload(globals(), "ConfigParser traceback util")
+
+def dupconfig(orig):
+    new = util.configparser(orig.defaults())
+    updateconfig(orig, new)
+    return new
+
+def updateconfig(source, dest, sections=None):
+    if not sections:
+        sections = source.sections()
+    for section in sections:
+        if not dest.has_section(section):
+            dest.add_section(section)
+        for name, value in source.items(section, raw=True):
+            dest.set(section, name, value)
 
 class ui(object):
     def __init__(self, verbose=False, debug=False, quiet=False,
                  interactive=True, traceback=False, parentui=None):
-        self.overlay = {}
+        self.overlay = None
+        self.header = []
+        self.prev_header = []
         if parentui is None:
             # this is the parent of all ui children
             self.parentui = None
-            self.cdata = ConfigParser.SafeConfigParser()
+            self.readhooks = []
+            self.quiet = quiet
+            self.verbose = verbose
+            self.debugflag = debug
+            self.interactive = interactive
+            self.traceback = traceback
+            self.cdata = util.configparser()
             self.readconfig(util.rcpath())
-
-            self.quiet = self.configbool("ui", "quiet")
-            self.verbose = self.configbool("ui", "verbose")
-            self.debugflag = self.configbool("ui", "debug")
-            self.interactive = self.configbool("ui", "interactive", True)
-            self.traceback = traceback
-
             self.updateopts(verbose, debug, quiet, interactive)
-            self.diffcache = None
-            self.header = []
-            self.prev_header = []
-            self.revlogopts = self.configrevlog()
         else:
             # parentui may point to an ui object which is already a child
             self.parentui = parentui.parentui or parentui
-            parent_cdata = self.parentui.cdata
-            self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
-            # make interpolation work
-            for section in parent_cdata.sections():
-                self.cdata.add_section(section)
-                for name, value in parent_cdata.items(section, raw=True):
-                    self.cdata.set(section, name, value)
+            self.readhooks = self.parentui.readhooks[:]
+            self.cdata = dupconfig(self.parentui.cdata)
+            if self.parentui.overlay:
+                self.overlay = dupconfig(self.parentui.overlay)
 
     def __getattr__(self, key):
         return getattr(self.parentui, key)
 
     def updateopts(self, verbose=False, debug=False, quiet=False,
                    interactive=True, traceback=False, config=[]):
-        self.quiet = (self.quiet or quiet) and not verbose and not debug
-        self.verbose = (self.verbose or verbose) or debug
-        self.debugflag = (self.debugflag or debug)
-        self.interactive = (self.interactive and interactive)
+        for section, name, value in config:
+            self.setconfig(section, name, value)
+
+        if quiet or verbose or debug:
+            self.setconfig('ui', 'quiet', str(bool(quiet)))
+            self.setconfig('ui', 'verbose', str(bool(verbose)))
+            self.setconfig('ui', 'debug', str(bool(debug)))
+
+        self.verbosity_constraints()
+
+        if not interactive:
+            self.setconfig('ui', 'interactive', 'False')
+            self.interactive = False
+
         self.traceback = self.traceback or traceback
-        for cfg in config:
-            try:
-                name, value = cfg.split('=', 1)
-                section, name = name.split('.', 1)
-                if not self.cdata.has_section(section):
-                    self.cdata.add_section(section)
-                if not section or not name:
-                    raise IndexError
-                self.cdata.set(section, name, value)
-            except (IndexError, ValueError):
-                raise util.Abort(_('malformed --config option: %s') % cfg)
+
+    def verbosity_constraints(self):
+        self.quiet = self.configbool('ui', 'quiet')
+        self.verbose = self.configbool('ui', 'verbose')
+        self.debugflag = self.configbool('ui', 'debug')
+
+        if self.debugflag:
+            self.verbose = True
+            self.quiet = False
+        elif self.verbose and self.quiet:
+            self.quiet = self.verbose = False
 
     def readconfig(self, fn, root=None):
         if isinstance(fn, basestring):
@@ -72,28 +90,84 @@
                 self.cdata.read(f)
             except ConfigParser.ParsingError, inst:
                 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
-        # translate paths relative to root (or home) into absolute paths
+        # override data from config files with data set with ui.setconfig
+        if self.overlay:
+            updateconfig(self.overlay, self.cdata)
         if root is None:
             root = os.path.expanduser('~')
-        for name, path in self.configitems("paths"):
-            if path and "://" not in path and not os.path.isabs(path):
-                self.cdata.set("paths", name, os.path.join(root, path))
+        self.fixconfig(root=root)
+        for hook in self.readhooks:
+            hook(self)
+
+    def addreadhook(self, hook):
+        self.readhooks.append(hook)
+
+    def readsections(self, filename, *sections):
+        "read filename and add only the specified sections to the config data"
+        if not sections:
+            return
+
+        cdata = util.configparser()
+        try:
+            cdata.read(filename)
+        except ConfigParser.ParsingError, inst:
+            raise util.Abort(_("failed to parse %s\n%s") % (f, inst))
+
+        for section in sections:
+            if not cdata.has_section(section):
+                cdata.add_section(section)
+
+        updateconfig(cdata, self.cdata, sections)
 
-    def setconfig(self, section, name, val):
-        self.overlay[(section, name)] = val
+    def fixconfig(self, section=None, name=None, value=None, root=None):
+        # translate paths relative to root (or home) into absolute paths
+        if section is None or section == 'paths':
+            if root is None:
+                root = os.getcwd()
+            items = section and [(name, value)] or []
+            for cdata in self.cdata, self.overlay:
+                if not cdata: continue
+                if not items and cdata.has_section('paths'):
+                    pathsitems = cdata.items('paths')
+                else:
+                    pathsitems = items
+                for n, path in pathsitems:
+                    if path and "://" not in path and not os.path.isabs(path):
+                        cdata.set("paths", n, os.path.join(root, path))
+
+        # update quiet/verbose/debug and interactive status
+        if section is None or section == 'ui':
+            if name is None or name in ('quiet', 'verbose', 'debug'):
+                self.verbosity_constraints()
+
+            if name is None or name == 'interactive':
+                self.interactive = self.configbool("ui", "interactive", True)
+
+    def setconfig(self, section, name, value):
+        if not self.overlay:
+            self.overlay = util.configparser()
+        for cdata in (self.overlay, self.cdata):
+            if not cdata.has_section(section):
+                cdata.add_section(section)
+            cdata.set(section, name, value)
+        self.fixconfig(section, name, value)
+
+    def _config(self, section, name, default, funcname):
+        if self.cdata.has_option(section, name):
+            try:
+                func = getattr(self.cdata, funcname)
+                return func(section, name)
+            except ConfigParser.InterpolationError, inst:
+                raise util.Abort(_("Error in configuration section [%s] "
+                                   "parameter '%s':\n%s")
+                                 % (section, name, inst))
+        return default
 
     def config(self, section, name, default=None):
-        if self.overlay.has_key((section, name)):
-            return self.overlay[(section, name)]
-        if self.cdata.has_option(section, name):
-            try:
-                return self.cdata.get(section, name)
-            except ConfigParser.InterpolationError, inst:
-                raise util.Abort(_("Error in configuration:\n%s") % inst)
-        if self.parentui is None:
-            return default
-        else:
-            return self.parentui.config(section, name, default)
+        return self._config(section, name, default, 'get')
+
+    def configbool(self, section, name, default=False):
+        return self._config(section, name, default, 'getboolean')
 
     def configlist(self, section, name, default=None):
         """Return a list of comma/space separated strings"""
@@ -104,50 +178,28 @@
             result = result.replace(",", " ").split()
         return result
 
-    def configbool(self, section, name, default=False):
-        if self.overlay.has_key((section, name)):
-            return self.overlay[(section, name)]
-        if self.cdata.has_option(section, name):
-            try:
-                return self.cdata.getboolean(section, name)
-            except ConfigParser.InterpolationError, inst:
-                raise util.Abort(_("Error in configuration:\n%s") % inst)
-        if self.parentui is None:
-            return default
-        else:
-            return self.parentui.configbool(section, name, default)
-
     def has_config(self, section):
         '''tell whether section exists in config.'''
         return self.cdata.has_section(section)
 
     def configitems(self, section):
         items = {}
-        if self.parentui is not None:
-            items = dict(self.parentui.configitems(section))
         if self.cdata.has_section(section):
             try:
                 items.update(dict(self.cdata.items(section)))
             except ConfigParser.InterpolationError, inst:
-                raise util.Abort(_("Error in configuration:\n%s") % inst)
+                raise util.Abort(_("Error in configuration section [%s]:\n%s")
+                                 % (section, inst))
         x = items.items()
         x.sort()
         return x
 
-    def walkconfig(self, seen=None):
-        if seen is None:
-            seen = {}
-        for (section, name), value in self.overlay.iteritems():
-            yield section, name, value
-            seen[section, name] = 1
-        for section in self.cdata.sections():
-            for name, value in self.cdata.items(section):
-                if (section, name) in seen: continue
+    def walkconfig(self):
+        sections = self.cdata.sections()
+        sections.sort()
+        for section in sections:
+            for name, value in self.configitems(section):
                 yield section, name, value.replace('\n', '\\n')
-                seen[section, name] = 1
-        if self.parentui is not None:
-            for parent in self.parentui.walkconfig(seen):
-                yield parent
 
     def extensions(self):
         result = self.configitems("extensions")
@@ -169,17 +221,6 @@
             result[key.lower()] = value
         return result
 
-    def diffopts(self):
-        if self.diffcache:
-            return self.diffcache
-        result = {'showfunc': True, 'ignorews': False,
-                  'ignorewsamount': False, 'ignoreblanklines': False}
-        for key, value in self.configitems("diff"):
-            if value:
-                result[key.lower()] = (value.lower() == 'true')
-        self.diffcache = result
-        return result
-
     def username(self):
         """Return default username to be used in commits.
 
@@ -292,62 +333,6 @@
 
         return t
 
-    def sendmail(self):
-        '''send mail message. object returned has one method, sendmail.
-        call as sendmail(sender, list-of-recipients, msg).'''
-
-        def smtp():
-            '''send mail using smtp.'''
-
-            local_hostname = self.config('smtp', 'local_hostname')
-            s = smtplib.SMTP(local_hostname=local_hostname)
-            mailhost = self.config('smtp', 'host')
-            if not mailhost:
-                raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
-            mailport = int(self.config('smtp', 'port', 25))
-            self.note(_('sending mail: smtp host %s, port %s\n') %
-                      (mailhost, mailport))
-            s.connect(host=mailhost, port=mailport)
-            if self.configbool('smtp', 'tls'):
-                self.note(_('(using tls)\n'))
-                s.ehlo()
-                s.starttls()
-                s.ehlo()
-            username = self.config('smtp', 'username')
-            password = self.config('smtp', 'password')
-            if username and password:
-                self.note(_('(authenticating to mail server as %s)\n') %
-                          (username))
-                s.login(username, password)
-            return s
-
-        class sendmail(object):
-            '''send mail using sendmail.'''
-
-            def __init__(self, ui, program):
-                self.ui = ui
-                self.program = program
-
-            def sendmail(self, sender, recipients, msg):
-                cmdline = '%s -f %s %s' % (
-                    self.program, templater.email(sender),
-                    ' '.join(map(templater.email, recipients)))
-                self.ui.note(_('sending mail: %s\n') % cmdline)
-                fp = os.popen(cmdline, 'w')
-                fp.write(msg)
-                ret = fp.close()
-                if ret:
-                    raise util.Abort('%s %s' % (
-                        os.path.basename(self.program.split(None, 1)[0]),
-                        util.explain_exit(ret)[0]))
-
-        method = self.config('email', 'method', 'smtp')
-        if method == 'smtp':
-            mail = smtp()
-        else:
-            mail = sendmail(self, method)
-        return mail
-
     def print_exc(self):
         '''print exception traceback if traceback printing enabled.
         only to call in exception handler. returns true if traceback
--- a/mercurial/util.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/util.py	Sat Oct 21 15:22:08 2006 -0400
@@ -2,6 +2,8 @@
 util.py - Mercurial utility functions and platform specfic implementations
 
  Copyright 2005 K. Thananchayan <thananck@yahoo.com>
+ Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+ Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 
 This software may be used and distributed according to the terms
 of the GNU General Public License, incorporated herein by reference.
@@ -13,7 +15,7 @@
 from i18n import gettext as _
 from demandload import *
 demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
-demandload(globals(), "os threading time")
+demandload(globals(), "os threading time calendar ConfigParser")
 
 # used by parsedate
 defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M',
@@ -22,6 +24,30 @@
 class SignalInterrupt(Exception):
     """Exception raised on SIGTERM and SIGHUP."""
 
+# like SafeConfigParser but with case-sensitive keys
+class configparser(ConfigParser.SafeConfigParser):
+    def optionxform(self, optionstr):
+        return optionstr
+
+def cachefunc(func):
+    '''cache the result of function calls'''
+    # XXX doesn't handle keywords args
+    cache = {}
+    if func.func_code.co_argcount == 1:
+        # we gain a small amount of time because
+        # we don't need to pack/unpack the list
+        def f(arg):
+            if arg not in cache:
+                cache[arg] = func(arg)
+            return cache[arg]
+    else:
+        def f(*args):
+            if args not in cache:
+                cache[args] = func(*args)
+            return cache[args]
+
+    return f
+
 def pipefilter(s, cmd):
     '''filter string S through command CMD, returning its output'''
     (pout, pin) = popen2.popen2(cmd, -1, 'b')
@@ -93,27 +119,6 @@
             return p_name
     return default
 
-def patch(strip, patchname, ui, cwd=None):
-    """apply the patch <patchname> to the working directory.
-    a list of patched files is returned"""
-    patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
-    args = []
-    if cwd:
-        args.append('-d %s' % shellquote(cwd))
-    fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
-                                       shellquote(patchname)))
-    files = {}
-    for line in fp:
-        line = line.rstrip()
-        ui.status("%s\n" % line)
-        if line.startswith('patching file '):
-            pf = parse_patch_output(line)
-            files.setdefault(pf, 1)
-    code = fp.close()
-    if code:
-        raise Abort(_("patch command failed: %s") % explain_exit(code)[0])
-    return files.keys()
-
 def binary(s):
     """return true if a string is binary data using diff's heuristic"""
     if s and '\0' in s[:4096]:
@@ -634,7 +639,8 @@
         try:
             rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
                         if f.endswith(".rc")])
-        except OSError, inst: pass
+        except OSError:
+            pass
         return rcs
 
     def os_rcpath():
@@ -902,14 +908,22 @@
                (string[-5] == '+' or string[-5] == '-') and
                string[-6].isspace())
 
+    # NOTE: unixtime = localunixtime + offset
     if hastimezone(string):
         date, tz = string[:-6], string[-5:]
         tz = int(tz)
         offset = - 3600 * (tz / 100) - 60 * (tz % 100)
     else:
-        date, offset = string, 0
-    when = int(time.mktime(time.strptime(date, format))) + offset
-    return when, offset
+        date, offset = string, None
+    timetuple = time.strptime(date, format)
+    localunixtime = int(calendar.timegm(timetuple))
+    if offset is None:
+        # local timezone
+        unixtime = int(time.mktime(timetuple))
+        offset = unixtime - localunixtime
+    else:
+        unixtime = localunixtime + offset
+    return unixtime, offset
 
 def parsedate(string, formats=None):
     """parse a localized time string and return a (unixtime, offset) tuple.
@@ -928,7 +942,9 @@
             else:
                 break
         else:
-            raise ValueError(_('invalid date: %r') % string)
+            raise ValueError(_('invalid date: %r '
+                               'see hg(1) manual page for details')
+                             % string)
     # validate explicit (probably user-specified) date and
     # time zone offset. values must fit in signed 32 bits for
     # current 32-bit linux runtimes. timezones go from UTC-12
@@ -947,6 +963,9 @@
     f = user.find('<')
     if f >= 0:
         user = user[f+1:]
+    f = user.find(' ')
+    if f >= 0:
+        user = user[:f]
     return user
 
 def walkrepos(path):
--- a/mercurial/verify.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/verify.py	Sat Oct 21 15:22:08 2006 -0400
@@ -102,21 +102,15 @@
                     (short(n), short(p)))
 
         try:
-            delta = mdiff.patchtext(repo.manifest.delta(n))
+            for f, fn in repo.manifest.readdelta(n).iteritems():
+                filenodes.setdefault(f, {})[fn] = 1
         except KeyboardInterrupt:
             repo.ui.warn(_("interrupted"))
             raise
         except Exception, inst:
-            err(_("unpacking manifest %s: %s") % (short(n), inst))
+            err(_("reading delta for manifest %s: %s") % (short(n), inst))
             continue
 
-        try:
-            ff = [ l.split('\0') for l in delta.splitlines() ]
-            for f, fn in ff:
-                filenodes.setdefault(f, {})[bin(fn[:40])] = 1
-        except (ValueError, TypeError), inst:
-            err(_("broken delta in manifest %s: %s") % (short(n), inst))
-
     repo.ui.status(_("crosschecking files in changesets and manifests\n"))
 
     for m, c in neededmanifests.items():
--- a/mercurial/version.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/mercurial/version.py	Sat Oct 21 15:22:08 2006 -0400
@@ -1,4 +1,4 @@
-# Copyright (C) 2005 by Intevation GmbH
+# Copyright (C) 2005, 2006 by Intevation GmbH
 # Author(s):
 # Thomas Arendsen Hein <thomas@intevation.de>
 #
--- a/setup.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/setup.py	Sat Oct 21 15:22:08 2006 -0400
@@ -9,7 +9,7 @@
 if not hasattr(sys, 'version_info') or sys.version_info < (2, 3):
     raise SystemExit, "Mercurial requires python 2.3 or later."
 
-import glob
+import os
 from distutils.core import setup, Extension
 from distutils.command.install_data import install_data
 
@@ -55,9 +55,9 @@
                 self.includes = []
             else:
                 self.includes = self.includes.split(',')
-            mercurial.packagescan.scan(self.build_lib,'mercurial')
-            mercurial.packagescan.scan(self.build_lib,'mercurial.hgweb')
-            mercurial.packagescan.scan(self.build_lib,'hgext')
+            mercurial.packagescan.scan(self.build_lib, 'mercurial')
+            mercurial.packagescan.scan(self.build_lib, 'mercurial.hgweb')
+            mercurial.packagescan.scan(self.build_lib, 'hgext')
             self.includes += mercurial.packagescan.getmodules()
             build_exe.finalize_options(self)
 except ImportError:
@@ -79,26 +79,25 @@
 if py2exe_for_demandload is not None:
     cmdclass['py2exe'] = py2exe_for_demandload
     py2exe_opts['console'] = ['hg']
+
 setup(name='mercurial',
-        version=mercurial.version.get_version(),
-        author='Matt Mackall',
-        author_email='mpm@selenic.com',
-        url='http://selenic.com/mercurial',
-        description='Scalable distributed SCM',
-        license='GNU GPL',
-        packages=['mercurial', 'mercurial.hgweb', 'hgext'],
-        ext_modules=[Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
-                    Extension('mercurial.bdiff', ['mercurial/bdiff.c'])],
-        data_files=[('mercurial/templates',
-                    ['templates/map'] +
-                    glob.glob('templates/map-*') +
-                    glob.glob('templates/*.tmpl')),
-                    ('mercurial/templates/static',
-                    glob.glob('templates/static/*'))],
-        cmdclass=cmdclass,
-        scripts=['hg', 'hgmerge'],
-        options=dict(bdist_mpkg=dict(zipdist=True,
-                                    license='COPYING',
-                                    readme='contrib/macosx/Readme.html',
-                                    welcome='contrib/macosx/Welcome.html')),
-        **py2exe_opts)
+      version=mercurial.version.get_version(),
+      author='Matt Mackall',
+      author_email='mpm@selenic.com',
+      url='http://selenic.com/mercurial',
+      description='Scalable distributed SCM',
+      license='GNU GPL',
+      packages=['mercurial', 'mercurial.hgweb', 'hgext'],
+      ext_modules=[Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
+                   Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
+                   Extension('mercurial.base85', ['mercurial/base85.c'])],
+      data_files=[(os.path.join('mercurial', root),
+                   [os.path.join(root, file_) for file_ in files])
+                  for root, dirs, files in os.walk('templates')],
+      cmdclass=cmdclass,
+      scripts=['hg', 'hgmerge'],
+      options=dict(bdist_mpkg=dict(zipdist=True,
+                                   license='COPYING',
+                                   readme='contrib/macosx/Readme.html',
+                                   welcome='contrib/macosx/Welcome.html')),
+      **py2exe_opts)
--- a/templates/changelog-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#header#
-<title>#repo|escape#: Changelog</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / changelog
-</div>
-
-<form action="#">
-<div class="search">
-<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"  />
-</div>
-</form>
-</div>
-
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;rev=#rev#;style=gitweb">shortlog</a> | changelog | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>#archives%archiveentry#<br/>
-<br/>
-#changenav%naventry#<br/>
-</div>
-
-#entries%changelogentry#
-
-<div class="page_nav">
-#changenav%naventry#<br/>
-</div>
-
-#footer#
--- a/templates/changelog-rss.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#header#
-    <title>#repo|escape# Changelog</title>
-    <description>#repo|escape# Changelog</description>
-    #entries%changelogentry#
-  </channel>
-</rss>
\ No newline at end of file
--- a/templates/changelog.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/changelog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -1,24 +1,24 @@
 #header#
 <title>#repo|escape#: changelog</title>
 <link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
+   href="#url#rss-log" title="RSS feed for #repo|escape#">
 </head>
 <body>
 
 <div class="buttons">
-<a href="?sl=#rev#">shortlog</a>
-<a href="?cmd=tags">tags</a>
-<a href="?mf=#manifest|short#;path=/">manifest</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#{sessionvars%urlparameter}">manifest</a>
 #archives%archiveentry#
-<a type="application/rss+xml" href="?style=rss">rss</a>
+<a type="application/rss+xml" href="#url#rss-log">rss</a>
 </div>
 
 <h2>changelog for #repo|escape#</h2>
 
-<form action="#">
+<form action="#url#log">
+{sessionvars%hiddenformentry}
 <p>
 <label for="search1">search:</label>
-<input type="hidden" name="cmd" value="changelog">
 <input name="rev" id="search1" type="text" size="30">
 navigate: <small class="navigate">#changenav%naventry#</small>
 </p>
@@ -26,10 +26,10 @@
 
 #entries%changelogentry#
 
-<form action="#">
+<form action="#url#log">
+{sessionvars%hiddenformentry}
 <p>
 <label for="search2">search:</label>
-<input type="hidden" name="cmd" value="changelog">
 <input name="rev" id="search2" type="text" size="30">
 navigate: <small class="navigate">#changenav%naventry#</small>
 </p>
--- a/templates/changelogentry-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-<div>
-<a class="title" href="?cmd=changeset;node=#node#;style=gitweb"><span class="age">#date|age# ago</span>#desc|strip|firstline|escape#</a>
-</div>
-<div class="title_text">
-<div class="log_link">
-<a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a><br/>
-</div>
-<i>#author|obfuscate# [#date|rfc822date#] rev #rev#</i><br/>
-</div>
-<div class="log_body">
-#desc|strip|escape|addbreaks#
-<br/>
-<br/>
-</div>
--- a/templates/changelogentry-rss.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-<item>
-    <title>#desc|strip|firstline|strip|escape#</title>
-    <link>#url#?cs=#node|short#</link>
-    <description><![CDATA[#desc|strip|escape|addbreaks#]]></description>
-    <author>#author|obfuscate#</author>
-    <pubDate>#date|rfc822date#</pubDate>
-</item>
--- a/templates/changelogentry.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/changelogentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -5,7 +5,7 @@
  </tr>
  <tr>
   <th class="revision">changeset #rev#:</th>
-  <td class="node"><a href="?cs=#node|short#">#node|short#</a></td>
+  <td class="node"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td>
  </tr>
  #parent%changelogparent#
  #child%changelogchild#
@@ -19,7 +19,7 @@
   <td class="date">#date|date#</td>
  </tr>
  <tr>
-  <th class="files"><a href="?mf=#manifest|short#;path=/">files</a>:</th>
+  <th class="files"><a href="#url#file/#node|short#{sessionvars%urlparameter}">files</a>:</th>
   <td class="files">#files#</td>
  </tr>
 </table>
--- a/templates/changeset-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-#header#
-<title>#repo|escape#: Changeset</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / changeset
-</div>
-
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;rev=#rev#;style=gitweb">shortlog</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>
-<a class="title" href="?cmd=changeset;node=#node#;style=raw">#desc|strip|escape|firstline#</a>
-</div>
-<div class="title_text">
-<table cellspacing="0">
-<tr><td>author</td><td>#author|obfuscate#</td></tr>
-<tr><td></td><td>#date|date# (#date|age# ago)</td></tr>
-<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|strip|escape|addbreaks#
-</div>
-
-<div class="title_text">
-<table cellspacing="0">
-#files#
-</table></div>
-
-<div class="page_body">#diff#</div>
-
-#footer#
--- a/templates/changeset-raw.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-#header#
-# HG changeset patch
-# User #author#
-# Date #date|hgdate#
-# Node ID #node#
-#parent%changesetparent#
-#desc#
-
-#diff#
--- a/templates/changeset.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/changeset.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -4,11 +4,11 @@
 <body>
 
 <div class="buttons">
-<a href="?cl=#rev#">changelog</a>
-<a href="?sl=#rev#">shortlog</a>
-<a href="?cmd=tags">tags</a>
-<a href="?mf=#manifest|short#;path=/">manifest</a>
-<a href="?cs=#node|short#;style=raw">raw</a>
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#{sessionvars%urlparameter}">manifest</a>
+<a href="#url#raw-rev/#node|short#">raw</a>
 #archives%archiveentry#
 </div>
 
@@ -17,7 +17,7 @@
 <table id="changesetEntry">
 <tr>
  <th class="changeset">changeset #rev#:</th>
- <td class="changeset"><a href="?cs=#node|short#">#node|short#</a></td>
+ <td class="changeset"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td>
 </tr>
 #parent%changesetparent#
 #child%changesetchild#
--- a/templates/error-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-#header#
-<title>#repo|escape#: Error</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / error
-</div>
-
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/>
-</div>
-
-<div>
-<br/>
-<i>An error occured while processing your request</i><br/>
-<br/>
-</div>
-
-#footer#
--- a/templates/fileannotate-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-#header#
-<title>#repo|escape#: Annotate</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / annotate
-</div>
-
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</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 | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/>
-</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>
-#rename%filerename#
-#parent%fileannotateparent#
-#child%fileannotatechild#
-<tr>
- <td class="metatag">manifest:</td>
- <td><a href="?mf=#manifest|short#;path=/;style=gitweb">#manifest|short#</a></td></tr>
-<tr>
- <td class="metatag">author:</td>
- <td>#author|obfuscate#</td></tr>
-<tr>
- <td class="metatag">date:</td>
- <td>#date|date# (#date|age# ago)</td></tr>
-<tr>
- <td class="metatag">permissions:</td>
- <td>#permissions|permissions#</td></tr>
-</table>
-
-<div class="page_body">
-<table>
-#annotate%annotateline#
-</table>
-</div>
-
-#footer#
--- a/templates/fileannotate-raw.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-#header#
-#annotate%annotateline#
-#footer#
-
-
--- a/templates/fileannotate.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/fileannotate.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -4,14 +4,14 @@
 <body>
 
 <div class="buttons">
-<a href="?cl=#rev#">changelog</a>
-<a href="?sl=#rev#">shortlog</a>
-<a href="?tags=">tags</a>
-<a href="?cs=#node|short#">changeset</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>
-<a href="?fa=#filenode|short#;file=#file|urlescape#;style=raw">raw</a>
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#rev/#node|short#{sessionvars%urlparameter}">changeset</a>
+<a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a>
+<a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>
+<a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a>
+<a href="#url#raw-annotate/#node|short#/#file|urlescape#">raw</a>
 </div>
 
 <h2>Annotate #file|escape#</h2>
@@ -19,8 +19,7 @@
 <table>
 <tr>
  <td class="metatag">changeset #rev#:</td>
- <td><a href="?cs=#node|short#">#node|short#</a></td></tr>
-#rename%filerename#
+ <td><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>
 #parent%fileannotateparent#
 #child%fileannotatechild#
 <tr>
@@ -32,6 +31,10 @@
 <tr>
  <td class="metatag">permissions:</td>
  <td>#permissions|permissions#</td></tr>
+<tr>
+  <td class="metatag">description:</td>
+  <td>{desc|strip|escape|addbreaks}</td>
+</tr>
 </table>
 
 <br/>
--- a/templates/filediff-raw.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-#header#
-#diff#
-#footer#
-
-
--- a/templates/filediff.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/filediff.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -4,14 +4,14 @@
 <body>
 
 <div class="buttons">
-<a href="?cl=#rev#">changelog</a>
-<a href="?sl=#rev#">shortlog</a>
-<a href="?tags=">tags</a>
-<a href="?cs=#node|short#">changeset</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>
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#rev/#node|short#{sessionvars%urlparameter}">changeset</a>
+<a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>
+<a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a>
+<a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a>
+<a href="#url#raw-diff/#node|short#/#file|urlescape#">raw</a>
 </div>
 
 <h2>#file|escape#</h2>
@@ -19,7 +19,7 @@
 <table id="filediffEntry">
 <tr>
  <th class="revision">revision #rev#:</th>
- <td class="revision"><a href="?cs=#node|short#">#node|short#</a></td>
+ <td class="revision"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td>
 </tr>
 #parent%filediffparent#
 #child%filediffchild#
--- a/templates/filelog-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-#header#
-<title>#repo|escape#: File revisions</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / file revisions
-</div>
-
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</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>
-
-<div class="title" >#file|urlescape#</div>
-
-<table>
-#entries%filelogentry#
-</table>
-
-#footer#
--- a/templates/filelog-rss.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#header#
-    <title>#repo|escape#: #file|escape# history</title>
-    <description>#file|escape# revision history</description>
-    #entries%filelogentry#
-  </channel>
-</rss>
--- a/templates/filelog.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/filelog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -1,22 +1,24 @@
 #header#
 <title>#repo|escape#: #file|escape# history</title>
 <link rel="alternate" type="application/rss+xml"
-   href="?fl=0;file=#file|urlescape#;style=rss" title="RSS feed for #repo|escape#:#file#">
+   href="#url#rss-log/tip/#file|urlescape#" title="RSS feed for #repo|escape#:#file#">
 </head>
 </head>
 <body>
 
 <div class="buttons">
-<a href="?cl=tip">changelog</a>
-<a href="?sl=tip">shortlog</a>
-<a href="?tags=">tags</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>
+<a href="#url#log{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>
+<a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a>
+<a type="application/rss+xml" href="#url#rss-log/tip/#file|urlescape#">rss</a>
 </div>
 
 <h2>#file|escape# revision history</h2>
 
+<p>navigate: <small class="navigate">{nav%filenaventry}</small></p>
+
 #entries%filelogentry#
 
 #footer#
--- a/templates/filelogentry-rss.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-<item>
-    <title>#desc|strip|firstline|strip|escape#</title>
-    <link>#url#?f=#filenode|short#;file=#file|urlescape#</link>
-    <description><![CDATA[#desc|strip|escape|addbreaks#]]></description>
-    <author>#author|obfuscate#</author>
-    <pubDate>#date|rfc822date#</pubDate>>
-</item>
--- a/templates/filelogentry.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/filelogentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -1,14 +1,14 @@
 <table class="logEntry parity#parity#">
  <tr>
   <th class="age">#date|age# ago:</th>
-  <th class="firstline"><a href="?cs=#node|short#">#desc|strip|firstline|escape#</a></th>
+  <th class="firstline"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#desc|strip|firstline|escape#</a></th>
  </tr>
  <tr>
   <th class="revision">revision #filerev#:</td>
   <td class="node">
-   <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>
+   <a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a>
+   <a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">(diff)</a>
+   <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">(annotate)</a>
   </td>
  </tr>
  #rename%filelogrename#
--- a/templates/filerevision-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-#header#
-<title>#repo|escape#: File revision</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / file revision
-</div>
-
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</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|escape#</div>
-
-<table>
-<tr>
- <td class="metatag">changeset #rev#:</td>
- <td><a href="?cs=#node|short#;style=gitweb">#node|short#</a></td></tr>
-#rename%filerename#
-#parent%fileannotateparent#
-#child%fileannotatechild#
-<tr>
- <td class="metatag">manifest:</td>
- <td><a href="?mf=#manifest|short#;path=/;style=gitweb">#manifest|short#</a></td></tr>
-<tr>
- <td class="metatag">author:</td>
- <td>#author|obfuscate#</td></tr>
-<tr>
- <td class="metatag">date:</td>
- <td>#date|date# (#date|age# ago)</td></tr>
-<tr>
- <td class="metatag">permissions:</td>
- <td>#permissions|permissions#</td></tr>
-</table>
-
-<div class="page_body">
-#text%fileline#
-</div>
-
-#footer#
--- a/templates/filerevision.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/filerevision.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -4,14 +4,14 @@
 <body>
 
 <div class="buttons">
-<a href="?cl=#rev#">changelog</a>
-<a href="?sl=#rev#">shortlog</a>
-<a href="?tags=">tags</a>
-<a href="?cs=#node|short#">changeset</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>
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#rev/#node|short#{sessionvars%urlparameter}">changeset</a>
+<a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a>
+<a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a>
+<a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a>
+<a href="#url#raw-file/#node|short#/#file|urlescape#">raw</a>
 </div>
 
 <h2>#file|escape#</h2>
@@ -19,8 +19,7 @@
 <table>
 <tr>
  <td class="metatag">changeset #rev#:</td>
- <td><a href="?cs=#node|short#">#node|short#</a></td></tr>
-#rename%filerename#
+ <td><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>
 #parent%filerevparent#
 #child%filerevchild#
 <tr>
@@ -32,6 +31,10 @@
 <tr>
  <td class="metatag">permissions:</td>
  <td>#permissions|permissions#</td></tr>
+<tr>
+  <td class="metatag">description:</td>
+  <td>{desc|strip|escape|addbreaks}</td>
+</tr>
 </table>
 
 <pre>
--- a/templates/footer-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-<div class="page_footer">
-<div class="page_footer_text">#repo|escape#</div>
-<a class="rss_logo" href="?cmd=changelog;style=rss">RSS</a>
-</div>
-</body>
-</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/changelog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,32 @@
+#header#
+<title>#repo|escape#: Changelog</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">#repo|escape#</a> / changelog
+</div>
+
+<form action="{url}log">
+{sessionvars%hiddenformentry}
+<div class="search">
+<input type="text" name="rev"  />
+</div>
+</form>
+</div>
+
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> | <a href="{url}shortlog/#rev#{sessionvars%urlparameter}">shortlog</a> | changelog | <a href="{url}tags{sessionvars%urlparameter}">tags</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a>#archives%archiveentry#<br/>
+<br/>
+#changenav%naventry#<br/>
+</div>
+
+#entries%changelogentry#
+
+<div class="page_nav">
+#changenav%naventry#<br/>
+</div>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/changelogentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,14 @@
+<div>
+<a class="title" href="{url}rev/#node|short#{sessionvars%urlparameter}"><span class="age">#date|age# ago</span>#desc|strip|firstline|escape#</a>
+</div>
+<div class="title_text">
+<div class="log_link">
+<a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a><br/>
+</div>
+<i>#author|obfuscate# [#date|rfc822date#] rev #rev#</i><br/>
+</div>
+<div class="log_body">
+#desc|strip|escape|addbreaks#
+<br/>
+<br/>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/changeset.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,41 @@
+#header#
+<title>#repo|escape#: Changeset</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="#url#summary{sessionvars%urlparameter}">#repo|escape#</a> / changeset
+</div>
+
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> | <a href="{url}shortlog/#rev#{sessionvars%urlparameter}">shortlog</a> | <a href="{url}log/#rev#{sessionvars%urlparameter}">changelog</a> | <a href="{url}tags{sessionvars%urlparameter}">tags</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a> | changeset | <a href="{url}raw-rev/#node|short#">raw</a> #archives%archiveentry#<br/>
+</div>
+
+<div>
+<a class="title" href="{url}raw-rev/#node|short#">#desc|strip|escape|firstline#</a>
+</div>
+<div class="title_text">
+<table cellspacing="0">
+<tr><td>author</td><td>#author|obfuscate#</td></tr>
+<tr><td></td><td>#date|date# (#date|age# ago)</td></tr>
+<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="{url}file/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>
+#parent%changesetparent#
+#child%changesetchild#
+#changesettag#
+</table></div>
+
+<div class="page_body">
+#desc|strip|escape|addbreaks#
+</div>
+<div class="list_head"></div>
+<div class="title_text">
+<table cellspacing="0">
+#files#
+</table></div>
+
+<div class="page_body">#diff#</div>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/error.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,23 @@
+#header#
+<title>#repo|escape#: Error</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">#repo|escape#</a> / error
+</div>
+
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> | <a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> | <a href="{url}log{sessionvars%urlparameter}">changelog</a> | <a href="{url}tags{sessionvars%urlparameter}">tags</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a><br/>
+</div>
+
+<div class="page_body">
+<br/>
+<i>An error occured while processing your request</i><br/>
+<br/>
+{error|escape}
+</div>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/fileannotate.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,59 @@
+#header#
+<title>#repo|escape#: Annotate</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">#repo|escape#</a> / annotate
+</div>
+
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
+<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
+<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
+<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
+<a href="{url}file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a> |
+<a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> |
+<a href="{url}file/{node|short}/#file|urlescape#{sessionvars%urlparameter}">file</a> |
+<a href="{url}log/{node|short}/#file|urlescape#{sessionvars%urlparameter}">revisions</a> |
+annotate |
+<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
+<a href="{url}raw-annotate/{node|short}/#file|urlescape#">raw</a><br/>
+</div>
+
+<div class="title">#file|escape#</div>
+
+<div class="title_text">
+<table>
+<tr>
+ <td class="metatag">changeset #rev#:</td>
+ <td><a href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>
+#parent%fileannotateparent#
+#child%fileannotatechild#
+<tr>
+ <td class="metatag">manifest:</td>
+ <td><a href="{url}file/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>
+<tr>
+ <td class="metatag">author:</td>
+ <td>#author|obfuscate#</td></tr>
+<tr>
+ <td class="metatag">date:</td>
+ <td>#date|date# (#date|age# ago)</td></tr>
+<tr>
+ <td class="metatag">permissions:</td>
+ <td>#permissions|permissions#</td></tr>
+</table>
+</div>
+
+<div class="page_path">
+{desc|strip|escape|addbreaks}
+</div>
+<div class="page_body">
+<table>
+#annotate%annotateline#
+</table>
+</div>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/filediff.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,47 @@
+{header}
+<title>{repo|escape}: diff {file|escape}</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for {repo|escape}">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">{repo|escape}</a> / annotate
+</div>
+
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
+<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
+<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
+<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
+<a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">manifest</a> |
+<a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a> |
+<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
+<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">revisions</a> |
+<a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> |
+diff |
+<a href="{url}raw-diff/{node|short}/{file|urlescape}">raw</a><br/>
+</div>
+
+<div class="title">{file|escape}</div>
+
+<table>
+<tr>
+ <td class="metatag">changeset {rev}:</td>
+ <td><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
+</tr>
+{parent%filediffparent}
+{child%filediffchild}
+<tr>
+ <td class="metatag">manifest:</td>
+ <td><a href="{url}file/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
+</tr>
+</table>
+
+<div class="page_body">
+<table>
+{diff}
+</table>
+</div>
+
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/filelog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,33 @@
+#header#
+<title>#repo|escape#: File revisions</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">#repo|escape#</a> / file revisions
+</div>
+
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
+<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
+<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
+<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
+<a href="{url}file/{node|short}/#file|urlescape#{sessionvars%urlparameter}">file</a> |
+revisions |
+<a href="{url}annotate/{node|short}/#file|urlescape#{sessionvars%urlparameter}">annotate</a> |
+<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
+<a href="{url}rss-log/#node|short#/#file|urlescape#">rss</a><br/>
+
+<br/>
+{nav%filenaventry}<br/>
+</div>
+
+<div class="title" >#file|urlescape#</div>
+
+<table>
+#entries%filelogentry#
+</table>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/filerevision.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,58 @@
+#header#
+<title>#repo|escape#: File revision</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">#repo|escape#</a> / file revision
+</div>
+
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
+<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
+<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
+<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
+<a href="{url}file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a> |
+<a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> |
+file |
+<a href="{url}log/{node|short}/#file|urlescape#{sessionvars%urlparameter}">revisions</a> |
+<a href="{url}annotate/{node|short}/#file|urlescape#{sessionvars%urlparameter}">annotate</a> |
+<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
+<a href="{url}raw-file/{node|short}/#file|urlescape#">raw</a><br/>
+</div>
+
+<div class="title">#file|escape#</div>
+
+<div class="title_text">
+<table>
+<tr>
+ <td class="metatag">changeset #rev#:</td>
+ <td><a href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>
+#parent%filerevparent#
+#child%filerevchild#
+<tr>
+ <td class="metatag">manifest:</td>
+ <td><a href="{url}file/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>
+<tr>
+ <td class="metatag">author:</td>
+ <td>#author|obfuscate#</td></tr>
+<tr>
+ <td class="metatag">date:</td>
+ <td>#date|date# (#date|age# ago)</td></tr>
+<tr>
+ <td class="metatag">permissions:</td>
+ <td>#permissions|permissions#</td></tr>
+</table>
+</div>
+
+<div class="page_path">
+{desc|strip|escape|addbreaks}
+</div>
+
+<div class="page_body">
+#text%fileline#
+</div>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/footer.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,6 @@
+<div class="page_footer">
+<div class="page_footer_text">#repo|escape#</div>
+<a class="rss_logo" href="#url#rss-log">RSS</a>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/header.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,11 @@
+Content-type: text/html
+
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+<head>
+<link rel="icon" href="{url}static/hgicon.png" type="image/png">
+<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
+<meta name="robots" content="index, nofollow"/>
+<link rel="stylesheet" href="{url}static/style-gitweb.css" type="text/css" />
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/index.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,23 @@
+#header#
+<title>Mercurial repositories index</title>
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a>Repositories list
+</div>
+
+<table cellspacing="0">
+    <tr>
+        <td><a href="?sort=#sort_name#">Name</a></td>
+        <td><a href="?sort=#sort_description#">Description</a></td>
+        <td><a href="?sort=#sort_contact#">Contact</a></td>
+        <td><a href="?sort=#sort_lastchange#">Last change</a></td>
+        <td>&nbsp;</td>
+    <tr>
+    #entries%indexentry#
+</table>
+<div class="page_footer">
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/manifest.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,33 @@
+#header#
+<title>#repo|escape#: Manifest</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">#repo|escape#</a> / manifest
+</div>
+
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
+<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
+<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
+<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
+manifest |
+<a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> #archives%archiveentry#<br/>
+</div>
+
+<div class="title" >#path|escape#</div>
+<div class="page_body">
+<table cellspacing="0">
+<tr class="light">
+<td style="font-family:monospace">drwxr-xr-x</td>
+<td style="font-family:monospace"></td>
+<td><a href="{url}file/#node|short##up|urlescape#{sessionvars%urlparameter}">[up]</a></td>
+<td class="link">&nbsp;</td>
+</tr>
+#dentries%manifestdirentry#
+#fentries%manifestfileentry#
+</table>
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/map	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,56 @@
+default = 'summary'
+header = header.tmpl
+footer = footer.tmpl
+search = search.tmpl
+changelog = changelog.tmpl
+summary = summary.tmpl
+error = error.tmpl
+naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
+navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
+filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
+filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#</a> '
+filenodelink = '<tr class="parity#parity#"><td><a class="list" href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">#file|escape#</a></td><td></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> | <a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a> | <a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a></td></tr>'
+fileellipses = '...'
+changelogentry = changelogentry.tmpl
+searchentry = changelogentry.tmpl
+changeset = changeset.tmpl
+manifest = manifest.tmpl
+manifestdirentry = '<tr class="parity#parity#"><td style="font-family:monospace">drwxr-xr-x</td><td style="font-family:monospace"></td><td><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">#basename|escape#/</a></td><td class="link"><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a></td></tr>'
+manifestfileentry = '<tr class="parity#parity#"><td style="font-family:monospace">#permissions|permissions#</td><td style="font-family:monospace" align=right>#size#</td><td class="list"><a class="list" href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#basename|escape#</a></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a> | <a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a></td></tr>'
+filerevision = filerevision.tmpl
+fileannotate = fileannotate.tmpl
+filediff = filediff.tmpl
+filelog = filelog.tmpl
+fileline = '<div style="font-family:monospace" class="parity#parity#"><pre><span class="linenr">   #linenumber#</span> #line|escape#</pre></div>'
+annotateline = '<tr style="font-family:monospace" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
+difflineplus = '<div style="color:#008800;">#line|escape#</div>'
+difflineminus = '<div style="color:#cc0000;">#line|escape#</div>'
+difflineat = '<div style="color:#990099;">#line|escape#</div>'
+diffline = '<div>#line|escape#</div>'
+changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+changesetparent = '<tr><td>parent</td><td style="font-family:monospace"><a class="list" href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filerevparent = '<tr><td class="metatag">parent:</td><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
+filerename = '{file|escape}@'
+filelogrename = '| <a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">base</a>'
+fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
+changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+changesetchild = '<tr><td>child</td><td style="font-family:monospace"><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filerevchild = '<tr><td class="metatag">child:</td><td><a href="{url}file/{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="{url}annotate/{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+tags = tags.tmpl
+tagentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/{node|short}{sessionvars%urlparameter}"><b>#tag|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}log/#node|short#{sessionvars%urlparameter}">changelog</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
+diffblock = '<pre>#lines#</pre>'
+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="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
+filelogparent = '<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="{url}file/{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filediffchild = '<tr><th class="child">child {rev}:</th><td class="child"><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
+filelogchild = '<tr><td align="right">child #rev#:&nbsp;</td><td><a href="{url}file{node|short}/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+shortlog = shortlog.tmpl
+shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
+filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>&nbsp;|&nbsp;<a href="{url}diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a>&nbsp;|&nbsp;<a href="{url}annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> #rename%filelogrename#</td></tr>'
+archiveentry = ' | <a href="{url}archive/{node|short}{extension}">#type|escape#</a> '
+indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#{sessionvars%urlparameter}"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>' 
+index = index.tmpl
+urlparameter = '#separator##name#=#value|urlescape#'
+hiddenformentry = '<input type="hidden" name="#name#" value="#value|escape#" />'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/search.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,27 @@
+#header#
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
+<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
+<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
+<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
+<a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a><br/>
+</div>
+
+<h2>searching for #query|escape#</h2>
+
+<form action="{url}log">
+{sessionvars%hiddenformentry}
+search:
+<input name="rev" type="text" width="30" value="#query|escape#">
+</form>
+
+#entries#
+
+<form action="{url}log">
+{sessionvars%hiddenformentry}
+search:
+<input type="hidden" name="style" value="gitweb">
+<input name="rev" type="text" width="30">
+</form>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/shortlog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,34 @@
+#header#
+<title>#repo|escape#: Shortlog</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">#repo|escape#</a> / shortlog
+</div>
+
+<form action="{url}log">
+{sessionvars%hiddenformentry}
+<div class="search">
+<input type="text" name="rev"  />
+</div>
+</form>
+</div>
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
+shortlog |
+<a href="{url}log/#rev#{sessionvars%urlparameter}">changelog</a> |
+<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
+<a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a>#archives%archiveentry#<br/>
+<br/>
+
+#changenav%navshortentry#<br/>
+</div>
+
+<table cellspacing="0">
+#entries%shortlogentry#
+</table>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/summary.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,39 @@
+#header#
+<title>#repo|escape#: Summary</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">#repo|escape#</a> / summary
+</div>
+<div class="page_nav">
+summary |
+<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
+<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
+<a href="{url}tags{sessionvars%urlparameter}">tags</a> |
+<a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a>#archives%archiveentry#
+<br/>
+</div>
+
+<div class="title">&nbsp;</div>
+<table cellspacing="0">
+<tr><td>description</td><td>#desc#</td></tr>
+<tr><td>owner</td><td>#owner|escape#</td></tr>
+<tr><td>last change</td><td>#lastchange|rfc822date#</td></tr>
+</table>
+
+<div><a  class="title" href="{url}log{sessionvars%urlparameter}">changes</a></div>
+<table cellspacing="0">
+#shortlog#
+<tr class="light"><td colspan="3"><a class="list" href="{url}log{sessionvars%urlparameter}">...</a></td></tr>
+</table>
+
+<div><a class="title" href="{url}tags{sessionvars%urlparameter}">tags</a></div>
+<table cellspacing="0">
+#tags#
+<tr class="light"><td colspan="3"><a class="list" href="{url}tags{sessionvars%urlparameter}">...</a></td></tr>
+</table>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/gitweb/tags.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,25 @@
+#header#
+<title>#repo|escape#: Tags</title>
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{sessionvars%urlparameter}">#repo|escape#</a> / tags
+</div>
+
+<div class="page_nav">
+<a href="{url}summary{sessionvars%urlparameter}">summary</a> |
+<a href="{url}shortlog{sessionvars%urlparameter}">shortlog</a> |
+<a href="{url}log{sessionvars%urlparameter}">changelog</a> |
+tags |
+<a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a>
+<br/>
+</div>
+
+<table cellspacing="0">
+#entries%tagentry#
+</table>
+
+#footer#
--- a/templates/header-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-Content-type: text/html
-
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
-<head>
-<link rel="icon" href="?static=hgicon.png" type="image/png">
-<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
-<meta name="robots" content="index, nofollow"/>
-<link rel="stylesheet" href="?static=style-gitweb.css" type="text/css" />
-
--- a/templates/header-raw.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-Content-type: text/plain
--- a/templates/header-rss.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-Content-type: text/xml
-
-<rss version="2.0">
-  <channel>
-    <link>#url#</link>
-    <language>en-us</language>
--- a/templates/header.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/header.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -3,6 +3,6 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
-<link rel="icon" href="?static=hgicon.png" type="image/png">
+<link rel="icon" href="#url#static/hgicon.png" type="image/png">
 <meta name="robots" content="index, nofollow" />
-<link rel="stylesheet" href="?static=style.css" type="text/css" />
+<link rel="stylesheet" href="#url#static/style.css" type="text/css" />
--- a/templates/manifest-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#header#
-<title>#repo|escape#: Manifest</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / manifest
-</div>
-
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</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>
-<div class="page_body">
-<table cellspacing="0">
-<tr class="light">
-<td style="font-family:monospace">drwxr-xr-x</td>
-<td><a href="?cmd=manifest;manifest=#manifest#;path=#up|urlescape#;style=gitweb">[up]</a></td>
-<td class="link">&nbsp;</td>
-</tr>
-#dentries%manifestdirentry#
-#fentries%manifestfileentry#
-</table>
-#footer#
--- a/templates/manifest.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/manifest.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -1,13 +1,13 @@
 #header#
-<title>#repo|escape#: manifest #manifest|short#</title>
+<title>#repo|escape#: manifest for changeset #node|short#</title>
 </head>
 <body>
 
 <div class="buttons">
-<a href="?cl=#rev#">changelog</a>
-<a href="?sl=#rev#">shortlog</a>
-<a href="?tags=">tags</a>
-<a href="?cs=#node|short#">changeset</a>
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#rev/#node|short#{sessionvars%urlparameter}">changeset</a>
 #archives%archiveentry#
 </div>
 
@@ -16,7 +16,9 @@
 <table cellpadding="0" cellspacing="0">
 <tr class="parity1">
   <td><tt>drwxr-xr-x</tt>&nbsp;
-  <td><a href="?mf=#manifest|short#;path=#up|urlescape#">[up]</a>
+  <td>&nbsp;
+  <td><a href="#url#file/#node|short##up|urlescape#{sessionvars%urlparameter}">[up]</a>
+</tr>
 #dentries%manifestdirentry#
 #fentries%manifestfileentry#
 </table>
--- a/templates/map	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/map	Sat Oct 21 15:22:08 2006 -0400
@@ -5,49 +5,52 @@
 changelog = changelog.tmpl
 shortlog = shortlog.tmpl
 shortlogentry = shortlogentry.tmpl
-naventry = '<a href="?cl=#rev#">#label|escape#</a> '
-navshortentry = '<a href="?sl=#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> '
+naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
+navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
+filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
+filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#</a> '
+filenodelink = '<a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#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|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>'
+manifestdirentry = '<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td>&nbsp;<td><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">#basename|escape#/</a>'
+manifestfileentry = '<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td align=right><tt>#size#</tt>&nbsp;<td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#basename|escape#</a>'
 filerevision = filerevision.tmpl
 fileannotate = fileannotate.tmpl
 filediff = filediff.tmpl
 filelog = filelog.tmpl
 fileline = '<div class="parity#parity#"><span class="lineno">#linenumber#</span>#line|escape#</div>'
 filelogentry = filelogentry.tmpl
-annotateline = '<tr class="parity#parity#"><td class="annotate"><a href="?cs=#node|short#">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
+annotateline = '<tr class="parity#parity#"><td class="annotate"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
 difflineplus = '<span class="plusline">#line|escape#</span>'
 difflineminus = '<span class="minusline">#line|escape#</span>'
 difflineat = '<span class="atline">#line|escape#</span>'
 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|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><th>base:</th><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>'
+changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+changesetparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filerevparent = '<tr><td class="metatag">parent:</td><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
+filerename = '{file|escape}@'
+filelogrename = '<tr><th>base:</th><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#@#node|short#</a></td></tr>'
+fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
+changesetchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filerevchild = '<tr><td class="metatag">child:</td><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
 tags = tags.tmpl
-tagentry = '<li class="tagEntry parity#parity#"><tt class="node">#node#</tt> <a href="?cs=#node|short#">#tag|escape#</a></li>'
+tagentry = '<li class="tagEntry parity#parity#"><tt class="node">#node#</tt> <a href="#url#rev/#node|short#{sessionvars%urlparameter}">#tag|escape#</a></li>'
 diffblock = '<pre class="parity#parity#">#lines#</pre>'
 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><th>parent #rev#:</th><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><th>child #rev#:</th><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>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a href="#url#?cl=tip;style=rss">RSS</a> #archives%archiveentry#</td></tr>'
+filediffparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filelogparent = '<tr><th>parent #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filediffchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filelogchild = '<tr><th>child #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+indexentry = '<tr class="parity#parity#"><td><a href="#url#{sessionvars%urlparameter}">#name|escape#</a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
 index = index.tmpl
-archiveentry = '<a href="#url#?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> '
+archiveentry = '<a href="#url#archive/#node|short##extension|urlescape#">#type|escape#</a> '
 notfound = notfound.tmpl
 error = error.tmpl
+urlparameter = '#separator##name#=#value|urlescape#'
+hiddenformentry = '<input type="hidden" name="#name#" value="#value|escape#" />'
--- a/templates/map-cmdline.default	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/map-cmdline.default	Sat Oct 21 15:22:08 2006 -0400
@@ -1,12 +1,15 @@
 changeset = 'changeset:   {rev}:{node|short}\n{tags}{short_parents}user:        {author}\ndate:        {date|date}\nsummary:     {desc|firstline}\n\n'
 changeset_quiet = '{rev}:{node|short}\n'
-changeset_verbose = 'changeset:   {rev}:{node}\n{tags}{parents}{manifest}user:        {author}\ndate:        {date|date}\nfiles:       {files}\n{file_adds}{file_dels}description:\n{desc|strip}\n\n\n'
+changeset_verbose = 'changeset:   {rev}:{node}\n{tags}{parents}{manifest}user:        {author}\ndate:        {date|date}\nfiles:       {files}\n{file_adds}{file_dels}{file_copies}description:\n{desc|strip}\n\n\n'
 start_file_adds = 'files+:     '
 file_add = ' {file_add}'
 end_file_adds = '\n'
 start_file_dels = 'files-:     '
 file_del = ' {file_del}'
 end_file_dels = '\n'
+start_file_copies = 'copies:     '
+file_copy = ' {name} ({source})'
+end_file_copies = '\n'
 short_parent = 'parent:      {rev}:{node|short}\n'
 parent = 'parent:      {rev}:{node}\n'
 manifest = 'manifest:    {rev}:{node}\n'
--- a/templates/map-gitweb	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-default = 'summary'
-header = header-gitweb.tmpl
-footer = footer-gitweb.tmpl
-search = search-gitweb.tmpl
-changelog = changelog-gitweb.tmpl
-summary = summary-gitweb.tmpl
-error = error-gitweb.tmpl
-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|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
-fileline = '<div style="font-family:monospace; white-space: pre;" class="parity#parity#"><span class="linenr">   #linenumber#</span> #line|escape#</div>'
-annotateline = '<tr style="font-family:monospace; white-space: pre;" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="?cs=#node|short#;style=gitweb">#author|obfuscate#@#rev#</a></td><td>#line|escape#</td></tr>'
-difflineplus = '<div class="pre" style="color:#008800;">#line|escape#</div>'
-difflineminus = '<div class="pre" style="color:#cc0000;">#line|escape#</div>'
-difflineat = '<div class="pre" style="color:#990099;">#line|escape#</div>'
-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|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>'
-filerename = '<tr><td class="metatag">parent:</td><td><a href="?f=#node|short#;file=#file|urlescape#;style=gitweb">#file|escape#@#node|short#</a></td></tr>'
-filelogrename = '| <a href="?f=#node|short#;file=#file|urlescape#;style=gitweb">base</a>'
-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 class="age"><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|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|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 class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|strip|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 class="age"><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|strip|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> #rename%filelogrename#</td></tr>'
-archiveentry = ' | <a href="?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> '
--- a/templates/map-raw	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-header = header-raw.tmpl
-footer = ''
-changeset = changeset-raw.tmpl
-difflineplus = '#line#'
-difflineminus = '#line#'
-difflineat = '#line#'
-diffline = '#line#'
-changesetparent = '# Parent #node#'
-changesetchild = '# Child #node#'
-filenodelink = ''
-filerevision = '#rawfileheader##raw#'
-fileline = '#line#'
-diffblock = '#lines#'
-filediff = filediff-raw.tmpl
-fileannotate = fileannotate-raw.tmpl
-annotateline = '#author#@#rev#: #line#'
--- a/templates/map-rss	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-default = 'changelog'
-header = header-rss.tmpl
-changelog = changelog-rss.tmpl
-changelogentry = changelogentry-rss.tmpl
-filelog = filelog-rss.tmpl
-filelogentry = filelogentry-rss.tmpl
-tags = tags-rss.tmpl
-tagentry = tagentry-rss.tmpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/changelog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,38 @@
+#header#
+<title>#repo|escape#: changelog</title>
+<link rel="alternate" type="application/rss+xml"
+   href="#url#rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#{sessionvars%urlparameter}">manifest</a>
+#archives%archiveentry#
+<a type="application/rss+xml" href="#url#rss-log">rss</a>
+</div>
+
+<h2>changelog for #repo|escape#</h2>
+
+<form action="#url#log">
+{sessionvars%hiddenformentry}
+<p>
+<label for="search1">search:</label>
+<input name="rev" id="search1" type="text" size="30">
+navigate: <small class="navigate">#changenav%naventry#</small>
+</p>
+</form>
+
+#entries%changelogentry#
+
+<form action="#url#log">
+{sessionvars%hiddenformentry}
+<p>
+<label for="search2">search:</label>
+<input name="rev" id="search2" type="text" size="30">
+navigate: <small class="navigate">#changenav%naventry#</small>
+</p>
+</form>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/changelogentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,25 @@
+<table class="logEntry parity#parity#">
+ <tr>
+  <th class="age">#date|age# ago:</th>
+  <th class="firstline">#desc|strip|firstline|escape#</th>
+ </tr>
+ <tr>
+  <th class="revision">changeset #rev#:</th>
+  <td class="node"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td>
+ </tr>
+ #parent%changelogparent#
+ #child%changelogchild#
+ #changelogtag#
+ <tr>
+  <th class="author">author:</th>
+  <td class="author">#author|obfuscate#</td>
+ </tr>
+ <tr>
+  <th class="date">date:</th>
+  <td class="date">#date|date#</td>
+ </tr>
+ <tr>
+  <th class="files"><a href="#url#file/#node|short#{sessionvars%urlparameter}">files</a>:</th>
+  <td class="files">#files#</td>
+ </tr>
+</table>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/changeset.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,47 @@
+#header#
+<title>#repo|escape#: changeset #node|short#</title>
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#{sessionvars%urlparameter}">manifest</a>
+<a href="#url#raw-rev/#node|short#">raw</a>
+#archives%archiveentry#
+</div>
+
+<h2>changeset: #desc|strip|escape|firstline#</h2>
+
+<table id="changesetEntry">
+<tr>
+ <th class="changeset">changeset #rev#:</th>
+ <td class="changeset"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td>
+</tr>
+#parent%changesetparent#
+#child%changesetchild#
+#changesettag#
+<tr>
+ <th class="author">author:</th>
+ <td class="author">#author|obfuscate#</td>
+</tr>
+<tr>
+ <th class="date">date:</th>
+ <td class="date">#date|date# (#date|age# ago)</td></tr>
+<tr>
+ <th class="files">files:</th>
+ <td class="files">#files#</td></tr>
+<tr>
+ <th class="description">description:</th>
+ <td class="description">#desc|strip|escape|addbreaks#</td>
+</tr>
+</table>
+
+<div id="changesetDiff">
+#diff#
+</div>
+
+#footer#
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/fileannotate.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,46 @@
+#header#
+<title>#repo|escape#: #file|escape# annotate</title>
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#rev/#node|short#{sessionvars%urlparameter}">changeset</a>
+<a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a>
+<a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>
+<a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a>
+<a href="#url#raw-annotate/#node|short#/#file|urlescape#">raw</a>
+</div>
+
+<h2>Annotate #file|escape#</h2>
+
+<table>
+<tr>
+ <td class="metatag">changeset #rev#:</td>
+ <td><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>
+#parent%fileannotateparent#
+#child%fileannotatechild#
+<tr>
+ <td class="metatag">author:</td>
+ <td>#author|obfuscate#</td></tr>
+<tr>
+ <td class="metatag">date:</td>
+ <td>#date|date# (#date|age# ago)</td></tr>
+<tr>
+ <td class="metatag">permissions:</td>
+ <td>#permissions|permissions#</td></tr>
+<tr>
+  <td class="metatag">description:</td>
+  <td>{desc|strip|escape|addbreaks}</td>
+</tr>
+</table>
+
+<br/>
+
+<table cellspacing="0" cellpadding="0">
+#annotate%annotateline#
+</table>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/filediff.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,34 @@
+#header#
+<title>#repo|escape#: #file|escape# diff</title>
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#rev/#node|short#{sessionvars%urlparameter}">changeset</a>
+<a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>
+<a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a>
+<a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a>
+<a href="#url#raw-diff/#node|short#/#file|urlescape#">raw</a>
+</div>
+
+<h2>#file|escape#</h2>
+
+<table id="filediffEntry">
+<tr>
+ <th class="revision">revision #rev#:</th>
+ <td class="revision"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td>
+</tr>
+#parent%filediffparent#
+#child%filediffchild#
+</table>
+
+<div id="fileDiff">
+#diff#
+</div>
+
+#footer#
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/filelog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,24 @@
+#header#
+<title>#repo|escape#: #file|escape# history</title>
+<link rel="alternate" type="application/rss+xml"
+   href="#url#rss-log/tip/#file|urlescape#" title="RSS feed for #repo|escape#:#file#">
+</head>
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#log{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>
+<a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a>
+<a type="application/rss+xml" href="#url#rss-log/tip/#file|urlescape#">rss</a>
+</div>
+
+<h2>#file|escape# revision history</h2>
+
+<p>navigate: <small class="navigate">{nav%filenaventry}</small></p>
+
+#entries%filelogentry#
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/filelogentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,25 @@
+<table class="logEntry parity#parity#">
+ <tr>
+  <th class="age">#date|age# ago:</th>
+  <th class="firstline"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#desc|strip|firstline|escape#</a></th>
+ </tr>
+ <tr>
+  <th class="revision">revision #filerev#:</td>
+  <td class="node">
+   <a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a>
+   <a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">(diff)</a>
+   <a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">(annotate)</a>
+  </td>
+ </tr>
+ #rename%filelogrename#
+ <tr>
+  <th class="author">author:</th>
+  <td class="author">#author|obfuscate#</td>
+ </tr>
+ <tr>
+  <th class="date">date:</th>
+  <td class="date">#date|date#</td>
+ </tr>
+</table>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/filerevision.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,44 @@
+#header#
+<title>#repo|escape#:#file|escape#</title>
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#rev/#node|short#{sessionvars%urlparameter}">changeset</a>
+<a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">manifest</a>
+<a href="#url#log/#node|short#/#file|urlescape#{sessionvars%urlparameter}">revisions</a>
+<a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a>
+<a href="#url#raw-file/#node|short#/#file|urlescape#">raw</a>
+</div>
+
+<h2>#file|escape#</h2>
+
+<table>
+<tr>
+ <td class="metatag">changeset #rev#:</td>
+ <td><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>
+#parent%filerevparent#
+#child%filerevchild#
+<tr>
+ <td class="metatag">author:</td>
+ <td>#author|obfuscate#</td></tr>
+<tr>
+ <td class="metatag">date:</td>
+ <td>#date|date# (#date|age# ago)</td></tr>
+<tr>
+ <td class="metatag">permissions:</td>
+ <td>#permissions|permissions#</td></tr>
+<tr>
+  <td class="metatag">description:</td>
+  <td>{desc|strip|escape|addbreaks}</td>
+</tr>
+</table>
+
+<pre>
+#text%fileline#
+</pre>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/footer.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,8 @@
+#motd#
+<div class="logo">
+powered by<br/>
+<a href="http://www.selenic.com/mercurial/">mercurial</a>
+</div>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/header.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,8 @@
+Content-type: text/html
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<link rel="icon" href="?static=hgicon.png" type="image/png">
+<meta name="robots" content="index, nofollow" />
+<link rel="stylesheet" href="?static=style.css" type="text/css" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/manifest.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,25 @@
+#header#
+<title>#repo|escape#: manifest for changeset #node|short#</title>
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog/#rev#{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#rev/#node|short#{sessionvars%urlparameter}">changeset</a>
+#archives%archiveentry#
+</div>
+
+<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>&nbsp;
+  <td><a href="#url#file/#node|short##up|urlescape#{sessionvars%urlparameter}">[up]</a>
+</tr>
+#dentries%manifestdirentry#
+#fentries%manifestfileentry#
+</table>
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/map	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,56 @@
+default = 'changelog'
+header = header.tmpl
+footer = footer.tmpl
+search = search.tmpl
+changelog = changelog.tmpl
+shortlog = shortlog.tmpl
+shortlogentry = shortlogentry.tmpl
+naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
+navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
+filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
+filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#</a> '
+filenodelink = '<a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#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>&nbsp;<td><a href="#url#file/#node|short##path|urlescape#{sessionvars%urlparameter}">#basename|escape#/</a>'
+manifestfileentry = '<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td align=right><tt>#size#</tt>&nbsp;<td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#basename|escape#</a>'
+filerevision = filerevision.tmpl
+fileannotate = fileannotate.tmpl
+filediff = filediff.tmpl
+filelog = filelog.tmpl
+fileline = '<div class="parity#parity#"><span class="lineno">#linenumber#</span>#line|escape#</div>'
+filelogentry = filelogentry.tmpl
+annotateline = '<tr class="parity#parity#"><td class="annotate"><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
+difflineplus = '<span class="plusline">#line|escape#</span>'
+difflineminus = '<span class="minusline">#line|escape#</span>'
+difflineat = '<span class="atline">#line|escape#</span>'
+diffline = '#line|escape#'
+changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+changesetparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filerevparent = '<tr><td class="metatag">parent:</td><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
+filerename = '{file|escape}@'
+filelogrename = '<tr><th>base:</th><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#file|escape#@#node|short#</a></td></tr>'
+fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
+changesetchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filerevchild = '<tr><td class="metatag">child:</td><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="#url#annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+tags = tags.tmpl
+tagentry = '<li class="tagEntry parity#parity#"><tt class="node">#node#</tt> <a href="#url#rev/#node|short#{sessionvars%urlparameter}">#tag|escape#</a></li>'
+diffblock = '<pre class="parity#parity#">#lines#</pre>'
+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="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filelogparent = '<tr><th>parent #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filediffchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+filelogchild = '<tr><th>child #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">#node|short#</a></td></tr>'
+indexentry = '<tr class="parity#parity#"><td><a href="#url#{sessionvars%urlparameter}">#name|escape#</a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
+index = index.tmpl
+archiveentry = '<a href="#url#archive/#node|short##extension|urlescape#">#type|escape#</a> '
+notfound = notfound.tmpl
+error = error.tmpl
+urlparameter = '#separator##name#=#value|urlescape#'
+hiddenformentry = '<input type="hidden" name="#name#" value="#value|escape#" />'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/search.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,33 @@
+#header#
+<title>#repo|escape#: searching for #query|escape#</title>
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#log{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#{sessionvars%urlparameter}">manifest</a>
+</div>
+
+<h2>searching for #query|escape#</h2>
+
+<form>
+{sessionvars%hiddenformentry}
+<p>
+search:
+<input name="rev" type="text" width="30" value="#query|escape#">
+</p>
+</form>
+
+#entries#
+
+<form>
+{sessionvars%hiddenformentry}
+<p>
+search:
+<input name="rev" type="text" width="30" value="#query|escape#">
+</p>
+</form>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/shortlog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,38 @@
+#header#
+<title>#repo|escape#: shortlog</title>
+<link rel="alternate" type="application/rss+xml"
+   href="#url#rss-log" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#/{sessionvars%urlparameter}">manifest</a>
+#archives%archiveentry#
+<a type="application/rss+xml" href="#url#rss-log">rss</a>
+</div>
+
+<h2>shortlog for #repo|escape#</h2>
+
+<form action="#url#log">
+{sessionvars%hiddenformentry}
+<p>
+<label for="search1">search:</label>
+<input name="rev" id="search1" type="text" size="30">
+navigate: <small class="navigate">#changenav%navshortentry#</small>
+</p>
+</form>
+
+#entries%shortlogentry#
+
+<form action="#url#log">
+{sessionvars%hiddenformentry}
+<p>
+<label for="search2">search:</label>
+<input name="rev" id="search2" type="text" size="30">
+navigate: <small class="navigate">#changenav%navshortentry#</small>
+</p>
+</form>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/shortlogentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,7 @@
+<table class="slogEntry parity#parity#">
+ <tr>
+  <td class="age">#date|age#</td>
+  <td class="author">#author|obfuscate#</td>
+  <td class="node"><a href="?cs=#node|short#">#desc|strip|firstline|escape#</a></td>
+ </tr>
+</table>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/old/tags.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,21 @@
+#header#
+<title>#repo|escape#: tags</title>
+<link rel="alternate" type="application/rss+xml"
+   href="#url#rss-tags" title="RSS feed for #repo|escape#: tags">
+</head>
+<body>
+
+<div class="buttons">
+<a href="#url#log{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#file/#node|short#/{sessionvars%urlparameter}">manifest</a>
+<a type="application/rss+xml" href="#url#rss-tags">rss</a>
+</div>
+
+<h2>tags:</h2>
+
+<ul id="tagEntries">
+#entries%tagentry#
+</ul>
+
+#footer#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/raw/changeset.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,9 @@
+#header#
+# HG changeset patch
+# User #author#
+# Date #date|hgdate#
+# Node ID #node#
+#parent%changesetparent#
+#desc#
+
+#diff#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/raw/fileannotate.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,5 @@
+#header#
+#annotate%annotateline#
+#footer#
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/raw/filediff.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,5 @@
+#header#
+#diff#
+#footer#
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/raw/header.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,1 @@
+Content-type: text/plain
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/raw/map	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,16 @@
+header = header.tmpl
+footer = ''
+changeset = changeset.tmpl
+difflineplus = '#line#'
+difflineminus = '#line#'
+difflineat = '#line#'
+diffline = '#line#'
+changesetparent = '# Parent #node#'
+changesetchild = '# Child #node#'
+filenodelink = ''
+filerevision = '#rawfileheader##raw#'
+fileline = '#line#'
+diffblock = '#lines#'
+filediff = filediff.tmpl
+fileannotate = fileannotate.tmpl
+annotateline = '#author#@#rev#: #line#'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/rss/changelog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,6 @@
+#header#
+    <title>#repo|escape# Changelog</title>
+    <description>#repo|escape# Changelog</description>
+    #entries%changelogentry#
+  </channel>
+</rss>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/rss/changelogentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,7 @@
+<item>
+    <title>#desc|strip|firstline|strip|escape#</title>
+    <link>{urlbase}{url}rev/{node|short}</link>
+    <description><![CDATA[#desc|strip|escape|addbreaks#]]></description>
+    <author>#author|obfuscate#</author>
+    <pubDate>#date|rfc822date#</pubDate>
+</item>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/rss/filelog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,6 @@
+#header#
+    <title>#repo|escape#: #file|escape# history</title>
+    <description>#file|escape# revision history</description>
+    #entries%filelogentry#
+  </channel>
+</rss>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/rss/filelogentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,7 @@
+<item>
+    <title>#desc|strip|firstline|strip|escape#</title>
+    <link>{urlbase}{url}log{#node|short#}/{file|urlescape}</link>
+    <description><![CDATA[#desc|strip|escape|addbreaks#]]></description>
+    <author>#author|obfuscate#</author>
+    <pubDate>#date|rfc822date#</pubDate>
+</item>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/rss/header.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,6 @@
+Content-type: text/xml
+
+<rss version="2.0">
+  <channel>
+    <link>{urlbase}{url}</link>
+    <language>en-us</language>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/rss/map	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,8 @@
+default = 'changelog'
+header = header.tmpl
+changelog = changelog.tmpl
+changelogentry = changelogentry.tmpl
+filelog = filelog.tmpl
+filelogentry = filelogentry.tmpl
+tags = tags.tmpl
+tagentry = tagentry.tmpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/rss/tagentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,6 @@
+<item>
+    <title>#tag|escape#</title>
+    <link>{urlbase}{url}rev/{node|short}</link>
+    <description><![CDATA[#tag|strip|escape|addbreaks#]]></description>
+    <pubDate>#date|rfc822date#</pubDate>
+</item>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/rss/tags.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,6 @@
+#header#
+    <title>#repo|escape#: tags </title>
+    <description>#repo|escape# tag history</description>
+    #entriesnotip%tagentry#
+  </channel>
+</rss>
--- a/templates/search-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-#header#
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/>
-</div>
-
-<h2>searching for #query|escape#</h2>
-
-<form>
-search:
-<input type="hidden" name="cmd" value="changelog">
-<input type="hidden" name="style" value="gitweb">
-<input name="rev" type="text" width="30" value="#query|escape#">
-</form>
-
-#entries#
-
-<form>
-search:
-<input type="hidden" name="cmd" value="changelog">
-<input type="hidden" name="style" value="gitweb">
-<input name="rev" type="text" width="30">
-</form>
-
-#footer#
--- a/templates/search.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/search.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -4,18 +4,18 @@
 <body>
 
 <div class="buttons">
-<a href="?cl=tip">changelog</a>
-<a href="?sl=tip">shortlog</a>
-<a href="?tags=">tags</a>
-<a href="?mf=#manifest|short#;path=/">manifest</a>
+<a href="#url#log{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#{sessionvars%urlparameter}">manifest</a>
 </div>
 
 <h2>searching for #query|escape#</h2>
 
 <form>
+{sessionvars%hiddenformentry}
 <p>
 search:
-<input type="hidden" name="cmd" value="changelog">
 <input name="rev" type="text" width="30" value="#query|escape#">
 </p>
 </form>
@@ -23,9 +23,9 @@
 #entries#
 
 <form>
+{sessionvars%hiddenformentry}
 <p>
 search:
-<input type="hidden" name="cmd" value="changelog">
 <input name="rev" type="text" width="30" value="#query|escape#">
 </p>
 </form>
--- a/templates/shortlog-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-#header#
-<title>#repo|escape#: Shortlog</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / shortlog
-</div>
-
-<form action="#">
-<div class="search">
-<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"  />
-</div>
-</form>
-</div>
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | shortlog | <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>#archives%archiveentry#<br/>
-<br/>
-
-#changenav%navshortentry#<br/>
-</div>
-
-<table cellspacing="0">
-#entries%shortlogentry#
-</table>
-
-#footer#
--- a/templates/shortlog.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/shortlog.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -1,24 +1,24 @@
 #header#
 <title>#repo|escape#: shortlog</title>
 <link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
+   href="#url#rss-log" title="RSS feed for #repo|escape#">
 </head>
 <body>
 
 <div class="buttons">
-<a href="?cl=#rev#">changelog</a>
-<a href="?cmd=tags">tags</a>
-<a href="?mf=#manifest|short#;path=/">manifest</a>
+<a href="#url#log/#rev#{sessionvars%urlparameter}">changelog</a>
+<a href="#url#tags{sessionvars%urlparameter}">tags</a>
+<a href="#url#file/#node|short#/{sessionvars%urlparameter}">manifest</a>
 #archives%archiveentry#
-<a type="application/rss+xml" href="?style=rss">rss</a>
+<a type="application/rss+xml" href="#url#rss-log">rss</a>
 </div>
 
 <h2>shortlog for #repo|escape#</h2>
 
-<form action="#">
+<form action="#url#log">
+{sessionvars%hiddenformentry}
 <p>
 <label for="search1">search:</label>
-<input type="hidden" name="cmd" value="changelog">
 <input name="rev" id="search1" type="text" size="30">
 navigate: <small class="navigate">#changenav%navshortentry#</small>
 </p>
@@ -26,10 +26,10 @@
 
 #entries%shortlogentry#
 
-<form action="#">
+<form action="#url#log">
+{sessionvars%hiddenformentry}
 <p>
 <label for="search2">search:</label>
-<input type="hidden" name="cmd" value="changelog">
 <input name="rev" id="search2" type="text" size="30">
 navigate: <small class="navigate">#changenav%navshortentry#</small>
 </p>
--- a/templates/shortlogentry.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/shortlogentry.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -2,6 +2,6 @@
  <tr>
   <td class="age">#date|age#</td>
   <td class="author">#author|obfuscate#</td>
-  <td class="node"><a href="?cs=#node|short#">#desc|strip|firstline|escape#</a></td>
+  <td class="node"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#desc|strip|firstline|escape#</a></td>
  </tr>
 </table>
--- a/templates/static/style-gitweb.css	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/static/style-gitweb.css	Sat Oct 21 15:22:08 2006 -0400
@@ -47,3 +47,4 @@
 	text-align:center; text-decoration:none;
 }
 a.rss_logo:hover { background-color:#ee5500; }
+pre { margin: 0; }
--- a/templates/summary-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-#header#
-<title>#repo|escape#: Summary</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / summary
-</div>
-<div class="page_nav">
-summary | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>#archives%archiveentry#
-<br/>
-</div>
-
-<div class="title">&nbsp;</div>
-<table cellspacing="0">
-<tr><td>description</td><td>#desc#</td></tr>
-<tr><td>owner</td><td>#owner|escape#</td></tr>
-<!-- <tr><td>last change</td><td>#lastchange|rfc822date#</td></tr> -->
-</table>
-
-<div><a  class="title" href="?cmd=changelog;style=gitweb">changes</a></div>
-<table cellspacing="0">
-#shortlog#
-<tr class="light"><td colspan="3"><a class="list" href="?cmd=changelog;style=gitweb">...</a></td></tr>
-</table>
-
-<div><a class="title" href="?cmd=tags;style=gitweb">tags</a></div>
-<table cellspacing="0">
-#tags#
-<tr class="light"><td colspan="3"><a class="list" href="?cmd=tags;style=gitweb">...</a></td></tr>
-</table>
-
-#footer#
--- a/templates/tagentry-rss.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-<item>
-    <title>#tag|escape#</title>
-    <link>#url#?cs=#node|short#</link>
-    <description><![CDATA[#tag|strip|escape|addbreaks#]]></description>
-    <pubDate>#date|rfc822date#</pubDate>
-</item>
--- a/templates/tags-gitweb.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#header#
-<title>#repo|escape#: Tags</title>
-<link rel="alternate" type="application/rss+xml"
-   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
-</head>
-<body>
-
-<div class="page_header">
-<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / tags
-</div>
-
-<div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | tags | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>
-<br/>
-</div>
-
-<table cellspacing="0">
-#entries%tagentry#
-</table>
-
-#footer#
--- a/templates/tags-rss.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#header#
-    <title>#repo|escape#: tags </title>
-    <description>#repo|escape# tag history</description>
-    #entriesnotip%tagentry#
-  </channel>
-</rss>
--- a/templates/tags.tmpl	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/tags.tmpl	Sat Oct 21 15:22:08 2006 -0400
@@ -1,15 +1,15 @@
 #header#
 <title>#repo|escape#: tags</title>
 <link rel="alternate" type="application/rss+xml"
-   href="?cmd=tags;style=rss" title="RSS feed for #repo|escape#: tags">
+   href="#url#rss-tags" title="RSS feed for #repo|escape#: tags">
 </head>
 <body>
 
 <div class="buttons">
-<a href="?cl=tip">changelog</a>
-<a href="?sl=tip">shortlog</a>
-<a href="?mf=#manifest|short#;path=/">manifest</a>
-<a type="application/rss+xml" href="?cmd=tags;style=rss">rss</a>
+<a href="#url#log{sessionvars%urlparameter}">changelog</a>
+<a href="#url#shortlog{sessionvars%urlparameter}">shortlog</a>
+<a href="#url#file/#node|short#/{sessionvars%urlparameter}">manifest</a>
+<a type="application/rss+xml" href="#url#rss-tags">rss</a>
 </div>
 
 <h2>tags:</h2>
--- a/templates/template-vars.txt	Sat Sep 02 22:58:02 2006 -0400
+++ b/templates/template-vars.txt	Sat Oct 21 15:22:08 2006 -0400
@@ -3,19 +3,16 @@
 node          a changeset node
 changesets    total number of changesets
 file          a filename
-filenode      a file node
 filerev       a file revision
 filerevs      total number of file revisions
 up            the directory of the relevant file
 path          a path in the manifest, starting with "/"
 basename      a short pathname
-manifest      a manifest node
-manifestrev   a manifest revision
 date          a date string
 age           age in hours, days, etc
 line          a line of text (escaped)
 desc          a description (escaped, with breaks)
-shortdesc         a short description (escaped)
+shortdesc     a short description (escaped)
 author        a name or email addressv(obfuscated)
 parent        a list of the parent
 child         a list of the children
@@ -25,6 +22,7 @@
 footer        the global page footer
 
 files         a list of file links
+file_copies   a list of pairs of name, source filenames
 dirs          a set of directory links
 diff          a diff of one or more files
 annotate      an annotated file
@@ -36,4 +34,4 @@
     filenodelink - jump to file diff
     fileellipses - printed after maxfiles
     changelogentry - an entry in the log
-  manifest - browse a manifest as a directory tree
\ No newline at end of file
+  manifest - browse a manifest as a directory tree
--- a/tests/README	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/README	Sat Oct 21 15:22:08 2006 -0400
@@ -26,8 +26,68 @@
 
   use commit -m "test" -u test -d "1000000 0"
 
-- diff will show the current time
+- diff and export may show the current time
+
+  use -D/--nodates to strip the dates
+
+- You can append your own hgrc settings to the file that the environment
+  variable HGRCPATH points to. This file is cleared before running a test.
+
+You also need to be careful that the tests are portable from one platform
+to another.  You're probably working on Linux, where the GNU toolchain has
+more (or different) functionality than on MacOS, *BSD, Solaris, AIX, etc.
+While testing on all platforms is the only sure-fire way to make sure that
+you've written portable code, here's a list of problems that have been
+found and fixed in the tests.  Another, more comprehensive list may be
+found in the GNU Autoconf manual, online here:
+
+    http://www.gnu.org/software/autoconf/manual/html_node/Portable-Shell.html
+
+sh:
+
+The Bourne shell is a very basic shell.  /bin/sh on Linux is typically
+bash, which even in Bourne-shell mode has many features that Bourne shells
+on other Unix systems don't have (and even on Linux /bin/sh isn't
+guaranteed to be bash).  You'll need to be careful about constructs that
+seem ubiquitous, but are actually not available in the least common
+denominator.  While using another shell (ksh, bash explicitly, posix shell,
+etc.) explicitly may seem like another option, these may not exist in a
+portable location, and so are generally probably not a good idea.  You may
+find that rewriting the test in python will be easier.
+
+- don't use pushd/popd; save the output of "pwd" and use "cd" in place of
+  the pushd, and cd back to the saved pwd instead of popd.
 
-  use hg diff | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" to strip
-  dates
+- don't use math expressions like let, (( ... )), or $(( ... )); use "expr"
+  instead.
+
+grep:
+
+- don't use the -q option; redirect stdout to /dev/null instead.
+
+- don't use extended regular expressions with grep; use egrep instead, and
+  don't escape any regex operators.
+
+sed:
+
+- make sure that the beginning-of-line matcher ("^") is at the very
+  beginning of the expression -- it may not be supported inside parens.
+
+echo:
 
+- echo may interpret "\n" and print a newline; use printf instead if you
+  want a literal "\n" (backslash + n).
+
+false:
+
+- false is guaranteed only to return a non-zero value; you cannot depend on
+  it being 1.  On Solaris in particular, /bin/false returns 255.  Rewrite
+  your test to not depend on a particular return value, or create a
+  temporary "false" executable, and call that instead.
+
+diff:
+
+- don't use the -N option.  There's no particularly good workaround short
+  of writing a reasonably complicated replacement script, but substituting
+  gdiff for diff if you can't rewrite the test not to need -N will probably
+  do.
Binary file tests/binfile.bin has changed
--- a/tests/coverage.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/coverage.py	Sat Oct 21 15:22:08 2006 -0400
@@ -87,19 +87,19 @@
         self.excluded = excluded
         self.suite_spots = suite_spots
         self.excluding_suite = 0
-        
+
     def doRecursive(self, node):
         self.recordNodeLine(node)
         for n in node.getChildNodes():
             self.dispatch(n)
 
     visitStmt = visitModule = doRecursive
-    
+
     def doCode(self, node):
         if hasattr(node, 'decorators') and node.decorators:
             self.dispatch(node.decorators)
         self.doSuite(node, node.code)
-    
+
     visitFunction = visitClass = doCode
 
     def getFirstLine(self, node):
@@ -119,17 +119,17 @@
         for n in node.getChildNodes():
             lineno = max(lineno, self.getLastLine(n))
         return lineno
-    
+
     def doStatement(self, node):
         self.recordLine(self.getFirstLine(node))
 
     visitAssert = visitAssign = visitAssTuple = visitDiscard = visitPrint = \
         visitPrintnl = visitRaise = visitSubscript = visitDecorators = \
         doStatement
-    
+
     def recordNodeLine(self, node):
         return self.recordLine(node.lineno)
-    
+
     def recordLine(self, lineno):
         # Returns a bool, whether the line is included or excluded.
         if lineno:
@@ -153,9 +153,9 @@
                 self.statements[lineno] = 1
                 return 1
         return 0
-    
+
     default = recordNodeLine
-    
+
     def recordAndDispatch(self, node):
         self.recordNodeLine(node)
         self.dispatch(node)
@@ -166,7 +166,7 @@
             self.excluding_suite = 1
         self.recordAndDispatch(body)
         self.excluding_suite = exsuite
-        
+
     def doPlainWordSuite(self, prevsuite, suite):
         # Finding the exclude lines for else's is tricky, because they aren't
         # present in the compiler parse tree.  Look at the previous suite,
@@ -180,11 +180,11 @@
                 break
         else:
             self.doSuite(None, suite)
-        
+
     def doElse(self, prevsuite, node):
         if node.else_:
             self.doPlainWordSuite(prevsuite, node.else_)
-    
+
     def visitFor(self, node):
         self.doSuite(node, node.body)
         self.doElse(node.body, node)
@@ -216,11 +216,11 @@
             else:
                 self.doSuite(a, h)
         self.doElse(node.handlers[-1][2], node)
-    
+
     def visitTryFinally(self, node):
         self.doSuite(node, node.body)
         self.doPlainWordSuite(node.body, node.final)
-        
+
     def visitGlobal(self, node):
         # "global" statements don't execute like others (they don't call the
         # trace function), so don't record their line numbers.
@@ -240,7 +240,7 @@
     # A dictionary with an entry for (Python source file name, line number
     # in that file) if that line has been executed.
     c = {}
-    
+
     # A map from canonical Python source file name to a dictionary in
     # which there's an entry for each line number that has been
     # executed.
@@ -266,12 +266,12 @@
         self.xstack = []
         self.relative_dir = os.path.normcase(os.path.abspath(os.curdir)+os.path.sep)
 
-    # t(f, x, y).  This method is passed to sys.settrace as a trace function.  
-    # See [van Rossum 2001-07-20b, 9.2] for an explanation of sys.settrace and 
+    # t(f, x, y).  This method is passed to sys.settrace as a trace function.
+    # See [van Rossum 2001-07-20b, 9.2] for an explanation of sys.settrace and
     # the arguments and return value of the trace function.
     # See [van Rossum 2001-07-20a, 3.2] for a description of frame and code
     # objects.
-    
+
     def t(self, f, w, a):                                   #pragma: no cover
         #print w, f.f_code.co_filename, f.f_lineno
         if w == 'line':
@@ -279,7 +279,7 @@
             for c in self.cstack:
                 c[(f.f_code.co_filename, f.f_lineno)] = 1
         return self.t
-    
+
     def help(self, error=None):
         if error:
             print error
@@ -330,7 +330,7 @@
             self.help("You must specify at least one of -e, -x, -r, or -a.")
         if not args_needed and args:
             self.help("Unexpected arguments %s." % args)
-        
+
         self.get_ready()
         self.exclude('#pragma[: ]+[nN][oO] [cC][oO][vV][eE][rR]')
 
@@ -359,14 +359,14 @@
 
     def use_cache(self, usecache):
         self.usecache = usecache
-        
+
     def get_ready(self):
         if self.usecache and not self.cache:
             self.cache = os.path.abspath(os.environ.get(self.cache_env,
                                                         self.cache_default))
             self.restore()
         self.analysis_cache = {}
-        
+
     def start(self):
         self.get_ready()
         if self.nesting == 0:                               #pragma: no cover
@@ -374,7 +374,7 @@
             if hasattr(threading, 'settrace'):
                 threading.settrace(self.t)
         self.nesting += 1
-        
+
     def stop(self):
         self.nesting -= 1
         if self.nesting == 0:                               #pragma: no cover
@@ -398,7 +398,7 @@
     def begin_recursive(self):
         self.cstack.append(self.c)
         self.xstack.append(self.exclude_re)
-        
+
     def end_recursive(self):
         self.c = self.cstack.pop()
         self.exclude_re = self.xstack.pop()
@@ -452,7 +452,7 @@
             self.canonical_filename_cache[filename] = cf
         return self.canonical_filename_cache[filename]
 
-    # canonicalize_filenames().  Copy results from "c" to "cexecuted", 
+    # canonicalize_filenames().  Copy results from "c" to "cexecuted",
     # canonicalizing filenames on the way.  Clear the "c" map.
 
     def canonicalize_filenames(self):
@@ -550,7 +550,7 @@
         import parser
         tree = parser.suite(text+'\n\n').totuple(1)
         self.get_suite_spots(tree, suite_spots)
-            
+
         # Use the compiler module to parse the text and find the executable
         # statements.  We add newlines to be impervious to final partial lines.
         statements = {}
@@ -713,7 +713,7 @@
             except:
                 if not ignore_errors:
                     raise
-                
+
     def annotate_file(self, filename, statements, excluded, missing, directory=None):
         source = open(filename, 'r')
         if directory:
@@ -741,7 +741,7 @@
             if self.blank_re.match(line):
                 dest.write('  ')
             elif self.else_re.match(line):
-                # Special logic for lines containing only 'else:'.  
+                # Special logic for lines containing only 'else:'.
                 # See [GDR 2001-12-04b, 3.2].
                 if i >= len(statements) and j >= len(missing):
                     dest.write('! ')
@@ -850,7 +850,7 @@
 # Thanks, Allen.
 #
 # 2005-12-02 NMB Call threading.settrace so that all threads are measured.
-# Thanks Martin Fuzzey. Add a file argument to report so that reports can be 
+# Thanks Martin Fuzzey. Add a file argument to report so that reports can be
 # captured to a different destination.
 #
 # 2005-12-03 NMB coverage.py can now measure itself.
--- a/tests/md5sum.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/md5sum.py	Sat Oct 21 15:22:08 2006 -0400
@@ -16,7 +16,7 @@
     except IOError, msg:
         sys.stderr.write('%s: Can\'t open: %s\n' % (filename, msg))
         sys.exit(1)
-    
+
     m = md5.new()
     try:
         while 1:
--- a/tests/run-tests.py	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/run-tests.py	Sat Oct 21 15:22:08 2006 -0400
@@ -32,6 +32,11 @@
     help="print a test coverage report inc. standard libraries")
 parser.add_option("-C", "--annotate", action="store_true",
     help="output files annotated with coverage")
+parser.add_option("-r", "--retest", action="store_true",
+    help="retest failed tests")
+parser.add_option("-f", "--first", action="store_true",
+    help="exit on the first test failure")
+
 parser.set_defaults(timeout=180)
 (options, args) = parser.parse_args()
 verbose = options.verbose
@@ -104,7 +109,7 @@
         # windows fallback
         shutil.copyfile(sys.executable, my_python)
         shutil.copymode(sys.executable, my_python)
-            
+
 def install_hg():
     vlog("# Performing temporary installation of HG")
     installerrs = os.path.join("tests", "install.err")
@@ -211,6 +216,10 @@
         sys.stdout.write('.')
         sys.stdout.flush()
 
+    # create a fresh hgrc
+    hgrc = file(HGRCPATH, 'w+')
+    hgrc.close()
+
     err = os.path.join(TESTDIR, test+".err")
     ref = os.path.join(TESTDIR, test+".out")
 
@@ -319,11 +328,11 @@
 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
 os.environ["HGMERGE"]  = sys.executable + ' -c "import sys; sys.exit(0)"'
 os.environ["HGUSER"]   = "test"
-os.environ["HGRCPATH"] = ""
 
 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
 HGTMP   = os.environ["HGTMP"]   = tempfile.mkdtemp("", "hgtests.")
 DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
+HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
 
 vlog("# Using TESTDIR", TESTDIR)
 vlog("# Using HGTMP", HGTMP)
@@ -354,13 +363,18 @@
             args = os.listdir(".")
         for test in args:
             if (test.startswith("test-") and '~' not in test and
-                ('.' not in test or test.endswith('.py') or 
+                ('.' not in test or test.endswith('.py') or
                  test.endswith('.bat'))):
+                if options.retest and not os.path.exists(test + ".err"):
+                    skipped += 1
+                    continue
                 ret = run_one(test)
                 if ret is None:
                     skipped += 1
                 elif not ret:
                     failed += 1
+                    if options.first:
+                        break
                 tests += 1
 
         print "\n# Ran %d tests, %d skipped, %d failed." % (tests, skipped,
--- a/tests/test-abort-checkin	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-abort-checkin	Sat Oct 21 15:22:08 2006 -0400
@@ -1,8 +1,12 @@
 #!/bin/sh
 
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+cat > $HGTMP/false <<EOF
+#!/bin/sh
+exit 1
+EOF
+chmod +x $HGTMP/false
 
 hg init foo
 cd foo
@@ -11,7 +15,7 @@
 
 # mq may keep a reference to the repository so __del__ will not be called
 # and .hg/journal.dirstate will not be deleted:
-HGEDITOR=false hg ci
-HGEDITOR=false hg ci
+HGEDITOR=$HGTMP/false hg ci
+HGEDITOR=$HGTMP/false hg ci
 
 exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-acl	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,109 @@
+#!/bin/sh
+
+do_push()
+{
+    user=$1
+    shift
+
+    echo "Pushing as user $user"
+    echo 'hgrc = """'
+    sed -e 1,2d b/.hg/hgrc
+    echo '"""'
+    if [ -e acl.config ]; then
+	echo 'acl.config = """'
+	cat acl.config
+	echo '"""'
+    fi
+    LOGNAME=$user hg --cwd a --debug push ../b
+    hg --cwd b rollback
+    hg --cwd b --quiet tip
+    echo
+}
+
+hg init a
+cd a
+mkdir foo foo/Bar quux
+echo 'in foo' > foo/file.txt
+echo 'in foo/Bar' > foo/Bar/file.txt
+echo 'in quux' > quux/file.py
+hg add
+hg ci -m 'add files' -d '1000000 0'
+echo >> foo/file.txt
+hg ci -m 'change foo/file' -d '1000001 0'
+echo >> foo/Bar/file.txt
+hg ci -m 'change foo/Bar/file' -d '1000002 0'
+echo >> quux/file.py
+hg ci -m 'change quux/file' -d '1000003 0'
+hg tip --quiet
+
+cd ..
+hg clone -r 0 a b
+
+echo '[extensions]' >> $HGRCPATH
+echo 'hgext.acl =' >> $HGRCPATH
+
+config=b/.hg/hgrc
+
+echo
+
+echo 'Extension disabled for lack of a hook'
+do_push fred
+
+echo '[hooks]' >> $config
+echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
+
+echo 'Extension disabled for lack of acl.sources'
+do_push fred
+
+echo 'No [acl.allow]/[acl.deny]'
+echo '[acl]' >> $config
+echo 'sources = push' >> $config
+do_push fred
+
+echo 'Empty [acl.allow]'
+echo '[acl.allow]' >> $config
+do_push fred
+
+echo 'fred is allowed inside foo/'
+echo 'foo/** = fred' >> $config
+do_push fred
+
+echo 'Empty [acl.deny]'
+echo '[acl.deny]' >> $config
+do_push barney
+
+echo 'fred is allowed inside foo/, but not foo/bar/ (case matters)'
+echo 'foo/bar/** = fred' >> $config
+do_push fred
+
+echo 'fred is allowed inside foo/, but not foo/Bar/'
+echo 'foo/Bar/** = fred' >> $config
+do_push fred
+
+echo 'barney is not mentioned => not allowed anywhere'
+do_push barney
+
+echo 'barney is allowed everywhere'
+echo '[acl.allow]' >> $config
+echo '** = barney' >> $config
+do_push barney
+
+echo 'wilma can change files with a .txt extension'
+echo '**/*.txt = wilma' >> $config
+do_push wilma
+
+echo 'file specified by acl.config does not exist'
+echo '[acl]' >> $config
+echo 'config = ../acl.config' >> $config
+do_push barney
+
+echo 'betty is allowed inside foo/ by a acl.config file'
+echo '[acl.allow]' >> acl.config
+echo 'foo/** = betty' >> acl.config
+do_push betty
+
+echo 'acl.config can set only [acl.allow]/[acl.deny]'
+echo '[hooks]' >> acl.config
+echo 'changegroup.acl = false' >> acl.config
+do_push barney
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-acl.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,517 @@
+adding foo/Bar/file.txt
+adding foo/file.txt
+adding quux/file.py
+3:911600dab2ae
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 3 changes to 3 files
+3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Extension disabled for lack of a hook
+Pushing as user fred
+hgrc = """
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+rolling back last transaction
+0:6675d58eff77
+
+Extension disabled for lack of acl.sources
+Pushing as user fred
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow not enabled
+acl: acl.deny not enabled
+acl: changes have source "push" - skipping
+rolling back last transaction
+0:6675d58eff77
+
+No [acl.allow]/[acl.deny]
+Pushing as user fred
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow not enabled
+acl: acl.deny not enabled
+acl: allowing changeset ef1ea85a6374
+acl: allowing changeset f9cafe1212c8
+acl: allowing changeset 911600dab2ae
+rolling back last transaction
+0:6675d58eff77
+
+Empty [acl.allow]
+Pushing as user fred
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 0 entries for user fred
+acl: acl.deny not enabled
+acl: user fred not allowed on foo/file.txt
+error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
+abort: acl: access denied for changeset ef1ea85a6374
+transaction abort!
+rollback completed
+no rollback information available
+0:6675d58eff77
+
+fred is allowed inside foo/
+Pushing as user fred
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 1 entries for user fred
+acl: acl.deny not enabled
+acl: allowing changeset ef1ea85a6374
+acl: allowing changeset f9cafe1212c8
+acl: user fred not allowed on quux/file.py
+error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
+abort: acl: access denied for changeset 911600dab2ae
+transaction abort!
+rollback completed
+no rollback information available
+0:6675d58eff77
+
+Empty [acl.deny]
+Pushing as user barney
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+[acl.deny]
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 0 entries for user barney
+acl: acl.deny enabled, 0 entries for user barney
+acl: user barney not allowed on foo/file.txt
+error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
+abort: acl: access denied for changeset ef1ea85a6374
+transaction abort!
+rollback completed
+no rollback information available
+0:6675d58eff77
+
+fred is allowed inside foo/, but not foo/bar/ (case matters)
+Pushing as user fred
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+[acl.deny]
+foo/bar/** = fred
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 1 entries for user fred
+acl: acl.deny enabled, 1 entries for user fred
+acl: allowing changeset ef1ea85a6374
+acl: allowing changeset f9cafe1212c8
+acl: user fred not allowed on quux/file.py
+error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
+abort: acl: access denied for changeset 911600dab2ae
+transaction abort!
+rollback completed
+no rollback information available
+0:6675d58eff77
+
+fred is allowed inside foo/, but not foo/Bar/
+Pushing as user fred
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+[acl.deny]
+foo/bar/** = fred
+foo/Bar/** = fred
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 1 entries for user fred
+acl: acl.deny enabled, 2 entries for user fred
+acl: allowing changeset ef1ea85a6374
+acl: user fred denied on foo/Bar/file.txt
+error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
+abort: acl: access denied for changeset f9cafe1212c8
+transaction abort!
+rollback completed
+no rollback information available
+0:6675d58eff77
+
+barney is not mentioned => not allowed anywhere
+Pushing as user barney
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+[acl.deny]
+foo/bar/** = fred
+foo/Bar/** = fred
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 0 entries for user barney
+acl: acl.deny enabled, 0 entries for user barney
+acl: user barney not allowed on foo/file.txt
+error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
+abort: acl: access denied for changeset ef1ea85a6374
+transaction abort!
+rollback completed
+no rollback information available
+0:6675d58eff77
+
+barney is allowed everywhere
+Pushing as user barney
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+[acl.deny]
+foo/bar/** = fred
+foo/Bar/** = fred
+[acl.allow]
+** = barney
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 1 entries for user barney
+acl: acl.deny enabled, 0 entries for user barney
+acl: allowing changeset ef1ea85a6374
+acl: allowing changeset f9cafe1212c8
+acl: allowing changeset 911600dab2ae
+rolling back last transaction
+0:6675d58eff77
+
+wilma can change files with a .txt extension
+Pushing as user wilma
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+[acl.deny]
+foo/bar/** = fred
+foo/Bar/** = fred
+[acl.allow]
+** = barney
+**/*.txt = wilma
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 1 entries for user wilma
+acl: acl.deny enabled, 0 entries for user wilma
+acl: allowing changeset ef1ea85a6374
+acl: allowing changeset f9cafe1212c8
+acl: user wilma not allowed on quux/file.py
+error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
+abort: acl: access denied for changeset 911600dab2ae
+transaction abort!
+rollback completed
+no rollback information available
+0:6675d58eff77
+
+file specified by acl.config does not exist
+Pushing as user barney
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+[acl.deny]
+foo/bar/** = fred
+foo/Bar/** = fred
+[acl.allow]
+** = barney
+**/*.txt = wilma
+[acl]
+config = ../acl.config
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 1 entries for user barney
+acl: acl.deny enabled, 0 entries for user barney
+acl: allowing changeset ef1ea85a6374
+acl: allowing changeset f9cafe1212c8
+acl: allowing changeset 911600dab2ae
+rolling back last transaction
+0:6675d58eff77
+
+betty is allowed inside foo/ by a acl.config file
+Pushing as user betty
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+[acl.deny]
+foo/bar/** = fred
+foo/Bar/** = fred
+[acl.allow]
+** = barney
+**/*.txt = wilma
+[acl]
+config = ../acl.config
+"""
+acl.config = """
+[acl.allow]
+foo/** = betty
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 1 entries for user betty
+acl: acl.deny enabled, 0 entries for user betty
+acl: allowing changeset ef1ea85a6374
+acl: allowing changeset f9cafe1212c8
+acl: user betty not allowed on quux/file.py
+error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
+abort: acl: access denied for changeset 911600dab2ae
+transaction abort!
+rollback completed
+no rollback information available
+0:6675d58eff77
+
+acl.config can set only [acl.allow]/[acl.deny]
+Pushing as user barney
+hgrc = """
+[hooks]
+pretxnchangegroup.acl = python:hgext.acl.hook
+[acl]
+sources = push
+[acl.allow]
+foo/** = fred
+[acl.deny]
+foo/bar/** = fred
+foo/Bar/** = fred
+[acl.allow]
+** = barney
+**/*.txt = wilma
+[acl]
+config = ../acl.config
+"""
+acl.config = """
+[acl.allow]
+foo/** = betty
+[hooks]
+changegroup.acl = false
+"""
+pushing to ../b
+searching for changes
+common changesets up to 6675d58eff77
+adding changesets
+add changeset ef1ea85a6374
+add changeset f9cafe1212c8
+add changeset 911600dab2ae
+adding manifests
+adding file changes
+adding foo/Bar/file.txt revisions
+adding foo/file.txt revisions
+adding quux/file.py revisions
+added 3 changesets with 3 changes to 3 files
+calling hook pretxnchangegroup.acl: hgext.acl.hook
+acl: acl.allow enabled, 1 entries for user barney
+acl: acl.deny enabled, 0 entries for user barney
+acl: allowing changeset ef1ea85a6374
+acl: allowing changeset f9cafe1212c8
+acl: allowing changeset 911600dab2ae
+rolling back last transaction
+0:6675d58eff77
+
--- a/tests/test-addremove	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-addremove	Sat Oct 21 15:22:08 2006 -0400
@@ -10,3 +10,17 @@
 touch ../foo_2 bar_2
 hg -v addremove
 hg -v commit -m "add 2" -d "1000000 0"
+
+cd ..
+hg init sim
+cd sim
+echo a > a
+echo a >> a
+echo a >> a
+echo c > c
+hg commit -Ama
+mv a b
+rm c
+echo d > d
+hg addremove -s 0.5
+hg commit -mb
--- a/tests/test-addremove.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-addremove.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,10 +1,15 @@
-(the addremove command is deprecated; use add and remove --after instead)
 adding dir/bar
 adding foo
 dir/bar
 foo
-(the addremove command is deprecated; use add and remove --after instead)
 adding dir/bar_2
 adding foo_2
 dir/bar_2
 foo_2
+adding a
+adding c
+adding b
+adding d
+removing a
+removing c
+recording removal of a as rename to b (100% similar)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-annotate	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+echo % init
+hg init
+
+echo % commit
+echo 'a' > a
+hg ci -A -m test -u nobody -d '1 0'
+
+echo % annotate -c
+hg annotate -c a
+
+echo % annotate -d
+hg annotate -d a
+
+echo % annotate -n
+hg annotate -n a
+
+echo % annotate -u
+hg annotate -u a
+
+echo % annotate -cdnu
+hg annotate -cdnu a
+
+cat <<EOF >>a
+a
+a
+EOF
+hg ci -ma1 -d '1 0'
+hg cp a b
+hg ci -mb -d '1 0'
+cat <<EOF >> b
+b
+b
+b
+EOF
+hg ci -mb2 -d '2 0'
+
+echo % annotate b
+hg annotate b
+echo % annotate -nf b
+hg annotate -nf b
+
+hg up -C 2
+cat <<EOF >> b
+b
+c
+b
+EOF
+hg ci -mb2.1 -d '2 0'
+hg merge
+hg ci -mmergeb -d '3 0'
+echo % annotate after merge
+hg annotate -nf b
+
+hg up -C 1
+hg cp a b
+cat <<EOF > b
+a
+z
+a
+EOF
+hg ci -mc -d '3 0'
+hg merge
+cat <<EOF >> b
+b
+c
+b
+EOF
+echo d >> b
+hg ci -mmerge2 -d '4 0'
+echo % annotate after rename merge
+hg annotate -nf b
+
+echo % linkrev vs rev
+hg annotate -r tip a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-annotate.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,54 @@
+% init
+% commit
+adding a
+% annotate -c
+8435f90966e4: a
+% annotate -d
+Thu Jan 01 00:00:01 1970 +0000: a
+% annotate -n
+0: a
+% annotate -u
+nobody: a
+% annotate -cdnu
+nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
+% annotate b
+2: a
+2: a
+2: a
+3: b
+3: b
+3: b
+% annotate -nf b
+0 a: a
+1 a: a
+1 a: a
+3 b: b
+3 b: b
+3 b: b
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+merging b
+0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% annotate after merge
+0 a: a
+1 a: a
+1 a: a
+3 b: b
+4 b: c
+3 b: b
+0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+merging b
+0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% annotate after rename merge
+0 a: a
+6 b: z
+1 a: a
+3 b: b
+4 b: c
+3 b: b
+7 b: d
+% linkrev vs rev
+0: a
+1: a
+1: a
--- a/tests/test-archive.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-archive.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,8 +1,5 @@
-(the addremove command is deprecated; use add and remove --after instead)
 adding foo
-(the addremove command is deprecated; use add and remove --after instead)
 adding bar
-(the addremove command is deprecated; use add and remove --after instead)
 adding baz/bletch
 test-archive-TIP/.hg_archival.txt
 test-archive-TIP/bar
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bad-extension	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo 'syntax error' > badext.py
+abspath=`pwd`/badext.py
+
+echo '[extensions]' >> $HGRCPATH
+echo "badext = $abspath" >> $HGRCPATH
+
+hg -q help help
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bad-extension.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,4 @@
+*** failed to import extension badext: invalid syntax (badext.py, line 1)
+hg help [COMMAND]
+
+show help for a command, extension, or list of commands
--- a/tests/test-bad-pull	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-bad-pull	Sat Oct 21 15:22:08 2006 -0400
@@ -2,7 +2,7 @@
 
 hg clone http://localhost:20059/ copy
 echo $?
-ls copy 2>/dev/null || echo copy: No such file or directory
+test -e copy || echo copy: No such file or directory
 
 cat > dumb.py <<EOF
 import BaseHTTPServer, SimpleHTTPServer, signal
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bisect	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+set -e
+
+echo "[extensions]" >> $HGRCPATH
+echo "hbisect=" >> $HGRCPATH
+
+echo % init
+hg init
+
+echo % committing changes
+count=0
+echo > a
+while test $count -lt 32 ; do
+    echo 'a' >> a
+    test $count -eq 0 && hg add
+    hg ci -m "msg $count" -d "$count 0"
+    echo % committed changeset $count
+    count=`expr $count + 1`
+done
+
+echo % log
+hg log
+
+echo % hg up -C
+hg up -C
+
+echo % bisect test
+hg bisect init
+hg bisect bad
+hg bisect good 1
+hg bisect good
+hg bisect good
+hg bisect good
+hg bisect bad
+hg bisect good
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bisect.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,216 @@
+% init
+% committing changes
+adding a
+% committed changeset 0
+% committed changeset 1
+% committed changeset 2
+% committed changeset 3
+% committed changeset 4
+% committed changeset 5
+% committed changeset 6
+% committed changeset 7
+% committed changeset 8
+% committed changeset 9
+% committed changeset 10
+% committed changeset 11
+% committed changeset 12
+% committed changeset 13
+% committed changeset 14
+% committed changeset 15
+% committed changeset 16
+% committed changeset 17
+% committed changeset 18
+% committed changeset 19
+% committed changeset 20
+% committed changeset 21
+% committed changeset 22
+% committed changeset 23
+% committed changeset 24
+% committed changeset 25
+% committed changeset 26
+% committed changeset 27
+% committed changeset 28
+% committed changeset 29
+% committed changeset 30
+% committed changeset 31
+% log
+changeset:   31:58c80a7c8a40
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:31 1970 +0000
+summary:     msg 31
+
+changeset:   30:ed2d2f24b11c
+user:        test
+date:        Thu Jan 01 00:00:30 1970 +0000
+summary:     msg 30
+
+changeset:   29:b5bd63375ab9
+user:        test
+date:        Thu Jan 01 00:00:29 1970 +0000
+summary:     msg 29
+
+changeset:   28:8e0c2264c8af
+user:        test
+date:        Thu Jan 01 00:00:28 1970 +0000
+summary:     msg 28
+
+changeset:   27:288867a866e9
+user:        test
+date:        Thu Jan 01 00:00:27 1970 +0000
+summary:     msg 27
+
+changeset:   26:3efc6fd51aeb
+user:        test
+date:        Thu Jan 01 00:00:26 1970 +0000
+summary:     msg 26
+
+changeset:   25:02a84173a97a
+user:        test
+date:        Thu Jan 01 00:00:25 1970 +0000
+summary:     msg 25
+
+changeset:   24:10e0acd3809e
+user:        test
+date:        Thu Jan 01 00:00:24 1970 +0000
+summary:     msg 24
+
+changeset:   23:5ec79163bff4
+user:        test
+date:        Thu Jan 01 00:00:23 1970 +0000
+summary:     msg 23
+
+changeset:   22:06c7993750ce
+user:        test
+date:        Thu Jan 01 00:00:22 1970 +0000
+summary:     msg 22
+
+changeset:   21:e5db6aa3fe2a
+user:        test
+date:        Thu Jan 01 00:00:21 1970 +0000
+summary:     msg 21
+
+changeset:   20:7128fb4fdbc9
+user:        test
+date:        Thu Jan 01 00:00:20 1970 +0000
+summary:     msg 20
+
+changeset:   19:52798545b482
+user:        test
+date:        Thu Jan 01 00:00:19 1970 +0000
+summary:     msg 19
+
+changeset:   18:86977a90077e
+user:        test
+date:        Thu Jan 01 00:00:18 1970 +0000
+summary:     msg 18
+
+changeset:   17:03515f4a9080
+user:        test
+date:        Thu Jan 01 00:00:17 1970 +0000
+summary:     msg 17
+
+changeset:   16:a2e6ea4973e9
+user:        test
+date:        Thu Jan 01 00:00:16 1970 +0000
+summary:     msg 16
+
+changeset:   15:e7fa0811edb0
+user:        test
+date:        Thu Jan 01 00:00:15 1970 +0000
+summary:     msg 15
+
+changeset:   14:ce8f0998e922
+user:        test
+date:        Thu Jan 01 00:00:14 1970 +0000
+summary:     msg 14
+
+changeset:   13:9d7d07bc967c
+user:        test
+date:        Thu Jan 01 00:00:13 1970 +0000
+summary:     msg 13
+
+changeset:   12:1941b52820a5
+user:        test
+date:        Thu Jan 01 00:00:12 1970 +0000
+summary:     msg 12
+
+changeset:   11:7b4cd9578619
+user:        test
+date:        Thu Jan 01 00:00:11 1970 +0000
+summary:     msg 11
+
+changeset:   10:7c5eff49a6b6
+user:        test
+date:        Thu Jan 01 00:00:10 1970 +0000
+summary:     msg 10
+
+changeset:   9:eb44510ef29a
+user:        test
+date:        Thu Jan 01 00:00:09 1970 +0000
+summary:     msg 9
+
+changeset:   8:453eb4dba229
+user:        test
+date:        Thu Jan 01 00:00:08 1970 +0000
+summary:     msg 8
+
+changeset:   7:03750880c6b5
+user:        test
+date:        Thu Jan 01 00:00:07 1970 +0000
+summary:     msg 7
+
+changeset:   6:a3d5c6fdf0d3
+user:        test
+date:        Thu Jan 01 00:00:06 1970 +0000
+summary:     msg 6
+
+changeset:   5:7874a09ea728
+user:        test
+date:        Thu Jan 01 00:00:05 1970 +0000
+summary:     msg 5
+
+changeset:   4:9b2ba8336a65
+user:        test
+date:        Thu Jan 01 00:00:04 1970 +0000
+summary:     msg 4
+
+changeset:   3:b53bea5e2fcb
+user:        test
+date:        Thu Jan 01 00:00:03 1970 +0000
+summary:     msg 3
+
+changeset:   2:db07c04beaca
+user:        test
+date:        Thu Jan 01 00:00:02 1970 +0000
+summary:     msg 2
+
+changeset:   1:5cd978ea5149
+user:        test
+date:        Thu Jan 01 00:00:01 1970 +0000
+summary:     msg 1
+
+changeset:   0:b99c7b9c8e11
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     msg 0
+
+% hg up -C
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% bisect test
+Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+Testing changeset 27:288867a866e9 (8 changesets remaining, ~3 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+The first bad revision is:
+changeset:   29:b5bd63375ab9
+user:        test
+date:        Thu Jan 01 00:00:29 1970 +0000
+summary:     msg 29
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-branch	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# test for branch handling
+#
+# XXX: need more tests
+
+hg init
+echo a > a
+echo b > b
+hg ci -A -m 0 -d "1000000 0"
+echo aa > a
+echo bb > b
+hg ci -m 1 -d "1000000 0"
+hg tag -l foo
+hg update 0
+hg parents -b 
+
+# test update
+hg update -b foo
+hg parents
+
+# test merge
+hg update 0
+echo c > c
+hg ci -A -m 0.0 -d "1000000 0"
+hg merge -b foo
+hg parents -b 
+
+# re-test with more branches
+hg update -C 0
+echo d > d
+hg ci -A -m 0.0 -d "1000000 0"
+hg merge -b foo
+hg parents -b 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-branch.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,55 @@
+adding a
+adding b
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+changeset:   0:b544c4ac4389
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     0
+
+Using head f4ac749470f2 for branch foo
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+changeset:   1:f4ac749470f2
+tag:         foo
+tag:         tip
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     1
+
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+adding c
+Using head f4ac749470f2 for branch foo
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+changeset:   2:1505d56ee00e
+tag:         tip
+parent:      0:b544c4ac4389
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     0.0
+
+changeset:   1:f4ac749470f2
+tag:         foo
+branch:      foo
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     1
+
+2 files updated, 0 files merged, 1 files removed, 0 files unresolved
+adding d
+Using head f4ac749470f2 for branch foo
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+changeset:   3:53b72df12ae5
+tag:         tip
+parent:      0:b544c4ac4389
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     0.0
+
+changeset:   1:f4ac749470f2
+tag:         foo
+branch:      foo
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     1
+
--- a/tests/test-bundle	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-bundle	Sat Oct 21 15:22:08 2006 -0400
@@ -57,4 +57,5 @@
 hg -R bundle://../full.hg log
 hg incoming bundle://../full.hg
 hg -R bundle://../full.hg outgoing ../partial2
+hg -R bundle://../does-not-exist.hg outgoing ../partial2
 cd ..
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bundle-r	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+hg init test
+cd test
+cat >>afile <<EOF
+0
+EOF
+hg add afile
+hg commit -m "0.0" -d "1000000 0"
+cat >>afile <<EOF
+1
+EOF
+hg commit -m "0.1" -d "1000000 0"
+cat >>afile <<EOF
+2
+EOF
+hg commit -m "0.2" -d "1000000 0"
+cat >>afile <<EOF
+3
+EOF
+hg commit -m "0.3" -d "1000000 0"
+hg update -C 0
+cat >>afile <<EOF
+1
+EOF
+hg commit -m "1.1" -d "1000000 0"
+cat >>afile <<EOF
+2
+EOF
+hg commit -m "1.2" -d "1000000 0"
+cat >fred <<EOF
+a line
+EOF
+cat >>afile <<EOF
+3
+EOF
+hg add fred
+hg commit -m "1.3" -d "1000000 0"
+hg mv afile adifferentfile
+hg commit -m "1.3m" -d "1000000 0"
+hg update -C 3
+hg mv afile anotherfile
+hg commit -m "0.3m" -d "1000000 0"
+hg debugindex .hg/data/afile.i
+hg debugindex .hg/data/adifferentfile.i
+hg debugindex .hg/data/anotherfile.i
+hg debugindex .hg/data/fred.i
+hg debugindex .hg/00manifest.i
+hg verify
+cd ..
+for i in 0 1 2 3 4 5 6 7 8; do
+   mkdir test-"$i"
+   hg --cwd test-"$i" init
+   hg -R test bundle -r "$i" test-"$i".hg test-"$i"
+   cd test-"$i"
+   hg unbundle ../test-"$i".hg
+   hg verify
+   hg tip -q
+   cd ..
+done
+cd test-8
+hg pull ../test-7
+hg verify
+hg rollback
+cd ..
+
+echo % should fail
+hg -R test bundle --base 2 -r tip test-bundle-branch1.hg test-3
+hg -R test bundle -r tip test-bundle-branch1.hg
+
+hg -R test bundle --base 2 -r tip test-bundle-branch1.hg
+hg -R test bundle --base 2 -r 7 test-bundle-branch2.hg
+hg -R test bundle --base 2 test-bundle-all.hg
+hg -R test bundle --base 3 -r tip test-bundle-should-fail.hg
+
+# issue76 msg2163
+hg -R test bundle --base 3 -r 3 -r 3 test-bundle-cset-3.hg
+
+hg clone test-2 test-9
+cd test-9
+echo % 2
+hg tip -q
+hg unbundle ../test-bundle-should-fail.hg
+echo % 2
+hg tip -q
+hg unbundle ../test-bundle-all.hg
+echo % 8
+hg tip -q
+hg verify
+hg rollback
+echo % 2
+hg tip -q
+hg unbundle ../test-bundle-branch1.hg
+echo % 4
+hg tip -q
+hg verify
+hg rollback
+hg unbundle ../test-bundle-branch2.hg
+echo % 6
+hg tip -q
+hg verify
+
+cd ../test
+hg merge 7
+hg ci -m merge -d "1000000 0"
+cd ..
+hg -R test bundle --base 2 test-bundle-head.hg
+hg clone test-2 test-10
+cd test-10
+hg unbundle ../test-bundle-head.hg
+echo % 9
+hg tip -q
+hg verify
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bundle-r.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,214 @@
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       3      0       0 362fef284ce2 000000000000 000000000000
+     1         3       5      1       1 125144f7e028 362fef284ce2 000000000000
+     2         8       7      2       2 4c982badb186 125144f7e028 000000000000
+     3        15       9      3       3 19b1fc555737 4c982badb186 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      75      0       7 905359268f77 000000000000 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      75      0       8 905359268f77 000000000000 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       8      0       6 12ab3bcc5ea4 000000000000 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      48      0       0 43eadb1d2d06 000000000000 000000000000
+     1        48      48      1       1 8b89697eba2c 43eadb1d2d06 000000000000
+     2        96      48      2       2 626a32663c2f 8b89697eba2c 000000000000
+     3       144      48      3       3 f54c32f13478 626a32663c2f 000000000000
+     4       192      58      3       6 de68e904d169 626a32663c2f 000000000000
+     5       250      68      3       7 3b45cc2ab868 de68e904d169 000000000000
+     6       318      54      6       8 24d86153a002 f54c32f13478 000000000000
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 1 changesets, 1 total revisions
+0:5649c9d34dd8
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 2 changesets, 2 total revisions
+1:10b2180f755b
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 3 changes to 1 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+2:d62976ca1e50
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 4 changes to 1 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 4 changesets, 4 total revisions
+3:ac69c658229d
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 2 changesets, 2 total revisions
+1:5f4f3ceb285e
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 3 changes to 1 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+2:024e4e7df376
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 5 changes to 2 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 4 changesets, 5 total revisions
+3:1e3f6b843bd6
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 5 changesets with 6 changes to 3 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+3 files, 5 changesets, 6 total revisions
+4:80fe151401c2
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 5 changesets with 5 changes to 2 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 5 changesets, 5 total revisions
+4:836ac62537ab
+pulling from ../test-7
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 2 changes to 3 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
+rolling back last transaction
+% should fail
+abort: --base is incompatible with specifiying a destination
+abort: repository default-push not found!
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% 2
+2:d62976ca1e50
+adding changesets
+abort: unknown parent ac69c658229d!
+transaction abort!
+rollback completed
+% 2
+2:d62976ca1e50
+adding changesets
+adding manifests
+adding file changes
+added 6 changesets with 4 changes to 4 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+% 8
+8:836ac62537ab
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
+rolling back last transaction
+% 2
+2:d62976ca1e50
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 2 files
+(run 'hg update' to get a working copy)
+% 4
+4:836ac62537ab
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 5 changesets, 5 total revisions
+rolling back last transaction
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 3 changes to 3 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+% 6
+6:80fe151401c2
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+3 files, 7 changesets, 6 total revisions
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+adding changesets
+adding manifests
+adding file changes
+added 7 changesets with 4 changes to 4 files
+(run 'hg update' to get a working copy)
+% 9
+9:607fe5912aad
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 10 changesets, 7 total revisions
--- a/tests/test-bundle.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-bundle.out	Sat Oct 21 15:22:08 2006 -0400
@@ -208,3 +208,4 @@
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     0.3m
 
+abort: No such file or directory: ../does-not-exist.hg
--- a/tests/test-command-template	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-command-template	Sat Oct 21 15:22:08 2006 -0400
@@ -65,6 +65,10 @@
 echo 'style = t' >> .hg/hgrc
 hg log
 
+echo '# issue338'
+hg log --style=changelog > changelog
+cat changelog
+
 echo "# keys work"
 for key in author branches date desc file_adds file_dels files \
         manifest node parents rev tags; do
--- a/tests/test-command-template.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-command-template.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,4 +1,20 @@
 # default style is like normal output
+1c1
+< changeset:   3:10e46f2dcbf4
+---
+> changeset:   3:10e46f2dcbf4823578cf180f33ecf0b957964c47
+10c10
+< changeset:   2:97054abb4ab8
+---
+> changeset:   2:97054abb4ab824450e9164180baf491ae0078465
+18c18
+< changeset:   1:b608e9d1a3f0
+---
+> changeset:   1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
+29c29
+< changeset:   0:1e4e1b8f71e0
+---
+> changeset:   0:1e4e1b8f71e05681d422154f5421e385fec3454f
 18a19
 > files:       
 29a31
@@ -43,9 +59,9 @@
   line 1
 
 # error if style not readable
-abort: Permission denied - ./q
+abort: Permission denied: ./q
 # error if no style
-abort: No such file or directory - notexist
+abort: No such file or directory: notexist
 # error if style missing key
 abort: ./t: no key named 'changeset'
 # error if include fails
@@ -60,6 +76,33 @@
 2
 1
 0
+# issue338
+1970-01-16  person  <person>
+
+	* c:
+	no user, no domain
+	[10e46f2dcbf4] [tip]
+
+1970-01-14  other  <other@place>
+
+	* c:
+	no person
+	[97054abb4ab8]
+
+1970-01-13  A. N. Other  <other@place>
+
+	* b:
+	other 1 other 2
+
+	other 3
+	[b608e9d1a3f0]
+
+1970-01-12  User Name  <user@hostname>
+
+	* a:
+	line 1 line 2
+	[1e4e1b8f71e0]
+
 # keys work
 author: person
 author: other@place
--- a/tests/test-commit.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-commit.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,16 +1,17 @@
 abort: impossible time zone offset: 4444444
 transaction abort!
 rollback completed
-abort: invalid date: '1\t15.1'
+abort: invalid date: '1\t15.1' see hg(1) manual page for details
 transaction abort!
 rollback completed
-abort: invalid date: 'foo bar'
+abort: invalid date: 'foo bar' see hg(1) manual page for details
 transaction abort!
 rollback completed
-abort: invalid date: ' 1 4444'
+abort: invalid date: ' 1 4444' see hg(1) manual page for details
 transaction abort!
 rollback completed
 abort: date exceeds 32 bits: 111111111111
 transaction abort!
 rollback completed
+trouble committing bar!
 abort: No such file or directory: .../test/bar
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-config-case	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+echo '[Section]' >> $HGRCPATH
+echo 'KeY = Case Sensitive' >> $HGRCPATH
+echo 'key = lower case' >> $HGRCPATH
+
+hg showconfig
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-config-case.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,2 @@
+Section.KeY=Case Sensitive
+Section.key=lower case
--- a/tests/test-confused-revert	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-confused-revert	Sat Oct 21 15:22:08 2006 -0400
@@ -13,7 +13,7 @@
 hg status
 
 echo "reverting..."
-hg revert
+hg revert --all
 
 echo "%%% should show b unknown and a back to normal"
 hg status
@@ -42,10 +42,10 @@
 hg status
 
 echo "%%% revert should fail"
-hg revert
+hg revert --all
 
 echo "%%% revert should be ok now"
-hg revert -r2
+hg revert -r2 --all
 
 echo "%%% should show b unknown and a marked modified (merged)"
 hg status
--- a/tests/test-confused-revert.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-confused-revert.out	Sat Oct 21 15:22:08 2006 -0400
@@ -17,7 +17,7 @@
 A b
 R a
 %%% revert should fail
-abort: working dir has two parents; you must specify the revision to revert to
+abort: uncommitted merge - please provide a specific revision
 %%% revert should be ok now
 undeleting a
 forgetting b
--- a/tests/test-copy.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-copy.out	Sat Oct 21 15:22:08 2006 -0400
@@ -2,7 +2,7 @@
 b
  b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
 we should see two history entries
-changeset:   1:386a3cc01532710ca78aed9a54fa2f459c04f29c
+changeset:   1:386a3cc01532
 tag:         tip
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
@@ -11,7 +11,7 @@
 2
 
 
-changeset:   0:33aaa84a386bd609094aeb21a97c09436c482ef1
+changeset:   0:33aaa84a386b
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
 files:       a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-debugcomplete	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+echo '% Show all commands except debug commands'
+hg debugcomplete
+
+echo
+echo '% Show all commands that start with "a"'
+hg debugcomplete a
+
+echo
+echo '% Do not show debug commands if there are other candidates'
+hg debugcomplete d
+
+echo
+echo '% Show debug commands if there are no other candidates'
+hg debugcomplete debug
+
+echo
+echo '% Do not show the alias of a debug command if there are other candidates'
+echo '% (this should hide rawcommit)'
+hg debugcomplete r
+
+echo
+echo '% Show the alias of a debug command if there are no other candidates'
+hg debugcomplete rawc
+
+echo
+echo '% Show the global options'
+hg debugcomplete --options | sort
+
+echo
+echo '% Show the options for the "serve" command'
+hg debugcomplete --options serve | sort
+
+echo
+echo '% Show an error if we use --options with an ambiguous abbreviation'
+hg debugcomplete --options s
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-debugcomplete.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,150 @@
+% Show all commands except debug commands
+add
+addremove
+annotate
+archive
+backout
+bundle
+cat
+clone
+commit
+copy
+diff
+export
+grep
+heads
+help
+identify
+import
+incoming
+init
+locate
+log
+manifest
+merge
+outgoing
+parents
+paths
+pull
+push
+recover
+remove
+rename
+revert
+rollback
+root
+serve
+showconfig
+status
+tag
+tags
+tip
+unbundle
+update
+verify
+version
+
+% Show all commands that start with "a"
+add
+addremove
+annotate
+archive
+
+% Do not show debug commands if there are other candidates
+diff
+
+% Show debug commands if there are no other candidates
+debugancestor
+debugcheckstate
+debugcomplete
+debugconfig
+debugdata
+debugforget
+debugindex
+debugindexdot
+debugrawcommit
+debugrebuildstate
+debugrename
+debugsetparents
+debugstate
+debugundo
+debugwalk
+
+% Do not show the alias of a debug command if there are other candidates
+% (this should hide rawcommit)
+recover
+remove
+rename
+revert
+rollback
+root
+
+% Show the alias of a debug command if there are no other candidates
+rawcommit
+
+% Show the global options
+--config
+--cwd
+--debug
+--debugger
+--help
+--lsprof
+--noninteractive
+--profile
+--quiet
+--repository
+--time
+--traceback
+--verbose
+--version
+-R
+-h
+-q
+-v
+-y
+
+% Show the options for the "serve" command
+--accesslog
+--address
+--config
+--cwd
+--daemon
+--daemon-pipefds
+--debug
+--debugger
+--errorlog
+--help
+--ipv6
+--lsprof
+--name
+--noninteractive
+--pid-file
+--port
+--profile
+--quiet
+--repository
+--stdio
+--style
+--templates
+--time
+--traceback
+--verbose
+--version
+--webdir-conf
+-6
+-A
+-E
+-R
+-a
+-d
+-h
+-n
+-p
+-q
+-t
+-v
+-y
+
+% Show an error if we use --options with an ambiguous abbreviation
+hg: command 's' is ambiguous:
+    serve showconfig status
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-hashes	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+hg init a
+cd a
+echo bar > foo
+hg add foo
+hg ci -m 'add foo' -d '1000000 0'
+
+echo foobar > foo
+hg ci -m 'change foo' -d '1000001 0'
+
+echo 'quiet:'
+hg --quiet diff -r 0 -r 1
+echo
+
+echo 'normal:'
+hg diff -r 0 -r 1
+echo
+
+echo 'verbose:'
+hg --verbose diff -r 0 -r 1
+echo
+
+echo 'debug:'
+hg --debug diff -r 0 -r 1
+echo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-hashes.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,31 @@
+quiet:
+--- a/foo	Mon Jan 12 13:46:40 1970 +0000
++++ b/foo	Mon Jan 12 13:46:41 1970 +0000
+@@ -1,1 +1,1 @@ bar
+-bar
++foobar
+
+normal:
+diff -r 74de3f1392e2 -r b8b5f023a6ad foo
+--- a/foo	Mon Jan 12 13:46:40 1970 +0000
++++ b/foo	Mon Jan 12 13:46:41 1970 +0000
+@@ -1,1 +1,1 @@ bar
+-bar
++foobar
+
+verbose:
+diff -r 74de3f1392e2 -r b8b5f023a6ad foo
+--- a/foo	Mon Jan 12 13:46:40 1970 +0000
++++ b/foo	Mon Jan 12 13:46:41 1970 +0000
+@@ -1,1 +1,1 @@ bar
+-bar
++foobar
+
+debug:
+diff -r 74de3f1392e2d67856fb155963441f2610494e1a -r b8b5f023a6ad77fc378bd95cf3fa00cd1414d107 foo
+--- a/foo	Mon Jan 12 13:46:40 1970 +0000
++++ b/foo	Mon Jan 12 13:46:41 1970 +0000
+@@ -1,1 +1,1 @@ bar
+-bar
++foobar
+
--- a/tests/test-diff-ignore-whitespace	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-diff-ignore-whitespace	Sat Oct 21 15:22:08 2006 -0400
@@ -3,8 +3,7 @@
 # GNU diff is the reference for all of these results.
 
 hgdiff() {
-    hg diff "$@" | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-                  -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+    hg diff --nodates "$@"
 }
 
 test_added_blank_lines() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-subdir	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+hg init
+
+mkdir alpha
+touch alpha/one
+mkdir beta
+touch beta/two
+
+hg add alpha/one beta/two
+hg ci -m "start" -d "1000000 0"
+
+echo 1 > alpha/one
+echo 2 > beta/two
+
+echo EVERYTHING
+hg diff --nodates
+
+echo BETA ONLY
+hg diff --nodates beta
+
+echo INSIDE BETA
+cd beta
+hg diff --nodates .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-subdir.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,23 @@
+EVERYTHING
+diff -r ec612a6291f1 alpha/one
+--- a/alpha/one
++++ b/alpha/one
+@@ -0,0 +1,1 @@
++1
+diff -r ec612a6291f1 beta/two
+--- a/beta/two
++++ b/beta/two
+@@ -0,0 +1,1 @@
++2
+BETA ONLY
+diff -r ec612a6291f1 beta/two
+--- a/beta/two
++++ b/beta/two
+@@ -0,0 +1,1 @@
++2
+INSIDE BETA
+diff -r ec612a6291f1 beta/two
+--- a/beta/two
++++ b/beta/two
+@@ -0,0 +1,1 @@
++2
--- a/tests/test-diffdir	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-diffdir	Sat Oct 21 15:22:08 2006 -0400
@@ -7,12 +7,9 @@
 
 echo 123 > b
 hg add b
-hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+hg diff --nodates
 
-hg diff -r tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-                     -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+hg diff --nodates -r tip
 
 echo foo > a
-hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+hg diff --nodates
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-doctest.py	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+#
+
+import doctest
+
+import mercurial.changelog
+# test doctest from changelog
+
+doctest.testmod(mercurial.changelog)
+
--- a/tests/test-empty-dir	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-empty-dir	Sat Oct 21 15:22:08 2006 -0400
@@ -11,6 +11,6 @@
 cat sub/b
 hg co 0
 cat sub/b 2>/dev/null || echo "sub/b not present"
-ls sub 2>/dev/null || echo "sub not present"
+test -e sub || echo "sub not present"
 
 true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extdiff	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "extdiff=" >> $HGRCPATH
+
+hg init a
+cd a
+echo a > a
+hg add
+diff -N /dev/null /dev/null 2> /dev/null
+if [ $? -ne 0 ]; then
+	opt="-p gdiff"
+fi
+hg extdiff -o -Nr $opt
+
+echo "[extdiff]" >> $HGRCPATH
+echo "cmd.falabala=echo" >> $HGRCPATH
+echo "opts.falabala=diffing" >> $HGRCPATH
+
+hg falabala
+
+hg help falabala
+
+hg ci -d '0 0' -mtest1
+
+echo b >> a
+hg ci -d '1 0' -mtest2
+
+hg falabala -r 0:1
+
+# test diff during merge
+hg update 0
+echo b >> b
+hg add b
+hg ci -m "new branch" -d '1 0'
+hg update -C 1
+hg merge tip
+hg falabala || echo "diff-like tools yield a non-zero exit code"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extdiff.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,39 @@
+adding a
+making snapshot of 0 files from rev 000000000000
+making snapshot of 1 files from working dir
+diff -Nr a.000000000000/a a/a
+0a1
+> a
+making snapshot of 0 files from rev 000000000000
+making snapshot of 1 files from working dir
+diffing a.000000000000 a
+hg falabala [OPT]... [FILE]...
+
+use 'echo' to diff repository (or selected files)
+
+            Show differences between revisions for the specified
+            files, using the 'echo' program.
+
+            When two revision arguments are given, then changes are
+            shown between those revisions. If only one revision is
+            specified then that revision is compared to the working
+            directory, and, when no revisions are specified, the
+            working directory files are compared to its parent.
+
+options:
+
+ -o --option   pass option to comparison program
+ -r --rev      revision
+ -I --include  include names matching the given patterns
+ -X --exclude  exclude names matching the given patterns
+making snapshot of 1 files from rev e27a2475d60a
+making snapshot of 1 files from rev 5e49ec8d3f05
+diffing a.e27a2475d60a a.5e49ec8d3f05
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+making snapshot of 1 files from rev 5e49ec8d3f05
+making snapshot of 1 files from working dir
+diffing a.5e49ec8d3f05 a
+diff-like tools yield a non-zero exit code
--- a/tests/test-fetch	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-fetch	Sat Oct 21 15:22:08 2006 -0400
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "fetch=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "fetch=" >> $HGRCPATH
 
 hg init a
 echo a > a/a
--- a/tests/test-filebranch.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-filebranch.out	Sat Oct 21 15:22:08 2006 -0400
@@ -19,7 +19,6 @@
 resolving manifests
 getting bar
 merging foo
-resolving foo
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 we shouldn't have anything but foo in merge state here
@@ -31,10 +30,10 @@
      2       150      71      2       2 a6aef98656b7 c36078bec30d 000000000000
      3       221      72      3       3 0c2cc6fc80e2 182b283965f1 a6aef98656b7
 log should show foo and quux changed
-changeset:   3:0c2cc6fc80e2d4ee289bb658dbbe9ad932380fe9
+changeset:   3:0c2cc6fc80e2
 tag:         tip
-parent:      1:182b283965f1069c0112784e30e7755ad1c0dd52
-parent:      2:a6aef98656b71154cae9d87408abe6d0218c8045
+parent:      1:182b283965f1
+parent:      2:a6aef98656b7
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
 files:       foo quux
--- a/tests/test-flags	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-flags	Sat Oct 21 15:22:08 2006 -0400
@@ -10,6 +10,7 @@
 hg ci -m "added a b" -d "1000000 0"
 
 cd ..
+hg clone test1 test3
 mkdir test2
 cd test2
 
@@ -29,6 +30,19 @@
 
 hg -v merge
 
-ls -l ../test[12]/a > foo
+cd ../test3
+echo 123 >>b
+hg ci -m "b updated" -d "1000000 0"
+
+hg pull ../test2
+hg heads
+hg history
+
+hg -v merge
+
+ls -l ../test[123]/a > foo
 cut -b 1-10 < foo
 
+hg debugindex .hg/data/a.i
+hg debugindex ../test2/.hg/data/a.i
+hg debugindex ../test1/.hg/data/a.i
--- a/tests/test-flags.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-flags.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,3 +1,4 @@
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 pulling from ../test1
 requesting all changes
 adding changesets
@@ -44,8 +45,58 @@
 
 resolving manifests
 merging a
-resolving a
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
+pulling from ../test2
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+changeset:   2:b833d578451e
+tag:         tip
+parent:      0:4536b1c2ca69
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     chmod +x a
+
+changeset:   1:d54568174d8e
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     b updated
+
+changeset:   2:b833d578451e
+tag:         tip
+parent:      0:4536b1c2ca69
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     chmod +x a
+
+changeset:   1:d54568174d8e
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     b updated
+
+changeset:   0:4536b1c2ca69
+user:        test
+date:        Mon Jan 12 13:46:40 1970 +0000
+summary:     added a b
+
+resolving manifests
+getting a
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
 -rwxr-x---
 -rwxr-x---
+-rwxr-x---
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       0      0       0 b80de5d13875 000000000000 000000000000
+     1         0       0      0       2 37c42bd6cc03 b80de5d13875 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       0      0       0 b80de5d13875 000000000000 000000000000
+     1         0       0      0       1 37c42bd6cc03 b80de5d13875 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       0      0       0 b80de5d13875 000000000000 000000000000
+     1         0       5      1       1 7fe919cc0336 b80de5d13875 000000000000
+     2         5       0      2       2 37c42bd6cc03 b80de5d13875 000000000000
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-export	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+hg init a
+cd a
+
+echo start > start
+hg ci -Amstart -d '0 0'
+echo new > new
+hg ci -Amnew -d '0 0'
+echo '% new file'
+hg diff --git -r 0
+
+hg cp new copy
+hg ci -mcopy -d '0 0'
+echo '% copy'
+hg diff --git -r 1:tip
+
+hg mv copy rename
+hg ci -mrename -d '0 0'
+echo '% rename'
+hg diff --git -r 2:tip
+
+hg rm rename
+hg ci -mdelete -d '0 0'
+echo '% delete'
+hg diff --git -r 3:tip
+
+cat > src <<EOF
+1
+2
+3
+4
+5
+EOF
+hg ci -Amsrc -d '0 0'
+chmod +x src
+hg ci -munexec -d '0 0'
+echo '% chmod 644'
+hg diff --git -r 5:tip
+
+hg mv src dst
+chmod -x dst
+echo a >> dst
+hg ci -mrenamemod -d '0 0'
+echo '% rename+mod+chmod'
+hg diff --git -r 6:tip
+
+echo '% nonexistent in tip+chmod'
+hg diff --git -r 5:6
+
+echo '% binary diff'
+cp $TESTDIR/binfile.bin .
+hg add binfile.bin
+hg diff --git > b.diff
+cat b.diff
+
+echo '% import binary diff'
+hg revert binfile.bin
+rm binfile.bin
+hg import -mfoo b.diff
+cmp binfile.bin $TESTDIR/binfile.bin
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-export.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,67 @@
+adding start
+adding new
+% new file
+diff --git a/new b/new
+new file mode 100644
+--- /dev/null
++++ b/new
+@@ -0,0 +1,1 @@
++new
+% copy
+diff --git a/new b/copy
+copy from new
+copy to copy
+% rename
+diff --git a/copy b/rename
+rename from copy
+rename to rename
+% delete
+diff --git a/rename b/rename
+deleted file mode 100644
+--- a/rename
++++ /dev/null
+@@ -1,1 +0,0 @@
+-new
+adding src
+% chmod 644
+diff --git a/src b/src
+old mode 100644
+new mode 100755
+% rename+mod+chmod
+diff --git a/src b/dst
+old mode 100755
+new mode 100644
+rename from src
+rename to dst
+--- a/dst
++++ b/dst
+@@ -3,3 +3,4 @@ 3
+ 3
+ 4
+ 5
++a
+% nonexistent in tip+chmod
+diff --git a/src b/src
+old mode 100644
+new mode 100755
+% binary diff
+diff --git a/binfile.bin b/binfile.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..37ba3d1c6f17137d9c5f5776fa040caf5fe73ff9
+GIT binary patch
+literal 593
+zc$@)I0<QguP)<h;3K|Lk000e1NJLTq000mG000mO0ssI2kdbIM00009a7bBm000XU
+z000XU0RWnu7ytkO2XskIMF-Uh9TW;VpMjwv0005-Nkl<ZD9@FWPs=e;7{<>W$NUkd
+zX$nnYLt$-$V!?uy+1V%`z&Eh=ah|duER<4|QWhju3gb^nF*8iYobxWG-qqXl=2~5M
+z*IoDB)sG^CfNuoBmqLTVU^<;@nwHP!1wrWd`{(mHo6VNXWtyh{alzqmsH*yYzpvLT
+zLdY<T=ks|woh-`&01!ej#(xbV1f|pI*=%;d-%F*E*X#ZH`4I%6SS+$EJDE&ct=8po
+ziN#{?_j|kD%Cd|oiqds`xm@;oJ-^?NG3Gdqrs?5u*zI;{nogxsx~^|Fn^Y?Gdc6<;
+zfMJ+iF1J`LMx&A2?dEwNW8ClebzPTbIh{@$hS6*`kH@1d%Lo7fA#}N1)oN7`gm$~V
+z+wDx#)OFqMcE{s!JN0-xhG8ItAjVkJwEcb`3WWlJfU2r?;Pd%dmR+q@mSri5q9_W-
+zaR2~ECX?B2w+zELozC0s*6Z~|QG^f{3I#<`?)Q7U-JZ|q5W;9Q8i_=pBuSzunx=U;
+z9C)5jBoYw9^?EHyQl(M}1OlQcCX>lXB*ODN003Z&P17_@)3Pi=i0wb04<W?v-u}7K
+zXmmQA+wDgE!qR9o8jr`%=ab_&uh(l?R=r;Tjiqon91I2-hIu?57~@*4h7h9uORK#=
+fQItJW-{SoTm)8|5##k|m00000NkvXXu0mjf{mKw4
+
+% import binary diff
+applying b.diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-import	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+hg init a
+cd a
+
+echo % new file
+hg import -mnew - <<EOF
+diff --git a/new b/new
+new file mode 100644
+index 0000000..7898192
+--- /dev/null
++++ b/new
+@@ -0,0 +1 @@
++a
+EOF
+
+echo % chmod +x
+hg import -msetx - <<EOF
+diff --git a/new b/new
+old mode 100644
+new mode 100755
+EOF
+
+test -x new || echo failed
+
+echo % copy
+hg import -mcopy - <<EOF
+diff --git a/new b/copy
+old mode 100755
+new mode 100644
+similarity index 100%
+copy from new
+copy to copy
+diff --git a/new b/copyx
+similarity index 100%
+copy from new
+copy to copyx
+EOF
+
+test -f copy -a ! -x copy || echo failed
+test -x copyx || echo failed
+cat copy
+hg cat copy
+
+echo % rename
+hg import -mrename - <<EOF
+diff --git a/copy b/rename
+similarity index 100%
+rename from copy
+rename to rename
+EOF
+
+hg locate
+
+echo % delete
+hg import -mdelete - <<EOF
+diff --git a/copyx b/copyx
+deleted file mode 100755
+index 7898192..0000000
+--- a/copyx
++++ /dev/null
+@@ -1 +0,0 @@
+-a
+EOF
+
+hg locate
+test -f copyx && echo failed || true
+
+echo % regular diff
+hg import -mregular - <<EOF
+diff --git a/rename b/rename
+index 7898192..72e1fe3 100644
+--- a/rename
++++ b/rename
+@@ -1 +1,5 @@
+ a
++a
++a
++a
++a
+EOF
+
+echo % copy and modify
+hg import -mcopymod - <<EOF
+diff --git a/rename b/copy2
+similarity index 80%
+copy from rename
+copy to copy2
+index 72e1fe3..b53c148 100644
+--- a/rename
++++ b/copy2
+@@ -1,5 +1,5 @@
+ a
+ a
+-a
++b
+ a
+ a
+EOF
+
+hg cat copy2
+
+echo % rename and modify
+hg import -mrenamemod - <<EOF
+diff --git a/copy2 b/rename2
+similarity index 80%
+rename from copy2
+rename to rename2
+index b53c148..8f81e29 100644
+--- a/copy2
++++ b/rename2
+@@ -1,5 +1,5 @@
+ a
+ a
+ b
+-a
++c
+ a
+EOF
+
+hg locate copy2
+hg cat rename2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-import.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,34 @@
+% new file
+applying patch from stdin
+% chmod +x
+applying patch from stdin
+% copy
+applying patch from stdin
+a
+a
+% rename
+applying patch from stdin
+copyx
+new
+rename
+% delete
+applying patch from stdin
+new
+rename
+% regular diff
+applying patch from stdin
+% copy and modify
+applying patch from stdin
+a
+a
+b
+a
+a
+% rename and modify
+applying patch from stdin
+copy2: No such file or directory
+a
+a
+b
+c
+a
--- a/tests/test-globalopts	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-globalopts	Sat Oct 21 15:22:08 2006 -0400
@@ -45,7 +45,7 @@
 hg --cwd b tip --verbose
 
 echo %% --config
-hg --cwd c --config paths.quuxfoo=bar paths | grep -q quuxfoo && echo quuxfoo
+hg --cwd c --config paths.quuxfoo=bar paths | grep quuxfoo > /dev/null && echo quuxfoo
 hg --cwd c --config '' tip -q
 hg --cwd c --config a.b tip -q
 hg --cwd c --config a tip -q
--- a/tests/test-globalopts.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-globalopts.out	Sat Oct 21 15:22:08 2006 -0400
@@ -47,7 +47,7 @@
 0:8580ff50825a
 1:b6c483daf290
 %% -v/--verbose
-changeset:   1:b6c483daf2907ce5825c0bb50f5716226281cc1a
+changeset:   1:b6c483daf290
 tag:         tip
 user:        test
 date:        Thu Jan 01 00:00:01 1970 +0000
@@ -56,7 +56,7 @@
 b
 
 
-changeset:   0:8580ff50825a50c8f716709acdf8de0deddcd6ab
+changeset:   0:8580ff50825a
 user:        test
 date:        Thu Jan 01 00:00:01 1970 +0000
 files:       a
@@ -64,7 +64,7 @@
 a
 
 
-changeset:   0:b6c483daf2907ce5825c0bb50f5716226281cc1a
+changeset:   0:b6c483daf290
 tag:         tip
 user:        test
 date:        Thu Jan 01 00:00:01 1970 +0000
@@ -105,6 +105,7 @@
 
 
 %% --traceback
+Traceback (most recent call last):
 %% --time
 Time: real x.x secs (user x.x+x.x sys x.x+x.x)
 %% --version
@@ -114,92 +115,96 @@
 
 list of commands (use "hg help -v" to show aliases and global options):
 
- add        add the specified files on the next commit
- annotate   show changeset information per file line
- archive    create unversioned archive of a repository revision
- backout    reverse effect of earlier changeset
- bundle     create a changegroup file
- cat        output the latest or given revisions of files
- clone      make a copy of an existing repository
- commit     commit the specified files or all outstanding changes
- copy       mark files as copied for the next commit
- diff       diff repository (or selected files)
- export     dump the header and diffs for one or more changesets
- grep       search for a pattern in specified files and revisions
- heads      show current repository heads
- help       show help for a command, extension, or list of commands
- identify   print information about the working copy
- import     import an ordered set of patches
- incoming   show new changesets found in source
- init       create a new repository in the given directory
- locate     locate files matching specific patterns
- log        show revision history of entire repository or files
- manifest   output the latest or given revision of the project manifest
- merge      Merge working directory with another revision
- outgoing   show changesets not found in destination
- parents    show the parents of the working dir or revision
- paths      show definition of symbolic path names
- pull       pull changes from the specified source
- push       push changes to the specified destination
- recover    roll back an interrupted transaction
- remove     remove the specified files on the next commit
- rename     rename files; equivalent of copy + remove
- revert     revert files or dirs to their states as of some revision
- rollback   roll back the last transaction in this repository
- root       print the root (top) of the current working dir
- serve      export the repository via HTTP
- status     show changed files in the working directory
- tag        add a tag for the current tip or a given revision
- tags       list repository tags
- tip        show the tip revision
- unbundle   apply a changegroup file
- update     update or merge working directory
- verify     verify the integrity of the repository
- version    output version and copyright information
+ add          add the specified files on the next commit
+ addremove    add all new files, delete all missing files
+ annotate     show changeset information per file line
+ archive      create unversioned archive of a repository revision
+ backout      reverse effect of earlier changeset
+ bundle       create a changegroup file
+ cat          output the latest or given revisions of files
+ clone        make a copy of an existing repository
+ commit       commit the specified files or all outstanding changes
+ copy         mark files as copied for the next commit
+ diff         diff repository (or selected files)
+ export       dump the header and diffs for one or more changesets
+ grep         search for a pattern in specified files and revisions
+ heads        show current repository heads
+ help         show help for a command, extension, or list of commands
+ identify     print information about the working copy
+ import       import an ordered set of patches
+ incoming     show new changesets found in source
+ init         create a new repository in the given directory
+ locate       locate files matching specific patterns
+ log          show revision history of entire repository or files
+ manifest     output the latest or given revision of the project manifest
+ merge        Merge working directory with another revision
+ outgoing     show changesets not found in destination
+ parents      show the parents of the working dir or revision
+ paths        show definition of symbolic path names
+ pull         pull changes from the specified source
+ push         push changes to the specified destination
+ recover      roll back an interrupted transaction
+ remove       remove the specified files on the next commit
+ rename       rename files; equivalent of copy + remove
+ revert       revert files or dirs to their states as of some revision
+ rollback     roll back the last transaction in this repository
+ root         print the root (top) of the current working dir
+ serve        export the repository via HTTP
+ showconfig   show combined config settings from all hgrc files
+ status       show changed files in the working directory
+ tag          add a tag for the current tip or a given revision
+ tags         list repository tags
+ tip          show the tip revision
+ unbundle     apply a changegroup file
+ update       update or merge working directory
+ verify       verify the integrity of the repository
+ version      output version and copyright information
 Mercurial Distributed SCM
 
 list of commands (use "hg help -v" to show aliases and global options):
 
- add        add the specified files on the next commit
- annotate   show changeset information per file line
- archive    create unversioned archive of a repository revision
- backout    reverse effect of earlier changeset
- bundle     create a changegroup file
- cat        output the latest or given revisions of files
- clone      make a copy of an existing repository
- commit     commit the specified files or all outstanding changes
- copy       mark files as copied for the next commit
- diff       diff repository (or selected files)
- export     dump the header and diffs for one or more changesets
- grep       search for a pattern in specified files and revisions
- heads      show current repository heads
- help       show help for a command, extension, or list of commands
- identify   print information about the working copy
- import     import an ordered set of patches
- incoming   show new changesets found in source
- init       create a new repository in the given directory
- locate     locate files matching specific patterns
- log        show revision history of entire repository or files
- manifest   output the latest or given revision of the project manifest
- merge      Merge working directory with another revision
- outgoing   show changesets not found in destination
- parents    show the parents of the working dir or revision
- paths      show definition of symbolic path names
- pull       pull changes from the specified source
- push       push changes to the specified destination
- recover    roll back an interrupted transaction
- remove     remove the specified files on the next commit
- rename     rename files; equivalent of copy + remove
- revert     revert files or dirs to their states as of some revision
- rollback   roll back the last transaction in this repository
- root       print the root (top) of the current working dir
- serve      export the repository via HTTP
- status     show changed files in the working directory
- tag        add a tag for the current tip or a given revision
- tags       list repository tags
- tip        show the tip revision
- unbundle   apply a changegroup file
- update     update or merge working directory
- verify     verify the integrity of the repository
- version    output version and copyright information
+ add          add the specified files on the next commit
+ addremove    add all new files, delete all missing files
+ annotate     show changeset information per file line
+ archive      create unversioned archive of a repository revision
+ backout      reverse effect of earlier changeset
+ bundle       create a changegroup file
+ cat          output the latest or given revisions of files
+ clone        make a copy of an existing repository
+ commit       commit the specified files or all outstanding changes
+ copy         mark files as copied for the next commit
+ diff         diff repository (or selected files)
+ export       dump the header and diffs for one or more changesets
+ grep         search for a pattern in specified files and revisions
+ heads        show current repository heads
+ help         show help for a command, extension, or list of commands
+ identify     print information about the working copy
+ import       import an ordered set of patches
+ incoming     show new changesets found in source
+ init         create a new repository in the given directory
+ locate       locate files matching specific patterns
+ log          show revision history of entire repository or files
+ manifest     output the latest or given revision of the project manifest
+ merge        Merge working directory with another revision
+ outgoing     show changesets not found in destination
+ parents      show the parents of the working dir or revision
+ paths        show definition of symbolic path names
+ pull         pull changes from the specified source
+ push         push changes to the specified destination
+ recover      roll back an interrupted transaction
+ remove       remove the specified files on the next commit
+ rename       rename files; equivalent of copy + remove
+ revert       revert files or dirs to their states as of some revision
+ rollback     roll back the last transaction in this repository
+ root         print the root (top) of the current working dir
+ serve        export the repository via HTTP
+ showconfig   show combined config settings from all hgrc files
+ status       show changed files in the working directory
+ tag          add a tag for the current tip or a given revision
+ tags         list repository tags
+ tip          show the tip revision
+ unbundle     apply a changegroup file
+ update       update or merge working directory
+ verify       verify the integrity of the repository
+ version      output version and copyright information
 %% not tested: --debugger
--- a/tests/test-grep	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-grep	Sat Oct 21 15:22:08 2006 -0400
@@ -18,6 +18,13 @@
 mv port1 port
 hg commit -m 4 -u spam -d '4 0'
 hg grep port port
-echo 'FIXME: history is wrong here'
 hg grep --all -nu port port
 hg grep import port
+
+hg cp port port2
+hg commit -m 4 -u spam -d '5 0'
+echo '% follow'
+hg grep -f 'import$' port2
+echo deport >> port2
+hg commit -m 5 -u eggs -d '6 0'
+hg grep -f --all -nu port port2
--- a/tests/test-grep.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-grep.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,10 +1,25 @@
 port:4:export
 port:4:vaportight
 port:4:import/export
-FIXME: history is wrong here
-port:1:1:-:eggs:import
-port:1:2:+:eggs:vaportight
-port:1:3:+:eggs:import/export
-port:0:2:+:spam:export
-port:0:1:+:spam:import
+port:4:4:-:spam:import/export
+port:3:4:+:eggs:import/export
+port:2:1:-:spam:import
+port:2:2:-:spam:export
+port:2:1:+:spam:export
+port:2:2:+:spam:vaportight
+port:2:3:+:spam:import/export
+port:1:2:+:eggs:export
+port:0:1:+:eggs:import
 port:4:import/export
+% follow
+port:0:import
+port2:6:4:+:eggs:deport
+port:4:4:-:spam:import/export
+port:3:4:+:eggs:import/export
+port:2:1:-:spam:import
+port:2:2:-:spam:export
+port:2:1:+:spam:export
+port:2:2:+:spam:vaportight
+port:2:3:+:spam:import/export
+port:1:2:+:eggs:export
+port:0:1:+:eggs:import
--- a/tests/test-help.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-help.out	Sat Oct 21 15:22:08 2006 -0400
@@ -38,90 +38,94 @@
 
 list of commands (use "hg help -v" to show aliases and global options):
 
- add        add the specified files on the next commit
- annotate   show changeset information per file line
- archive    create unversioned archive of a repository revision
- backout    reverse effect of earlier changeset
- bundle     create a changegroup file
- cat        output the latest or given revisions of files
- clone      make a copy of an existing repository
- commit     commit the specified files or all outstanding changes
- copy       mark files as copied for the next commit
- diff       diff repository (or selected files)
- export     dump the header and diffs for one or more changesets
- grep       search for a pattern in specified files and revisions
- heads      show current repository heads
- help       show help for a command, extension, or list of commands
- identify   print information about the working copy
- import     import an ordered set of patches
- incoming   show new changesets found in source
- init       create a new repository in the given directory
- locate     locate files matching specific patterns
- log        show revision history of entire repository or files
- manifest   output the latest or given revision of the project manifest
- merge      Merge working directory with another revision
- outgoing   show changesets not found in destination
- parents    show the parents of the working dir or revision
- paths      show definition of symbolic path names
- pull       pull changes from the specified source
- push       push changes to the specified destination
- recover    roll back an interrupted transaction
- remove     remove the specified files on the next commit
- rename     rename files; equivalent of copy + remove
- revert     revert files or dirs to their states as of some revision
- rollback   roll back the last transaction in this repository
- root       print the root (top) of the current working dir
- serve      export the repository via HTTP
- status     show changed files in the working directory
- tag        add a tag for the current tip or a given revision
- tags       list repository tags
- tip        show the tip revision
- unbundle   apply a changegroup file
- update     update or merge working directory
- verify     verify the integrity of the repository
- version    output version and copyright information
- add        add the specified files on the next commit
- annotate   show changeset information per file line
- archive    create unversioned archive of a repository revision
- backout    reverse effect of earlier changeset
- bundle     create a changegroup file
- cat        output the latest or given revisions of files
- clone      make a copy of an existing repository
- commit     commit the specified files or all outstanding changes
- copy       mark files as copied for the next commit
- diff       diff repository (or selected files)
- export     dump the header and diffs for one or more changesets
- grep       search for a pattern in specified files and revisions
- heads      show current repository heads
- help       show help for a command, extension, or list of commands
- identify   print information about the working copy
- import     import an ordered set of patches
- incoming   show new changesets found in source
- init       create a new repository in the given directory
- locate     locate files matching specific patterns
- log        show revision history of entire repository or files
- manifest   output the latest or given revision of the project manifest
- merge      Merge working directory with another revision
- outgoing   show changesets not found in destination
- parents    show the parents of the working dir or revision
- paths      show definition of symbolic path names
- pull       pull changes from the specified source
- push       push changes to the specified destination
- recover    roll back an interrupted transaction
- remove     remove the specified files on the next commit
- rename     rename files; equivalent of copy + remove
- revert     revert files or dirs to their states as of some revision
- rollback   roll back the last transaction in this repository
- root       print the root (top) of the current working dir
- serve      export the repository via HTTP
- status     show changed files in the working directory
- tag        add a tag for the current tip or a given revision
- tags       list repository tags
- tip        show the tip revision
- unbundle   apply a changegroup file
- update     update or merge working directory
- verify     verify the integrity of the repository
- version    output version and copyright information
+ add          add the specified files on the next commit
+ addremove    add all new files, delete all missing files
+ annotate     show changeset information per file line
+ archive      create unversioned archive of a repository revision
+ backout      reverse effect of earlier changeset
+ bundle       create a changegroup file
+ cat          output the latest or given revisions of files
+ clone        make a copy of an existing repository
+ commit       commit the specified files or all outstanding changes
+ copy         mark files as copied for the next commit
+ diff         diff repository (or selected files)
+ export       dump the header and diffs for one or more changesets
+ grep         search for a pattern in specified files and revisions
+ heads        show current repository heads
+ help         show help for a command, extension, or list of commands
+ identify     print information about the working copy
+ import       import an ordered set of patches
+ incoming     show new changesets found in source
+ init         create a new repository in the given directory
+ locate       locate files matching specific patterns
+ log          show revision history of entire repository or files
+ manifest     output the latest or given revision of the project manifest
+ merge        Merge working directory with another revision
+ outgoing     show changesets not found in destination
+ parents      show the parents of the working dir or revision
+ paths        show definition of symbolic path names
+ pull         pull changes from the specified source
+ push         push changes to the specified destination
+ recover      roll back an interrupted transaction
+ remove       remove the specified files on the next commit
+ rename       rename files; equivalent of copy + remove
+ revert       revert files or dirs to their states as of some revision
+ rollback     roll back the last transaction in this repository
+ root         print the root (top) of the current working dir
+ serve        export the repository via HTTP
+ showconfig   show combined config settings from all hgrc files
+ status       show changed files in the working directory
+ tag          add a tag for the current tip or a given revision
+ tags         list repository tags
+ tip          show the tip revision
+ unbundle     apply a changegroup file
+ update       update or merge working directory
+ verify       verify the integrity of the repository
+ version      output version and copyright information
+ add          add the specified files on the next commit
+ addremove    add all new files, delete all missing files
+ annotate     show changeset information per file line
+ archive      create unversioned archive of a repository revision
+ backout      reverse effect of earlier changeset
+ bundle       create a changegroup file
+ cat          output the latest or given revisions of files
+ clone        make a copy of an existing repository
+ commit       commit the specified files or all outstanding changes
+ copy         mark files as copied for the next commit
+ diff         diff repository (or selected files)
+ export       dump the header and diffs for one or more changesets
+ grep         search for a pattern in specified files and revisions
+ heads        show current repository heads
+ help         show help for a command, extension, or list of commands
+ identify     print information about the working copy
+ import       import an ordered set of patches
+ incoming     show new changesets found in source
+ init         create a new repository in the given directory
+ locate       locate files matching specific patterns
+ log          show revision history of entire repository or files
+ manifest     output the latest or given revision of the project manifest
+ merge        Merge working directory with another revision
+ outgoing     show changesets not found in destination
+ parents      show the parents of the working dir or revision
+ paths        show definition of symbolic path names
+ pull         pull changes from the specified source
+ push         push changes to the specified destination
+ recover      roll back an interrupted transaction
+ remove       remove the specified files on the next commit
+ rename       rename files; equivalent of copy + remove
+ revert       revert files or dirs to their states as of some revision
+ rollback     roll back the last transaction in this repository
+ root         print the root (top) of the current working dir
+ serve        export the repository via HTTP
+ showconfig   show combined config settings from all hgrc files
+ status       show changed files in the working directory
+ tag          add a tag for the current tip or a given revision
+ tags         list repository tags
+ tip          show the tip revision
+ unbundle     apply a changegroup file
+ update       update or merge working directory
+ verify       verify the integrity of the repository
+ version      output version and copyright information
 hg add [OPTION]... [FILE]...
 
 add the specified files on the next commit
@@ -176,6 +180,8 @@
  -r --rev                  revision
  -a --text                 treat all files as text
  -p --show-function        show which function each change is in
+ -g --git                  use git extended diff format
+    --nodates              don't include dates in diff headers
  -w --ignore-all-space     ignore white space when comparing lines
  -b --ignore-space-change  ignore changes in the amount of white space
  -B --ignore-blank-lines   ignore changes whose lines are all blank
--- a/tests/test-hook.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-hook.out	Sat Oct 21 15:22:08 2006 -0400
@@ -36,43 +36,43 @@
 (run 'hg update' to get a working copy)
 pretag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
 precommit hook: p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
-pretxncommit hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
-4:4f92e785b90a
-commit hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
+pretxncommit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
+4:8ea2ef7ad3e8
+commit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
 commit hook b
 tag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
-pretag hook: t=la n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
-tag hook: t=la n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
-pretag hook: t=fa n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=0
+pretag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
+tag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
+pretag hook: t=fa n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=0
 pretag.forbid hook
 abort: pretag.forbid hook exited with status 1
-pretag hook: t=fla n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
+pretag hook: t=fla n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
 pretag.forbid hook
 abort: pretag.forbid hook exited with status 1
-4:4f92e785b90a
-precommit hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
-pretxncommit hook: n=7792358308a2026661cea44f9d47c072813004cb p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
-5:7792358308a2
-pretxncommit.forbid hook: tip=5:7792358308a2
+4:8ea2ef7ad3e8
+precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
+pretxncommit hook: n=fad284daf8c032148abaffcd745dafeceefceb61 p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
+5:fad284daf8c0
+pretxncommit.forbid hook: tip=5:fad284daf8c0
 abort: pretxncommit.forbid hook exited with status 1
 transaction abort!
 rollback completed
-4:4f92e785b90a
-precommit hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
+4:8ea2ef7ad3e8
+precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
 precommit.forbid hook
 abort: precommit.forbid hook exited with status 1
-4:4f92e785b90a
-preupdate hook: p1=b702efe9688826e3a91283852b328b84dbf37bc2 p2=
+4:8ea2ef7ad3e8
+preupdate hook: p1=b702efe96888 p2=
 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
-preupdate hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
-update hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2= err=0
+preupdate hook: p1=8ea2ef7ad3e8 p2=
+update hook: p1=8ea2ef7ad3e8 p2= err=0
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 3:4c52fb2e4022
 prechangegroup.forbid hook
 pulling from ../a
 searching for changes
 abort: prechangegroup.forbid hook exited with status 1
-pretxnchangegroup.forbid hook: tip=4:4f92e785b90a
+pretxnchangegroup.forbid hook: tip=4:8ea2ef7ad3e8
 pulling from ../a
 searching for changes
 adding changesets
@@ -84,7 +84,7 @@
 rollback completed
 3:4c52fb2e4022
 preoutgoing hook: s=pull
-outgoing hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 s=pull
+outgoing hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 s=pull
 pulling from ../a
 searching for changes
 adding changesets
--- a/tests/test-http	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-http	Sat Oct 21 15:22:08 2006 -0400
@@ -11,7 +11,7 @@
 
 echo % clone via stream
 http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \
-  sed -e 's/[0-9][0-9.]*/XXX/g'
+  sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/'
 hg verify -R copy
 
 echo % try to clone via stream, should use pull instead
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-http-clone-r	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+hg init remote
+cd remote
+echo "# creating 'remote'"
+cat >>afile <<EOF
+0
+EOF
+hg add afile
+hg commit -m "0.0"
+cat >>afile <<EOF
+1
+EOF
+hg commit -m "0.1"
+cat >>afile <<EOF
+2
+EOF
+hg commit -m "0.2"
+cat >>afile <<EOF
+3
+EOF
+hg commit -m "0.3"
+hg update -C 0
+cat >>afile <<EOF
+1
+EOF
+hg commit -m "1.1"
+cat >>afile <<EOF
+2
+EOF
+hg commit -m "1.2"
+cat >fred <<EOF
+a line
+EOF
+cat >>afile <<EOF
+3
+EOF
+hg add fred
+hg commit -m "1.3"
+hg mv afile adifferentfile
+hg commit -m "1.3m"
+hg update -C 3
+hg mv afile anotherfile
+hg commit -m "0.3m"
+hg debugindex .hg/data/afile.i
+hg debugindex .hg/data/adifferentfile.i
+hg debugindex .hg/data/anotherfile.i
+hg debugindex .hg/data/fred.i
+hg debugindex .hg/00manifest.i
+hg verify
+echo "# Starting server"
+hg serve -p 20061 -d --pid-file=../hg1.pid
+cd ..
+cat hg1.pid >> $DAEMON_PIDS
+
+echo "# clone remote via stream"
+for i in 0 1 2 3 4 5 6 7 8; do
+   hg clone -r "$i" http://localhost:20061/ test-"$i" 2>&1
+   if cd test-"$i"; then
+      hg verify
+      cd ..
+   fi
+done
+cd test-8
+hg pull ../test-7
+hg verify
+cd ..
+cd test-1
+hg pull -r 4 http://localhost:20061/ 2>&1
+hg verify
+hg pull http://localhost:20061/ 2>&1
+cd ..
+cd test-2
+hg pull -r 5 http://localhost:20061/ 2>&1
+hg verify
+hg pull http://localhost:20061/ 2>&1
+hg verify
+cd ..
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-http-clone-r.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,183 @@
+# creating 'remote'
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       3      0       0 362fef284ce2 000000000000 000000000000
+     1         3       5      1       1 125144f7e028 362fef284ce2 000000000000
+     2         8       7      2       2 4c982badb186 125144f7e028 000000000000
+     3        15       9      3       3 19b1fc555737 4c982badb186 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      75      0       7 905359268f77 000000000000 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      75      0       8 905359268f77 000000000000 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       8      0       6 12ab3bcc5ea4 000000000000 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      48      0       0 43eadb1d2d06 000000000000 000000000000
+     1        48      48      1       1 8b89697eba2c 43eadb1d2d06 000000000000
+     2        96      48      2       2 626a32663c2f 8b89697eba2c 000000000000
+     3       144      48      3       3 f54c32f13478 626a32663c2f 000000000000
+     4       192      58      3       6 de68e904d169 626a32663c2f 000000000000
+     5       250      68      3       7 3b45cc2ab868 de68e904d169 000000000000
+     6       318      54      6       8 24d86153a002 f54c32f13478 000000000000
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
+# Starting server
+# clone remote via stream
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 1 changesets, 1 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 2 changesets, 2 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 3 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 4 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 4 changesets, 4 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 2 changesets, 2 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 3 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 5 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 4 changesets, 5 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 5 changesets with 6 changes to 3 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+3 files, 5 changesets, 6 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 5 changesets with 5 changes to 2 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 5 changesets, 5 total revisions
+pulling from ../test-7
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 2 changes to 3 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
+pulling from http://localhost:20061/
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 0 changes to 1 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 2 total revisions
+pulling from http://localhost:20061/
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 6 changesets with 5 changes to 4 files
+(run 'hg update' to get a working copy)
+pulling from http://localhost:20061/
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 0 changes to 1 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 5 changesets, 3 total revisions
+pulling from http://localhost:20061/
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 4 changes to 4 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
--- a/tests/test-http-proxy	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-http-proxy	Sat Oct 21 15:22:08 2006 -0400
@@ -15,7 +15,7 @@
 
 echo %% url for proxy, stream
 http_proxy=http://localhost:20060/ hg --config http_proxy.always=True clone --uncompressed http://localhost:20059/ b | \
-  sed -e 's/[0-9][0-9.]*/XXX/g'
+  sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/'
 cd b
 hg verify
 cd ..
--- a/tests/test-http-proxy.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-http-proxy.out	Sat Oct 21 15:22:08 2006 -0400
@@ -2,7 +2,7 @@
 %% url for proxy, stream
 streaming all changes
 XXX files to transfer, XXX bytes of data
-transferred XXX bytes in XXX seconds (XXX KB/sec)
+transferred XXX bytes in XXX seconds (XXX XB/sec)
 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
 checking changesets
 checking manifests
--- a/tests/test-http.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-http.out	Sat Oct 21 15:22:08 2006 -0400
@@ -2,7 +2,7 @@
 % clone via stream
 streaming all changes
 XXX files to transfer, XXX bytes of data
-transferred XXX bytes in XXX seconds (XXX KB/sec)
+transferred XXX bytes in XXX seconds (XXX XB/sec)
 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
 checking changesets
 checking manifests
--- a/tests/test-import	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-import	Sat Oct 21 15:22:08 2006 -0400
@@ -72,7 +72,7 @@
 
 echo % plain diff in email, no subject, no message body, should fail
 hg clone -r0 a b
-grep -v '^\(Subject\|email\)' msg.patch | hg --cwd b import -
+egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
 rm -rf b
 
 echo % hg export in email, should use patch header
@@ -89,9 +89,10 @@
 echo % hg import in a subdirectory
 hg clone -r0 a b
 hg --cwd a export tip | sed -e 's/d1\/d2\///' > tip.patch
-pushd b/d1/d2 2>&1 > /dev/null
+dir=`pwd`
+cd b/d1/d2 2>&1 > /dev/null
 hg import  ../../../tip.patch
-popd  2>&1 > /dev/null
+cd $dir
 echo "% message should be 'subdir change'"
 hg --cwd b tip | grep 'subdir change'
 echo "% committer should be 'someoneelse'"
--- a/tests/test-import.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-import.out	Sat Oct 21 15:22:08 2006 -0400
@@ -8,7 +8,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../tip.patch
-patching file a
 % message should be same
 summary:     second change
 % committer should be same
@@ -21,7 +20,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../tip.patch
-patching file a
 transaction abort!
 rollback completed
 % import of plain diff should be ok with message
@@ -32,7 +30,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../tip.patch
-patching file a
 % import from stdin
 requesting all changes
 adding changesets
@@ -41,7 +38,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
-patching file a
 % override commit message
 requesting all changes
 adding changesets
@@ -50,7 +46,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
-patching file a
 summary:     override
 % plain diff in email, subject, message body
 requesting all changes
@@ -60,7 +55,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../msg.patch
-patching file a
 user:        email patcher
 summary:     email patch
 % plain diff in email, no subject, message body
@@ -71,7 +65,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
-patching file a
 % plain diff in email, subject, no message body
 requesting all changes
 adding changesets
@@ -80,7 +73,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
-patching file a
 % plain diff in email, no subject, no message body, should fail
 requesting all changes
 adding changesets
@@ -89,7 +81,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
-patching file a
 transaction abort!
 rollback completed
 % hg export in email, should use patch header
@@ -100,7 +91,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying patch from stdin
-patching file a
 summary:     second change
 % hg import in a subdirectory
 requesting all changes
@@ -110,7 +100,6 @@
 added 1 changesets with 2 changes to 2 files
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 applying ../../../tip.patch
-patching file a
 % message should be 'subdir change'
 summary:     subdir change
 % committer should be 'someoneelse'
--- a/tests/test-init	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-init	Sat Oct 21 15:22:08 2006 -0400
@@ -27,6 +27,9 @@
 echo this > local/foo
 hg ci --cwd local -A -m "init" -d "1000000 0"
 
+echo "#test failure"
+hg init local
+
 echo "# init+push to remote2"
 hg init -e ./dummyssh ssh://user@dummy/remote2
 hg incoming -R remote2 local
@@ -35,6 +38,12 @@
 echo "# clone to remote1"
 hg clone -e ./dummyssh local ssh://user@dummy/remote1
 
+echo "# init to existing repo"
+hg init -e ./dummyssh ssh://user@dummy/remote1
+
+echo "# clone to existing repo"
+hg clone -e ./dummyssh local ssh://user@dummy/remote1
+
 echo "# output of dummyssh"
 cat dummylog
 
--- a/tests/test-init.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-init.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,5 +1,7 @@
 # creating 'local'
 adding foo
+#test failure
+abort: repository local already exists!
 # init+push to remote2
 changeset:   0:c4e059d443be
 tag:         tip
@@ -15,20 +17,24 @@
 remote: added 1 changesets with 1 changes to 1 files
 # clone to remote1
 searching for changes
-remote: abort: repository remote1 not found!
 remote: adding changesets
 remote: adding manifests
 remote: adding file changes
 remote: added 1 changesets with 1 changes to 1 files
+# init to existing repo
+abort: repository remote1 already exists!
+abort: could not create remote repo!
+# clone to existing repo
+abort: repository remote1 already exists!
+abort: could not create remote repo!
 # output of dummyssh
-Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5:
 Got arguments 1:user@dummy 2:hg init remote2 3: 4: 5:
 Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5:
 Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5:
-Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio 3: 4: 5:
+Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5:
 Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio 3: 4: 5:
 Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5:
-Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio 3: 4: 5:
+Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5:
 # comparing repositories
 0:c4e059d443be
 0:c4e059d443be
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue322	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,49 @@
+#!/bin/sh
+# http://www.selenic.com/mercurial/bts/issue322
+
+echo % file replaced with directory
+
+hg init a
+cd a       
+echo a > a 
+hg commit -Ama 
+rm a       
+mkdir a    
+echo a > a/a
+
+echo % should fail - would corrupt dirstate
+hg add a/a
+
+cd ..      
+
+echo % directory replaced with file
+
+hg init c
+cd c
+mkdir a
+echo a > a/a
+hg commit -Ama
+
+rm -rf a
+echo a > a
+
+echo % should fail - would corrupt dirstate
+hg add a
+
+cd ..
+
+echo % directory replaced with file
+
+hg init d
+cd d
+mkdir b
+mkdir b/c
+echo a > b/c/d
+hg commit -Ama
+rm -rf b
+echo a > b
+
+echo % should fail - would corrupt dirstate
+hg add b
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue322.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,12 @@
+% file replaced with directory
+adding a
+% should fail - would corrupt dirstate
+abort: file named 'a' already in dirstate
+% directory replaced with file
+adding a/a
+% should fail - would corrupt dirstate
+abort: directory named 'a' already in dirstate
+% directory replaced with file
+adding b/c/d
+% should fail - would corrupt dirstate
+abort: directory named 'b' already in dirstate
--- a/tests/test-log	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-log	Sat Oct 21 15:22:08 2006 -0400
@@ -29,6 +29,16 @@
 echo % many renames
 hg log -vf e
 
+echo % log copies
+hg log -vC --template '{rev} {file_copies%filecopy}\n'
+
+echo % log copies, non-linear manifest
+hg up -C 3
+hg mv dir/b e
+echo foo > foo
+hg ci -Ame2 -d '6 0'
+hg log -vC --template '{rev} {file_copies%filecopy}\n' -r 5
+
 # log --follow tests
 hg init ../follow
 cd ../follow
@@ -63,3 +73,6 @@
 
 echo % log --follow-first
 hg log --follow-first
+
+echo % log -P 2
+hg log -P 2
--- a/tests/test-log.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-log.out	Sat Oct 21 15:22:08 2006 -0400
@@ -34,7 +34,7 @@
 summary:     a
 
 % one rename
-changeset:   0:8580ff50825a50c8f716709acdf8de0deddcd6ab
+changeset:   0:8580ff50825a
 user:        test
 date:        Thu Jan 01 00:00:01 1970 +0000
 files:       a
@@ -43,7 +43,7 @@
 
 
 % many renames
-changeset:   4:8c1c8408f7371319750ea2d4fa7969828effbcf4
+changeset:   4:8c1c8408f737
 tag:         tip
 user:        test
 date:        Thu Jan 01 00:00:05 1970 +0000
@@ -52,7 +52,7 @@
 e
 
 
-changeset:   2:21fba396af4c801f9717de6c415b6cc9620437e8
+changeset:   2:21fba396af4c
 user:        test
 date:        Thu Jan 01 00:00:03 1970 +0000
 files:       b dir/b
@@ -60,7 +60,7 @@
 c
 
 
-changeset:   1:c0296dabce9bf0cd3fdd608de26693c91cd6bbf4
+changeset:   1:c0296dabce9b
 user:        test
 date:        Thu Jan 01 00:00:02 1970 +0000
 files:       b
@@ -68,7 +68,7 @@
 b
 
 
-changeset:   0:8580ff50825a50c8f716709acdf8de0deddcd6ab
+changeset:   0:8580ff50825a
 user:        test
 date:        Thu Jan 01 00:00:01 1970 +0000
 files:       a
@@ -76,6 +76,16 @@
 a
 
 
+% log copies
+4 e (dir/b)
+3 b (a)
+2 dir/b (b)
+1 b (a)
+0 
+% log copies, non-linear manifest
+1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+adding foo
+5 e (dir/b)
 adding base
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 adding b1
@@ -149,3 +159,29 @@
 date:        Thu Jan 01 00:00:01 1970 +0000
 summary:     base
 
+% log -P 2
+changeset:   6:2404bbcab562
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:01 1970 +0000
+summary:     b1.1
+
+changeset:   5:302e9dd6890d
+parent:      3:e62f78d544b4
+parent:      4:ddb82e70d1a1
+user:        test
+date:        Thu Jan 01 00:00:01 1970 +0000
+summary:     m12
+
+changeset:   4:ddb82e70d1a1
+parent:      0:67e992f2c4f3
+user:        test
+date:        Thu Jan 01 00:00:01 1970 +0000
+summary:     b2
+
+changeset:   3:e62f78d544b4
+parent:      1:3d5bf5654eda
+user:        test
+date:        Thu Jan 01 00:00:01 1970 +0000
+summary:     b1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-manifest-merging	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+echo % init foo-base
+hg init foo-base
+
+echo % create alpha in first repo
+cd foo-base
+echo 'alpha' > alpha
+hg ci -A -m 'add alpha' -d '1 0'
+cd ..
+
+echo % clone foo-base to foo-work
+hg clone foo-base foo-work
+
+echo % create beta in second repo
+cd foo-work
+echo 'beta' > beta
+hg ci -A -m 'add beta' -d '2 0'
+cd ..
+
+echo % create gamma in first repo
+cd foo-base
+echo 'gamma' > gamma
+hg ci -A -m 'add gamma' -d '3 0'
+cd ..
+
+echo % pull into work and merge
+cd foo-work
+hg pull -q
+hg merge
+
+echo % revert to changeset 1 to simulate a failed merge
+rm -fr *
+hg up -C 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-manifest-merging.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,14 @@
+% init foo-base
+% create alpha in first repo
+adding alpha
+% clone foo-base to foo-work
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% create beta in second repo
+adding beta
+% create gamma in first repo
+adding gamma
+% pull into work and merge
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% revert to changeset 1 to simulate a failed merge
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-merge-default	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+hg init
+echo a > a
+hg commit -A -ma
+
+echo a >> a
+hg commit -mb
+
+echo a >> a
+hg commit -mc
+
+hg up 1
+echo a >> a
+hg commit -md
+
+hg up 1
+echo a >> a
+hg commit -me
+
+hg up 1
+echo % should fail because not at a head
+hg merge
+
+hg up
+echo % should fail because \> 2 heads
+hg merge
+
+echo % should succeed
+hg merge 2
+hg commit -mm1
+
+echo % should succeed - 2 heads
+hg merge
+hg commit -mm2
+
+echo % should fail because 1 head
+hg merge
+
+true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-merge-default.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,17 @@
+adding a
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% should fail because not at a head
+abort: repo has 3 heads - please merge with an explicit rev
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% should fail because > 2 heads
+abort: repo has 3 heads - please merge with an explicit rev
+% should succeed
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% should succeed - 2 heads
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% should fail because 1 head
+abort: there is nothing to merge - use "hg update" instead
--- a/tests/test-merge-revert	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-merge-revert	Sat Oct 21 15:22:08 2006 -0400
@@ -15,7 +15,7 @@
 hg id
 echo "changed file1" >> file1
 hg id
-hg revert
+hg revert --all
 hg diff
 hg status
 hg id
@@ -29,11 +29,11 @@
 hg diff
 hg status
 hg id
-hg revert
+hg revert --all
 hg diff
 hg status
 hg id
-hg revert -r tip
+hg revert -r tip --all
 hg diff
 hg status
 hg id
--- a/tests/test-merge-revert.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-merge-revert.out	Sat Oct 21 15:22:08 2006 -0400
@@ -11,8 +11,7 @@
 ? file1.orig
 016807e6fdaf tip
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-merging file1
-0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 ? file1.orig
 016807e6fdaf tip
 ? file1.orig
--- a/tests/test-merge-revert2	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-merge-revert2	Sat Oct 21 15:22:08 2006 -0400
@@ -16,7 +16,7 @@
 hg id
 echo "changed file1" >> file1
 hg id
-hg revert --no-backup
+hg revert --no-backup --all
 hg diff
 hg status
 hg id
@@ -27,15 +27,14 @@
 hg update -C 0
 echo "changed file1 different" >> file1
 HGMERGE=merge hg update
-hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(<<<<<<<\) .*/\1/" \
-              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(>>>>>>>\) .*/\1/"
+hg diff --nodates | sed -e "s/\(<<<<<<<\) .*/\1/" -e "s/\(>>>>>>>\) .*/\1/"
 hg status
 hg id
-hg revert --no-backup
+hg revert --no-backup --all
 hg diff
 hg status
 hg id
-hg revert -r tip --no-backup
+hg revert -r tip --no-backup --all
 hg diff
 hg status
 hg id
--- a/tests/test-merge1	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-merge1	Sat Oct 21 15:22:08 2006 -0400
@@ -23,6 +23,8 @@
 echo This is file b1 > b
 echo %% no merges expected
 env HGMERGE=../merge hg merge 1
+hg diff --nodates
+hg status
 cd ..; /bin/rm -rf t
 
 mkdir t
@@ -44,6 +46,8 @@
 env HGMERGE=../merge hg merge 1
 echo %% merge of b expected
 env HGMERGE=../merge hg merge -f 1
+hg diff --nodates
+hg status
 cd ..; /bin/rm -rf t
 echo %%
 
@@ -71,6 +75,8 @@
 env HGMERGE=../merge hg merge 2
 echo %% merge expected!
 env HGMERGE=../merge hg merge -f 2
+hg diff --nodates
+hg status
 cd ..; /bin/rm -rf t
 
 mkdir t
@@ -93,4 +99,6 @@
 env HGMERGE=../merge hg merge 2
 echo %% merge of b expected
 env HGMERGE=../merge hg merge -f 2
+hg diff --nodates
+hg status
 cd ..; /bin/rm -rf t
--- a/tests/test-merge1.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-merge1.out	Sat Oct 21 15:22:08 2006 -0400
@@ -2,6 +2,12 @@
 %% no merges expected
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
+diff -r d9e5953b9dec b
+--- /dev/null
++++ b/b
+@@ -0,0 +1,1 @@
++This is file b1
+M b
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
 %% merge should fail
 abort: 'b' already exists in the working dir and differs from remote
@@ -10,6 +16,12 @@
 merging b
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
+diff -r d9e5953b9dec b
+--- /dev/null
++++ b/b
+@@ -0,0 +1,1 @@
++This is file b2
+M b
 %%
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 Contents of b should be "this is file b1"
@@ -17,10 +29,15 @@
 %% merge fails
 abort: outstanding uncommitted changes
 %% merge expected!
-merging for b
-merging b
-0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
+diff -r c1dd73cbf59f b
+--- a/b
++++ b/b
+@@ -1,1 +1,1 @@ This is file b1
+-This is file b1
++This is file b22
+M b
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 %% merge of b should fail
 abort: outstanding uncommitted changes
@@ -29,3 +46,10 @@
 merging b
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
+diff -r c1dd73cbf59f b
+--- a/b
++++ b/b
+@@ -1,1 +1,1 @@ This is file b1
+-This is file b1
++This is file b33
+M b
--- a/tests/test-merge7.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-merge7.out	Sat Oct 21 15:22:08 2006 -0400
@@ -22,12 +22,11 @@
 (run 'hg heads' to see heads, 'hg merge' to merge)
 merge: warning: conflicts during merge
 resolving manifests
- overwrite None branchmerge True partial False linear False
- ancestor 055d847dd401 local 2eded9ab0a5c remote 84cf5750dd20
- test.txt versions differ, resolve
+ overwrite None partial False
+ ancestor faaea63e63a9 local 451c744aabcc+ remote a070d41e8360
+ test.txt: versions differ -> m
 merging test.txt
-resolving test.txt
-file test.txt: my fc3148072371 other d40249267ae3 ancestor 8fe46a3eb557
+my test.txt@451c744aabcc+ other test.txt@a070d41e8360 ancestor test.txt@faaea63e63a9
 merging test.txt failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
 There are unresolved merges, you can redo the full merge using:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-merge8	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# Test for changeset ba7c74081861
+# (update dirstate correctly for non-branchmerge updates)
+hg init a
+cd a
+echo a > a
+hg add a
+hg commit -m a
+cd ..
+hg clone a b
+cd a
+hg mv a b
+hg commit -m move
+echo b >> b
+hg commit -m b
+cd ../b
+hg pull ../a
+hg update
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-merge8.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,10 @@
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+pulling from ../a
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+(run 'hg update' to get a working copy)
+merging a and b
+0 files updated, 1 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-mq	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-mq	Sat Oct 21 15:22:08 2006 -0400
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
 
 echo % help
 hg help mq
@@ -10,6 +9,10 @@
 hg init a
 cd a
 echo a > a
+hg ci -Ama
+
+hg clone . ../k
+
 mkdir b
 echo z > b/z
 hg ci -Ama
@@ -48,7 +51,7 @@
 
 echo a >> a
 hg qrefresh
-sed -e "s/\(^diff -r \)\([a-f0-9]* \)/\1 x/" \
+sed -e "s/^\(diff -r \)\([a-f0-9]* \)/\1 x/" \
     -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
     -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch
 
@@ -103,12 +106,94 @@
 hg qprev
 hg qapplied
 
+echo % commit should fail
+hg commit
+
+echo % push should fail
+hg push ../../k
+
 echo % qunapplied
 hg qunapplied
 
+echo % qpush/qpop with index
+hg qnew test1b.patch
+echo 1b > 1b
+hg add 1b
+hg qrefresh
+hg qpush 2
+hg qpop 0
+hg qpush test.patch+1
+hg qpush test.patch+2
+hg qpop test2.patch-1
+hg qpop test2.patch-2
+hg qpush test1b.patch+1
+
+echo % push should succeed
+hg qpop -a
+hg push ../../k
+
 echo % strip
 cd ../../b
 echo x>x
 hg ci -Ama
 hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
 hg unbundle .hg/strip-backup/*
+
+echo '% cd b; hg qrefresh'
+hg init refresh
+cd refresh
+echo a > a
+hg ci -Ama -d'0 0'
+hg qnew -mfoo foo
+echo a >> a
+hg qrefresh
+mkdir b
+cd b
+echo f > f
+hg add f
+hg qrefresh
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+    -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo
+echo % hg qrefresh .
+hg qrefresh .
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+    -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" ../.hg/patches/foo
+hg status
+
+echo % qpush failure
+cd ..
+hg qrefresh
+hg qnew -mbar bar
+echo foo > foo
+hg add foo
+hg qrefresh
+hg qpop -a
+echo bar > foo
+hg qpush -a
+
+cat >>$HGRCPATH <<EOF
+[diff]
+git = True
+EOF
+cd ..
+hg init git
+cd git
+hg qinit
+
+hg qnew -m'new file' new
+echo foo > new
+chmod +x new
+hg add new
+hg qrefresh
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+    -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new
+
+hg qnew -m'copy file' copy
+hg cp new copy
+hg qrefresh
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+    -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy
+
+hg qpop
+hg qpush
+hg qdiff
--- a/tests/test-mq-guards	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-mq-guards	Sat Oct 21 15:22:08 2006 -0400
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
 
 hg init
 hg qinit
@@ -63,22 +62,39 @@
 hg qpush -a
 
 hg qpop -a
-hg qguard a.patch +1 +2
+hg qguard a.patch +1
+hg qguard b.patch +2
 hg qselect 1
+echo % should push a.patch, not b.patch
+hg qpush
+hg qpush
+hg qpop -a
+
+hg qselect 2
 echo % should push b.patch
 hg qpush
 hg qpop -a
 
-hg qselect 2
+hg qselect 1 2
+echo % should push a.patch, b.patch
 hg qpush
-hg qpop -a
-
-hg qselect 1 2
-echo % should push a.patch
 hg qpush
 hg qpop -a
 
 hg qguard a.patch +1 +2 -3
 hg qselect 1 2 3
+echo % list patches and guards
+hg qguard -l
+echo % list series
+hg qseries -v
+echo % list guards
+hg qselect
 echo % should push b.patch
 hg qpush
+
+hg qpush -a
+hg qselect -n --reapply
+echo % guards in series file: +1 +2 -3
+hg qselect -s
+echo % should show c.patch
+hg qapplied
--- a/tests/test-mq-guards.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-mq-guards.out	Sat Oct 21 15:22:08 2006 -0400
@@ -13,7 +13,7 @@
 applying b.patch
 Now at: b.patch
 Patch queue now empty
-3 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 2 to 3
 % should push a.patch
 applying a.patch
 Now at: a.patch
@@ -28,27 +28,57 @@
 Now at: c.patch
 Patch queue now empty
 guards deactivated
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 3 to 2
 % should push all
 applying b.patch
 applying c.patch
 Now at: c.patch
 Patch queue now empty
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 1 to 2
+% should push a.patch, not b.patch
+applying a.patch
+Now at: a.patch
+applying c.patch
+Now at: c.patch
+Patch queue now empty
 % should push b.patch
 applying b.patch
 Now at: b.patch
 Patch queue now empty
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 2 to 3
+% should push a.patch, b.patch
+applying a.patch
+Now at: a.patch
 applying b.patch
 Now at: b.patch
 Patch queue now empty
-3 of 3 unapplied patches active
-% should push a.patch
-applying a.patch
-Now at: a.patch
-Patch queue now empty
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 3 to 2
+% list patches and guards
+a.patch: +1 +2 -3
+b.patch: +2
+c.patch: unguarded
+% list series
+0 G a.patch
+1 U b.patch
+2 U c.patch
+% list guards
+1
+2
+3
 % should push b.patch
 applying b.patch
 Now at: b.patch
+applying c.patch
+Now at: c.patch
+guards deactivated
+popping guarded patches
+Patch queue now empty
+reapplying unguarded patches
+applying c.patch
+Now at: c.patch
+% guards in series file: +1 +2 -3
++1
++2
+-3
+% should show c.patch
+c.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qdelete	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+
+hg init a
+cd a
+
+echo 'base' > base
+hg ci -Ambase -d '1 0'
+
+hg qnew a
+hg qnew b
+hg qnew c
+
+hg qdel c
+hg qpop
+hg qdel c
+hg qseries
+ls .hg/patches
+hg qpop
+hg qdel -k b
+ls .hg/patches
+hg qdel -r a
+hg qapplied
+hg log --template '{rev} {desc}\n'
+
+hg qnew d
+hg qnew e
+hg qnew f
+
+hg qdel -r e
+hg qdel -r qbase:e
+hg qapplied
+hg log --template '{rev} {desc}\n'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qdelete.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,23 @@
+adding base
+abort: cannot delete applied patch c
+Now at: b
+a
+b
+a
+b
+series
+status
+Now at: a
+a
+b
+series
+status
+1 New patch: a
+0 base
+abort: cannot delete revision 3 above applied patches
+f
+4 New patch: f
+3 New patch: e
+2 New patch: d
+1 New patch: a
+0 base
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qdiff	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+
+echo % init
+hg init a
+cd a
+
+echo % commit
+echo 'base' > base
+hg ci -Ambase -d '1 0'
+
+echo % qnew mqbase
+hg qnew -mmqbase mqbase
+
+echo % qrefresh
+echo 'patched' > base
+hg qrefresh
+
+echo % qdiff
+hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+               -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % qdiff dirname
+hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+                 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qdiff.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,19 @@
+% init
+% commit
+adding base
+% qnew mqbase
+% qrefresh
+% qdiff
+diff -r 67e992f2c4f3 base
+--- a/base
++++ b/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% qdiff dirname
+diff -r 67e992f2c4f3 base
+--- a/base
++++ b/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
--- a/tests/test-mq-qnew-twice	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-mq-qnew-twice	Sat Oct 21 15:22:08 2006 -0400
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
 
 hg init a
 cd a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qrefresh	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+
+echo % init
+hg init a
+cd a
+
+echo % commit
+mkdir 1 2
+echo 'base' > 1/base
+echo 'base' > 2/base
+hg ci -Ambase -d '1 0'
+
+echo % qnew mqbase
+hg qnew -mmqbase mqbase
+
+echo % qrefresh
+echo 'patched' > 1/base
+echo 'patched' > 2/base
+hg qrefresh
+
+echo % qdiff
+hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+               -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % qdiff dirname
+hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+                 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % patch file contents
+cat .hg/patches/mqbase | \
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+    -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % qrefresh 1
+echo 'patched again' > base
+hg qrefresh 1
+
+echo % qdiff
+hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+               -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % qdiff dirname
+hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+                 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % patch file contents
+cat .hg/patches/mqbase | \
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+    -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % qrefresh . in subdir
+( cd 1 ; hg qrefresh . )
+
+echo % qdiff
+hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+               -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % qdiff dirname
+hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+                 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % patch file contents
+cat .hg/patches/mqbase | \
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+    -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % qrefresh in hg-root again
+hg qrefresh
+
+echo % qdiff
+hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+               -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % qdiff dirname
+hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+                 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % patch file contents
+cat .hg/patches/mqbase | \
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+    -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- a/tests/test-mq-qrefresh-replace-log-message	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-mq-qrefresh-replace-log-message	Sat Oct 21 15:22:08 2006 -0400
@@ -1,9 +1,8 @@
 #!/bin/sh
 
 # Environement setup for MQ
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
 
 #Repo init
 hg init
@@ -33,7 +32,7 @@
 echo bbbb > file
 hg qrefresh -l logfile
 echo =======================
-echo "Should display 'Third commit message\n This is the 3rd log message'"
+printf "Should display 'Third commit message\\\n This is the 3rd log message'\n"
 hg log -l1 -v | sed -n '/description/,$p'
 echo
 
@@ -46,6 +45,6 @@
 echo " This is the 5th log message" >> logfile) |\
 hg qrefresh -l-
 echo =======================
-echo "Should display 'Fifth commit message\n This is the 5th log message'"
+printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n"
 hg log -l1 -v | sed -n '/description/,$p'
 echo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qrefresh.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,161 @@
+% init
+% commit
+adding 1/base
+adding 2/base
+% qnew mqbase
+% qrefresh
+% qdiff
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% qdiff dirname
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% patch file contents
+mqbase
+
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% qrefresh 1
+% qdiff
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% qdiff dirname
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% patch file contents
+mqbase
+
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% qrefresh . in subdir
+% qdiff
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% qdiff dirname
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% patch file contents
+mqbase
+
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% qrefresh in hg-root again
+% qdiff
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% qdiff dirname
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% patch file contents
+mqbase
+
+diff -r b55ecdccb5cf 1/base
+--- a/1/base
++++ b/1/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+diff -r b55ecdccb5cf 2/base
+--- a/2/base
++++ b/2/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qrename	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+
+hg init a
+cd a
+
+echo 'base' > base
+hg ci -Ambase -d '1 0'
+
+hg qnew -mmqbase mqbase
+hg qrename mqbase renamed
+mkdir .hg/patches/foo
+hg qrename renamed foo
+hg qseries
+ls .hg/patches/foo
+mkdir .hg/patches/bar
+hg qrename foo/renamed bar
+hg qseries
+ls .hg/patches/bar
+hg qrename bar/renamed baz
+hg qseries
+ls .hg/patches/baz
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qrename.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,7 @@
+adding base
+foo/renamed
+renamed
+bar/renamed
+renamed
+baz
+.hg/patches/baz
--- a/tests/test-mq-qsave	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-mq-qsave	Sat Oct 21 15:22:08 2006 -0400
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
 
 hg init a
 cd a
--- a/tests/test-mq.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-mq.out	Sat Oct 21 15:22:08 2006 -0400
@@ -27,7 +27,7 @@
  qapplied     print the patches already applied
  qclone       clone main and patch repository at same time
  qcommit      commit changes in the queue repository
- qdelete      remove a patch from the series file
+ qdelete      remove patches from queue
  qdiff        diff of the current patch
  qfold        fold the named patches into the current patch
  qguard       set or print guards for a patch
@@ -49,6 +49,7 @@
  qunapplied   print the patches not yet applied
  strip        strip a revision and all later revs on the same branch
 adding a
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 adding b/z
 % qinit
 % -R qinit
@@ -102,8 +103,34 @@
 test2.patch
 Only one patch applied
 test.patch
+% commit should fail
+abort: cannot commit over an applied mq patch
+% push should fail
+pushing to ../../k
+abort: source has mq patches applied
 % qunapplied
 test2.patch
+% qpush/qpop with index
+applying test2.patch
+Now at: test2.patch
+Now at: test.patch
+applying test1b.patch
+Now at: test1b.patch
+applying test2.patch
+Now at: test2.patch
+Now at: test1b.patch
+Now at: test.patch
+applying test1b.patch
+applying test2.patch
+Now at: test2.patch
+% push should succeed
+Patch queue now empty
+pushing to ../../k
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
 % strip
 adding x
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
@@ -113,3 +140,54 @@
 adding file changes
 added 1 changesets with 1 changes to 1 files
 (run 'hg update' to get a working copy)
+% cd b; hg qrefresh
+adding a
+foo
+
+diff -r cb9a9f314b8b a
+--- a/a
++++ b/a
+@@ -1,1 +1,2 @@ a
+ a
++a
+diff -r cb9a9f314b8b b/f
+--- /dev/null
++++ b/b/f
+@@ -0,0 +1,1 @@
++f
+% hg qrefresh .
+foo
+
+diff -r cb9a9f314b8b b/f
+--- /dev/null
++++ b/b/f
+@@ -0,0 +1,1 @@
++f
+M a
+% qpush failure
+Patch queue now empty
+applying foo
+applying bar
+1 out of 1 hunk ignored -- saving rejects to file foo.rej
+patch failed, unable to continue (try -v)
+patch failed, rejects left in working dir
+Errors during apply, please fix and refresh bar
+new file
+
+diff --git a/new b/new
+new file mode 100755
+--- /dev/null
++++ b/new
+@@ -0,0 +1,1 @@
++foo
+copy file
+
+diff --git a/new b/copy
+copy from new
+copy to copy
+Now at: new
+applying copy
+Now at: copy
+diff --git a/new b/copy
+copy from new
+copy to copy
--- a/tests/test-nested-repo	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-nested-repo	Sat Oct 21 15:22:08 2006 -0400
@@ -14,6 +14,6 @@
 echo '# should print A b/x'
 hg st
 echo '# should forget b/x'
-hg revert
+hg revert --all
 echo '# should print nothing'
 hg st b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-newbranch	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+hg init t
+cd t
+
+echo foo > a
+hg add a
+hg ci -m "initial" -d "0 0"
+echo foo > .hg/branch
+hg ci -m "add branch name" -d "0 0"
+echo bar > .hg/branch
+hg ci -m "change branch name" -d "0 0"
+rm .hg/branch
+hg ci -m "clear branch name" -d "0 0"
+
+hg co foo
+cat .hg/branch
+echo bleah > a
+hg ci -m "modify a branch" -d "0 0"
+
+hg merge
+cat .hg/branch
+HG_MERGE=true hg ci -m "merge" -d "0 0"
+hg log
+
+echo % test for invalid branch cache
+hg rollback
+hg tip
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-newbranch.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,53 @@
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+foo
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+foo
+changeset:   5:dc140083783b
+branch:      foo
+tag:         tip
+parent:      4:98d14f698afe
+parent:      3:9d567d0b51f9
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     merge
+
+changeset:   4:98d14f698afe
+branch:      foo
+parent:      1:0079f24813e2
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     modify a branch
+
+changeset:   3:9d567d0b51f9
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     clear branch name
+
+changeset:   2:ed2bbf4e0102
+branch:      bar
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     change branch name
+
+changeset:   1:0079f24813e2
+branch:      foo
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     add branch name
+
+changeset:   0:db01e8ea3388
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     initial
+
+% test for invalid branch cache
+rolling back last transaction
+changeset:   4:98d14f698afe
+branch:      foo
+tag:         tip
+parent:      1:0079f24813e2
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     modify a branch
+
--- a/tests/test-parse-date	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-parse-date	Sat Oct 21 15:22:08 2006 -0400
@@ -1,5 +1,6 @@
 #!/bin/sh
 
+# This runs with TZ="GMT"
 hg init
 echo "test-parse-date" > a
 hg add a
@@ -13,4 +14,21 @@
 hg ci -d "should fail" -m "fail"
 hg ci -d "100000000000000000 1400" -m "fail"
 hg ci -d "100000 1400000" -m "fail"
+
+# Check with local timezone other than GMT and with DST
+TZ="PST+8PDT"
+export TZ
+# PST=UTC-8 / PDT=UTC-7
+hg debugrebuildstate
+echo "a" > a
+hg ci -d "2006-07-15 13:30" -m "summer@UTC-7"
+hg debugrebuildstate
+echo "b" > a
+hg ci -d "2006-07-15 13:30 +0500" -m "summer@UTC+5"
+hg debugrebuildstate
+echo "c" > a
+hg ci -d "2006-01-15 13:30" -m "winter@UTC-8"
+hg debugrebuildstate
+echo "d" > a
+hg ci -d "2006-01-15 13:30 +0500" -m "winter@UTC+5"
 hg log --template '{date|date}\n'
--- a/tests/test-parse-date.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-parse-date.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,9 +1,9 @@
 reverting a
 changeset 3:107ce1ee2b43 backs out changeset 1:25a1420a55f8
-merging with changeset 2:99a1acecff55
+merging with changeset 2:e6c3abc120e7
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
-abort: invalid date: 'should fail'
+abort: invalid date: 'should fail' see hg(1) manual page for details
 transaction abort!
 rollback completed
 abort: date exceeds 32 bits: 100000000000000000
@@ -12,6 +12,10 @@
 abort: impossible time zone offset: 1400000
 transaction abort!
 rollback completed
+Sun Jan 15 13:30:00 2006 +0500
+Sun Jan 15 13:30:00 2006 -0800
+Sat Jul 15 13:30:00 2006 +0500
+Sat Jul 15 13:30:00 2006 -0700
 Sun Jun 11 00:26:40 2006 -0400
 Sat Apr 15 13:30:00 2006 +0200
 Sat Apr 15 13:30:00 2006 +0000
--- a/tests/test-pull.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-pull.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,4 +1,3 @@
-(the addremove command is deprecated; use add and remove --after instead)
 adding foo
 checking changesets
 checking manifests
--- a/tests/test-rawcommit1	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-rawcommit1	Sat Oct 21 15:22:08 2006 -0400
@@ -10,24 +10,24 @@
 echo this is c1 > c
 hg rawcommit -p 1 -d "1000000 0" -m2 c
 hg manifest 2
-hg parents
+hg -v parents
 rm b
 hg rawcommit -p 2 -d "1000000 0" -m3 b
 hg manifest 3
-hg parents
+hg -v parents
 echo this is a22 > a
 hg rawcommit -p 3 -d "1000000 0" -m4 a
 hg manifest 4
-hg parents
+hg -v parents
 echo this is c22 > c
 hg rawcommit -p 1 -d "1000000 0" -m5 c
 hg manifest 5
-hg parents
+hg -v parents
 # merge, but no files changed
 hg rawcommit -p 4 -p 5 -d "1000000 0" -m6
 hg manifest 6
-hg parents
+hg -v parents
 # no changes what-so-ever
 hg rawcommit -p 6 -d "1000000 0" -m7
 hg manifest 7
-hg parents
+hg -v parents
--- a/tests/test-rawcommit1.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-rawcommit1.out	Sat Oct 21 15:22:08 2006 -0400
@@ -8,52 +8,70 @@
 tag:         tip
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
-summary:     2
+files:       c
+description:
+2
+
 
 (the rawcommit command is deprecated)
 05f9e54f4c9b86b09099803d8b49a50edcb4eaab 644 a
 76d5e637cbec1bcc04a5a3fa4bcc7d13f6847c00 644 c
-changeset:   3:0f9843914735
+changeset:   3:20652cf30cc0
 tag:         tip
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
-summary:     3
+files:       b
+description:
+3
+
 
 (the rawcommit command is deprecated)
 d6e3c4976c13feb1728cd3ac851abaf7256a5c23 644 a
 76d5e637cbec1bcc04a5a3fa4bcc7d13f6847c00 644 c
-changeset:   4:909a3d1d3ee1
+changeset:   4:42556b925639
 tag:         tip
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
-summary:     4
+files:       a
+description:
+4
+
 
 (the rawcommit command is deprecated)
 05f9e54f4c9b86b09099803d8b49a50edcb4eaab 644 a
 54837d97f2932a8194e69745a280a2c11e61ff9c 644 b
 3570202ceac2b52517df64ebd0a062cb0d8fe33a 644 c
-changeset:   4:909a3d1d3ee1
+changeset:   4:42556b925639
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
-summary:     4
+files:       a
+description:
+4
+
 
 (the rawcommit command is deprecated)
 d6e3c4976c13feb1728cd3ac851abaf7256a5c23 644 a
 76d5e637cbec1bcc04a5a3fa4bcc7d13f6847c00 644 c
-changeset:   6:725fdd0728db
+changeset:   6:8a0c9254b0ab
 tag:         tip
-parent:      4:909a3d1d3ee1
+parent:      4:42556b925639
 parent:      5:f56d4c64ab98
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
-summary:     6
+files:       
+description:
+6
+
 
 (the rawcommit command is deprecated)
 d6e3c4976c13feb1728cd3ac851abaf7256a5c23 644 a
 76d5e637cbec1bcc04a5a3fa4bcc7d13f6847c00 644 c
-changeset:   7:2c11b55105cb
+changeset:   7:a5a6e1f312b9
 tag:         tip
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
-summary:     7
+files:       
+description:
+7
 
+
--- a/tests/test-remove	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-remove	Sat Oct 21 15:22:08 2006 -0400
@@ -9,12 +9,12 @@
 hg remove
 rm foo
 hg remove foo
-hg revert
+hg revert --all
 rm foo
 hg remove --after
 hg commit -m 2 -d "1000000 0"
-hg export 0
-hg export 1
+hg export --nodates 0
+hg export --nodates 1
 hg log -p -r 0
 hg log -p -r 1
 
--- a/tests/test-remove.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-remove.out	Sat Oct 21 15:22:08 2006 -0400
@@ -10,8 +10,8 @@
 1
 
 diff -r 000000000000 -r 8ba83d44753d foo
---- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/foo	Mon Jan 12 13:46:40 1970 +0000
+--- /dev/null
++++ b/foo
 @@ -0,0 +1,1 @@
 +a
 # HG changeset patch
@@ -22,8 +22,8 @@
 2
 
 diff -r 8ba83d44753d -r a1fce69c50d9 foo
---- a/foo	Mon Jan 12 13:46:40 1970 +0000
-+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
+--- a/foo
++++ /dev/null
 @@ -1,1 +0,0 @@
 -a
 changeset:   0:8ba83d44753d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-rename-merge1	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+mkdir t
+cd t
+hg init
+echo "[merge]" >> .hg/hgrc
+echo "followcopies = 1" >> .hg/hgrc
+echo foo > a
+echo foo > a2
+hg add a a2
+hg ci -m "start" -d "0 0"
+hg mv a b
+hg mv a2 b2
+hg ci -m "rename" -d "0 0"
+echo "checkout"
+hg co 0
+echo blahblah > a
+echo blahblah > a2
+hg mv a2 c2
+hg ci -m "modify" -d "0 0"
+echo "merge"
+hg merge -y --debug
+hg status -AC
+cat b
+hg ci -m "merge" -d "0 0"
+hg debugindex .hg/data/b.i
+hg debugrename b
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-rename-merge1.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,25 @@
+checkout
+2 files updated, 0 files merged, 2 files removed, 0 files unresolved
+merge
+resolving manifests
+ overwrite None partial False
+ ancestor af1939970a1c local f26ec4fc3fa3+ remote 8e765a822af2
+ a: remote moved -> m
+ b2: remote created -> g
+merging a and b
+my a@f26ec4fc3fa3+ other b@8e765a822af2 ancestor a@af1939970a1c
+copying a to b
+removing a
+getting b2
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+M b
+  a
+M b2
+R a
+C c2
+blahblah
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      67      0       1 dc51707dfc98 000000000000 000000000000
+     1        67      72      1       3 b2494a44f0a9 000000000000 dc51707dfc98
+renamed from a:dd03b83622e78778b403775d0d074b9ac7387a66
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-rename-merge2	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+mkdir -p t
+cd t
+
+cat <<'EOF' > merge
+#!/bin/sh
+echo merge $1 $2 $3 > $1
+EOF
+chmod +x merge
+
+# perform a test merge with possible renaming
+# 
+# args:
+# $1 = action in local branch
+# $2 = action in remote branch
+# $3 = action in working dir
+# $4 = expected result
+tm()
+{
+    mkdir t
+    cd t
+    hg init
+    echo "[merge]" >> .hg/hgrc
+    echo "followcopies = 1" >> .hg/hgrc
+
+    # base
+    echo base > a
+    echo base > rev # used to force commits
+    hg add a rev
+    hg ci -m "base" -d "0 0"
+
+    # remote
+    echo remote > rev
+    if [ "$2" != "" ] ; then $2 ; fi
+    hg ci -m "remote" -d "0 0"
+
+    # local
+    hg co -q 0
+    echo local > rev
+    if [ "$1" != "" ] ; then $1 ; fi
+    hg ci -m "local" -d "0 0"
+
+    # working dir
+    echo local > rev
+    if [ "$3" != "" ] ; then $3 ; fi
+
+    # merge
+    echo "--------------"
+    echo "test L:$1 R:$2 W:$3 - $4"
+    echo "--------------"
+    env HGMERGE=../merge hg merge -y --debug --traceback
+
+    echo "--------------"
+    hg status -camC -X rev
+
+    hg ci -m "merge" -d "0 0"
+    
+    echo "--------------"
+    echo
+
+    cd ..
+    rm -rf t
+}
+
+up() { 
+    cp rev $1
+    hg add $1 2> /dev/null
+    if [ "$2" != "" ] ; then 
+	cp rev $2
+	hg add $2 2> /dev/null
+    fi
+}
+
+uc() { up $1; hg cp $1 $2; } # update + copy
+um() { up $1; hg mv $1 $2; }
+nc() { hg cp $1 $2; } # just copy
+nm() { hg mv $1 $2; } # just move
+
+tm "up a  " "nc a b" "      " "1  get local a to b"
+tm "nc a b" "up a  " "      " "2  get rem change to a and b"
+tm "up a  " "nm a b" "      " "3  get local a change to b, remove a"
+tm "nm a b" "up a  " "      " "4  get remote change to b"
+tm "      " "nc a b" "      " "5  get b"
+tm "nc a b" "      " "      " "6  nothing"
+tm "      " "nm a b" "      " "7  get b"
+tm "nm a b" "      " "      " "8  nothing"
+tm "um a b" "um a b" "      " "9  do merge with ancestor in a"
+#tm "um a c" "um x c" "      " "10 do merge with no ancestor"
+tm "nm a b" "nm a c" "      " "11 get c, keep b"
+tm "nc a b" "up b  " "      " "12 merge b no ancestor"
+tm "up b  " "nm a b" "      " "13 merge b no ancestor"
+tm "nc a b" "up a b" "      " "14 merge b no ancestor"
+tm "up b  " "nm a b" "      " "15 merge b no ancestor, remove a"
+tm "nc a b" "up a b" "      " "16 get a, merge b no ancestor"
+tm "up a b" "nc a b" "      " "17 keep a, merge b no ancestor" 
+tm "nm a b" "up a b" "      " "18 merge b no ancestor"
+tm "up a b" "nm a b" "      " "19 merge b no ancestor, prompt remove a"
+tm "up a  " "um a b" "      " "20 merge a and b to b, remove a"
+tm "um a b" "up a  " "      " "21 merge a and b to b"
+#tm "nm a b" "um x a" "      " "22 get a, keep b"
+tm "nm a b" "up a c" "      " "23 get c, keep b"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-rename-merge2.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,414 @@
+--------------
+test L:up a   R:nc a b W:       - 1  get local a to b
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local e300d1c794ec+ remote 735846fee2d7
+ rev: versions differ -> m
+ a: remote copied -> m
+merging a and b
+my a@e300d1c794ec+ other b@735846fee2d7 ancestor a@924404dff337
+copying a to b
+merging rev
+my rev@e300d1c794ec+ other rev@735846fee2d7 ancestor rev@924404dff337
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M a
+M b
+  a
+--------------
+
+--------------
+test L:nc a b R:up a   W:       - 2  get rem change to a and b
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ac809aeed39a+ remote f4db7e329e71
+ a: remote is newer -> g
+ b: local copied -> m
+ rev: versions differ -> m
+getting a
+merging b and a
+my b@ac809aeed39a+ other a@f4db7e329e71 ancestor a@924404dff337
+merging rev
+my rev@ac809aeed39a+ other rev@f4db7e329e71 ancestor rev@924404dff337
+1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M a
+M b
+  a
+--------------
+
+--------------
+test L:up a   R:nm a b W:       - 3  get local a change to b, remove a
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local e300d1c794ec+ remote e03727d2d66b
+ a: remote moved -> m
+ rev: versions differ -> m
+merging a and b
+my a@e300d1c794ec+ other b@e03727d2d66b ancestor a@924404dff337
+copying a to b
+removing a
+merging rev
+my rev@e300d1c794ec+ other rev@e03727d2d66b ancestor rev@924404dff337
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+  a
+--------------
+
+--------------
+test L:nm a b R:up a   W:       - 4  get remote change to b
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ecf3cb2a4219+ remote f4db7e329e71
+ b: local moved -> m
+ rev: versions differ -> m
+merging b and a
+my b@ecf3cb2a4219+ other a@f4db7e329e71 ancestor a@924404dff337
+merging rev
+my rev@ecf3cb2a4219+ other rev@f4db7e329e71 ancestor rev@924404dff337
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+  a
+--------------
+
+--------------
+test L:       R:nc a b W:       - 5  get b
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local 94b33a1b7f2d+ remote 735846fee2d7
+ rev: versions differ -> m
+ a: remote copied -> m
+copying a to b
+merging rev
+my rev@94b33a1b7f2d+ other rev@735846fee2d7 ancestor rev@924404dff337
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+  a
+C a
+--------------
+
+--------------
+test L:nc a b R:       W:       - 6  nothing
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ac809aeed39a+ remote 97c705ade336
+ b: local copied -> m
+ rev: versions differ -> m
+merging rev
+my rev@ac809aeed39a+ other rev@97c705ade336 ancestor rev@924404dff337
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+  a
+C a
+--------------
+
+--------------
+test L:       R:nm a b W:       - 7  get b
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local 94b33a1b7f2d+ remote e03727d2d66b
+ a: remote moved -> m
+ rev: versions differ -> m
+copying a to b
+removing a
+merging rev
+my rev@94b33a1b7f2d+ other rev@e03727d2d66b ancestor rev@924404dff337
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+  a
+--------------
+
+--------------
+test L:nm a b R:       W:       - 8  nothing
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ecf3cb2a4219+ remote 97c705ade336
+ b: local moved -> m
+ rev: versions differ -> m
+merging rev
+my rev@ecf3cb2a4219+ other rev@97c705ade336 ancestor rev@924404dff337
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+  a
+--------------
+
+--------------
+test L:um a b R:um a b W:       - 9  do merge with ancestor in a
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ec03c2ca8642+ remote 79cc6877a3b7
+ b: versions differ -> m
+ rev: versions differ -> m
+merging b
+my b@ec03c2ca8642+ other b@79cc6877a3b7 ancestor a@924404dff337
+merging rev
+my rev@ec03c2ca8642+ other rev@79cc6877a3b7 ancestor rev@924404dff337
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+--------------
+
+--------------
+test L:nm a b R:nm a c W:       - 11 get c, keep b
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ecf3cb2a4219+ remote e6abcc1a30c2
+ rev: versions differ -> m
+ c: remote created -> g
+getting c
+merging rev
+my rev@ecf3cb2a4219+ other rev@e6abcc1a30c2 ancestor rev@924404dff337
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M c
+C b
+--------------
+
+--------------
+test L:nc a b R:up b   W:       - 12 merge b no ancestor
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ac809aeed39a+ remote af30c7647fc7
+ b: versions differ -> m
+ rev: versions differ -> m
+merging b
+my b@ac809aeed39a+ other b@af30c7647fc7 ancestor b@000000000000
+merging rev
+my rev@ac809aeed39a+ other rev@af30c7647fc7 ancestor rev@924404dff337
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+C a
+--------------
+
+--------------
+test L:up b   R:nm a b W:       - 13 merge b no ancestor
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local 59318016310c+ remote e03727d2d66b
+ a: other deleted -> r
+ b: versions differ -> m
+ rev: versions differ -> m
+removing a
+merging b
+my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000
+merging rev
+my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337
+0 files updated, 2 files merged, 1 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+--------------
+
+--------------
+test L:nc a b R:up a b W:       - 14 merge b no ancestor
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ac809aeed39a+ remote 8dbce441892a
+ a: remote is newer -> g
+ b: versions differ -> m
+ rev: versions differ -> m
+getting a
+merging b
+my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000
+merging rev
+my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337
+1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M a
+M b
+--------------
+
+--------------
+test L:up b   R:nm a b W:       - 15 merge b no ancestor, remove a
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local 59318016310c+ remote e03727d2d66b
+ a: other deleted -> r
+ b: versions differ -> m
+ rev: versions differ -> m
+removing a
+merging b
+my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000
+merging rev
+my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337
+0 files updated, 2 files merged, 1 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+--------------
+
+--------------
+test L:nc a b R:up a b W:       - 16 get a, merge b no ancestor
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ac809aeed39a+ remote 8dbce441892a
+ a: remote is newer -> g
+ b: versions differ -> m
+ rev: versions differ -> m
+getting a
+merging b
+my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000
+merging rev
+my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337
+1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M a
+M b
+--------------
+
+--------------
+test L:up a b R:nc a b W:       - 17 keep a, merge b no ancestor
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local 0b76e65c8289+ remote 735846fee2d7
+ b: versions differ -> m
+ rev: versions differ -> m
+merging b
+my b@0b76e65c8289+ other b@735846fee2d7 ancestor b@000000000000
+merging rev
+my rev@0b76e65c8289+ other rev@735846fee2d7 ancestor rev@924404dff337
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+C a
+--------------
+
+--------------
+test L:nm a b R:up a b W:       - 18 merge b no ancestor
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ecf3cb2a4219+ remote 8dbce441892a
+ b: versions differ -> m
+ rev: versions differ -> m
+ a: prompt recreating -> g
+getting a
+merging b
+my b@ecf3cb2a4219+ other b@8dbce441892a ancestor b@000000000000
+merging rev
+my rev@ecf3cb2a4219+ other rev@8dbce441892a ancestor rev@924404dff337
+1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M a
+M b
+--------------
+
+--------------
+test L:up a b R:nm a b W:       - 19 merge b no ancestor, prompt remove a
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local 0b76e65c8289+ remote e03727d2d66b
+ b: versions differ -> m
+ rev: versions differ -> m
+merging b
+my b@0b76e65c8289+ other b@e03727d2d66b ancestor b@000000000000
+merging rev
+my rev@0b76e65c8289+ other rev@e03727d2d66b ancestor rev@924404dff337
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+C a
+--------------
+
+--------------
+test L:up a   R:um a b W:       - 20 merge a and b to b, remove a
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local e300d1c794ec+ remote 79cc6877a3b7
+ a: remote moved -> m
+ rev: versions differ -> m
+merging a and b
+my a@e300d1c794ec+ other b@79cc6877a3b7 ancestor a@924404dff337
+copying a to b
+removing a
+merging rev
+my rev@e300d1c794ec+ other rev@79cc6877a3b7 ancestor rev@924404dff337
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+  a
+--------------
+
+--------------
+test L:um a b R:up a   W:       - 21 merge a and b to b
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ec03c2ca8642+ remote f4db7e329e71
+ b: local moved -> m
+ rev: versions differ -> m
+merging b and a
+my b@ec03c2ca8642+ other a@f4db7e329e71 ancestor a@924404dff337
+merging rev
+my rev@ec03c2ca8642+ other rev@f4db7e329e71 ancestor rev@924404dff337
+0 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+  a
+--------------
+
+--------------
+test L:nm a b R:up a c W:       - 23 get c, keep b
+--------------
+resolving manifests
+ overwrite None partial False
+ ancestor 924404dff337 local ecf3cb2a4219+ remote 2b958612230f
+ b: local moved -> m
+ rev: versions differ -> m
+ c: remote created -> g
+merging b and a
+my b@ecf3cb2a4219+ other a@2b958612230f ancestor a@924404dff337
+getting c
+merging rev
+my rev@ecf3cb2a4219+ other rev@2b958612230f ancestor rev@924404dff337
+1 files updated, 2 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+--------------
+M b
+  a
+M c
+--------------
+
--- a/tests/test-revert	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-revert	Sat Oct 21 15:22:08 2006 -0400
@@ -31,7 +31,7 @@
 ls
 echo %% should verbosely save backup to e.orig
 echo z > e
-hg revert -v
+hg revert --all -v
 echo %% should say no changes needed
 hg revert a
 echo %% should say file not managed
@@ -46,9 +46,9 @@
 hg add z
 hg st
 echo %% should add a, forget z
-hg revert -r0
+hg revert --all -r0
 echo %% should forget a
-hg revert -rtip
+hg revert --all -rtip
 rm -f a *.orig
 echo %% should silently add a
 hg revert -r0 a
@@ -56,7 +56,7 @@
 
 hg update -C
 chmod +x c
-hg revert
+hg revert --all
 echo %% should print non-executable
 test -x c || echo non-executable
 
@@ -64,7 +64,7 @@
 hg commit -d '1000001 0' -m exe
 
 chmod -x c
-hg revert
+hg revert --all
 echo %% should print executable
 test -x c && echo executable
 
@@ -78,6 +78,15 @@
 hg update 0
 mkdir b
 echo b > b/b
+
+echo % should fail - no arguments
 hg revert -rtip
 
+echo % should succeed
+hg revert --all -rtip
+
+echo %% issue332
+hg ci -A -m b -d '1000001 0'
+echo foobar > b/b
+hg revert b
 true
--- a/tests/test-revert-unknown	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-revert-unknown	Sat Oct 21 15:22:08 2006 -0400
@@ -13,7 +13,7 @@
 
 echo %% Should show unknown
 hg status
-hg revert -r 0
+hg revert -r 0 --all
 echo %% Should show unknown and b removed
 hg status
 echo %% Should show a and unknown
--- a/tests/test-revert.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-revert.out	Sat Oct 21 15:22:08 2006 -0400
@@ -54,4 +54,10 @@
 %% issue 241
 adding a
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% should fail - no arguments
+abort: no files or directories specified; use --all to revert the whole repo
+% should succeed
 reverting a
+%% issue332
+adding b/b
+reverting b/b
--- a/tests/test-ro-message.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-ro-message.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,3 +1,3 @@
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-abort: Permission denied - test-ro-message/b/vehicle
+abort: Permission denied: test-ro-message/b/vehicle
--- a/tests/test-simple-update.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-simple-update.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,4 +1,3 @@
-(the addremove command is deprecated; use add and remove --after instead)
 adding foo
 checking changesets
 checking manifests
--- a/tests/test-ssh	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-ssh	Sat Oct 21 15:22:08 2006 -0400
@@ -36,9 +36,12 @@
 
 cd ..
 
+echo "# repo not found error"
+hg clone -e ./dummyssh ssh://user@dummy/nonexistent local
+
 echo "# clone remote via stream"
 hg clone -e ./dummyssh --uncompressed ssh://user@dummy/remote local-stream 2>&1 | \
-  sed -e 's/[0-9][0-9.]*/XXX/g'
+  sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/'
 cd local-stream
 hg verify
 cd ..
@@ -80,7 +83,7 @@
 echo "# check remote tip"
 hg tip
 hg verify
-hg cat foo
+hg cat -r tip foo
 
 echo z > z
 hg ci -A -m z -d '1000001 0' z
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-ssh-clone-r	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,99 @@
+#!/bin/sh
+
+# This test tries to exercise the ssh functionality with a dummy script
+
+cat <<'EOF' > dummyssh
+#!/bin/sh
+# this attempts to deal with relative pathnames
+cd `dirname $0`
+
+# check for proper args
+if [ $1 != "user@dummy" ] ; then
+	exit -1
+fi
+
+# check that we're in the right directory
+if [ ! -x dummyssh ] ; then
+	exit -1
+fi
+
+SSH_CLIENT='127.0.0.1 1 2'
+export SSH_CLIENT
+echo Got arguments 1:$1 2:$2 3:$3 4:$4 5:$5 >> dummylog
+$2
+EOF
+chmod +x dummyssh
+
+hg init remote
+cd remote
+echo "# creating 'remote'"
+cat >>afile <<EOF
+0
+EOF
+hg add afile
+hg commit -m "0.0"
+cat >>afile <<EOF
+1
+EOF
+hg commit -m "0.1"
+cat >>afile <<EOF
+2
+EOF
+hg commit -m "0.2"
+cat >>afile <<EOF
+3
+EOF
+hg commit -m "0.3"
+hg update -C 0
+cat >>afile <<EOF
+1
+EOF
+hg commit -m "1.1"
+cat >>afile <<EOF
+2
+EOF
+hg commit -m "1.2"
+cat >fred <<EOF
+a line
+EOF
+cat >>afile <<EOF
+3
+EOF
+hg add fred
+hg commit -m "1.3"
+hg mv afile adifferentfile
+hg commit -m "1.3m"
+hg update -C 3
+hg mv afile anotherfile
+hg commit -m "0.3m"
+hg debugindex .hg/data/afile.i
+hg debugindex .hg/data/adifferentfile.i
+hg debugindex .hg/data/anotherfile.i
+hg debugindex .hg/data/fred.i
+hg debugindex .hg/00manifest.i
+hg verify
+cd ..
+
+echo "# clone remote via stream"
+for i in 0 1 2 3 4 5 6 7 8; do
+   hg clone -e ./dummyssh --uncompressed -r "$i" ssh://user@dummy/remote test-"$i" 2>&1
+   if cd test-"$i"; then
+      hg verify
+      cd ..
+   fi
+done
+cd test-8
+hg pull ../test-7
+hg verify
+cd ..
+cd test-1
+hg pull -e ../dummyssh -r 4 ssh://user@dummy/remote 2>&1
+hg verify
+hg pull -e ../dummyssh ssh://user@dummy/remote 2>&1
+cd ..
+cd test-2
+hg pull -e ../dummyssh -r 5 ssh://user@dummy/remote 2>&1
+hg verify
+hg pull -e ../dummyssh ssh://user@dummy/remote 2>&1
+hg verify
+cd ..
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-ssh-clone-r.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,182 @@
+# creating 'remote'
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       3      0       0 362fef284ce2 000000000000 000000000000
+     1         3       5      1       1 125144f7e028 362fef284ce2 000000000000
+     2         8       7      2       2 4c982badb186 125144f7e028 000000000000
+     3        15       9      3       3 19b1fc555737 4c982badb186 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      75      0       7 905359268f77 000000000000 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      75      0       8 905359268f77 000000000000 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       8      0       6 12ab3bcc5ea4 000000000000 000000000000
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      48      0       0 43eadb1d2d06 000000000000 000000000000
+     1        48      48      1       1 8b89697eba2c 43eadb1d2d06 000000000000
+     2        96      48      2       2 626a32663c2f 8b89697eba2c 000000000000
+     3       144      48      3       3 f54c32f13478 626a32663c2f 000000000000
+     4       192      58      3       6 de68e904d169 626a32663c2f 000000000000
+     5       250      68      3       7 3b45cc2ab868 de68e904d169 000000000000
+     6       318      54      6       8 24d86153a002 f54c32f13478 000000000000
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
+# clone remote via stream
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 1 changesets, 1 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 2 changesets, 2 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 3 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 4 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 4 changesets, 4 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 2 changesets, 2 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 3 changes to 1 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 5 changes to 2 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 4 changesets, 5 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 5 changesets with 6 changes to 3 files
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+3 files, 5 changesets, 6 total revisions
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 5 changesets with 5 changes to 2 files
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 5 changesets, 5 total revisions
+pulling from ../test-7
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 2 changes to 3 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
+pulling from ssh://user@dummy/remote
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 0 changes to 1 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 2 total revisions
+pulling from ssh://user@dummy/remote
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 6 changesets with 5 changes to 4 files
+(run 'hg update' to get a working copy)
+pulling from ssh://user@dummy/remote
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 0 changes to 1 files (+1 heads)
+(run 'hg heads' to see heads, 'hg merge' to merge)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 5 changesets, 3 total revisions
+pulling from ssh://user@dummy/remote
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 4 changes to 4 files
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
--- a/tests/test-ssh.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-ssh.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,8 +1,11 @@
 # creating 'remote'
+# repo not found error
+remote: abort: repository nonexistent not found!
+abort: no suitable response from remote hg!
 # clone remote via stream
 streaming all changes
 XXX files to transfer, XXX bytes of data
-transferred XXX bytes in XXX seconds (XXX KB/sec)
+transferred XXX bytes in XXX seconds (XXX XB/sec)
 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
 checking changesets
 checking manifests
@@ -77,6 +80,7 @@
 remote: adding manifests
 remote: adding file changes
 remote: added 1 changesets with 1 changes to 1 files
+Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio 3: 4: 5:
 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
--- a/tests/test-static-http	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-static-http	Sat Oct 21 15:22:08 2006 -0400
@@ -2,7 +2,7 @@
 
 http_proxy= hg clone static-http://localhost:20059/ copy
 echo $?
-ls copy 2>/dev/null || echo copy: No such file or directory
+test -e copy || echo copy: No such file or directory
 
 # This server doesn't do range requests so it's basically only good for
 # one pull
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-strict	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+hg init
+
+echo a > a
+hg ci -d '0 0' -Ama
+
+hg an a
+
+echo "[ui]" >> $HGRCPATH
+echo "strict=True" >> $HGRCPATH
+
+hg an a
+hg annotate a
+
+echo % should succeed - up is an alias, not an abbreviation
+
+hg up
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-strict.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,26 @@
+adding a
+0: a
+hg: unknown command 'an'
+Mercurial Distributed SCM
+
+basic commands (use "hg help" for the full list or option "-v" for details):
+
+ add        add the specified files on the next commit
+ annotate   show changeset information per file line
+ clone      make a copy of an existing repository
+ commit     commit the specified files or all outstanding changes
+ diff       diff repository (or selected files)
+ export     dump the header and diffs for one or more changesets
+ init       create a new repository in the given directory
+ log        show revision history of entire repository or files
+ parents    show the parents of the working dir or revision
+ pull       pull changes from the specified source
+ push       push changes to the specified destination
+ remove     remove the specified files on the next commit
+ revert     revert files or dirs to their states as of some revision
+ serve      export the repository via HTTP
+ status     show changed files in the working directory
+ update     update or merge working directory
+0: a
+% should succeed - up is an alias, not an abbreviation
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-symlinks.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-symlinks.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,6 +1,4 @@
-(the addremove command is deprecated; use add and remove --after instead)
 adding foo
-(the addremove command is deprecated; use add and remove --after instead)
 adding bomb
 adding a.c
 adding dir/a.o
--- a/tests/test-tag.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-tag.out	Sat Oct 21 15:22:08 2006 -0400
@@ -4,11 +4,11 @@
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     test
 
-changeset:   1:c5c60883086f
+changeset:   1:3ecf002a1c57
 tag:         tip
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
-summary:     Added tag bleah for changeset 0acdaf8983679e0aac16e811534eb49d7ee1f2b4
+summary:     Added tag bleah for changeset 0acdaf898367
 
 changeset:   0:0acdaf898367
 tag:         bleah
@@ -24,9 +24,9 @@
 use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah
 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0
-c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1
+3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar
-c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1
+3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
 abort: '\n' cannot be used in a tag name
 abort: ':' cannot be used in a tag name
--- a/tests/test-tags	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-tags	Sat Oct 21 15:22:08 2006 -0400
@@ -9,7 +9,7 @@
 hg commit -m "test" -d "1000000 0"
 hg co
 hg identify
-T=`hg tip -v | head -n 1 | cut -d : -f 3`
+T=`hg tip --debug | head -n 1 | cut -d : -f 3`
 echo "$T first" > .hgtags
 cat .hgtags
 hg add .hgtags
--- a/tests/test-tags.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-tags.out	Sat Oct 21 15:22:08 2006 -0400
@@ -2,35 +2,35 @@
 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 0acdaf898367 tip
 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 first
-tip                                1:8a3ca90d111dc784e6575d373105be12570e8776
-first                              0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
+tip                                1:8a3ca90d111d
+first                              0:0acdaf898367
 8a3ca90d111d tip
 M a
 8a3ca90d111d+ tip
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
 0acdaf898367+ first
-0acdaf8983679e0aac16e811534eb49d7ee1f2b4+ first
+0acdaf898367+ first
 M a
 8216907a933d tip
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 8216907a933d+8a3ca90d111d+ tip
 M .hgtags
-tip                                6:c6af9d771a81bb9c7f267ec03491224a9f8ba1cd
-first                              0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
-.hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
-.hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
+tip                                6:e2174d339386
+first                              0:0acdaf898367
+.hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
+.hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
 localtags, line 1: tag 'invalid' refers to unknown node
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-.hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
-.hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
+.hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
+.hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
 localtags, line 1: tag 'invalid' refers to unknown node
-tip                                8:4ca6f1b1a68c77be687a03aaeb1614671ba59b20
-first                              0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
+tip                                8:4ca6f1b1a68c
+first                              0:0acdaf898367
 changeset:   8:4ca6f1b1a68c
-.hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
-.hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
+.hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
+.hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
 .hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
 localtags, line 1: tag 'invalid' refers to unknown node
 tag:         tip
--- a/tests/test-ui-config	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-ui-config	Sat Oct 21 15:22:08 2006 -0400
@@ -1,9 +1,9 @@
 #!/usr/bin/env python
 
-from mercurial import ui
+from mercurial import ui, util, commands
 
 testui = ui.ui()
-testui.updateopts(config=[
+parsed = commands.parseconfig([
     'values.string=string value',
     'values.bool1=true',
     'values.bool2=false',
@@ -11,10 +11,20 @@
     'lists.list2=foo bar baz',
     'lists.list3=alice, bob',
     'lists.list4=foo bar baz alice, bob',
+    'interpolation.value1=hallo',
+    'interpolation.value2=%(value1)s world',
+    'interpolation.value3=%(novalue)s',
+    'interpolation.value4=%(bad)1',
+    'interpolation.value5=%bad2',
 ])
+testui.updateopts(config=parsed)
 
 print repr(testui.configitems('values'))
 print repr(testui.configitems('lists'))
+try:
+    print repr(testui.configitems('interpolation'))
+except util.Abort, inst:
+    print inst
 print "---"
 print repr(testui.config('values', 'string'))
 print repr(testui.config('values', 'bool1'))
@@ -45,3 +55,18 @@
 print repr(testui.configlist('lists', 'unknown', ['foo bar']))
 print repr(testui.configlist('lists', 'unknown', ['foo', 'bar']))
 print "---"
+print repr(testui.config('interpolation', 'value1'))
+print repr(testui.config('interpolation', 'value2'))
+try:
+    print repr(testui.config('interpolation', 'value3'))
+except util.Abort, inst:
+    print inst
+try:
+    print repr(testui.config('interpolation', 'value4'))
+except util.Abort, inst:
+    print inst
+try:
+    print repr(testui.config('interpolation', 'value5'))
+except util.Abort, inst:
+    print inst
+print "---"
--- a/tests/test-ui-config.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-ui-config.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,5 +1,7 @@
 [('bool1', 'true'), ('bool2', 'false'), ('string', 'string value')]
 [('list1', 'foo'), ('list2', 'foo bar baz'), ('list3', 'alice, bob'), ('list4', 'foo bar baz alice, bob')]
+Error in configuration section [interpolation]:
+'%' must be followed by '%' or '(', found: '%bad2'
 ---
 'string value'
 'true'
@@ -27,3 +29,17 @@
 ['foo bar']
 ['foo', 'bar']
 ---
+'hallo'
+'hallo world'
+Error in configuration section [interpolation] parameter 'value3':
+Bad value substitution:
+	section: [interpolation]
+	option : value3
+	key    : novalue
+	rawval : 
+
+Error in configuration section [interpolation] parameter 'value4':
+bad interpolation variable reference '%(bad)1'
+Error in configuration section [interpolation] parameter 'value5':
+'%' must be followed by '%' or '(', found: '%bad2'
+---
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-ui-verbosity	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+import os
+from mercurial import ui
+
+hgrc = os.environ['HGRCPATH']
+
+print '      hgrc settings    command line options      final result   '
+print '    quiet verbo debug   quiet verbo debug      quiet verbo debug'
+
+for i in xrange(64):
+    hgrc_quiet   = bool(i & 1<<0)
+    hgrc_verbose = bool(i & 1<<1)
+    hgrc_debug   = bool(i & 1<<2)
+    cmd_quiet    = bool(i & 1<<3)
+    cmd_verbose  = bool(i & 1<<4)
+    cmd_debug    = bool(i & 1<<5)
+
+    f = open(hgrc, 'w')
+    f.write('[ui]\n')
+    if hgrc_quiet:
+        f.write('quiet = True\n')
+    if hgrc_verbose:
+        f.write('verbose = True\n')
+    if hgrc_debug:
+        f.write('debug = True\n')
+    f.close()
+
+    u = ui.ui()
+    u.updateopts(quiet=cmd_quiet, verbose=cmd_verbose, debug=cmd_debug)
+
+    check = ''
+    if u.debugflag:
+        if not u.verbose or u.quiet:
+            check = ' *'
+    elif u.verbose and u.quiet:
+        check = ' +'
+
+    print ('%2d  %5s %5s %5s   %5s %5s %5s  ->  %5s %5s %5s%s'
+           % (i, hgrc_quiet, hgrc_verbose, hgrc_debug,
+              cmd_quiet, cmd_verbose, cmd_debug,
+              u.quiet, u.verbose, u.debugflag, check))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-ui-verbosity.out	Sat Oct 21 15:22:08 2006 -0400
@@ -0,0 +1,66 @@
+      hgrc settings    command line options      final result   
+    quiet verbo debug   quiet verbo debug      quiet verbo debug
+ 0  False False False   False False False  ->  False False False
+ 1   True False False   False False False  ->   True False False
+ 2  False  True False   False False False  ->  False  True False
+ 3   True  True False   False False False  ->  False False False
+ 4  False False  True   False False False  ->  False  True  True
+ 5   True False  True   False False False  ->  False  True  True
+ 6  False  True  True   False False False  ->  False  True  True
+ 7   True  True  True   False False False  ->  False  True  True
+ 8  False False False    True False False  ->   True False False
+ 9   True False False    True False False  ->   True False False
+10  False  True False    True False False  ->   True False False
+11   True  True False    True False False  ->   True False False
+12  False False  True    True False False  ->   True False False
+13   True False  True    True False False  ->   True False False
+14  False  True  True    True False False  ->   True False False
+15   True  True  True    True False False  ->   True False False
+16  False False False   False  True False  ->  False  True False
+17   True False False   False  True False  ->  False  True False
+18  False  True False   False  True False  ->  False  True False
+19   True  True False   False  True False  ->  False  True False
+20  False False  True   False  True False  ->  False  True False
+21   True False  True   False  True False  ->  False  True False
+22  False  True  True   False  True False  ->  False  True False
+23   True  True  True   False  True False  ->  False  True False
+24  False False False    True  True False  ->  False False False
+25   True False False    True  True False  ->  False False False
+26  False  True False    True  True False  ->  False False False
+27   True  True False    True  True False  ->  False False False
+28  False False  True    True  True False  ->  False False False
+29   True False  True    True  True False  ->  False False False
+30  False  True  True    True  True False  ->  False False False
+31   True  True  True    True  True False  ->  False False False
+32  False False False   False False  True  ->  False  True  True
+33   True False False   False False  True  ->  False  True  True
+34  False  True False   False False  True  ->  False  True  True
+35   True  True False   False False  True  ->  False  True  True
+36  False False  True   False False  True  ->  False  True  True
+37   True False  True   False False  True  ->  False  True  True
+38  False  True  True   False False  True  ->  False  True  True
+39   True  True  True   False False  True  ->  False  True  True
+40  False False False    True False  True  ->  False  True  True
+41   True False False    True False  True  ->  False  True  True
+42  False  True False    True False  True  ->  False  True  True
+43   True  True False    True False  True  ->  False  True  True
+44  False False  True    True False  True  ->  False  True  True
+45   True False  True    True False  True  ->  False  True  True
+46  False  True  True    True False  True  ->  False  True  True
+47   True  True  True    True False  True  ->  False  True  True
+48  False False False   False  True  True  ->  False  True  True
+49   True False False   False  True  True  ->  False  True  True
+50  False  True False   False  True  True  ->  False  True  True
+51   True  True False   False  True  True  ->  False  True  True
+52  False False  True   False  True  True  ->  False  True  True
+53   True False  True   False  True  True  ->  False  True  True
+54  False  True  True   False  True  True  ->  False  True  True
+55   True  True  True   False  True  True  ->  False  True  True
+56  False False False    True  True  True  ->  False  True  True
+57   True False False    True  True  True  ->  False  True  True
+58  False  True False    True  True  True  ->  False  True  True
+59   True  True False    True  True  True  ->  False  True  True
+60  False False  True    True  True  True  ->  False  True  True
+61   True False  True    True  True  True  ->  False  True  True
+62  False  True  True    True  True  True  ->  False  True  True
+63   True  True  True    True  True  True  ->  False  True  True
--- a/tests/test-up-local-change	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-up-local-change	Sat Oct 21 15:22:08 2006 -0400
@@ -12,8 +12,7 @@
 cd ../r2
 hg up
 echo abc > a
-hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+hg diff --nodates
 
 cd ../r1
 echo b > b
@@ -34,8 +33,7 @@
 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/"
+hg diff --nodates
 
 # create a second head
 cd ../r1
@@ -53,8 +51,7 @@
 hg --debug merge || echo failed
 hg --debug merge -f
 hg parents
-hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+hg diff --nodates
 
 # test a local add
 cd ..
--- a/tests/test-up-local-change.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-up-local-change.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,4 +1,3 @@
-(the addremove command is deprecated; use add and remove --after instead)
 adding a
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -8,7 +7,6 @@
 @@ -1,1 +1,1 @@ a
 -a
 +abc
-(the addremove command is deprecated; use add and remove --after instead)
 adding b
 M a
 changeset:   0:33aaa84a386b
@@ -17,14 +15,13 @@
 summary:     1
 
 resolving manifests
- overwrite False branchmerge False partial False linear True
- ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
- a versions differ, resolve
-remote created b
+ overwrite False partial False
+ ancestor 33aaa84a386b local 33aaa84a386b+ remote 802f095af299
+ a: versions differ -> m
+ b: remote created -> g
+merging a
+my a@33aaa84a386b+ other a@802f095af299 ancestor a@33aaa84a386b
 getting b
-merging a
-resolving a
-file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 changeset:   1:802f095af299
 tag:         tip
@@ -33,9 +30,9 @@
 summary:     2
 
 resolving manifests
- overwrite False branchmerge False partial False linear True
- ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c
-remote deleted b
+ overwrite False partial False
+ ancestor 33aaa84a386b local 802f095af299+ remote 33aaa84a386b
+ b: remote deleted -> r
 removing b
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
 changeset:   0:33aaa84a386b
@@ -43,7 +40,7 @@
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     1
 
-abort: there is nothing to merge, just use 'hg update' or look at 'hg heads'
+abort: there is nothing to merge - use "hg update" instead
 failed
 changeset:   0:33aaa84a386b
 user:        test
@@ -51,14 +48,13 @@
 summary:     1
 
 resolving manifests
- overwrite False branchmerge False partial False linear True
- ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e
- a versions differ, resolve
-remote created b
+ overwrite False partial False
+ ancestor 33aaa84a386b local 33aaa84a386b+ remote 802f095af299
+ a: versions differ -> m
+ b: remote created -> g
+merging a
+my a@33aaa84a386b+ other a@802f095af299 ancestor a@33aaa84a386b
 getting b
-merging a
-resolving a
-file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 changeset:   1:802f095af299
 tag:         tip
@@ -66,7 +62,7 @@
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     2
 
-changeset:   1:802f095af299cde27a85b2f056aef3829870956c
+changeset:   1:802f095af299
 tag:         tip
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
@@ -75,7 +71,7 @@
 2
 
 
-changeset:   0:33aaa84a386bd609094aeb21a97c09436c482ef1
+changeset:   0:33aaa84a386b
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
 files:       a
@@ -90,7 +86,6 @@
 -a2
 +abc
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
-(the addremove command is deprecated; use add and remove --after instead)
 adding b
 M a
 changeset:   1:802f095af299
@@ -103,16 +98,14 @@
 abort: outstanding uncommitted changes
 failed
 resolving manifests
- overwrite False branchmerge True partial False linear False
- ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392
- a versions differ, resolve
- b versions differ, resolve
+ overwrite False partial False
+ ancestor 33aaa84a386b local 802f095af299+ remote 030602aee63d
+ a: versions differ -> m
+ b: versions differ -> m
 merging a
-resolving a
-file a: my d730145abbf9 other 13e0d5f949fa ancestor b789fdd96dc2
+my a@802f095af299+ other a@030602aee63d ancestor a@33aaa84a386b
 merging b
-resolving b
-file b: my 1e88685f5dde other 61de8c7723ca ancestor 000000000000
+my b@802f095af299+ other b@030602aee63d ancestor b@000000000000
 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 changeset:   1:802f095af299
--- a/tests/test-update-reverse.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-update-reverse.out	Sat Oct 21 15:22:08 2006 -0400
@@ -40,11 +40,11 @@
 side1
 side2
 resolving manifests
- overwrite True branchmerge False partial False linear False
- ancestor 8515d4bfda76 local 1c0f48f8ece6 remote 0594b9004bae
-remote deleted side2, clobbering
-remote deleted side1, clobbering
-remote created main
+ overwrite True partial False
+ ancestor 537353581d3d local ded32b0db104+ remote 221226fb2bd8
+ side2: remote deleted -> r
+ side1: remote deleted -> r
+ main: remote created -> g
 getting main
 removing side1
 removing side2
--- a/tests/test-walk.out	Sat Sep 02 22:58:02 2006 -0400
+++ b/tests/test-walk.out	Sat Oct 21 15:22:08 2006 -0400
@@ -1,4 +1,3 @@
-(the addremove command is deprecated; use add and remove --after instead)
 adding beans/black
 adding beans/borlotti
 adding beans/kidney