changeset 3097:fe9b13e35e46

Merge with crew
author Matt Mackall <mpm@selenic.com>
date Fri, 15 Sep 2006 15:22:45 -0500
parents 1b738357bba9 (current diff) f422c8265ae5 (diff)
children 09e8aecd8016
files mercurial/merge.py
diffstat 79 files changed, 1811 insertions(+), 479 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Aug 22 21:02:25 2006 -0500
+++ b/.hgignore	Fri Sep 15 15:22:45 2006 -0500
@@ -21,6 +21,7 @@
 MANIFEST
 patches
 mercurial/__version__.py
+.DS_Store
 
 syntax: regexp
 ^\.pc/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/churn.py	Fri Sep 15 15:22:45 2006 -0500
@@ -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/hgk	Tue Aug 22 21:02:25 2006 -0500
+++ b/contrib/hgk	Fri Sep 15 15:22:45 2006 -0500
@@ -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/mercurial.el	Tue Aug 22 21:02:25 2006 -0500
+++ b/contrib/mercurial.el	Fri Sep 15 15:22:45 2006 -0500
@@ -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.
@@ -724,6 +785,13 @@
 		 default-directory)
 	(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.
 With a prefix argument, prompt for the path to add."
@@ -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	Fri Sep 15 15:22:45 2006 -0500
@@ -0,0 +1,281 @@
+;;; 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-patch-history 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)
+
+
+;;; 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))
+
+(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-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/doc/hg.1.txt	Tue Aug 22 21:02:25 2006 -0500
+++ b/doc/hg.1.txt	Fri Sep 15 15:22:45 2006 -0500
@@ -193,6 +193,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)
--- a/doc/hgrc.5.txt	Tue Aug 22 21:02:25 2006 -0500
+++ b/doc/hgrc.5.txt	Fri Sep 15 15:22:45 2006 -0500
@@ -50,6 +50,8 @@
     particular repository.  This file is not version-controlled, and
     will not get transferred during a "clone" operation.  Options in
     this file override options in all other configuration files.
+    On Unix, this file is only read if it belongs to a trusted user
+    or to a trusted group.
 
 SYNTAX
 ------
@@ -133,6 +135,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;;
@@ -349,6 +366,16 @@
     6Mbps), uncompressed streaming is slower, because of the extra
     data transfer overhead.  Default is False.
 
+trusted::
+  Mercurial will only read the .hg/hgrc file from a repository if
+  it belongs to a trusted user or to a trusted group. This section
+  specifies what users and groups are trusted. To trust everybody,
+  list a user or a group with name "*".
+  users;;
+    Comma-separated list of trusted users.
+  groups;;
+    Comma-separated list of trusted groups.
+
 ui::
   User interface controls.
   debug;;
@@ -377,6 +404,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/hgeditor	Tue Aug 22 21:02:25 2006 -0500
+++ b/hgeditor	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Tue Aug 22 21:02:25 2006 -0500
+++ b/hgext/acl.py	Fri Sep 15 15:22:45 2006 -0500
@@ -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:
--- a/hgext/extdiff.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/hgext/extdiff.py	Fri Sep 15 15:22:45 2006 -0500
@@ -45,7 +45,7 @@
 from mercurial.demandload import demandload
 from mercurial.i18n import gettext as _
 from mercurial.node import *
-demandload(globals(), 'mercurial:commands,cmdutil,util os shutil tempfile')
+demandload(globals(), 'mercurial:cmdutil,util os shutil tempfile')
 
 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
     def snapshot_node(files, node):
@@ -90,7 +90,7 @@
                 fp.write(chunk)
         return dirname
 
-    node1, node2 = commands.revpair(ui, repo, opts['rev'])
+    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]
@@ -105,8 +105,7 @@
         else:
             dir2 = snapshot_wdir(modified + added)
         cmdline = ('%s %s %s %s' %
-                   (util.shellquote(diffcmd),
-                    ' '.join(map(util.shellquote, diffopts)),
+                   (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)
--- a/hgext/hgk.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/hgext/hgk.py	Fri Sep 15 15:22:45 2006 -0500
@@ -7,90 +7,39 @@
 
 from mercurial.demandload import *
 demandload(globals(), 'time sys signal os')
-demandload(globals(), 'mercurial: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.status(node1, node2, files, match=match)[:5]
-    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
+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.status(node1, node2)[:5]
-            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.status(node1)[:5]
+            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:
@@ -113,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]
@@ -139,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())
@@ -152,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"""
@@ -265,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)
@@ -274,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]
@@ -300,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
@@ -312,23 +276,29 @@
     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()])
+    os.system(ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc)))
 
 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	Tue Aug 22 21:02:25 2006 -0500
+++ b/hgext/mq.py	Fri Sep 15 15:22:45 2006 -0500
@@ -31,15 +31,16 @@
 
 from mercurial.demandload import *
 from mercurial.i18n import gettext as _
+from mercurial import commands
 demandload(globals(), "os sys re struct traceback errno bz2")
-demandload(globals(), "mercurial:cmdutil,commands,hg,patch,revlog,ui,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:
@@ -482,24 +483,35 @@
         tr.close()
         return (err, n)
 
-    def delete(self, repo, patches, keep=False):
+    def delete(self, repo, patches, opts):
         realpatches = []
+        appliedbase = 0
+        forget = opts.get('forget')
         for patch in patches:
             patch = self.lookup(patch, strict=True)
             info = self.isapplied(patch)
-            if info:
+            if info and not forget:
                 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 forget:
+                if not info:
+                    raise util.Abort(_("cannot forget unapplied patch %s") % patch)
+                if info[0] != appliedbase:
+                    raise util.Abort(_("patch %s not at base") % patch)
+                appliedbase += 1
             realpatches.append(patch)
 
-        if not keep:
+        if not opts.get('keep'):
             r = self.qrepo()
             if r:
                 r.remove(realpatches, True)
             else:
                 os.unlink(self.join(patch))
 
+        if forget:
+            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]:
@@ -693,8 +705,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)
@@ -756,25 +768,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:
@@ -915,16 +927,16 @@
     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")
+        patchf = self.opener(patchfn, "w")
         msg = opts.get('msg', '').rstrip()
         if msg:
             if comments:
@@ -994,8 +1006,11 @@
             r = list(util.unique(dd))
             a = list(util.unique(aa))
             filelist = filter(matchfn, util.unique(m + r + a))
-            self.printdiff(repo, patchparent, files=filelist,
-                           changes=(m, a, r, [], u), fp=patchf)
+            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)
@@ -1018,7 +1033,7 @@
 
             if not msg:
                 if not message:
-                    message = "patch queue: %s\n" % patch
+                    message = "patch queue: %s\n" % patchfn
                 else:
                     message = "\n".join(message)
             else:
@@ -1026,7 +1041,7 @@
 
             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:
             self.printdiff(repo, patchparent, fp=patchf)
@@ -1237,11 +1252,13 @@
             self.ui.write(p + '\n')
         else:
             self.ui.write("No patches applied\n")
+            return 1
 
     def next(self, repo):
         end = self.series_end()
         if end == len(self.series):
             self.ui.write("All patches applied\n")
+            return 1
         else:
             p = self.series[end]
             if self.ui.verbose:
@@ -1254,8 +1271,10 @@
             self.ui.write(p + '\n')
         elif len(self.applied) == 1:
             self.ui.write("Only one patch applied\n")
+            return 1
         else:
             self.ui.write("No patches applied\n")
+            return 1
 
     def qimport(self, repo, files, patch=None, existing=None, force=None):
         if len(files) > 1 and patch:
@@ -1298,10 +1317,15 @@
 def delete(ui, repo, patch, *patches, **opts):
     """remove patches from queue
 
-    The patches must not be applied.
-    With -k, the patch files are preserved in the patch directory."""
+    With --forget, mq will stop managing the named patches. 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,) + patches, keep=opts.get('keep'))
+    q.delete(repo, (patch,) + patches, opts)
     q.save_dirty()
     return 0
 
@@ -1402,18 +1426,15 @@
 
 def top(ui, repo, **opts):
     """print the name of the current patch"""
-    repo.mq.top(repo)
-    return 0
+    return repo.mq.top(repo)
 
 def next(ui, repo, **opts):
     """print the name of the next patch"""
-    repo.mq.next(repo)
-    return 0
+    return repo.mq.next(repo)
 
 def prev(ui, repo, **opts):
     """print the name of the previous patch"""
-    repo.mq.prev(repo)
-    return 0
+    return repo.mq.prev(repo)
 
 def new(ui, repo, patch, **opts):
     """create a new patch
@@ -1449,9 +1470,9 @@
         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, pats, msg=message, **opts)
+    ret = q.refresh(repo, pats, msg=message, **opts)
     q.save_dirty()
-    return 0
+    return ret
 
 def diff(ui, repo, *pats, **opts):
     """diff of the current patch"""
@@ -1476,7 +1497,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']:
@@ -1571,7 +1592,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]
 
@@ -1648,13 +1669,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:
@@ -1662,6 +1676,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))
@@ -1733,7 +1756,8 @@
         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):
@@ -1909,8 +1933,9 @@
                'hg qdiff [-I] [-X] [FILE]...'),
     "qdelete|qremove|qrm":
         (delete,
-         [('k', 'keep', None, _('keep patch file'))],
-          'hg qdelete [-k] PATCH'),
+         [('f', 'forget', None, _('stop managing an applied patch')),
+          ('k', 'keep', None, _('keep patch file'))],
+          'hg qdelete [-f] [-k] PATCH'),
     'qfold':
         (fold,
          [('e', 'edit', None, _('edit patch header')),
@@ -1961,6 +1986,7 @@
          [('e', 'edit', None, _('edit commit message')),
           ('m', 'message', '', _('change commit message with <text>')),
           ('l', 'logfile', '', _('change commit message with <file> content')),
+          ('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'))],
@@ -1992,7 +2018,7 @@
         (series,
          [('m', 'missing', None, 'print patches not in series'),
           ('s', 'summary', None, _('print first line of patch header'))],
-         'hg qseries [-m]'),
+         'hg qseries [-ms]'),
     "^strip":
         (strip,
          [('f', 'force', None, 'force multi-head removal'),
--- a/hgext/notify.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/hgext/notify.py	Fri Sep 15 15:22:45 2006 -0500
@@ -238,8 +238,11 @@
             return
         fp = templater.stringio()
         prev = self.repo.changelog.parents(node)[0]
-        patch.diff(self.repo, fp, 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	Tue Aug 22 21:02:25 2006 -0500
+++ b/hgext/patchbomb.py	Fri Sep 15 15:22:45 2006 -0500
@@ -65,7 +65,7 @@
 
 from mercurial.demandload import *
 demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
-                         mercurial:commands,hg,mail,ui
+                         mercurial:commands,hg,mail,ui,patch
                          os errno popen2 socket sys tempfile time''')
 from mercurial.i18n import gettext as _
 from mercurial.node import *
@@ -76,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
 
@@ -123,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')
@@ -140,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
 
@@ -205,7 +186,8 @@
 
     commands.export(ui, repo, *revs, **{'output': exportee(patches),
                                         'switch_parent': False,
-                                        'text': None})
+                                        'text': None,
+                                        'git': opts.get('git')})
 
     jumbo = []
     msgs = []
@@ -322,6 +304,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'),
--- a/mercurial/changelog.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/changelog.py	Fri Sep 15 15:22:45 2006 -0500
@@ -16,6 +16,14 @@
                         defversion)
 
     def extract(self, text):
+        """
+        format used:
+        nodeid\n  : manifest node in ascii
+        user\n    : user, no \n or \r allowed
+        time tz\n : date (time is int or float, timezone is int)
+        files\n\n : files modified by the cset, no \n or \r allowed
+        (.*)      : comment (free text, ideally utf-8)
+        """
         if not text:
             return (nullid, "", (0, 0), [], "")
         last = text.index("\n\n")
--- a/mercurial/cmdutil.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/cmdutil.py	Fri Sep 15 15:22:45 2006 -0500
@@ -11,6 +11,76 @@
 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 = {
@@ -53,8 +123,8 @@
             i += 1
         return ''.join(newname)
     except KeyError, inst:
-        raise util.Abort(_("invalid format spec '%%%s' in output file name"),
-                    inst.args[0])
+        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):
--- a/mercurial/commands.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/commands.py	Fri Sep 15 15:22:45 2006 -0500
@@ -8,7 +8,7 @@
 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 difflib patch random signal tempfile time")
 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
@@ -50,6 +50,21 @@
                              (logfile, inst.strerror))
     return message
 
+def defaultrev(repo, rev=None, default='tip'):
+    """returns rev if it is specified, otherwise the working dir
+    parent if there is only one, or tip if there is no working
+    dir"""
+    if rev:
+        return rev
+
+    p1, p2 = repo.dirstate.parents()
+    if p2 != nullid:
+        raise util.Abort(_('uncommitted merge - please provide a '
+                           'specific revision'))
+    if p1 != nullid:
+        return hex(p1)
+    return default
+
 def walkchangerevs(ui, repo, pats, opts):
     '''Iterate over files and the revs they changed in.
 
@@ -99,16 +114,10 @@
         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' % defaultrev(repo)
     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 = {}
@@ -252,76 +261,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 write_bundle(cg, filename=None, compress=True):
     """Write a bundle file and return its filename.
 
@@ -341,7 +280,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")
@@ -505,7 +444,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])
 
@@ -707,7 +646,7 @@
     if not opts['user'] and not opts['changeset'] and not opts['date']:
         opts['number'] = 1
 
-    ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
+    ctx = repo.changectx(defaultrev(repo, opts['rev']))
 
     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
                                              node=ctx.node()):
@@ -754,14 +693,7 @@
     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'))
-
+    node = repo.lookup(defaultrev(repo, opts['rev']))
     dest = cmdutil.make_filename(repo, dest, node)
     if os.path.realpath(dest) == repo.root:
         raise util.Abort(_('repository root cannot be destination'))
@@ -818,6 +750,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()
@@ -866,7 +799,8 @@
     """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
@@ -876,7 +810,7 @@
     %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")
+    ctx = repo.changectx(defaultrev(repo, 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)
@@ -1151,7 +1085,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:
@@ -1161,7 +1095,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))
 
@@ -1268,7 +1202,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"""
@@ -1343,7 +1277,7 @@
     it detects as binary. With -a, diff will generate a diff anyway,
     probably with undesirable results.
     """
-    node1, node2 = revpair(ui, repo, opts['rev'])
+    node1, node2 = cmdutil.revpair(ui, repo, opts['rev'])
 
     fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
 
@@ -1379,7 +1313,7 @@
     """
     if not changesets:
         raise util.Abort(_("export requires at least one changeset"))
-    revs = list(revrange(ui, repo, changesets))
+    revs = list(cmdutil.revrange(ui, repo, changesets))
     if len(revs) > 1:
         ui.note(_('exporting patches:\n'))
     else:
@@ -1939,7 +1873,7 @@
     revision to merge with must be provided.
     """
 
-    if node:
+    if node or branch:
         node = _lookup(repo, node, branch)
     else:
         heads = repo.heads()
@@ -2271,8 +2205,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
@@ -2286,16 +2220,15 @@
 
     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
+    node = repo.lookup(defaultrev(repo, opts['rev']))
     mf = repo.manifest.read(repo.changelog.read(node)[0])
     if node == parent:
         pmf = mf
@@ -2452,7 +2385,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()
 
@@ -2463,7 +2397,8 @@
             ui.setconfig("web", o, 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()
@@ -2478,7 +2413,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()
@@ -2593,15 +2528,10 @@
             raise util.Abort(_("use only one form to specify the revision"))
     if opts['rev']:
         rev_ = opts['rev']
-    if rev_:
-        r = 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 = p1
+    r = defaultrev(repo, rev_, nullid)
+    if r == nullid:
+        raise util.Abort(_('no revision to tag'))
+    r = repo.lookup(r)
 
     message = opts['message']
     if not message:
@@ -2728,7 +2658,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
@@ -2881,6 +2811,7 @@
         (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')),
           ('', 'switch-parent', None, _('diff against the second parent'))],
          _('hg export [-a] [-o OUTFILESPEC] REV...')),
     "debugforget|forget":
@@ -3046,7 +2977,8 @@
          _('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')),
@@ -3145,7 +3077,7 @@
           " debugindex debugindexdot")
 optionalrepo = ("paths serve debugconfig")
 
-def findpossible(cmd):
+def findpossible(ui, cmd):
     """
     Return cmd -> (aliases, command table entry)
     for each matching command.
@@ -3158,7 +3090,7 @@
         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
@@ -3174,9 +3106,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]
@@ -3211,11 +3143,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
@@ -3299,12 +3231,14 @@
         if num: signal.signal(num, catchterm)
 
     try:
-        u = ui.ui(traceback='--traceback' in sys.argv[1:],
-                  readhooks=[load_extensions])
+        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"]:
@@ -3439,7 +3373,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:
@@ -3461,18 +3395,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/hg.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/hg.py	Fri Sep 15 15:22:45 2006 -0500
@@ -115,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_):
@@ -127,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
--- a/mercurial/hgweb/server.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/hgweb/server.py	Fri Sep 15 15:22:45 2006 -0500
@@ -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/httprepo.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/httprepo.py	Fri Sep 15 15:22:45 2006 -0500
@@ -325,7 +325,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/localrepo.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/localrepo.py	Fri Sep 15 15:22:45 2006 -0500
@@ -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
@@ -75,12 +84,6 @@
         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 +134,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))
@@ -641,7 +644,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:
--- a/mercurial/mdiff.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/mdiff.py	Fri Sep 15 15:22:45 2006 -0500
@@ -50,6 +50,9 @@
 defaultopts = diffopts()
 
 def unidiff(a, ad, b, bd, fn, r=None, opts=defaultopts):
+    def datetag(date):
+        return opts.git and '\n' or '\t%s\n' % date
+
     if not a and not b: return ""
     epoch = util.datestr((0, 0))
 
@@ -58,19 +61,19 @@
     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:
@@ -79,8 +82,8 @@
         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':
--- a/mercurial/merge.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/merge.py	Fri Sep 15 15:22:45 2006 -0500
@@ -8,7 +8,7 @@
 from node import *
 from i18n import gettext as _
 from demandload import *
-demandload(globals(), "util os tempfile")
+demandload(globals(), "errno util os tempfile")
 
 def fmerge(f, local, other, ancestor):
     """merge executable flags"""
@@ -166,7 +166,8 @@
                     repo.ui.debug(_(" updating permissions for %s\n") % f)
                     util.set_exec(repo.wjoin(f), m2.execf(f))
                 else:
-                    if fmerge(f, m1, m2, ma) != m1.execf(f):
+                    mode = fmerge(f, m1, m2, ma)
+                    if mode != m1.execf(f):
                         repo.ui.debug(_(" updating permissions for %s\n")
                                       % f)
                         util.set_exec(repo.wjoin(f), mode)
--- a/mercurial/packagescan.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/packagescan.py	Fri Sep 15 15:22:45 2006 -0500
@@ -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])
--- a/mercurial/patch.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/patch.py	Fri Sep 15 15:22:45 2006 -0500
@@ -9,7 +9,8 @@
 from i18n import gettext as _
 from node import *
 demandload(globals(), "cmdutil mdiff util")
-demandload(globals(), "cStringIO email.Parser errno os re shutil sys tempfile")
+demandload(globals(), '''cStringIO email.Parser errno os re shutil sys tempfile
+                         popen2''')
 
 # helper functions
 
@@ -182,7 +183,7 @@
 
     return (dopatch, gitpatches)
 
-def dogitpatch(patchname, gitpatches):
+def dogitpatch(patchname, gitpatches, cwd=None):
     """Preprocess git patch so that vanilla patch can handle it"""
     pf = file(patchname)
     pfline = 1
@@ -196,7 +197,7 @@
             if not p.copymod:
                 continue
 
-            copyfile(p.oldpath, p.path)
+            copyfile(p.oldpath, p.path, basedir=cwd)
 
             # rewrite patch hunk
             while pfline < p.lineno:
@@ -227,23 +228,20 @@
     """apply the patch <patchname> to the working directory.
     a list of patched files is returned"""
 
-    (dopatch, gitpatches) = readgitpatch(patchname)
+    # helper function
+    def __patch(patchname):
+        """patch and updates the files and fuzz variables"""
+        files = {}
+        fuzz = False
 
-    files = {}
-    fuzz = False
-    if dopatch:
-        if dopatch == 'filter':
-            patchname = dogitpatch(patchname, gitpatches)
-        patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
+        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)))
 
-        if dopatch == 'filter':
-            False and os.unlink(patchname)
-
         for line in fp:
             line = line.rstrip()
             ui.note(line + '\n')
@@ -264,11 +262,24 @@
                     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)
+
+    if dopatch:
+        if dopatch == 'filter':
+            patchname = dogitpatch(patchname, gitpatches, cwd=cwd)
+        try:
+            files, fuzz = __patch(patchname)
+        finally:
+            if dopatch == 'filter':
+                os.unlink(patchname)
+    else:
+        files, fuzz = {}, False
 
     for gp in gitpatches:
         files[gp.path] = (gp.op, gp)
@@ -492,7 +503,10 @@
                     header.append('deleted file mode %s\n' % mode)
             else:
                 omode = gitmode(mmap.execf(f))
-                nmode = gitmode(util.is_exec(repo.wjoin(f), 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)
             r = None
             if dodiff:
@@ -537,3 +551,24 @@
 
     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/revlog.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/revlog.py	Fri Sep 15 15:22:45 2006 -0500
@@ -139,6 +139,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
--- a/mercurial/sshrepo.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/sshrepo.py	Fri Sep 15 15:22:45 2006 -0500
@@ -32,12 +32,6 @@
         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)
 
@@ -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)
 
@@ -90,7 +87,7 @@
             if not l: break
             self.ui.status(_("remote: "), l)
 
-    def __del__(self):
+    def cleanup(self):
         try:
             self.pipeo.close()
             self.pipei.close()
@@ -101,6 +98,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)
--- a/mercurial/ui.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/ui.py	Fri Sep 15 15:22:45 2006 -0500
@@ -12,13 +12,14 @@
 
 class ui(object):
     def __init__(self, verbose=False, debug=False, quiet=False,
-                 interactive=True, traceback=False, parentui=None,
-                 readhooks=[]):
+                 interactive=True, traceback=False, parentui=None):
         self.overlay = {}
         if parentui is None:
             # this is the parent of all ui children
             self.parentui = None
-            self.readhooks = list(readhooks)
+            self.readhooks = []
+            self.trusted_users = {}
+            self.trusted_groups = {}
             self.cdata = ConfigParser.SafeConfigParser()
             self.readconfig(util.rcpath())
 
@@ -36,7 +37,9 @@
         else:
             # parentui may point to an ui object which is already a child
             self.parentui = parentui.parentui or parentui
-            self.readhooks = list(parentui.readhooks or readhooks)
+            self.readhooks = parentui.readhooks[:]
+            self.trusted_users = parentui.trusted_users.copy()
+            self.trusted_groups = parentui.trusted_groups.copy()
             parent_cdata = self.parentui.cdata
             self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
             # make interpolation work
@@ -51,7 +54,7 @@
     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.verbose = ((self.verbose or verbose) or debug) and not self.quiet
         self.debugflag = (self.debugflag or debug)
         self.interactive = (self.interactive and interactive)
         self.traceback = self.traceback or traceback
@@ -72,7 +75,22 @@
             fn = [fn]
         for f in fn:
             try:
-                self.cdata.read(f)
+                fp = open(f)
+            except IOError:
+                continue
+            if ((self.trusted_users or self.trusted_groups) and
+                '*' not in self.trusted_users and
+                '*' not in self.trusted_groups):
+                st = util.fstat(fp)
+                user = util.username(st.st_uid)
+                group = util.groupname(st.st_gid)
+                if (user not in self.trusted_users and
+                    group not in self.trusted_groups):
+                    self.warn(_('not reading file %s from untrusted '
+                                'user %s, group %s\n') % (f, user, group))
+                    continue
+            try:
+                self.cdata.readfp(fp, 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
@@ -81,9 +99,19 @@
         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))
+        user = util.username()
+        if user is not None:
+            self.trusted_users[user] = 1
+            for user in self.configlist('trusted', 'users'):
+                self.trusted_users[user] = 1
+            for group in self.configlist('trusted', 'groups'):
+                self.trusted_groups[group] = 1
         for hook in self.readhooks:
             hook(self)
 
+    def addreadhook(self, hook):
+        self.readhooks.append(hook)
+
     def setconfig(self, section, name, val):
         self.overlay[(section, name)] = val
 
@@ -94,7 +122,9 @@
             try:
                 return self.cdata.get(section, name)
             except ConfigParser.InterpolationError, inst:
-                raise util.Abort(_("Error in configuration:\n%s") % inst)
+                raise util.Abort(_("Error in configuration section [%s] "
+                                   "parameter '%s':\n%s")
+                                 % (section, name, inst))
         if self.parentui is None:
             return default
         else:
@@ -116,7 +146,9 @@
             try:
                 return self.cdata.getboolean(section, name)
             except ConfigParser.InterpolationError, inst:
-                raise util.Abort(_("Error in configuration:\n%s") % inst)
+                raise util.Abort(_("Error in configuration section [%s] "
+                                   "parameter '%s':\n%s")
+                                 % (section, name, inst))
         if self.parentui is None:
             return default
         else:
@@ -134,7 +166,8 @@
             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
@@ -146,10 +179,14 @@
             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
-                yield section, name, value.replace('\n', '\\n')
-                seen[section, name] = 1
+            try:
+                for name, value in self.cdata.items(section):
+                    if (section, name) in seen: continue
+                    yield section, name, value.replace('\n', '\\n')
+                    seen[section, name] = 1
+            except ConfigParser.InterpolationError, inst:
+                raise util.Abort(_("Error in configuration section [%s]:\n%s")
+                                 % (section, inst))
         if self.parentui is not None:
             for parent in self.parentui.walkconfig(seen):
                 yield parent
--- a/mercurial/util.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/mercurial/util.py	Fri Sep 15 15:22:45 2006 -0500
@@ -15,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 pwd grp")
 
 # used by parsedate
 defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M',
@@ -509,6 +509,38 @@
     raise Abort(_('user name not available - set USERNAME '
                   'environment variable'))
 
+def username(uid=None):
+    """Return the name of the user with the given uid.
+
+    If uid is None, return the name of the current user."""
+    try:
+        # force an ImportError if there's no module pwd
+        getpwuid = pwd.getpwuid
+        if uid is None:
+            uid = os.getuid()
+        try:
+            return getpwuid(uid)[0]
+        except KeyError:
+            return str(uid)
+    except ImportError:
+        return None
+
+def groupname(gid=None):
+    """Return the name of the group with the given gid.
+
+    If gid is None, return the name of the current group."""
+    try:
+        # force an ImportError if there's no module grp
+        getgrgid = grp.getgrgid
+        if gid is None:
+            gid = os.getgid()
+        try:
+            return getgrgid(gid)[0]
+        except KeyError:
+            return str(gid)
+    except ImportError:
+        return None
+
 # Platform specific variants
 if os.name == 'nt':
     demandload(globals(), "msvcrt")
--- a/templates/map-gitweb	Tue Aug 22 21:02:25 2006 -0500
+++ b/templates/map-gitweb	Fri Sep 15 15:22:45 2006 -0500
@@ -8,7 +8,7 @@
 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>'
+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> | <a href="?fa=#filenode|short#;file=#file|urlescape#;style=gitweb">annotate</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
@@ -19,12 +19,12 @@
 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>'
+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="?cs=#node|short#;style=gitweb">#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="?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>'
@@ -37,7 +37,7 @@
 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#'
+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="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>'
@@ -46,5 +46,5 @@
 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>'
+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"><a href="?f=#node|short#;file=#file|urlescape#;style=gitweb">file</a> | <!-- 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/static/style-gitweb.css	Tue Aug 22 21:02:25 2006 -0500
+++ b/templates/static/style-gitweb.css	Fri Sep 15 15:22:45 2006 -0500
@@ -47,3 +47,4 @@
 	text-align:center; text-decoration:none;
 }
 a.rss_logo:hover { background-color:#ee5500; }
+pre { margin: 0; }
--- a/tests/README	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/README	Fri Sep 15 15:22:45 2006 -0500
@@ -31,3 +31,65 @@
   use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
                     -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
   to strip 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.
+
+- 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.
--- a/tests/run-tests.py	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/run-tests.py	Fri Sep 15 15:22:45 2006 -0500
@@ -211,6 +211,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 +323,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)
--- a/tests/test-abort-checkin	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-abort-checkin	Fri Sep 15 15:22:45 2006 -0500
@@ -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
 cat > $HGTMP/false <<EOF
 #!/bin/sh
 exit 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bad-extension	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Fri Sep 15 15:22:45 2006 -0500
@@ -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-bisect	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-bisect	Fri Sep 15 15:22:45 2006 -0500
@@ -2,9 +2,8 @@
 
 set -e
 
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "hbisect=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "hbisect=" >> $HGRCPATH
 
 echo % init
 hg init
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-branch	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Fri Sep 15 15:22:45 2006 -0500
@@ -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-command-template.out	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-command-template.out	Fri Sep 15 15:22:45 2006 -0500
@@ -59,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
--- a/tests/test-confused-revert	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-confused-revert	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-confused-revert.out	Fri Sep 15 15:22:45 2006 -0500
@@ -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-extdiff	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-extdiff	Fri Sep 15 15:22:45 2006 -0500
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "extdiff=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "extdiff=" >> $HGRCPATH
 
 hg init a
 cd a
@@ -14,9 +13,9 @@
 fi
 hg extdiff -o -Nr $opt
 
-echo "[extdiff]" >> $HGTMP/.hgrc
-echo "cmd.falabala=echo" >> $HGTMP/.hgrc
-echo "opts.falabala=diffing" >> $HGTMP/.hgrc
+echo "[extdiff]" >> $HGRCPATH
+echo "cmd.falabala=echo" >> $HGRCPATH
+echo "opts.falabala=diffing" >> $HGRCPATH
 
 hg falabala
 
--- a/tests/test-fetch	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-fetch	Fri Sep 15 15:22:45 2006 -0500
@@ -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-git-export	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-git-export	Fri Sep 15 15:22:45 2006 -0500
@@ -50,3 +50,7 @@
 echo '% rename+mod+chmod'
 hg diff --git -r 6:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
     -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo '% nonexistent in tip+chmod'
+hg diff --git -r 5:6 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+    -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- a/tests/test-git-export.out	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-git-export.out	Fri Sep 15 15:22:45 2006 -0500
@@ -40,3 +40,7 @@
  4
  5
 +a
+% nonexistent in tip+chmod
+diff --git a/src b/src
+old mode 100644
+new mode 100755
--- a/tests/test-http	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-http	Fri Sep 15 15:22:45 2006 -0500
@@ -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
--- a/tests/test-http-proxy	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-http-proxy	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-http-proxy.out	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-http.out	Fri Sep 15 15:22:45 2006 -0500
@@ -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-init	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-init	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-init.out	Fri Sep 15 15:22:45 2006 -0500
@@ -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
--- a/tests/test-merge-revert	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-merge-revert	Fri Sep 15 15:22:45 2006 -0500
@@ -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-revert2	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-merge-revert2	Fri Sep 15 15:22:45 2006 -0500
@@ -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
@@ -31,11 +31,11 @@
               -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\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-mq	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-mq	Fri Sep 15 15:22:45 2006 -0500
@@ -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
@@ -116,6 +115,19 @@
 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
@@ -127,7 +139,28 @@
 hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
 hg unbundle .hg/strip-backup/*
 
-cat >>$HGTMP/.hgrc <<EOF
+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
+
+cat >>$HGRCPATH <<EOF
 [diff]
 git = True
 EOF
--- a/tests/test-mq-guards	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-mq-guards	Fri Sep 15 15:22:45 2006 -0500
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qdelete	Fri Sep 15 15:22:45 2006 -0500
@@ -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 -f a
+hg qapplied
+hg log --template '{rev} {desc}\n'
+
+hg qnew d
+hg qnew e
+hg qnew f
+
+hg qdel -f e
+hg qdel -f d 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	Fri Sep 15 15:22:45 2006 -0500
@@ -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: patch e not at base
+f
+4 New patch: f
+3 New patch: e
+2 New patch: d
+1 New patch: a
+0 base
--- a/tests/test-mq-qdiff	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-mq-qdiff	Fri Sep 15 15:22:45 2006 -0500
@@ -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 % init
 hg init a
--- a/tests/test-mq-qnew-twice	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-mq-qnew-twice	Fri Sep 15 15:22:45 2006 -0500
@@ -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-qrefresh-replace-log-message	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-mq-qrefresh-replace-log-message	Fri Sep 15 15:22:45 2006 -0500
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qrename	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Fri Sep 15 15:22:45 2006 -0500
@@ -0,0 +1,7 @@
+adding base
+foo/renamed
+renamed
+bar/renamed
+renamed
+baz
+.hg/patches/baz
--- a/tests/test-mq-qsave	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-mq-qsave	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-mq.out	Fri Sep 15 15:22:45 2006 -0500
@@ -110,6 +110,19 @@
 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
@@ -127,6 +140,30 @@
 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
 new file
 
 diff --git a/new b/new
--- a/tests/test-nested-repo	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-nested-repo	Fri Sep 15 15:22:45 2006 -0500
@@ -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
--- a/tests/test-remove	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-remove	Fri Sep 15 15:22:45 2006 -0500
@@ -9,7 +9,7 @@
 hg remove
 rm foo
 hg remove foo
-hg revert
+hg revert --all
 rm foo
 hg remove --after
 hg commit -m 2 -d "1000000 0"
--- a/tests/test-revert	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-revert	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-revert-unknown	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-revert.out	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-ro-message.out	Fri Sep 15 15:22:45 2006 -0500
@@ -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-ssh	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-ssh	Fri Sep 15 15:22:45 2006 -0500
@@ -38,7 +38,7 @@
 
 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 +80,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
--- a/tests/test-ssh.out	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-ssh.out	Fri Sep 15 15:22:45 2006 -0500
@@ -2,7 +2,7 @@
 # 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-strict	Fri Sep 15 15:22:45 2006 -0500
@@ -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	Fri Sep 15 15:22:45 2006 -0500
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-trusted.py	Fri Sep 15 15:22:45 2006 -0500
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+# Since it's not easy to write a test that portably deals
+# with files from different users/groups, we cheat a bit by
+# monkey-patching some functions in the util module
+
+import os
+from mercurial import ui, util
+
+hgrc = os.environ['HGRCPATH']
+
+def testui(user='foo', group='bar', tusers=(), tgroups=(),
+           cuser='foo', cgroup='bar'):
+    # user, group => owners of the file
+    # tusers, tgroups => trusted users/groups
+    # cuser, cgroup => user/group of the current process
+
+    # write a global hgrc with the list of trusted users/groups and
+    # some setting so that we can be sure it was read
+    f = open(hgrc, 'w')
+    f.write('[paths]\n')
+    f.write('global = /some/path\n\n')
+
+    if tusers or tgroups:
+        f.write('[trusted]\n')
+        if tusers:
+            f.write('users = %s\n' % ', '.join(tusers))
+        if tgroups:
+            f.write('groups = %s\n' % ', '.join(tgroups))
+    f.close()
+
+    # override the functions that give names to uids and gids
+    def username(uid=None):
+        if uid is None:
+            return cuser
+        return user
+    util.username = username
+
+    def groupname(gid=None):
+        if gid is None:
+            return 'bar'
+        return group
+    util.groupname = groupname
+
+    # try to read everything
+    #print '# File belongs to user %s, group %s' % (user, group)
+    #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups)
+    kind = ('different', 'same')
+    who = ('', 'user', 'group', 'user and the group')
+    trusted = who[(user in tusers) + 2*(group in tgroups)]
+    if trusted:
+        trusted = ', but we trust the ' + trusted
+    print '# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup],
+                                     trusted)
+
+    parentui = ui.ui()
+    u = ui.ui(parentui=parentui)
+    u.readconfig('.hg/hgrc')
+    for name, path in u.configitems('paths'):
+        print name, '=', path
+    print
+
+    return u
+
+os.mkdir('repo')
+os.chdir('repo')
+os.mkdir('.hg')
+f = open('.hg/hgrc', 'w')
+f.write('[paths]\n')
+f.write('local = /another/path\n\n')
+f.close()
+
+#print '# Everything is run by user foo, group bar\n'
+
+# same user, same group
+testui()
+# same user, different group
+testui(group='def')
+# different user, same group
+testui(user='abc')
+# ... but we trust the group
+testui(user='abc', tgroups=['bar'])
+# different user, different group
+testui(user='abc', group='def')
+# ... but we trust the user
+testui(user='abc', group='def', tusers=['abc'])
+# ... but we trust the group
+testui(user='abc', group='def', tgroups=['def'])
+# ... but we trust the user and the group
+testui(user='abc', group='def', tusers=['abc'], tgroups=['def'])
+# ... but we trust all users
+print '# we trust all users'
+testui(user='abc', group='def', tusers=['*'])
+# ... but we trust all groups
+print '# we trust all groups'
+testui(user='abc', group='def', tgroups=['*'])
+# ... but we trust the whole universe
+print '# we trust all users and groups'
+testui(user='abc', group='def', tusers=['*'], tgroups=['*'])
+# ... check that users and groups are in different namespaces
+print "# we don't get confused by users and groups with the same name"
+testui(user='abc', group='def', tusers=['def'], tgroups=['abc'])
+# ... lists of user names work
+print "# list of user names"
+testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'],
+       tgroups=['bar', 'baz', 'qux'])
+# ... lists of group names work
+print "# list of group names"
+testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'],
+       tgroups=['bar', 'def', 'baz', 'qux'])
+
+print "# Can't figure out the name of the user running this process"
+testui(user='abc', group='def', cuser=None)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-trusted.py.out	Fri Sep 15 15:22:45 2006 -0500
@@ -0,0 +1,67 @@
+# same user, same group
+global = /some/path
+local = /another/path
+
+# same user, different group
+global = /some/path
+local = /another/path
+
+# different user, same group
+not reading file .hg/hgrc from untrusted user abc, group bar
+global = /some/path
+
+# different user, same group, but we trust the group
+global = /some/path
+local = /another/path
+
+# different user, different group
+not reading file .hg/hgrc from untrusted user abc, group def
+global = /some/path
+
+# different user, different group, but we trust the user
+global = /some/path
+local = /another/path
+
+# different user, different group, but we trust the group
+global = /some/path
+local = /another/path
+
+# different user, different group, but we trust the user and the group
+global = /some/path
+local = /another/path
+
+# we trust all users
+# different user, different group
+global = /some/path
+local = /another/path
+
+# we trust all groups
+# different user, different group
+global = /some/path
+local = /another/path
+
+# we trust all users and groups
+# different user, different group
+global = /some/path
+local = /another/path
+
+# we don't get confused by users and groups with the same name
+# different user, different group
+not reading file .hg/hgrc from untrusted user abc, group def
+global = /some/path
+
+# list of user names
+# different user, different group, but we trust the user
+global = /some/path
+local = /another/path
+
+# list of group names
+# different user, different group, but we trust the group
+global = /some/path
+local = /another/path
+
+# Can't figure out the name of the user running this process
+# different user, different group
+global = /some/path
+local = /another/path
+
--- a/tests/test-ui-config	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-ui-config	Fri Sep 15 15:22:45 2006 -0500
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-from mercurial import ui
+from mercurial import ui, util
 
 testui = ui.ui()
 testui.updateopts(config=[
@@ -11,10 +11,19 @@
     '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',
 ])
 
 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 +54,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	Tue Aug 22 21:02:25 2006 -0500
+++ b/tests/test-ui-config.out	Fri Sep 15 15:22:45 2006 -0500
@@ -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'
+---