changeset 981:4f81068ed8cd

Merge with jeffpc
author mpm@selenic.com
date Sat, 20 Aug 2005 13:08:07 -0700
parents a51991ebf229 (diff) 5197fb9d65d5 (current diff)
children 8d2e24bae760
files .hgignore .hgtags MANIFEST.in README contrib/bash_completion doc/hg.1.txt doc/hgrc.5.txt mercurial/bdiff.c mercurial/commands.py mercurial/fancyopts.py mercurial/hg.py mercurial/hgweb.py mercurial/ui.py templates/changelog.tmpl templates/fileannotate.tmpl templates/filelog.tmpl templates/filerevision.tmpl templates/manifest.tmpl templates/map templates/tags.tmpl tests/test-basic.out tests/test-copy.out tests/test-diffdir tests/test-flags.out tests/test-merge-revert2 tests/test-rawcommit1.out tests/test-tag.out tests/test-undo.out tests/test-unrelated-pull.out tests/test-up-local-change tests/test-up-local-change.out tests/test-walk.out
diffstat 29 files changed, 976 insertions(+), 179 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Wed Aug 17 22:59:47 2005 -0500
+++ b/.hgignore	Sat Aug 20 13:08:07 2005 -0700
@@ -1,3 +1,4 @@
+\.elc$
 \.orig$
 \.rej$
 ~$
--- a/.hgtags	Wed Aug 17 22:59:47 2005 -0500
+++ b/.hgtags	Sat Aug 20 13:08:07 2005 -0700
@@ -6,3 +6,4 @@
 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
+eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
--- a/MANIFEST.in	Wed Aug 17 22:59:47 2005 -0500
+++ b/MANIFEST.in	Sat Aug 20 13:08:07 2005 -0700
@@ -1,6 +1,6 @@
 include hg
 recursive-include mercurial *.py
-include hgweb.cgi
+include hgweb.cgi hgwebdir.cgi
 include hgeditor rewrite-log
 include tests/README tests/run-tests tests/test-*[a-z0-9] tests/*.out
 prune tests/*.err
@@ -12,5 +12,4 @@
 include README
 include CONTRIBUTORS
 include COPYING
-include TODO
 include MANIFEST.in
--- a/README	Wed Aug 17 22:59:47 2005 -0500
+++ b/README	Sat Aug 20 13:08:07 2005 -0700
@@ -92,3 +92,9 @@
  # Set up a CGI server on your webserver
  foo$ cp hgweb.cgi ~/public_html/hg/index.cgi
  foo$ emacs ~/public_html/hg/index.cgi # adjust the defaults
+
+For more info:
+
+ Documentation in doc/
+ Mercurial website at http://selenic.com/mercurial
+ Mercurial wiki at http://selenic.com/mercurial/wiki
--- a/contrib/bash_completion	Wed Aug 17 22:59:47 2005 -0500
+++ b/contrib/bash_completion	Sat Aug 20 13:08:07 2005 -0700
@@ -1,7 +1,7 @@
 _hg_commands()
 {
     local commands="$(hg -v help | sed -e '1,/^list of commands:/d' \
-                                       -e '/^global options:/Q' \
+                                       -e '/^global options:/,$d' \
 				       -e '/^ [^ ]/!d; s/[,:]//g;')"
     
     # hide debug commands from users, but complete them if 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/mercurial.el	Sat Aug 20 13:08:07 2005 -0700
@@ -0,0 +1,592 @@
+;;; mercurial.el --- Emacs support for the Mercurial distributed SCM
+
+;; Copyright (C) 2005 Bryan O'Sullivan
+
+;; Author: Bryan O'Sullivan <bos@serpentine.com>
+
+;; $Id$
+
+;; mercurial.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.
+
+;; mercurial.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 mercurial.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.
+
+;;; Commentary:
+
+;; This mode builds upon Emacs's VC mode to provide flexible
+;; integration with the Mercurial distributed SCM tool.
+
+;; To get going as quickly as possible, load mercurial.el into Emacs and
+;; type `C-c h h'; this runs hg-help-overview, which prints a helpful
+;; usage overview.
+
+;; Much of the inspiration for mercurial.el comes from Rajesh
+;; Vaidheeswarran's excellent p4.el, which does an admirably thorough
+;; job for the commercial Perforce SCM product.  In fact, substantial
+;; chunks of code are adapted from p4.el.
+
+;; This code has been developed under XEmacs 21.5, and may will not
+;; work as well under GNU Emacs (albeit tested under 21.2).  Patches
+;; to enhance the portability of this code, fix bugs, and add features
+;; are most welcome.  You can clone a Mercurial repository for this
+;; package from http://www.serpentine.com/hg/hg-emacs
+
+;; Please send problem reports and suggestions to bos@serpentine.com.
+
+
+;;; Code:
+
+(require 'advice)
+(require 'cl)
+(require 'diff-mode)
+(require 'easymenu)
+(require 'vc)
+
+
+;;; XEmacs has view-less, while GNU Emacs has view.  Joy.
+
+(condition-case nil
+    (require 'view-less)
+  (error nil))
+(condition-case nil
+    (require 'view)
+  (error nil))
+
+
+;;; Variables accessible through the custom system.
+
+(defgroup mercurial nil
+  "Mercurial distributed SCM."
+  :group 'tools)
+
+(defcustom hg-binary
+  (dolist (path '("~/bin/hg"
+		  "/usr/bin/hg"
+		  "/usr/local/bin/hg"))
+    (when (file-executable-p path)
+      (return path)))
+  "The path to Mercurial's hg executable."
+  :type '(file :must-match t)
+  :group 'mercurial)
+
+(defcustom hg-mode-hook nil
+  "Hook run when a buffer enters hg-mode."
+  :type 'sexp
+  :group 'mercurial)
+
+(defcustom hg-global-prefix "\C-ch"
+  "The global prefix for Mercurial keymap bindings."
+  :type 'sexp
+  :group 'mercurial)
+
+(defcustom hg-rev-completion-limit 100
+  "The maximum number of revisions that hg-read-rev will offer to complete.
+This affects memory usage and performance when prompting for revisions
+in a repository with a lot of history."
+  :type 'integer
+  :group 'mercurial)
+
+(defcustom hg-log-limit 50
+  "The maximum number of revisions that hg-log will display."
+  :type 'integer
+  :group 'mercurial)
+
+
+;;; Other variables.
+
+(defconst hg-running-xemacs (string-match "XEmacs" emacs-version)
+  "Is mercurial.el running under XEmacs?")
+
+(defvar hg-mode nil
+  "Is this file managed by Mercurial?")
+(make-variable-buffer-local 'hg-mode)
+(put 'hg-mode 'permanent-local t)
+
+(defvar hg-status nil)
+(make-variable-buffer-local 'hg-status)
+(put 'hg-status 'permanent-local t)
+
+(defvar hg-output-buffer-name "*Hg*"
+  "The name to use for Mercurial output buffers.")
+
+(defvar hg-file-history nil)
+(defvar hg-rev-history nil)
+
+
+;;; hg-mode keymap.
+
+(defvar hg-prefix-map
+  (let ((map (copy-keymap vc-prefix-map)))
+    (if (functionp 'set-keymap-name)
+      (set-keymap-name map 'hg-prefix-map)); XEmacs
+    map)
+  "This keymap overrides some default vc-mode bindings.")
+(fset 'hg-prefix-map hg-prefix-map)
+(define-key hg-prefix-map "=" 'hg-diff)
+(define-key hg-prefix-map "c" 'hg-undo)
+(define-key hg-prefix-map "g" 'hg-annotate)
+(define-key hg-prefix-map "l" 'hg-log)
+(define-key hg-prefix-map "n" 'hg-commit-file)
+;; (define-key hg-prefix-map "r" 'hg-update)
+(define-key hg-prefix-map "u" 'hg-revert-file)
+(define-key hg-prefix-map "~" 'hg-version-other-window)
+
+(defvar hg-mode-map (make-sparse-keymap))
+(define-key hg-mode-map "\C-xv" 'hg-prefix-map)
+
+(add-minor-mode 'hg-mode 'hg-mode hg-mode-map)
+
+
+;;; Global keymap.
+
+(global-set-key "\C-xvi" 'hg-add)
+
+(defvar hg-global-map (make-sparse-keymap))
+(fset 'hg-global-map hg-global-map)
+(global-set-key hg-global-prefix 'hg-global-map)
+(define-key hg-global-map "," 'hg-incoming)
+(define-key hg-global-map "." 'hg-outgoing)
+(define-key hg-global-map "<" 'hg-pull)
+(define-key hg-global-map "=" 'hg-diff)
+(define-key hg-global-map ">" 'hg-push)
+(define-key hg-global-map "?" 'hg-help-overview)
+(define-key hg-global-map "A" 'hg-addremove)
+(define-key hg-global-map "U" 'hg-revert)
+(define-key hg-global-map "a" 'hg-add)
+(define-key hg-global-map "c" 'hg-commit)
+(define-key hg-global-map "f" 'hg-forget)
+(define-key hg-global-map "h" 'hg-help-overview)
+(define-key hg-global-map "i" 'hg-init)
+(define-key hg-global-map "l" 'hg-log)
+(define-key hg-global-map "r" 'hg-root)
+(define-key hg-global-map "s" 'hg-status)
+(define-key hg-global-map "u" 'hg-update)
+
+
+;;; View mode keymap.
+
+(defvar hg-view-mode-map
+  (let ((map (copy-keymap (if (boundp 'view-minor-mode-map)
+			      view-minor-mode-map
+			    view-mode-map))))
+    (if (functionp 'set-keymap-name)
+      (set-keymap-name map 'hg-view-mode-map)); XEmacs
+    map))
+(fset 'hg-view-mode-map hg-view-mode-map)
+(define-key hg-view-mode-map
+  (if hg-running-xemacs [button2] [mouse-2])
+  'hg-buffer-mouse-clicked)
+
+
+;;; Convenience functions.
+
+(defun hg-binary ()
+  (if hg-binary
+      hg-binary
+    (error "No `hg' executable found!")))
+
+(defun hg-replace-in-string (str regexp newtext &optional literal)
+  "Replace all matches in STR for REGEXP with NEWTEXT string.
+Return the new string.  Optional LITERAL non-nil means do a literal
+replacement.
+
+This function bridges yet another pointless impedance gap between
+XEmacs and GNU Emacs."
+  (if (fboundp 'replace-in-string)
+      (replace-in-string str regexp newtext literal)
+    (replace-regexp-in-string regexp newtext str nil literal)))
+
+(defun hg-chomp (str)
+  "Strip trailing newlines from a string."
+  (hg-replace-in-string str "[\r\n]+$" ""))
+
+(defun hg-run-command (command &rest args)
+  "Run the shell command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT).
+The list ARGS contains a list of arguments to pass to the command."
+  (let* (exit-code
+	 (output
+	  (with-output-to-string
+	    (with-current-buffer
+		standard-output
+	      (setq exit-code
+		    (apply 'call-process command nil t nil args))))))
+    (cons exit-code output)))
+
+(defun hg-run (command &rest args)
+  "Run the Mercurial command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT)."
+  (apply 'hg-run-command (hg-binary) command args))
+
+(defun hg-run0 (command &rest args)
+  "Run the Mercurial command COMMAND, returning its output.
+If the command does not exit with a zero status code, raise an error."
+  (let ((res (apply 'hg-run-command (hg-binary) command args)))
+    (if (not (eq (car res) 0))
+	(error "Mercurial command failed %s - exit code %s"
+	       (cons command args)
+	       (car res))
+      (cdr res))))
+
+(defun hg-buffer-commands (pnt)
+  "Use the properties of a character to do something sensible."
+  (interactive "d")
+  (let ((rev (get-char-property pnt 'rev))
+	(file (get-char-property pnt 'file))
+	(date (get-char-property pnt 'date))
+	(user (get-char-property pnt 'user))
+	(host (get-char-property pnt 'host))
+	(prev-buf (current-buffer)))
+    (cond
+     (file
+      (find-file-other-window file))
+     (rev
+      (hg-diff hg-view-file-name rev rev prev-buf))
+     ((message "I don't know how to do that yet")))))
+
+(defun hg-buffer-mouse-clicked (event)
+  "Translate the mouse clicks in a HG log buffer to character events.
+These are then handed off to `hg-buffer-commands'.
+
+Handle frickin' frackin' gratuitous event-related incompatibilities."
+  (interactive "e")
+  (if hg-running-xemacs
+      (progn
+	(select-window (event-window event))
+	(hg-buffer-commands (event-point event)))
+    (select-window (posn-window (event-end event)))
+    (hg-buffer-commands (posn-point (event-start event)))))
+
+(unless (fboundp 'view-minor-mode)
+  (defun view-minor-mode (prev-buffer exit-func)
+    (view-mode)))
+
+(defun hg-abbrev-file-name (file)
+  (if hg-running-xemacs
+      (abbreviate-file-name file t)
+    (abbreviate-file-name file)))
+
+(defun hg-read-file-name (&optional prompt default)
+  "Read a file or directory name, or a pattern, to use with a command."
+  (let ((path (or default (buffer-file-name))))
+    (if (or (not path) current-prefix-arg)
+	(expand-file-name
+	 (read-file-name (format "File, directory or pattern%s: "
+				 (or prompt ""))
+			 (and path (file-name-directory path))
+			 nil nil
+			 (and path (file-name-nondirectory path))
+			 'hg-file-history))
+      path)))
+
+(defun hg-read-rev (&optional prompt default)
+  "Read a revision or tag, offering completions."
+  (let ((rev (or default "tip")))
+    (if (or (not rev) current-prefix-arg)
+	(let ((revs (split-string (hg-chomp
+				   (hg-run0 "-q" "log" "-r"
+					    (format "-%d"
+						    hg-rev-completion-limit)
+					    "-r" "tip"))
+				  "[\n:]")))
+	  (dolist (line (split-string (hg-chomp (hg-run0 "tags")) "\n"))
+	    (setq revs (cons (car (split-string line "\\s-")) revs)))
+	  (completing-read (format "Revision%s (%s): "
+				   (or prompt "")
+				   (or default "tip"))
+			   (map 'list 'cons revs revs)
+			   nil
+			   nil
+			   nil
+			   'hg-rev-history
+			   (or default "tip")))
+      rev)))
+
+;;; View mode bits.
+
+(defun hg-exit-view-mode (buf)
+  "Exit from hg-view-mode.
+We delete the current window if entering hg-view-mode split the
+current frame."
+  (when (and (eq buf (current-buffer))
+	     (> (length (window-list)) 1))
+    (delete-window))
+  (when (buffer-live-p buf)
+    (kill-buffer buf)))
+
+(defun hg-view-mode (prev-buffer &optional file-name)
+  (goto-char (point-min))
+  (set-buffer-modified-p nil)
+  (toggle-read-only t)
+  (view-minor-mode prev-buffer 'hg-exit-view-mode)
+  (use-local-map hg-view-mode-map)
+  (setq truncate-lines t)
+  (when file-name
+    (set (make-local-variable 'hg-view-file-name)
+	 (hg-abbrev-file-name file-name))))
+  
+(defun hg-file-status (file)
+  "Return status of FILE, or nil if FILE does not exist or is unmanaged."
+  (let* ((s (hg-run "status" file))
+	 (exit (car s))
+	 (output (cdr s)))
+    (if (= exit 0)
+	(let ((state (assoc (substring output 0 (min (length output) 2))
+			    '(("M " . modified)
+			      ("A " . added)
+			      ("R " . removed)))))
+	  (if state
+	      (cdr state)
+	    'normal)))))
+
+(defun hg-tip ()
+  (split-string (hg-chomp (hg-run0 "-q" "tip")) ":"))
+
+(defmacro hg-view-output (args &rest body)
+  "Execute BODY in a clean buffer, then quickly display that buffer.
+If the buffer contains one line, its contents are displayed in the
+minibuffer.  Otherwise, the buffer is displayed in view-mode.
+ARGS is of the form (BUFFER-NAME &optional FILE), where BUFFER-NAME is
+the name of the buffer to create, and FILE is the name of the file
+being viewed."
+  (let ((prev-buf (gensym "prev-buf-"))
+	(v-b-name (car args))
+	(v-m-rest (cdr args)))
+    `(let ((view-buf-name ,v-b-name)
+	   (,prev-buf (current-buffer)))
+       (get-buffer-create view-buf-name)
+       (kill-buffer view-buf-name)
+       (get-buffer-create view-buf-name)
+       (set-buffer view-buf-name)
+       (save-excursion
+	 ,@body)
+       (case (count-lines (point-min) (point-max))
+	 ((0)
+	  (kill-buffer view-buf-name)
+	  (message "(No output)"))
+	 ((1)
+	  (let ((msg (hg-chomp (buffer-substring (point-min) (point-max)))))
+	    (kill-buffer view-buf-name)
+	    (message "%s" msg)))
+	 (t
+	  (pop-to-buffer view-buf-name)
+	  (hg-view-mode ,prev-buf ,@v-m-rest))))))
+
+(put 'hg-view-output 'lisp-indent-function 1)
+
+;;; Hooks.
+
+(defun hg-mode-line ()
+  (when (hg-root)
+    (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)))
+
+(defun hg-find-file-hook ()
+  (when (hg-mode-line)
+    (run-hooks 'hg-mode-hook)))
+
+(add-hook 'find-file-hooks 'hg-find-file-hook)
+
+(defun hg-after-save-hook ()
+  (let ((old-status hg-status))
+    (hg-mode-line)
+    (if (and (not old-status) hg-status)
+	(run-hooks 'hg-mode-hook))))
+
+(add-hook 'after-save-hook 'hg-after-save-hook)
+
+
+;;; User interface functions.
+
+(defun hg-help-overview ()
+  "This is an overview of the Mercurial SCM mode for Emacs.
+
+You can find the source code, license (GPL v2), and credits for this
+code by typing `M-x find-library mercurial RET'.
+
+The Mercurial mode user interface is based on that of the older VC
+mode, so if you're already familiar with VC, the same keybindings and
+functions will generally work.
+
+Below is a list of common SCM tasks, with the key bindings needed to
+perform them, and the command names.  This list is not exhaustive.
+
+In the list below, `G/L' indicates whether a key binding is global (G)
+or local (L).  Global keybindings work on any file inside a Mercurial
+repository.  Local keybindings only apply to files under the control
+of Mercurial.  Many commands take a prefix argument.
+
+
+SCM Task                              G/L  Key Binding  Command Name
+--------                              ---  -----------  ------------
+Help overview (what you are reading)  G    C-c h h      hg-help-overview
+
+Tell Mercurial to manage a file       G    C-c h a      hg-add
+Commit changes to current file only   L    C-x v n      hg-commit
+Undo changes to file since commit     L    C-x v u      hg-revert-file
+
+Diff file vs last checkin             L    C-x v =      hg-diff
+
+View file change history              L    C-x v l      hg-log
+View annotated file                   L    C-x v a      hg-annotate
+
+Diff repo vs last checkin             G    C-c h =      hg-diff
+View status of files in repo          G    C-c h s      hg-status
+Commit all changes                    G    C-c h c      hg-commit
+
+Undo all changes since last commit    G    C-c h U      hg-revert
+View repo change history              G    C-c h l      hg-log
+
+See changes that can be pulled        G    C-c h ,      hg-incoming
+Pull changes                          G    C-c h <      hg-pull
+Update working directory after pull   G    C-c h u      hg-update
+See changes that can be pushed        G    C-c h .      hg-outgoing
+Push changes                          G    C-c h >      hg-push"
+  (interactive)
+  (hg-view-output ("Mercurial Help Overview")
+    (insert (documentation 'hg-help-overview))))
+
+(defun hg-add (path)
+  (interactive (list (hg-read-file-name " to add")))
+  (let ((buf (current-buffer))
+	(update (equal buffer-file-name path)))
+    (hg-view-output (hg-output-buffer-name)
+      (apply 'call-process (hg-binary) nil t nil (list "add" path)))
+    (when update
+      (with-current-buffer buf
+	(hg-mode-line)))))
+
+(defun hg-addremove ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-annotate ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-commit ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-diff (path &optional rev1 rev2)
+  (interactive (list (hg-read-file-name " to diff")
+		     (hg-read-rev " to start with")
+		     (let ((rev2 (hg-read-rev " to end with" 'working-dir)))
+		       (and (not (eq rev2 'working-dir)) rev2))))
+  (let ((a-path (hg-abbrev-file-name path)))
+    (hg-view-output ((if (equal rev1 rev2)
+			 (format "Mercurial: Rev %s of %s" rev1 a-path)
+		       (format "Mercurial: Rev %s to %s of %s"
+			       rev1 (or rev2 "Current") a-path)))
+      (if rev2
+	  (call-process (hg-binary) nil t nil "diff" "-r" rev1 "-r" rev2 path)
+	(call-process (hg-binary) nil t nil "diff" "-r" rev1 path))
+      (diff-mode)
+      (font-lock-fontify-buffer))))
+
+(defun hg-forget (path)
+  (interactive (list (hg-read-file-name " to forget")))
+  (let ((buf (current-buffer))
+	(update (equal buffer-file-name path)))
+    (hg-view-output (hg-output-buffer-name)
+      (apply 'call-process (hg-binary) nil t nil (list "forget" path)))
+    (when update
+      (with-current-buffer buf
+	(hg-mode-line)))))
+  
+(defun hg-incoming ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-init ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-log (path &optional rev1 rev2)
+  (interactive (list (hg-read-file-name " to log")
+		     (hg-read-rev " to start with" "-1")
+		     (hg-read-rev " to end with" (format "-%d" hg-log-limit))))
+  (message "log %s %s" rev1 rev2)
+  (sit-for 1)
+  (let ((a-path (hg-abbrev-file-name path)))
+    (hg-view-output ((if (equal rev1 rev2)
+			 (format "Mercurial: Rev %s of %s" rev1 a-path)
+		       (format "Mercurial: Rev %s to %s of %s"
+			       rev1 (or rev2 "Current") a-path)))
+      (call-process (hg-binary) nil t nil "log" "-r" rev1 "-r" rev2 path)
+      (diff-mode)
+      (font-lock-fontify-buffer))))
+
+(defun hg-outgoing ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-pull ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-push ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-revert ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-revert-file ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-root (&optional path)
+  (interactive (list (hg-read-file-name)))
+  (let ((root (do ((prev nil dir)
+		   (dir (file-name-directory (or path (buffer-file-name)))
+			(file-name-directory (directory-file-name dir))))
+		  ((equal prev dir))
+		(when (file-directory-p (concat dir ".hg"))
+		  (return dir)))))
+    (when (interactive-p)
+      (if root
+	  (message "The root of this repository is `%s'." root)
+	(message "The path `%s' is not in a Mercurial repository."
+		 (abbreviate-file-name path t))))
+    root))
+
+(defun hg-status (path)
+  (interactive (list (hg-read-file-name " for status" (hg-root))))
+  (let ((root (hg-root)))
+    (hg-view-output (hg-output-buffer-name)
+      (apply 'call-process (hg-binary) nil t nil
+	     (list "--cwd" root "status" path)))))
+
+(defun hg-undo ()
+  (interactive)
+  (error "not implemented"))
+
+(defun hg-version-other-window ()
+  (interactive)
+  (error "not implemented"))
+
+
+(provide 'mercurial)
+
+
+;;; Local Variables:
+;;; mode: emacs-lisp
+;;; prompt-to-byte-compile: nil
+;;; end:
--- a/doc/hg.1.txt	Wed Aug 17 22:59:47 2005 -0500
+++ b/doc/hg.1.txt	Sat Aug 20 13:08:07 2005 -0700
@@ -99,6 +99,8 @@
 
     options:
     -U, --noupdate   do not update the new working directory
+    -e, --ssh        specify ssh command to use
+    --remotecmd      specify hg command to run on the remote side
 
 commit [options] [files...]::
     Commit changes to the given files into the repository.
@@ -186,13 +188,14 @@
 
     aliases: id
 
-import [-p <n> -b <base> -q] <patches>::
+import [-p <n> -b <base> -f] <patches>::
     Import a list of patches and commit them individually.
 
     options:
     -p, --strip <n>   directory strip option for patch. This has the same
                       meaning as the correnponding patch option
     -b <path>         base directory to read patches from
+    -f, --force	      skip check for outstanding uncommitted changes
 
     aliases: patch
 
@@ -273,9 +276,8 @@
     Show definition of symbolic path name NAME. If no name is given, show
     definition of available names.
 
-    Path names are defined in the [paths] section of the $HOME/.hgrc and
-    <repo>/.hg/hgrc configuration files. If run outside a repo, 'paths'
-    queries only $HOME/.hgrc.
+    Path names are defined in the [paths] section of /etc/mercurial/hgrc
+    and $HOME/.hgrc.  If run inside a repository, .hg/hgrc is used, too.
 
 pull <repository path>::
     Pull changes from a remote repository to a local one.
@@ -284,8 +286,20 @@
     or URL and adds them to the local repository. By default, this
     does not update the copy of the project in the working directory.
 
+    Valid URLs are of the form:
+
+      local/filesystem/path
+      http://[user@]host[:port][/path]
+      https://[user@]host[:port][/path]
+      ssh://[user@]host[:port][/path]
+
+    SSH requires an accessible shell account on the destination
+    machine and a copy of hg in the remote path.
+      
     options:
     -u, --update   update the working directory to tip after pull
+    -e, --ssh    specify ssh command to use
+    --remotecmd  specify hg command to run on the remote side
 
 push <destination>::
     Push changes from the local repository to the given destination.
@@ -295,12 +309,23 @@
     destination is local this is identical to a pull in that directory
     from the current one.
 
-    The other currently available push method is SSH. This requires an
-    accessible shell account on the destination machine and a copy of
-    hg in the remote path. Destinations are specified in the following
-    form:
+    By default, push will refuse to run if it detects the result would
+    increase the number of remote heads. This generally indicates the
+    the client has forgotten to sync and merge before pushing.
+
+    Valid URLs are of the form:
 
-      ssh://[user@]host[:port]/path
+      local/filesystem/path
+      ssh://[user@]host[:port][/path]
+      
+    SSH requires an accessible shell account on the destination
+    machine and a copy of hg in the remote path.
+
+    options:
+
+    -f, --force  force update
+    -e, --ssh    specify ssh command to use
+    --remotecmd  specify hg command to run on the remote side
 
 rawcommit [-p -d -u -F -m -l]::
     Lowlevel commit, for use in helper scripts.
@@ -589,10 +614,11 @@
     seperated by spaces) that correspond to tagged versions of the repository
     contents.
 
- $HOME/.hgrc, .hg/hgrc::
+ /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc::
     This file contains defaults and configuration. Values in .hg/hgrc
-    override those in .hgrc.  See hgrc(5) for details of the contents
-    and format of these files.
+    override those in $HOME/.hgrc, and these override settings made in the
+    global /etc/mercurial/hgrc configuration.  See hgrc(5) for details of
+    the contents and format of these files.
 
 BUGS
 ----
--- a/doc/hgrc.5.txt	Wed Aug 17 22:59:47 2005 -0500
+++ b/doc/hgrc.5.txt	Sat Aug 20 13:08:07 2005 -0700
@@ -15,17 +15,22 @@
 FILES
 -----
 
-Mercurial reads configuration data from two files:
+Mercurial reads configuration data from three files:
+
+/etc/mercurial/hgrc::
+    Options in this global configuration file apply to all Mercurial
+    commands executed by any user in any directory.
 
 $HOME/.hgrc::
-    Global configuration options that apply to all Mercurial commands,
-    no matter where they are run.
+    Per-user configuration options that apply to all Mercurial commands,
+    no matter from which directory they are run.  Values in this file
+    override global settings.
 
 <repo>/.hg/hgrc::
     Per-repository configuration options that only apply in a
     particular repository.  This file is not version-controlled, and
     will not get transferred during a "clone" operation.  Values in
-    this file override global values.
+    this file override global and per-user settings.
 
 SYNTAX
 ------
@@ -65,6 +70,8 @@
   commit;;
     Run after a changeset has been created. Passed the ID of the newly
     created changeset.
+  changegroup;;
+    Run after a changegroup has been added via push or pull.
 
 http_proxy::
   Used to access web-based Mercurial repositories through a HTTP
@@ -85,11 +92,6 @@
   symbolic name, and the right gives the directory or URL that is the
   location of the repository.
 
-tags::
-  Tags that are local to a repository and not distributed or version
-  controlled.  The left side is the tag name, and the right is the
-  ID of the changeset to identify.
-
 ui::
   User interface controls.
   debug;;
@@ -109,6 +111,11 @@
     <fred@example.com>".  Default is $EMAIL or username@hostname.
   verbose;;
     Increase the amount of output printed.  True or False.  Default is False.
+  ssh;;
+    command to use for SSH connections. Default is 'ssh'.
+  remotecmd;;
+    remote command to use for clone/push/pull operations. Default is 'hg'.
+
 
 web::
   Web interface configuration.
@@ -127,6 +134,12 @@
     Where to output the error log. Default is stderr.
   templates;;
     Where to find the HTML templates. Default is install path.
+  maxchanges;;
+    Maximum number of changes to list on the changelog. Default is 10.
+  maxfiles;;
+    Maximum number of files to list per changeset. Default is 10.
+  allowpull;;
+    Whether to allow pulling from the repository. Default is true.
 
 AUTHOR
 ------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgwebdir.cgi	Sat Aug 20 13:08:07 2005 -0700
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+#
+# An example CGI script to export multiple hgweb repos, edit as necessary
+
+import cgi, cgitb, os, sys, ConfigParser
+cgitb.enable()
+
+# sys.path.insert(0, "/path/to/python/lib") # if not a system-wide install
+from mercurial import hgweb
+
+# The config file looks like this:
+# [paths]
+# virtual/path = /real/path
+# virtual/path = /real/path
+
+h = hgweb.hgwebdir("hgweb.config")
+h.run()
--- a/mercurial/bdiff.c	Wed Aug 17 22:59:47 2005 -0500
+++ b/mercurial/bdiff.c	Sat Aug 20 13:08:07 2005 -0700
@@ -253,7 +253,7 @@
 {
 	PyObject *sa, *sb, *rl = NULL, *m;
 	struct line *a, *b;
-	struct hunklist l;
+	struct hunklist l = {NULL, NULL};
 	struct hunk *h;
 	int an, bn, pos = 0;
 
@@ -287,7 +287,7 @@
 {
 	PyObject *sa, *sb, *result = NULL;
 	struct line *al, *bl;
-	struct hunklist l;
+	struct hunklist l = {NULL, NULL};
 	struct hunk *h;
 	char encode[12], *rb;
 	int an, bn, len = 0, la = 0, lb = 0;
--- a/mercurial/commands.py	Wed Aug 17 22:59:47 2005 -0500
+++ b/mercurial/commands.py	Sat Aug 20 13:08:07 2005 -0700
@@ -42,9 +42,10 @@
 def makewalk(repo, pats, opts, head = ''):
     cwd = repo.getcwd()
     files, matchfn = matchpats(repo, cwd, pats, opts, head)
+    exact = dict(zip(files, files))
     def walk():
         for src, fn in repo.walk(files = files, match = matchfn):
-            yield src, fn, util.pathto(cwd, fn)
+            yield src, fn, util.pathto(cwd, fn), fn in exact
     return files, matchfn, walk()
 
 def walk(repo, pats, opts, head = ''):
@@ -221,6 +222,14 @@
 
     changes = changelog.read(changenode)
 
+    t, tz = changes[2].split(' ')
+    # a conversion tool was sticking non-integer offsets into repos
+    try:
+        tz = int(tz)
+    except ValueError:
+        tz = 0
+    date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
+
     parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
                for p in log.parents(node)
                if ui.debugflag or p != hg.nullid]
@@ -246,8 +255,7 @@
     ui.debug("manifest:    %d:%s\n" % (repo.manifest.rev(changes[0]),
                                       hg.hex(changes[0])))
     ui.status("user:        %s\n" % changes[1])
-    ui.status("date:        %s\n" % time.asctime(
-        time.localtime(float(changes[2].split(' ')[0]))))
+    ui.status("date:        %s\n" % date)
 
     if ui.debugflag:
         files = repo.changes(changelog.parents(changenode)[0], changenode)
@@ -375,9 +383,8 @@
 def add(ui, repo, *pats, **opts):
     '''add the specified files on the next commit'''
     names = []
-    q = dict(zip(pats, pats))
-    for src, abs, rel in walk(repo, pats, opts):
-        if rel in q or abs in q:
+    for src, abs, rel, exact in walk(repo, pats, opts):
+        if exact:
             names.append(abs)
         elif repo.dirstate.state(abs) == '?':
             ui.status('adding %s\n' % rel)
@@ -386,15 +393,14 @@
 
 def addremove(ui, repo, *pats, **opts):
     """add all new files, delete all missing files"""
-    q = dict(zip(pats, pats))
     add, remove = [], []
-    for src, abs, rel in walk(repo, pats, opts):
+    for src, abs, rel, exact in walk(repo, pats, opts):
         if src == 'f' and repo.dirstate.state(abs) == '?':
             add.append(abs)
-            if rel not in q: ui.status('adding ', rel, '\n')
+            if not exact: ui.status('adding ', rel, '\n')
         if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
             remove.append(abs)
-            if rel not in q: ui.status('removing ', rel, '\n')
+            if not exact: ui.status('removing ', rel, '\n')
     repo.add(add)
     repo.remove(remove)
 
@@ -432,7 +438,7 @@
         node = repo.dirstate.parents()[0]
     change = repo.changelog.read(node)
     mmap = repo.manifest.read(change[0])
-    for src, abs, rel in walk(repo, pats, opts):
+    for src, abs, rel, exact in walk(repo, pats, opts):
         if abs not in mmap:
             ui.warn("warning: %s is not in the repository!\n" % rel)
             continue
@@ -490,9 +496,14 @@
             if self.dir_:
                 self.rmtree(self.dir_, True)
 
+    if opts['ssh']:
+        ui.setconfig("ui", "ssh", opts['ssh'])
+    if opts['remotecmd']:
+        ui.setconfig("ui", "remotecmd", opts['remotecmd'])
+
     d = Dircleanup(dest)
+    source = ui.expandpath(source)
     abspath = source
-    source = ui.expandpath(source)
     other = hg.repository(ui, source)
 
     if other.dev() != -1:
@@ -629,8 +640,12 @@
 def debugwalk(ui, repo, *pats, **opts):
     items = list(walk(repo, pats, opts))
     if not items: return
-    fmt = '%%s  %%-%ds  %%s' % max([len(abs) for (src, abs, rel) in items])
-    for i in items: print fmt % i
+    fmt = '%%s  %%-%ds  %%-%ds  %%s' % (
+        max([len(abs) for (src, abs, rel, exact) in items]),
+        max([len(rel) for (src, abs, rel, exact) in items]))
+    exactly = {True: 'exact', False: ''}
+    for src, abs, rel, exact in items:
+        print fmt % (src, abs, rel, exactly[exact])
 
 def diff(ui, repo, *pats, **opts):
     """diff working directory (or selected files)"""
@@ -645,7 +660,7 @@
     match = util.always
     if pats:
         roots, match, results = makewalk(repo, pats, opts)
-        for src, abs, rel in results:
+        for src, abs, rel, exact in results:
             files.append(abs)
     dodiff(sys.stdout, ui, repo, files, *revs, **{'match': match})
 
@@ -687,12 +702,11 @@
 
 def forget(ui, repo, *pats, **opts):
     """don't add the specified files on the next commit"""
-    q = dict(zip(pats, pats))
     forget = []
-    for src, abs, rel in walk(repo, pats, opts):
+    for src, abs, rel, exact in walk(repo, pats, opts):
         if repo.dirstate.state(abs) == 'a':
             forget.append(abs)
-            if rel not in q: ui.status('forgetting ', rel, '\n')
+            if not exact: ui.status('forgetting ', rel, '\n')
     repo.forget(forget)
 
 def heads(ui, repo, **opts):
@@ -730,6 +744,12 @@
     """import an ordered set of patches"""
     patches = (patch1,) + patches
 
+    if not opts['force']:
+        (c, a, d, u) = repo.changes()
+        if c or a or d:
+            ui.warn("abort: outstanding uncommitted changes!\n")
+            return 1
+
     d = opts["base"]
     strip = opts["strip"]
 
@@ -809,7 +829,7 @@
     end = '\n'
     if opts['print0']: end = '\0'
 
-    for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
+    for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
         if repo.dirstate.state(abs) == '?': continue
         if opts['fullpath']:
             ui.write(os.path.join(repo.root, abs), end)
@@ -914,6 +934,11 @@
     source = ui.expandpath(source)
     ui.status('pulling from %s\n' % (source))
 
+    if opts['ssh']:
+        ui.setconfig("ui", "ssh", opts['ssh'])
+    if opts['remotecmd']:
+        ui.setconfig("ui", "remotecmd", opts['remotecmd'])
+
     other = hg.repository(ui, source)
     r = repo.pull(other)
     if not r:
@@ -924,11 +949,16 @@
 
     return r
 
-def push(ui, repo, dest="default-push", force=False):
+def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
     """push changes to the specified destination"""
     dest = ui.expandpath(dest)
     ui.status('pushing to %s\n' % (dest))
 
+    if ssh:
+        ui.setconfig("ui", "ssh", ssh)
+    if remotecmd:
+        ui.setconfig("ui", "remotecmd", remotecmd)
+
     other = hg.repository(ui, dest)
     r = repo.push(other, force)
     return r
@@ -1263,8 +1293,10 @@
          'hg cat [-o OUTFILE] FILE [REV]'),
     "^clone":
         (clone,
-         [('U', 'noupdate', None, 'skip update after cloning')],
-         'hg clone [-U] SOURCE [DEST]'),
+         [('U', 'noupdate', None, 'skip update after cloning'),
+          ('e', 'ssh', "", 'ssh command'),
+          ('', 'remotecmd', "", 'remote hg command')],
+         'hg clone [OPTIONS] SOURCE [DEST]'),
     "^commit|ci":
         (commit,
          [('A', 'addremove', None, 'run add/remove during commit'),
@@ -1310,6 +1342,7 @@
     "import|patch":
         (import_,
          [('p', 'strip', 1, 'path strip'),
+          ('f', 'force', None, 'skip check for outstanding changes'),
           ('b', 'base', "", 'base path')],
          "hg import [-p NUM] [-b BASE] PATCH..."),
     "incoming|in": (incoming, [], 'hg incoming [SOURCE]'),
@@ -1333,11 +1366,15 @@
     "paths": (paths, [], 'hg paths [NAME]'),
     "^pull":
         (pull,
-         [('u', 'update', None, 'update working directory')],
-         'hg pull [-u] [SOURCE]'),
+         [('u', 'update', None, 'update working directory'),
+          ('e', 'ssh', "", 'ssh command'),
+          ('', 'remotecmd', "", 'remote hg command')],
+         'hg pull [OPTIONS] [SOURCE]'),
     "^push":
         (push,
-         [('f', 'force', None, 'force push')],
+         [('f', 'force', None, 'force push'),
+          ('e', 'ssh', "", 'ssh command'),
+          ('', 'remotecmd', "", 'remote hg command')],
          'hg push [-f] [DEST]'),
     "rawcommit":
         (rawcommit,
@@ -1402,6 +1439,7 @@
               ('', 'debug', None, 'debug mode'),
               ('q', 'quiet', None, 'quiet mode'),
               ('', 'profile', None, 'profile'),
+              ('', 'cwd', '', 'change working directory'),
               ('R', 'repository', "", 'repository root directory'),
               ('', 'traceback', None, 'print traceback on exception'),
               ('y', 'noninteractive', None, 'run non-interactively'),
@@ -1490,6 +1528,14 @@
         help_(u, 'shortlist')
         sys.exit(1)
 
+    if options['cwd']:
+        try:
+            os.chdir(options['cwd'])
+        except OSError, inst:
+            u = ui.ui()
+            u.warn('abort: %s: %s\n' % (options['cwd'], inst.strerror))
+            sys.exit(1)
+
     if options["time"]:
         def get_times():
             t = os.times()
--- a/mercurial/fancyopts.py	Wed Aug 17 22:59:47 2005 -0500
+++ b/mercurial/fancyopts.py	Sat Aug 20 13:08:07 2005 -0700
@@ -10,7 +10,9 @@
         map['-'+s] = map['--'+l]=l
         state[l] = d
         dt[l] = type(d)
-        if not d is None and not callable(d): s, l=s+':', l+'='
+        if not d is None and not callable(d):
+            if s: s += ':'
+            if l: l += '='
         if s: short = short + s
         if l: long.append(l)
 
--- a/mercurial/hg.py	Wed Aug 17 22:59:47 2005 -0500
+++ b/mercurial/hg.py	Sat Aug 20 13:08:07 2005 -0700
@@ -280,7 +280,10 @@
 
     def add(self, manifest, list, desc, transaction, p1=None, p2=None,
                   user=None, date=None):
-        date = date or "%d %d" % (time.time(), time.timezone)
+        if not date:
+            if time.daylight: offset = time.altzone
+            else: offset = time.timezone
+            date = "%d %d" % (time.time(), offset)
         list.sort()
         l = [hex(manifest), user, date] + list + ["", desc]
         text = "\n".join(l)
@@ -2106,8 +2109,10 @@
         if not path:
             raise RepoError("no remote repository path specified")
 
-        cmd = "ssh %s 'hg -R %s serve --stdio'"
-        cmd = cmd % (args, path)
+        sshcmd = self.ui.config("ui", "ssh", "ssh")
+        remotecmd = self.ui.config("ui", "remotecmd", "hg")
+        cmd = "%s %s '%s -R %s serve --stdio'"
+        cmd = cmd % (sshcmd, args, remotecmd, path)
 
         self.pipeo, self.pipei, self.pipee = os.popen3(cmd)
 
--- a/mercurial/hgweb.py	Wed Aug 17 22:59:47 2005 -0500
+++ b/mercurial/hgweb.py	Sat Aug 20 13:08:07 2005 -0700
@@ -125,34 +125,35 @@
 def rfc822date(x):
     return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(x))
 
+common_filters = {
+    "escape": cgi.escape,
+    "age": age,
+    "date": (lambda x: time.asctime(time.gmtime(x))),
+    "addbreaks": nl2br,
+    "obfuscate": obfuscate,
+    "short": (lambda x: x[:12]),
+    "firstline": (lambda x: x.splitlines(1)[0]),
+    "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
+    "rfc822date": rfc822date,
+    }
+
 class hgweb:
-    maxchanges = 10
-    maxfiles = 10
 
-    def __init__(self, path, name, templates = ""):
+    def __init__(self, path, name=None, templates=""):
         self.templates = templates
         self.reponame = name
         self.path = path
         self.mtime = -1
         self.viewonly = 0
 
-        self.filters = {
-            "escape": cgi.escape,
-            "age": age,
-            "date": (lambda x: time.asctime(time.gmtime(x))),
-            "addbreaks": nl2br,
-            "obfuscate": obfuscate,
-            "short": (lambda x: x[:12]),
-            "firstline": (lambda x: x.splitlines(1)[0]),
-            "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
-            "rfc822date": rfc822date,
-            }
-
     def refresh(self):
         s = os.stat(os.path.join(self.path, ".hg", "00changelog.i"))
         if s.st_mtime != self.mtime:
             self.mtime = s.st_mtime
             self.repo = repository(ui(), self.path)
+            self.maxchanges = self.repo.ui.config("web", "maxchanges", 10)
+            self.maxfiles = self.repo.ui.config("web", "maxchanges", 10)
+            self.allowpull = self.repo.ui.configbool("web", "allowpull", True)
 
     def date(self, cs):
         return time.asctime(time.gmtime(float(cs[2].split(' ')[0])))
@@ -638,7 +639,7 @@
 
         name = self.reponame or self.repo.ui.config("web", "name", os.getcwd())
 
-        self.t = templater(m, self.filters,
+        self.t = templater(m, common_filters,
                            {"url":url,
                             "repo":name,
                             "header":header,
@@ -707,7 +708,7 @@
         elif args['cmd'][0] == 'changegroup':
             httphdr("application/mercurial-0.1")
             nodes = []
-            if self.viewonly:
+            if not self.allowpull:
                 return
 
             if args.has_key('roots'):
@@ -837,3 +838,59 @@
     httpd = create_server(path, name, templates, address, port, use_ipv6,
                           accesslog, errorlog)
     httpd.serve_forever()
+
+# This is a stopgap
+class hgwebdir:
+    def __init__(self, config):
+        self.cp = ConfigParser.SafeConfigParser()
+        self.cp.read(config)
+
+    def run(self):
+        try:
+            virtual = os.environ["PATH_INFO"]
+        except:
+            virtual = ""
+
+        if virtual:
+            real = self.cp.get("paths", virtual[1:])
+            h = hgweb(real)
+            h.run()
+            return
+
+        def header(**map):
+            yield tmpl("header", **map)
+
+        def footer(**map):
+            yield tmpl("footer", **map)
+
+        templates = templatepath()
+        m = os.path.join(templates, "map")
+        tmpl = templater(m, common_filters,
+                         {"header": header, "footer": footer})
+
+        def entries(**map):
+            parity = 0
+            l = self.cp.items("paths")
+            l.sort()
+            for v,r in l:
+                cp2 = ConfigParser.SafeConfigParser()
+                cp2.read(os.path.join(r, ".hg", "hgrc"))
+
+                def get(sec, val, default):
+                    try:
+                        return cp2.get(sec, val)
+                    except:
+                        return default
+
+                yield tmpl("indexentry",
+                           author = get("web", "author", "unknown"),
+                           name = get("web", "name", v),
+                           url = os.environ["REQUEST_URI"] + "/" + v,
+                           parity = parity,
+                           shortdesc = get("web", "description", "unknown"),
+                           lastupdate = os.stat(os.path.join(r, ".hg",
+                                                "00changelog.d")).st_mtime)
+
+                parity = 1 - parity
+
+        write(tmpl("index", entries = entries))
--- a/mercurial/ui.py	Wed Aug 17 22:59:47 2005 -0500
+++ b/mercurial/ui.py	Sat Aug 20 13:08:07 2005 -0700
@@ -12,8 +12,10 @@
 class ui:
     def __init__(self, verbose=False, debug=False, quiet=False,
                  interactive=True):
+        self.overlay = {}
         self.cdata = ConfigParser.SafeConfigParser()
-        self.cdata.read(os.path.expanduser("~/.hgrc"))
+        self.cdata.read([os.path.normpath(hgrc) for hgrc in
+                         "/etc/mercurial/hgrc", os.path.expanduser("~/.hgrc")])
 
         self.quiet = self.configbool("ui", "quiet")
         self.verbose = self.configbool("ui", "verbose")
@@ -28,14 +30,21 @@
     def readconfig(self, fp):
         self.cdata.readfp(fp)
 
-    def config(self, section, val, default=None):
-        if self.cdata.has_option(section, val):
-            return self.cdata.get(section, val)
+    def setconfig(self, section, name, val):
+        self.overlay[(section, name)] = val
+
+    def config(self, section, name, default=None):
+        if self.overlay.has_key((section, name)):
+            return self.overlay[(section, name)]
+        if self.cdata.has_option(section, name):
+            return self.cdata.get(section, name)
         return default
 
-    def configbool(self, section, val, default=False):
-        if self.cdata.has_option(section, val):
-            return self.cdata.getboolean(section, val)
+    def configbool(self, section, name, default=False):
+        if self.overlay.has_key((section, name)):
+            return self.overlay[(section, name)]
+        if self.cdata.has_option(section, name):
+            return self.cdata.getboolean(section, name)
         return default
 
     def configitems(self, section):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/index.tmpl	Sat Aug 20 13:08:07 2005 -0700
@@ -0,0 +1,18 @@
+#header#
+<title>Mercurial repositories index</title>
+</head>
+<body>
+
+<h2>Mercurial Repositories</h2>
+
+<table>
+    <tr>
+        <td>Name</td>
+        <td>Description</td>
+        <td>Author</td>
+        <td>Last change</td>
+    <tr>
+    #entries#
+</table>
+
+#footer#
--- a/templates/map	Wed Aug 17 22:59:47 2005 -0500
+++ b/templates/map	Sat Aug 20 13:08:07 2005 -0700
@@ -35,3 +35,5 @@
 changesettag = "<tr><th class="tag">tag:</th><td class="tag">#tag#</td></tr>"
 filediffparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>"
 filelogparent = "<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="?cmd=file;file=#file#;filenode=#node#">#node|short#</a></td></tr>"
+indexentry = "<tr class="parity#parity#"><td><a  href="#url#">#name#</a></td><td>#shortdesc#</td><td>#author# <i>#email|obfuscate#</i></td><td>#lastupdate|age# ago</td></tr>"
+index = index.tmpl
--- a/tests/test-basic.out	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-basic.out	Sat Aug 20 13:08:07 2005 -0700
@@ -1,7 +1,7 @@
 changeset:   0:acb14030fe0a
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     test
 
 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 a
--- a/tests/test-copy.out	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-copy.out	Sat Aug 20 13:08:07 2005 -0700
@@ -4,17 +4,17 @@
 changeset:   1:3b5b84850bbe
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     2
 
 changeset:   0:c19d34741b0a
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     1
 
 changeset:   0:c19d34741b0a
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     1
 
 566e338d09a089ba737c21e0d3759980  .hg/data/b.d
--- a/tests/test-diffdir	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-diffdir	Sat Aug 20 13:08:07 2005 -0700
@@ -7,6 +7,8 @@
 
 echo 123 > b
 hg add b
-hg diff | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/"
+hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
 
-hg diff -r tip | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/"
+hg diff -r tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+                     -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- a/tests/test-flags.out	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-flags.out	Sat Aug 20 13:08:07 2005 -0700
@@ -16,29 +16,29 @@
 tag:         tip
 parent:      0:22a449e20da5
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     chmod +x a
 
 changeset:   1:c6ecefc45368
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     a updated
 
 changeset:   2:3ef543305655
 tag:         tip
 parent:      0:22a449e20da5
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     chmod +x a
 
 changeset:   1:c6ecefc45368
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     a updated
 
 changeset:   0:22a449e20da5
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     added a b
 
 resolving manifests
--- a/tests/test-merge-revert2	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-merge-revert2	Sat Aug 20 13:08:07 2005 -0700
@@ -27,7 +27,8 @@
 hg update -C 0
 echo "changed file1 different" >> file1
 HGMERGE=merge hg update
-hg diff | sed -e "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(<<<<<<<\|>>>>>>>\) .*/\1/"
+hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(<<<<<<<\) .*/\1/" \
+              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(>>>>>>>\) .*/\1/"
 hg status
 hg id
 hg revert
--- a/tests/test-rawcommit1.out	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-rawcommit1.out	Sat Aug 20 13:08:07 2005 -0700
@@ -6,7 +6,7 @@
 changeset:   2:9f827976dae4
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     2
 
 05f9e54f4c9b86b09099803d8b49a50edcb4eaab 644 a
@@ -14,7 +14,7 @@
 changeset:   3:c8225a106186
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     3
 
 d6e3c4976c13feb1728cd3ac851abaf7256a5c23 644 a
@@ -22,7 +22,7 @@
 changeset:   4:8dfeee82a94b
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     4
 
 05f9e54f4c9b86b09099803d8b49a50edcb4eaab 644 a
@@ -30,7 +30,7 @@
 3570202ceac2b52517df64ebd0a062cb0d8fe33a 644 c
 changeset:   4:8dfeee82a94b
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     4
 
 d6e3c4976c13feb1728cd3ac851abaf7256a5c23 644 a
@@ -40,7 +40,7 @@
 parent:      4:8dfeee82a94b
 parent:      5:a7925a42d0df
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     6
 
 d6e3c4976c13feb1728cd3ac851abaf7256a5c23 644 a
@@ -48,6 +48,6 @@
 changeset:   7:3a157da4365d
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     7
 
--- a/tests/test-tag.out	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-tag.out	Sat Aug 20 13:08:07 2005 -0700
@@ -1,19 +1,19 @@
 changeset:   0:acb14030fe0a
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     test
 
 changeset:   1:863197ef0378
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     Added tag bleah for changeset acb14030fe0a21b60322c440ad2d20cf7685a376
 
 changeset:   0:acb14030fe0a
 tag:         bleah
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     test
 
 abort: working copy of .hgtags is changed!
--- a/tests/test-undo.out	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-undo.out	Sat Aug 20 13:08:07 2005 -0700
@@ -6,7 +6,7 @@
 changeset:   0:acb14030fe0a
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     test
 
 rolling back last transaction
--- a/tests/test-unrelated-pull.out	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-unrelated-pull.out	Sat Aug 20 13:08:07 2005 -0700
@@ -9,11 +9,11 @@
 changeset:   1:9a79c33a9db3
 tag:         tip
 user:        a
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     a
 
 changeset:   0:01f8062b2de5
 user:        b
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     b
 
--- a/tests/test-up-local-change	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-up-local-change	Sat Aug 20 13:08:07 2005 -0700
@@ -12,8 +12,8 @@
 cd ../r2
 hg up
 echo abc > a
-hg diff > ../d
-sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" < ../d
+hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
 
 cd ../r1
 echo b > b
@@ -28,6 +28,6 @@
 hg --debug up -m
 hg parents
 hg -v history
-hg diff > ../d
-sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" < ../d
+hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+              -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
 
--- a/tests/test-up-local-change.out	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-up-local-change.out	Sat Aug 20 13:08:07 2005 -0700
@@ -22,13 +22,13 @@
 changeset:   1:1e71731e6fbb
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 summary:     2
 
 changeset:   1:1e71731e6fbb5b35fae293120dea6964371c13c6
 tag:         tip
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 files:       a b
 description:
 2
@@ -36,7 +36,7 @@
 
 changeset:   0:c19d34741b0a4ced8e4ba74bb834597d5193851e
 user:        test
-date:        Thu Jan  1 00:00:00 1970
+date:        Thu Jan  1 00:00:00 1970 +0000
 files:       a
 description:
 1
--- a/tests/test-walk.out	Wed Aug 17 22:59:47 2005 -0500
+++ b/tests/test-walk.out	Sat Aug 20 13:08:07 2005 -0700
@@ -12,76 +12,76 @@
 adding mammals/Procyonidae/cacomistle
 adding mammals/Procyonidae/coatimundi
 adding mammals/Procyonidae/raccoon
-f  fennel                          fennel
-f  fenugreek                       fenugreek
-f  fiddlehead                      fiddlehead
-f  glob:glob                       glob:glob
-f  beans/black                     beans/black
-f  beans/borlotti                  beans/borlotti
-f  beans/kidney                    beans/kidney
-f  beans/navy                      beans/navy
-f  beans/pinto                     beans/pinto
-f  beans/turtle                    beans/turtle
-f  mammals/skunk                   mammals/skunk
-f  mammals/Procyonidae/cacomistle  mammals/Procyonidae/cacomistle
-f  mammals/Procyonidae/coatimundi  mammals/Procyonidae/coatimundi
-f  mammals/Procyonidae/raccoon     mammals/Procyonidae/raccoon
-f  mammals/skunk                   skunk
-f  mammals/Procyonidae/cacomistle  Procyonidae/cacomistle
-f  mammals/Procyonidae/coatimundi  Procyonidae/coatimundi
-f  mammals/Procyonidae/raccoon     Procyonidae/raccoon
-f  mammals/Procyonidae/cacomistle  Procyonidae/cacomistle
-f  mammals/Procyonidae/coatimundi  Procyonidae/coatimundi
-f  mammals/Procyonidae/raccoon     Procyonidae/raccoon
-f  mammals/Procyonidae/cacomistle  cacomistle
-f  mammals/Procyonidae/coatimundi  coatimundi
-f  mammals/Procyonidae/raccoon     raccoon
-f  mammals/skunk                   ../skunk
-f  mammals/Procyonidae/cacomistle  cacomistle
-f  mammals/Procyonidae/coatimundi  coatimundi
-f  mammals/Procyonidae/raccoon     raccoon
-f  beans/black     ../beans/black
-f  beans/borlotti  ../beans/borlotti
-f  beans/kidney    ../beans/kidney
-f  beans/navy      ../beans/navy
-f  beans/pinto     ../beans/pinto
-f  beans/turtle    ../beans/turtle
-f  mammals/skunk                   skunk
-f  mammals/Procyonidae/cacomistle  Procyonidae/cacomistle
-f  mammals/Procyonidae/coatimundi  Procyonidae/coatimundi
-f  mammals/Procyonidae/raccoon     Procyonidae/raccoon
-f  beans/black     beans/black
-f  beans/borlotti  beans/borlotti
-f  beans/kidney    beans/kidney
-f  beans/navy      beans/navy
-f  beans/pinto     beans/pinto
-f  beans/turtle    beans/turtle
-f  beans/black     beans/black
-f  beans/borlotti  beans/borlotti
-f  mammals/skunk  mammals/skunk
-f  mammals/skunk                   mammals/skunk
-f  mammals/Procyonidae/cacomistle  mammals/Procyonidae/cacomistle
-f  mammals/Procyonidae/coatimundi  mammals/Procyonidae/coatimundi
-f  mammals/Procyonidae/raccoon     mammals/Procyonidae/raccoon
+f  fennel                          fennel                          
+f  fenugreek                       fenugreek                       
+f  fiddlehead                      fiddlehead                      
+f  glob:glob                       glob:glob                       
+f  beans/black                     beans/black                     
+f  beans/borlotti                  beans/borlotti                  
+f  beans/kidney                    beans/kidney                    
+f  beans/navy                      beans/navy                      
+f  beans/pinto                     beans/pinto                     
+f  beans/turtle                    beans/turtle                    
+f  mammals/skunk                   mammals/skunk                   
+f  mammals/Procyonidae/cacomistle  mammals/Procyonidae/cacomistle  
+f  mammals/Procyonidae/coatimundi  mammals/Procyonidae/coatimundi  
+f  mammals/Procyonidae/raccoon     mammals/Procyonidae/raccoon     
+f  mammals/skunk                   skunk                   
+f  mammals/Procyonidae/cacomistle  Procyonidae/cacomistle  
+f  mammals/Procyonidae/coatimundi  Procyonidae/coatimundi  
+f  mammals/Procyonidae/raccoon     Procyonidae/raccoon     
+f  mammals/Procyonidae/cacomistle  Procyonidae/cacomistle  
+f  mammals/Procyonidae/coatimundi  Procyonidae/coatimundi  
+f  mammals/Procyonidae/raccoon     Procyonidae/raccoon     
+f  mammals/Procyonidae/cacomistle  cacomistle  
+f  mammals/Procyonidae/coatimundi  coatimundi  
+f  mammals/Procyonidae/raccoon     raccoon     
+f  mammals/skunk                   ../skunk    
+f  mammals/Procyonidae/cacomistle  cacomistle  
+f  mammals/Procyonidae/coatimundi  coatimundi  
+f  mammals/Procyonidae/raccoon     raccoon     
+f  beans/black     ../beans/black     
+f  beans/borlotti  ../beans/borlotti  
+f  beans/kidney    ../beans/kidney    
+f  beans/navy      ../beans/navy      
+f  beans/pinto     ../beans/pinto     
+f  beans/turtle    ../beans/turtle    
+f  mammals/skunk                   skunk                   
+f  mammals/Procyonidae/cacomistle  Procyonidae/cacomistle  
+f  mammals/Procyonidae/coatimundi  Procyonidae/coatimundi  
+f  mammals/Procyonidae/raccoon     Procyonidae/raccoon     
+f  beans/black     beans/black     
+f  beans/borlotti  beans/borlotti  
+f  beans/kidney    beans/kidney    
+f  beans/navy      beans/navy      
+f  beans/pinto     beans/pinto     
+f  beans/turtle    beans/turtle    
+f  beans/black     beans/black     
+f  beans/borlotti  beans/borlotti  
+f  mammals/skunk  mammals/skunk  
+f  mammals/skunk                   mammals/skunk                   
+f  mammals/Procyonidae/cacomistle  mammals/Procyonidae/cacomistle  
+f  mammals/Procyonidae/coatimundi  mammals/Procyonidae/coatimundi  
+f  mammals/Procyonidae/raccoon     mammals/Procyonidae/raccoon     
 abort: .. not under repository root
 abort: beans/../.. not under repository root
-f  fennel      fennel
-f  fenugreek   fenugreek
-f  fiddlehead  fiddlehead
-f  glob:glob   glob:glob
-f  fenugreek      fenugreek
-f  glob:glob      glob:glob
-f  beans/black    beans/black
-f  mammals/skunk  mammals/skunk
-f  beans/black  beans/black
-f  beans/black     beans/black
-f  beans/borlotti  beans/borlotti
-f  beans/kidney    beans/kidney
-f  beans/navy      beans/navy
-f  beans/pinto     beans/pinto
-f  beans/turtle    beans/turtle
+f  fennel      fennel      
+f  fenugreek   fenugreek   
+f  fiddlehead  fiddlehead  
+f  glob:glob   glob:glob   
+f  fenugreek      fenugreek      
+f  glob:glob      glob:glob      
+f  beans/black    beans/black    
+f  mammals/skunk  mammals/skunk  
+f  beans/black  beans/black  
+f  beans/black     beans/black     
+f  beans/borlotti  beans/borlotti  
+f  beans/kidney    beans/kidney    
+f  beans/navy      beans/navy      
+f  beans/pinto     beans/pinto     
+f  beans/turtle    beans/turtle    
 NOEXIST: No such file or directory
 fifo: unsupported file type (type is fifo)
-m  fenugreek  fenugreek
-m  fenugreek  fenugreek
-f  new  new
+m  fenugreek  fenugreek  exact
+m  fenugreek  fenugreek  exact
+f  new  new  exact