changeset 1469:0847c45ffee6

Merge bundle -r work from Eric Hopper
author Matt Mackall <mpm@selenic.com>
date Thu, 27 Oct 2005 12:26:16 -0700
parents 214f42f23a3b (diff) dc1bbc456b96 (current diff)
children fb9b84c91222
files mercurial/commands.py mercurial/localrepo.py mercurial/revlog.py
diffstat 52 files changed, 1990 insertions(+), 1028 deletions(-) [+]
line wrap: on
line diff
--- a/CONTRIBUTORS	Sun Oct 16 16:24:40 2005 -0700
+++ b/CONTRIBUTORS	Thu Oct 27 12:26:16 2005 -0700
@@ -3,6 +3,7 @@
 Goffredo Baroncelli <kreijack at libero.it>
 Muli Ben-Yehuda <mulix at mulix.org>
 Mikael Berthe <mikael at lilotux.net>
+Benoit Boissinot <bboissin at gmail.com>
 Vincent Danjean <vdanjean.ml at free.fr>
 Jake Edge <jake at edge2.net>
 Michael Fetterman <michael.fetterman at intel.com>
--- a/Makefile	Sun Oct 16 16:24:40 2005 -0700
+++ b/Makefile	Thu Oct 27 12:26:16 2005 -0700
@@ -10,7 +10,7 @@
 clean:
 	-$(PYTHON) setup.py clean --all # ignore errors of this command
 	find . -name '*.py[co]' -exec rm -f '{}' ';'
-	make -C doc clean
+	$(MAKE) -C doc clean
 
 dist:	tests doc
 	TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py sdist --force-manifest
@@ -18,8 +18,11 @@
 tests:
 	cd tests && ./run-tests
 
+test-%:
+	cd tests && ./run-tests $@
+
 doc:
-	make -C doc
+	$(MAKE) -C doc
 
 
 .PHONY: all clean dist tests doc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/hg-menu.vim	Thu Oct 27 12:26:16 2005 -0700
@@ -0,0 +1,93 @@
+" vim600: set foldmethod=marker:
+" =============================================================================
+"  Name Of File: hg-menu.vim
+"   Description: Interface to Mercurial Version Control.
+"        Author: Steve Borho (modified Jeff Lanzarotta's RCS script)
+"          Date: Wednesday, October 5, 2005
+"       Version: 0.1.0
+"     Copyright: None.
+"         Usage: These command and gui menu displays useful hg functions
+" Configuration: Your hg executable must be in your path.
+" =============================================================================
+ 
+" Section: Init {{{1
+if exists("loaded_hg_menu")
+  finish
+endif
+let loaded_hg_menu = 1
+
+" Section: Menu Options {{{1
+if has("gui")
+"  amenu H&G.Commit\ File<Tab>,ci :!hg commit %<CR>:e!<CR>
+"  amenu H&G.Commit\ All<Tab>,call :!hg commit<CR>:e!<CR>
+"  amenu H&G.-SEP1-        <nul>
+  amenu H&G.Add<Tab>\\add :!hg add %<CR><CR>
+  amenu H&G.Forget\ Add<Tab>\\fgt :!hg forget %<CR><CR>
+  amenu H&G.Show\ Differences<Tab>\\diff :call ShowResults("FileDiff", "hg\ diff")<CR><CR>
+  amenu H&G.Revert\ to\ Last\ Version<Tab>\\revert :!hg revert %<CR>:e!<CR>
+  amenu H&G.Show\ History<Tab>\\log :call ShowResults("FileLog", "hg\ log")<CR><CR>
+  amenu H&G.Annotate<Tab>\\an :call ShowResults("annotate", "hg\ annotate")<CR><CR>
+  amenu H&G.-SEP1-        <nul>
+  amenu H&G.Repo\ Status<Tab>\\stat :call ShowResults("RepoStatus", "hg\ status")<CR><CR>
+  amenu H&G.Pull<Tab>\\pull :!hg pull<CR>:e!<CR>
+  amenu H&G.Update<Tab>\\upd :!hg update<CR>:e!<CR>
+endif
+
+" Section: Mappings {{{1
+if(v:version >= 600)
+  " The default Leader is \ 'backslash'
+  map <Leader>add       :!hg add %<CR><CR>
+  map <Leader>fgt       :!hg forget %<CR><CR>
+  map <Leader>diff      :call ShowResults("FileDiff", "hg\ diff")<CR><CR>
+  map <Leader>revert    :!hg revert %<CR>:e!<CR>
+  map <Leader>log       :call ShowResults("FileLog", "hg\ log")<CR><CR>
+  map <Leader>an        :call ShowResults("annotate", "hg\ annotate")<CR><CR>
+  map <Leader>stat      :call ShowResults("RepoStatus", "hg\ status")<CR><CR>
+  map <Leader>upd       :!hg update<CR>:e!<CR>
+  map <Leader>pull      :!hg pull<CR>:e!<CR>
+else
+  " pre 6.0, the default Leader was a comma
+  map ,add          :!hg add %<CR><CR>
+  map ,fgt          :!hg forget %<CR><CR>
+  map ,diff         :call ShowResults("FileDiff", "hg\ diff")<CR><CR>
+  map ,revert       :!hg revert<CR>:e!<CR>
+  map ,log          :call ShowResults("FileLog", "hg\ log")<CR><CR>
+  map ,an           :call ShowResults("annotate", "hg\ annotate")<CR><CR>
+  map ,stat         :call ShowResults("RepoStatus", "hg\ status")<CR><CR>
+  map ,upd          :!hg update<CR>:e!<CR>
+  map ,pull         :!hg pull<CR>:e!<CR>
+endif
+
+" Section: Functions {{{1
+" Show the log results of the current file with a revision control system.
+function! ShowResults(bufferName, cmdName)
+  " Modify the shortmess option:
+  " A  don't give the "ATTENTION" message when an existing swap file is
+  "    found.
+  set shortmess+=A
+
+  " Get the name of the current buffer.
+  let currentBuffer = bufname("%")
+
+  " If a buffer with the name rlog exists, delete it.
+  if bufexists(a:bufferName)
+    execute 'bd! ' a:bufferName
+  endif
+
+  " Create a new buffer.
+  execute 'new ' a:bufferName
+
+  " Execute the command.
+  execute 'r!' a:cmdName ' ' currentBuffer
+
+  " Make is so that the file can't be edited.
+  setlocal nomodified
+  setlocal nomodifiable
+  setlocal readonly
+
+  " Go to the beginning of the buffer.
+  execute "normal 1G"
+
+  " Restore the shortmess option.
+  set shortmess-=A
+endfunction
--- a/contrib/hgk	Sun Oct 16 16:24:40 2005 -0700
+++ b/contrib/hgk	Thu Oct 27 12:26:16 2005 -0700
@@ -403,9 +403,12 @@
     set ctext .ctop.cdet.left.ctext
     text $ctext -bg white -state disabled -font $textfont \
 	-width $geometry(ctextw) -height $geometry(ctexth) \
-	-yscrollcommand ".ctop.cdet.left.sb set" -wrap none
+	-yscrollcommand ".ctop.cdet.left.sb set" \
+	-xscrollcommand ".ctop.cdet.left.hb set" -wrap none
     scrollbar .ctop.cdet.left.sb -command "$ctext yview"
+    scrollbar .ctop.cdet.left.hb -orient horizontal -command "$ctext xview"
     pack .ctop.cdet.left.sb -side right -fill y
+    pack .ctop.cdet.left.hb -side bottom -fill x
     pack $ctext -side left -fill both -expand 1
     .ctop.cdet add .ctop.cdet.left
 
@@ -465,6 +468,7 @@
     bindkey ? findprev
     bindkey f nextfile
     bind . <Control-q> doquit
+    bind . <Control-w> doquit
     bind . <Control-f> dofind
     bind . <Control-g> {findnext 0}
     bind . <Control-r> findprev
--- a/contrib/zsh_completion	Sun Oct 16 16:24:40 2005 -0700
+++ b/contrib/zsh_completion	Thu Oct 27 12:26:16 2005 -0700
@@ -14,23 +14,38 @@
 
 local curcontext="$curcontext" state line
 typeset -A opt_args
-local subcmds repos tags newFiles addedFiles
+local subcmds repos tags newFiles addedFiles includeExclude
 
 tags=($(hg tags 2> /dev/null | sed -e 's/[0-9]*:[a-f0-9]\{40\}$//; s/ *$//'))
 subcmds=($(hg -v help | sed -e '1,/^list of commands:/d' \
-      -e '/^global options:/,$d' -e '/^ [^ ]/!d; s/[,:]//g;'))
+      -e '/^global options:/,$d' -e '/^ [^ ]/!d; s/[,:].*//g;'))
+
+# A lot of commands have these arguments
+includeExclude=(
+        '*-I-[include names matching the given patterns]:dir:_files -W $(hg root) -/'
+        '*--include-[include names matching the given patterns]:dir:_files -W $(hg root) -/'
+        '*-X-[exclude names matching the given patterns]:dir:_files -W $(hg root) -/'
+        '*--exclude-[exclude names matching the given patterns]:dir:_files -W $(hg root) -/')
 
 if [[ $service == "hg" ]]; then
     _arguments -C -A "-*" \
-    '-R+[repository root directory]' \
-    '-y[non-interactive]' \
-    '-v[verbose]' \
-    '-q[quiet]' \
+    '(--repository)-R[repository root directory]:root:_files -/' \
+    '(-R)--repository[repository root directory]:root:_files -/' \
+    '--cwd[change working directory]:new working directory:_files -/' \
+    '(--noninteractive)-y[do not prompt, assume yes for any required answers]' \
+    '(-y)--noninteractive[do not prompt, assume yes for any required answers]' \
+    '(--verbose)-v[enable additional output]' \
+    '(-v)--verbose[enable additional output]' \
+    '(--quiet)-q[suppress output]' \
+    '(-q)--quiet[suppress output]' \
+    '(--help)-h[display help and exit]' \
+    '(-h)--help[display help and exit]' \
+    '--debug[debug mode]' \
+    '--debugger[start debugger]' \
+    '--traceback[print traceback on exception]' \
     '--time[time how long the command takes]' \
     '--profile[profile]' \
-    '-h-[display help and exit]' \
-    '--version-[output version information and exit]' \
-    '--cwd[change working directory]:new working directory:_files -/' \
+    '--version[output version information and exit]' \
     '*::command:->subcmd' && return 0
 
     if (( CURRENT == 1 )); then
@@ -42,88 +57,344 @@
 fi
 
 case $service in
+    (add)
+        newFiles=( $(hg status -un) )
+        _arguments $includeExclude \
+        '*:file:->unknown'
+        _wanted files expl 'unknown files' compadd -a newFiles
+    ;;
+
     (addremove)
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
+        _arguments $includeExclude \
         '*:directories:_files -/'  # assume they want to add/remove a dir
     ;;
 
-    (add)
-        newFiles=( $(hg status -un) )
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/'
-        _wanted files expl 'unknown files' compadd -a newFiles
+    (forget)
+        addedFiles=( $(hg status -an) )
+        _arguments $includeExclude  \
+        '*:file:->added'
+        _wanted files expl 'newly added files' compadd -a addedFiles
     ;;
 
     (remove|rm)
+        _arguments $includeExclude \
+        '*:file:_files'
+    ;;
+
+    (copy|cp)
+        _arguments $includeExclude \
+        '(--after)-A[record a copy that has already occurred]' \
+        '(-A)--after[record a copy that has already occurred]' \
+        '(--force)-f[forcibly copy over an existing managed file]' \
+        '(-f)--force[forcibly copy over an existing managed file]' \
+        '(--parents)-p[append source path to dest]' \
+        '(-p)--parents[append source path to dest]' \
+        '*:files:_files'
+    ;;
+
+    (rename|mv)
+        if (( CURRENT == 2 )); then
+            _arguments $includeExclude \
+            '(--after)-A[record a rename that has already occurred]' \
+            '(-A)--after[record a rename that has already occurred]' \
+            '(--force)-f[replace destination if it exists]' \
+            '(-F)--force[replace destination if it exists]' \
+            '(--parents)-p[append source path to dest]' \
+            '(-p)--parents[append source path to dest]' \
+            '*:files:_files'
+        else
+            _arguments '*:destination:_files'
+        fi
+    ;;
+
+    (diff)
+        _arguments $includeExclude \
+        '*-r[revision]:revision:($tags)' \
+        '*--rev[revision]:revision:($tags)' \
+        '(--text)-a[treat all files as text]' \
+        '(-a)--text[treat all files as text]' \
+        '*:file:_files'
+    ;;
+
+    (status)
+        _arguments $includeExclude \
+        '(--no-status)-n[hide status prefix]' \
+        '(-n)--no-status[hide status prefix]' \
+        '(--print0)-0[end filenames with NUL, for use with xargs]' \
+        '(-0)--print0[end filenames with NUL, for use with xargs]' \
+        '(--modified)-m[show only modified files]' \
+        '(-m)--modified[show only modified files]' \
+        '(--added)-a[show only added files]' \
+        '(-a)--added[show only added files]' \
+        '(--removed)-r[show only removed files]' \
+        '(-r)--removed[show only removed files]' \
+        '(--unknown)-u[show only unknown files]' \
+        '(-u)--unknown[show only unknown files]' \
+        '*:search pattern, then files:_files'
+    ;;
+
+    (revert)
+        addedFiles=( $(hg status -mrn) ) # modified, removed
         _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '*:file:_files'
+        '(--rev)-r[revision to revert to]:revision:($tags)' \
+        '(-r)--rev[revision to revert to]:revision:($tags)' \
+        '(--nonrecursive)-n[do not recurse into subdirectories]' \
+        '(-n)--nonrecursive[do not recurse into subdirectories]' \
+        '*:file:->modified'
+        _wanted files expl 'mofified files' compadd -a addedFiles
+    ;;
+
+    (commit|ci)
+        addedFiles=( $(hg status -amrn) ) # added, modified, removed
+        _arguments $includeExclude \
+        '(--addremove)-A[run addremove during commit]' \
+        '(-A)--addremove[run addremove during commit]' \
+        '(--message)-m[use <txt> as commit message]:string:' \
+        '(-m)--message[use <txt> as commit message]:string:' \
+        '(--logfile)-l[read commit message from <file>]:.log file:_file -g \*.txt' \
+        '(-l)--logfile[read commit message from <file>]:.log file:_file -g \*.txt' \
+        '(--date)-d[record datecode as commit date]:date code:' \
+        '(-d)--date[record datecode as commit date]:date code:' \
+        '(--user)-u[record user as commiter]:user:' \
+        '(-u)--user[record user as commiter]:user:' \
+        '*:file:->modified'
+        _wanted files expl 'mofified files' compadd -a addedFiles
     ;;
 
     (cat)
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '-o[output to file]:file:' \
-        '-r[revision]:revision:($tags)' \
+        _arguments $includeExclude \
+        '(--output)-o[print output to file with formatted name]:filespec:' \
+        '(-o)--output[print output to file with formatted name]:filespec:' \
+        '(--rev)-r[revision]:revision:($tags)' \
+        '(-r)--rev[revision]:revision:($tags)' \
+        '*:file:_files'
+    ;;
+
+    (annotate)
+        _arguments $includeExclude \
+        '(--rev)-r[annotate the specified revision]:revision:($tags)' \
+        '(-r)--rev[annotate the specified revision]:revision:($tags)' \
+        '(--text)-a[treat all files as text]' \
+        '(-a)--text[treat all files as text]' \
+        '(--user)-u[list the author]' \
+        '(-u)--user[list the author]' \
+        '(--changeset)-c[list the changeset]' \
+        '(-c)--changeset[list the changeset]' \
+        '(--number)-n[list the revision number (default)]' \
+        '(-n)--number[list the revision number (default)]' \
+        '*:files:_files'
+    ;;
+
+    (grep)
+        _arguments $includeExclude \
+        '*-r[search in given revision range]:revision:($tags)' \
+        '*--rev[search in given revision range]:revision:($tags)' \
+        '--all[print all revisions with matches]' \
+        '(-print0)-0[end filenames with NUL, for use with xargs]' \
+        '(-0)--print0[end filenames with NUL, for use with xargs]' \
+        '(--ignore-case)-i[ignore case when matching]' \
+        '(-i)--ignore-case[ignore case when matching]' \
+        '(--files-with-matches)-l[print names of files and revs that match]' \
+        '(-l)--files-with-matches[print names of files and revs that match]' \
+        '(--line-number)-n[print matching line numbers]' \
+        '(-n)--line-number[print matching line numbers]' \
+        '(--user)-u[print user who committed change]' \
+        '(-u)--user[print user who committed change]' \
+        '*:search pattern:'
+    ;;
+
+    (locate)
+        _arguments $includeExclude \
+        '(--rev)-r[search repository as it stood at revision]:revision:($tags)' \
+        '(-r)--rev[search repository as it stood at revision]:revision:($tags)' \
+        '(--print0)-0[end filenames with NUL, for use with xargs]' \
+        '(-0)--print0[end filenames with NUL, for use with xargs]' \
+        '(--fullpath)-f[print complete paths]' \
+        '(-f)--fullpath[print complete paths]' \
+        '*:search pattern:'
+    ;;
+
+    (log|history)
+        _arguments $includeExclude \
+        '*-r[show the specified revision or range]:revision:($tags)' \
+        '*--rev[show the specified revision or range]:revision:($tags)' \
+        '(--no-merges -M --only-merges)-m[show only merge revisions]' \
+        '(--no-merges -M -m)--only-merges[show only merge revisions]' \
+        '(--only-merges -m --no-merges)-M[do not show merge revisions]' \
+        '(--only-merges -m -M)--no-merges[do not show merge revisions]' \
+        '(--keyword)-k[search for a keyword]:keyword:' \
+        '(-k)--keyword[search for a keyword]:keyword:' \
+        '(--branch)-b[show branches]' \
+        '(-b)--branch[show branches]' \
+        '(--patch)-p[show patch]' \
+        '(-p)--patch[show patch]' \
         '*:file:_files'
     ;;
 
-    (checkout|update|up|co)
+    (update|checkout|co)
+        _arguments \
+        '(--branch)-b[checkout the head of a specific branch]' \
+        '(-b)--branch[checkout the head of a specific branch]' \
+        '(-C --clean --merge)-m[allow merging of branches]' \
+        '(-C --clean -m)--merge[allow merging of branches]' \
+        '(-m --merge --clean)-C[overwrite locally modified files]' \
+        '(-m --merge -C)--clean[overwrite locally modified files]' \
+        '*:revision or tag:($tags)'
+    ;;
+
+    (tag)
+        _arguments \
+        '(--local)-l[make the tag local]' \
+        '(-l)--local[make the tag local]' \
+        '(--message)-m[message for tag commit log entry]:string:' \
+        '(-m)--message[message for tag commit log entry]:string:' \
+        '(--date)-d[record datecode as commit date]:date code:' \
+        '(-d)--date[record datecode as commit date]:date code:' \
+        '(--user)-u[record user as commiter]:user:' \
+        '(-u)--user[record user as commiter]:user:' \
+        '*:name, then revision:($tags)'
+    ;;
+
+    (clone)
+        if (( CURRENT == 2 )); then
+            _arguments \
+            '(--no-update)-U[do not update the new working directory]' \
+            '(-U)--no-update[do not update the new working directory]' \
+            '(--ssh)-e[specify ssh command to use]:string:' \
+            '(-e)--ssh[specify ssh command to use]:string:' \
+            '--pull[use pull protocol to copy metadata]' \
+            '--remotecmd[specify hg command to run on the remote side]:remote hg:' \
+            '*:local repo:_files -/'
+        elif (( CURRENT == 3 )); then
+            _arguments '*:dest repo:_files -/'
+        fi
+    ;;
+
+    (rawcommit)
         _arguments \
-        '-b[checkout the head of a specific branch]:tag:' \
-        '-m[allow merging of conflicts]' \
-        '-C[overwrite locally modified files]' \
+        '(--parent)-p[parent revision]:revision:($tags)' \
+        '(-p)--parent[parent revision]:revision:($tags)' \
+        '(--date)-d[record datecode as commit date]:date code:' \
+        '(-d)--date[record datecode as commit date]:date code:' \
+        '(--user)-u[record user as commiter]:user:' \
+        '(-u)--user[record user as commiter]:user:' \
+        '(--message)-m[use <txt> as commit message]:string:' \
+        '(-m)--message[use <txt> as commit message]:string:' \
+        '(--logfile)-l[read commit message from <file>]:.log file:_file -g \*.txt' \
+        '(-l)--logfile[read commit message from <file>]:.log file:_file -g \*.txt' \
+        '(--files)-F[file list]:file list:_files' \
+        '(-F)--files[file list]:file list:_files' \
+        '*:files to commit:_files'
+    ;;
+
+    (bundle)
+        if (( CURRENT == 2 )); then
+            _arguments '*:changegroup file:_files -g \*.hg'
+        elif (( CURRENT == 3 )); then
+            _arguments '*:other repo:_files -/'
+        fi
+    ;;
+
+    (unbundle)
+        _arguments '*:changegroup .hg file:_files -g \*.hg'
+    ;;
+
+    (incoming)
+        _arguments \
+        '(--patch)-p[show patch]' \
+        '(-p)--patch[show patch]' \
+        '(--no-merges)-M[do not show merge revisions]' \
+        '(-M)--no-merges[do not show merge revisions]' \
+        '(--newest-first)-n[show newest record first]' \
+        '(-n)--newest-first[show newest record first]' \
+        '*:mercurial repository:_files -/'
+    ;;
+
+    (import|patch)
+        _arguments \
+        '(--strip)-p[directory strip option for patch (default: 1)]:count:' \
+        '(-p)--strip[directory strip option for patch (default: 1)]:count:' \
+        '(--force)-f[skip check for outstanding uncommitted changes]' \
+        '(-f)--force[skip check for outstanding uncommitted changes]' \
+        '(--base)-b[base directory to read patches from]:file:_files -W $(hg root) -/' \
+        '(-b)--base[base directory to read patches from]:file:_files -W $(hg root) -/' \
+        '*:patch file:_files'
+    ;;
+
+    (pull)
+        repos=( $(hg paths | sed -e 's/^.*= //') )
+        _arguments \
+        '(--update)-u[update working directory to tip after pull]' \
+        '(-u)--update[update working directory to tip after pull]' \
+        '(--ssh)-e[specify ssh command to use]:ssh command:' \
+        '(-e)--ssh[specify ssh command to use]:ssh command:' \
+        '--remotecmd[specify hg command to run on the remote side]:remote hg:' \
+        '*:local repo:_files -/'
+        _wanted source expl 'source repository' compadd -a repos
+    ;;
+
+    (outgoing)
+        _arguments \
+        '(--patch)-p[show patch]' \
+        '(-p)--patch[show patch]' \
+        '(--no-merges)-M[do not show merge revisions]' \
+        '(-M)--no-merges[do not show merge revisions]' \
+        '(--newest-first)-n[show newest record first]' \
+        '(-n)--newest-first[show newest record first]' \
+        '*:local repo:_files -/'
+        _wanted source expl 'source repository' compadd -a repos
+    ;;
+
+    (export)
+        _arguments \
+        '(--outout)-o[print output to file with formatted name]:filespec:' \
+        '(-o)--output[print output to file with formatted name]:filespec:' \
+        '(--text)-a[treat all files as text]' \
+        '(-a)--text[treat all files as text]' \
         '*:revision:->revs'
         _wanted revs expl 'revision or tag' compadd -a tags
     ;;
 
-    (commit|ci)
+    (push)
+        repos=( $(hg paths | sed -e 's/^.*= //') )
         _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '-A[run addremove during commit]' \
-        '-m[commit message]:string:' \
-        '-d[date code]:string:' \
-        '-u[user]:string:' \
-        '*:file:_files'
+        '(--force)-f[force push]' \
+        '(-f)--force[force push]' \
+        '(--ssh)-e[specify ssh command to use]:ssh command:' \
+        '(-e)--ssh[specify ssh command to use]:ssh command:' \
+        '--remotecmd[specify hg command to run on the remote side]:remote hg:' \
+        '*:local repo:_files -/'
+        _wanted source expl 'source repository' compadd -a repos
     ;;
 
-    (tag)
+    (serve)
         _arguments \
-        '-l[make the tag local]:' \
-        '-m[commit message]:string:' \
-        '-d[date code]:string:' \
-        '-u[user]:string:' \
-        '*:name and revision:'
+        '(--accesslog)-A[name of access log file]:log file:_files' \
+        '(-A)--accesslog[name of access log file]:log file:_files' \
+        '(--errorlog)-E[name of error log file]:log file:_files' \
+        '(-E)--errorlog[name of error log file]:log file:_files' \
+        '(--port)-p[listen port]:listen port:' \
+        '(-p)--port[listen port]:listen port:' \
+        '(--address)-a[interface address]:interface address:' \
+        '(-a)--address[interface address]:interface address:' \
+        '(--name)-n[name to show in web pages]:repository name:' \
+        '(-n)--name[name to show in web pages]:repository name:' \
+        '(--templates)-t[web template directory]:template dir:_files -/' \
+        '(-t)--templates[web template directory]:template dir:_files -/' \
+        '--style[web template style]:style' \
+        '--stdio[for remote clients]' \
+        '(--ipv6)-6[use IPv6 in addition to IPv4]' \
+        '(-6)--ipv6[use IPv6 in addition to IPv4]'
     ;;
 
-    (clone)
-        _arguments \
-        '-U[skip update after cloning]' \
-        '-e[ssh command]:string:' \
-        '--pull[use pull protocol to copy metadata]' \
-        '--remotecmd[remote hg command]:command:->subcmd'
-    ;;
-
-    (export)
-        _arguments \
-        '-o[output to a file]:file:' \
-        '-a-[tread all files as text]' \
-        '*:revision:->revs'
-        _wanted revs expl 'revision or tag' compadd -a tags
+    (help)
+        _wanted commands expl 'hg command' compadd -a subcmds
     ;;
 
     (heads)
-        _arguments '-b[find branch info]'
-    ;;
-
-    (outgoing|out)
-        _arguments '-p[show patch]'
+        _arguments \
+        '(--branches)-b[find branch info]' \
+        '(-b)--branches[find branch info]'
     ;;
 
     (paths)
@@ -134,175 +405,15 @@
         _arguments '*:new repo directory:_files -/'
     ;;
 
-    (unbundle)
-        _arguments '*:changegroup file:_files'
-    ;;
-
     (manifest)
-        _arguments \
-        '*:revision:->revs'
-        _wanted revs expl 'revision or tag' compadd -a tags
+        _arguments '*:revision:($tags)'
     ;;
 
     (parents)
-        _arguments \
-        '*:revision:->revs'
-        _wanted revs expl 'revision or tag' compadd -a tags
-    ;;
-
-    (serve)
-        _arguments \
-        '-A[access log file]:log file:_files' \
-        '-E[error log file]:log file:_files' \
-        '-p[listen port]:listen port:' \
-        '-a[interface address]:interface address:' \
-        '-n[repository name]:repository name:' \
-        '--stdio[for remote clients]' \
-        '-t[template directory]:template dir:_files -/' \
-        '--style[template style]:style' \
-        '-6[use IPv6 in addition to IPv4]'
-    ;;
-
-    (pull)
-        repos=( $(hg paths | sed -e 's/^.*= //') )
-        _arguments \
-        '-u[update working directory]' \
-        '-e[ssh command]:remote commands:' \
-        '--remotecmd[remote hg command]:command:->subcmd' \
-        '*:pull source:->repo'
-        _wanted source expl 'source repository' compadd -a repos
-    ;;
-
-	(push)
-        repos=( $(hg paths | sed -e 's/^.*= //') )
-        _arguments \
-        '-f[force push]' \
-        '-e[ssh command]:remote commands:' \
-        '--remotecmd[remote hg command]:command:->subcmd' \
-        '*:pull source:->repo'
-        _wanted source expl 'source repository' compadd -a repos
-    ;;
-
-    (id|identify)
-    ;;
-
-    (recover)
-    ;;
-
-    (rawcommit)
-        _arguments \
-        '-p[parent]:revision:($tags)' \
-        '-d[date]:date:' \
-        '-u[user]:user:' \
-        '-F[file list]:file list:_files' \
-        '-m[commit message]:string:' \
-        '-l[commit message file]:message file:_files -g *.txt' \
-        '*:files to commit:_files'
-    ;;
-
-    (copy|cp)
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '-A-[record a copy after it has happened]' \
-        '-f[replace destination if it exists]' \
-        '-p[append source path to dest]' \
-        '*:destination:'
-    ;;
-
-    (rename|mv)
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '-A-[record a copy after it has happened]' \
-        '-f[replace destination if it exists]' \
-        '-p[append source path to dest]' \
-        '*:destination:'
+        _arguments '*:revision:($tags)'
     ;;
 
-    (forget)
-        addedFiles=( $(hg status -an) )
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/'
-        _wanted files expl 'newly added files' compadd -a addedFiles
-    ;;
-
-    (import|patch)
-        _arguments \
-        '-p[path strip (default: 1)]:count:' \
-        '-f[skip check for outstanding changes]' \
-        '-b[base path]:file:_files -W $(hg root)' \
-        '*:patch file:_files'
-    ;;
-
-    (incoming|in)
-        _arguments \
-        '-p[show patch]' \
-        '*:mercurial repository:_files'
-    ;;
-
-    (diff)
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '-r[revision]:revision:($tags)' \
-        '-a-[tread all files as text]' \
-        '*:file:_files'
-    ;;
-
-    (log|history)
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '-r[revision]:revision:($tags)' \
-        '-b[show branches]' \
-        '-p[show patch]' \
-        '*:file:_files'
-    ;;
-
-    (grep)
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '-0[end fields with NUL]' \
-        '--all[print all revisions with matches]' \
-        '-i[ignore case]' \
-        '-l[print names of files and revs with matches]' \
-        '-n[print line numbers]' \
-        '-r[search in revision rev]:revision:($tags)' \
-        '-u[print user who made change]' \
-        '*:search pattern, then files:_files'
-    ;;
-
-    (status)
-        _arguments \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '-0[end filenames with NUL]' \
-        '-m[show only modified files]' \
-        '-a[show only added files]' \
-        '-r[show only removed files]' \
-        '-u[show only unknown files]' \
-        '-n[hide status prefix]' \
-        '*:search pattern, then files:_files'
-    ;;
-
-    (locate)
-        _arguments \
-        '-r[search in revision rev]:revision:($tags)' \
-        '-0[end fields with NUL]' \
-        '-f[print complete paths]' \
-        '-I[include path in search]:dir:_files -W $(hg root) -/' \
-        '-X[exclude path in search]:dir:_files -W $(hg root) -/' \
-        '*:search pattern:'
-    ;;
-
-    (help)
-        _wanted commands expl 'hg command' compadd -a subcmds
-    ;;
-
-    (root|undo|view|verify|version)
+    (identify|recover|root|undo|view|verify|version|ct|tags)
         # no arguments for these commands
     ;;
 
--- a/doc/Makefile	Sun Oct 16 16:24:40 2005 -0700
+++ b/doc/Makefile	Thu Oct 27 12:26:16 2005 -0700
@@ -15,7 +15,7 @@
 	asciidoc -d manpage -b docbook $*.txt
 
 %.html: %.txt
-	asciidoc -b html $*.txt
+	asciidoc -b html4 $*.txt
 
 clean:
 	$(RM) $(MAN) $(MAN:%=%.xml) $(MAN:%=%.html)
--- a/doc/hg.1.txt	Sun Oct 16 16:24:40 2005 -0700
+++ b/doc/hg.1.txt	Thu Oct 27 12:26:16 2005 -0700
@@ -201,7 +201,6 @@
     -I, --include <pat>   include names matching the given patterns
     -X, --exclude <pat>   exclude names matching the given patterns
     -f, --force           forcibly copy over an existing managed file
-    -p, --parents         append source path to dest
 
     aliases: cp
 
@@ -493,7 +492,6 @@
     Options:
     -A, --after        record a rename that has already occurred
     -f, --force        forcibly copy over an existing managed file
-    -p, --parents      append source path to dest
 
     aliases: mv
 
--- a/hgmerge	Sun Oct 16 16:24:40 2005 -0700
+++ b/hgmerge	Thu Oct 27 12:26:16 2005 -0700
@@ -15,6 +15,17 @@
     EDITOR="vi"
 fi
 
+# find decent versions of our utilities, insisting on the GNU versions where we
+# need to
+DIFF3=gdiff3
+DIFF=gdiff
+PATCH=gpatch
+
+type $DIFF3 >/dev/null 2>&1 || DIFF3=diff3
+type $DIFF  >/dev/null 2>&1 || DIFF=diff
+type $PATCH  >/dev/null 2>&1 || PATCH=patch
+$DIFF3 --version >/dev/null 2>&1 || DIFF3=
+
 # Back up our file
 cp "$LOCAL" "$LOCAL.orig"
 
@@ -22,8 +33,14 @@
 if type merge > /dev/null 2>&1; then
     merge "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && exit 0
     cp "$LOCAL.orig" "$LOCAL"
-elif type diff3 > /dev/null 2>&1; then
-    diff3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" && exit 0
+elif [ -n "$DIFF3" ]; then
+    echo $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER"
+    $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" && exit 0
+    if [ $? -eq 2 ]; then
+        echo "$DIFF3 failed! Exiting." 1>&2
+        cp "$LOCAL.orig" "$LOCAL"
+        exit 1
+    fi
     cp "$LOCAL.orig" "$LOCAL"
 fi
 
@@ -48,10 +65,18 @@
     exit 0
 fi
 
-if type diff3 > /dev/null 2>&1; then
+if [ -n "$DIFF3" ]; then
     echo "conflicts detected in $LOCAL"
-    diff3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" || $EDITOR "$LOCAL"
-    exit 0
+    $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" || {
+        case $? in
+            1)
+                $EDITOR "$LOCAL" ;;
+            2)  echo "$DIFF3 failed! Exiting." 1>&2
+                cp "$LOCAL.orig" "$LOCAL"
+                exit 1 ;;
+        esac
+        exit 0
+    }
 fi
 
 HGTMP=""
@@ -60,7 +85,7 @@
 }
 
 # attempt to manually merge with diff and patch
-if type diff > /dev/null 2>&1 && type patch > /dev/null 2>&1; then
+if [ -n "$DIFF" -a -n "$PATCH" ]; then
     # Remove temporary files even if we get interrupted
     trap "cleanup_exit" 0 # normal exit
     trap "exit 1" 1 2 3 6 15 # HUP INT QUIT ABRT TERM
@@ -71,8 +96,8 @@
 	exit 1
     }
 
-    diff -u "$BASE" "$OTHER" > "$HGTMP/diff"
-    if patch "$LOCAL" < "$HGTMP/diff"; then
+    $DIFF -u "$BASE" "$OTHER" > "$HGTMP/diff" || :
+    if $PATCH "$LOCAL" < "$HGTMP/diff"; then
 	exit 0
     else
 	# If rejects are empty after using the editor, merge was ok
--- a/mercurial/bdiff.c	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/bdiff.c	Thu Oct 27 12:26:16 2005 -0700
@@ -53,7 +53,7 @@
 	struct hunk *base, *head;
 };
 
-static __inline uint32_t rol32(uint32_t word, unsigned int shift)
+static inline uint32_t rol32(uint32_t word, unsigned int shift)
 {
         return (word << shift) | (word >> (32 - shift));
 }
--- a/mercurial/changelog.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/changelog.py	Thu Oct 27 12:26:16 2005 -0700
@@ -6,6 +6,7 @@
 # of the GNU General Public License, incorporated herein by reference.
 
 from revlog import *
+from i18n import gettext as _
 from demandload import demandload
 demandload(globals(), "os time util")
 
@@ -43,11 +44,11 @@
             try:
                 when, offset = map(int, date.split(' '))
             except ValueError:
-                raise ValueError('invalid date: %r' % date)
+                raise ValueError(_('invalid date: %r') % date)
             if abs(when) > 0x7fffffff:
-                raise ValueError('date exceeds 32 bits: %d' % when)
+                raise ValueError(_('date exceeds 32 bits: %d') % when)
             if abs(offset) >= 43200:
-                raise ValueError('impossible time zone offset: %d' % offset)
+                raise ValueError(_('impossible time zone offset: %d') % offset)
         else:
             date = "%d %d" % util.makedate()
         list.sort()
--- a/mercurial/commands.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/commands.py	Thu Oct 27 12:26:16 2005 -0700
@@ -7,6 +7,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(), "fancyopts ui hg util lock revlog")
 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
@@ -31,7 +32,7 @@
     return args
 
 def matchpats(repo, cwd, pats=[], opts={}, head=''):
-    return util.matcher(repo.root, cwd, pats or ['.'], opts.get('include'),
+    return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
                         opts.get('exclude'), head)
 
 def makewalk(repo, pats, opts, head=''):
@@ -178,7 +179,7 @@
                 try:
                     num = revlog.rev(revlog.lookup(val))
                 except KeyError:
-                    raise util.Abort('invalid revision identifier %s', val)
+                    raise util.Abort(_('invalid revision identifier %s'), val)
         return num
     seen = {}
     for spec in revs:
@@ -238,7 +239,7 @@
             i += 1
         return ''.join(newname)
     except KeyError, inst:
-        raise util.Abort("invalid format spec '%%%s' in output file name",
+        raise util.Abort(_("invalid format spec '%%%s' in output file name"),
                     inst.args[0])
 
 def make_file(repo, r, pat, node=None,
@@ -332,52 +333,52 @@
         parents = []
 
     if ui.verbose:
-        ui.write("changeset:   %d:%s\n" % (rev, hex(changenode)))
+        ui.write(_("changeset:   %d:%s\n") % (rev, hex(changenode)))
     else:
-        ui.write("changeset:   %d:%s\n" % (rev, short(changenode)))
+        ui.write(_("changeset:   %d:%s\n") % (rev, short(changenode)))
 
     for tag in repo.nodetags(changenode):
-        ui.status("tag:         %s\n" % tag)
+        ui.status(_("tag:         %s\n") % tag)
     for parent in parents:
-        ui.write("parent:      %d:%s\n" % parent)
+        ui.write(_("parent:      %d:%s\n") % parent)
 
     if brinfo and changenode in brinfo:
         br = brinfo[changenode]
-        ui.write("branch:      %s\n" % " ".join(br))
+        ui.write(_("branch:      %s\n") % " ".join(br))
 
-    ui.debug("manifest:    %d:%s\n" % (repo.manifest.rev(changes[0]),
+    ui.debug(_("manifest:    %d:%s\n") % (repo.manifest.rev(changes[0]),
                                       hex(changes[0])))
-    ui.status("user:        %s\n" % changes[1])
-    ui.status("date:        %s\n" % date)
+    ui.status(_("user:        %s\n") % changes[1])
+    ui.status(_("date:        %s\n") % date)
 
     if ui.debugflag:
         files = repo.changes(log.parents(changenode)[0], changenode)
-        for key, value in zip(["files:", "files+:", "files-:"], files):
+        for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
             if value:
                 ui.note("%-12s %s\n" % (key, " ".join(value)))
     else:
-        ui.note("files:       %s\n" % " ".join(changes[3]))
+        ui.note(_("files:       %s\n") % " ".join(changes[3]))
 
     description = changes[4].strip()
     if description:
         if ui.verbose:
-            ui.status("description:\n")
+            ui.status(_("description:\n"))
             ui.status(description)
             ui.status("\n\n")
         else:
-            ui.status("summary:     %s\n" % description.splitlines()[0])
+            ui.status(_("summary:     %s\n") % description.splitlines()[0])
     ui.status("\n")
 
 def show_version(ui):
     """output version and copyright information"""
-    ui.write("Mercurial Distributed SCM (version %s)\n"
+    ui.write(_("Mercurial Distributed SCM (version %s)\n")
              % version.get_version())
-    ui.status(
+    ui.status(_(
         "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
         "This is free software; see the source for copying conditions. "
         "There is NO\nwarranty; "
         "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
-    )
+    ))
 
 def help_(ui, cmd=None, with_version=False):
     """show help for a given command or all commands"""
@@ -400,7 +401,7 @@
             # aliases
             aliases = ', '.join(key.split('|')[1:])
             if aliases:
-                ui.write("\naliases: %s\n" % aliases)
+                ui.write(_("\naliases: %s\n") % aliases)
 
             # options
             if i[1]:
@@ -411,18 +412,18 @@
         if ui.verbose or with_version:
             show_version(ui)
         else:
-            ui.status("Mercurial Distributed SCM\n")
+            ui.status(_("Mercurial Distributed SCM\n"))
         ui.status('\n')
 
         # list of commands
         if cmd == "shortlist":
-            ui.status('basic commands (use "hg help" '
-                      'for the full list or option "-v" for details):\n\n')
+            ui.status(_('basic commands (use "hg help" '
+                        'for the full list or option "-v" for details):\n\n'))
         elif ui.verbose:
-            ui.status('list of commands:\n\n')
+            ui.status(_('list of commands:\n\n'))
         else:
-            ui.status('list of commands (use "hg help -v" '
-                      'to show aliases and global options):\n\n')
+            ui.status(_('list of commands (use "hg help -v" '
+                        'to show aliases and global options):\n\n'))
 
         h = {}
         cmds = {}
@@ -461,7 +462,7 @@
             opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
                                           longopt and " --%s" % longopt),
                                "%s%s" % (desc,
-                                         default and " (default: %s)" % default
+                                         default and _(" (default: %s)") % default
                                          or "")))
 
     if opt_output:
@@ -475,34 +476,59 @@
 # Commands start here, listed alphabetically
 
 def add(ui, repo, *pats, **opts):
-    '''add the specified files on the next commit'''
+    """add the specified files on the next commit
+
+    Schedule files to be version controlled and added to the repository.
+
+    The files will be added to the repository at the next commit.
+
+    If no names are given, add all files in the current directory and
+    its subdirectories.
+    """
+
     names = []
     for src, abs, rel, exact in walk(repo, pats, opts):
         if exact:
-            if ui.verbose: ui.status('adding %s\n' % rel)
+            if ui.verbose: ui.status(_('adding %s\n') % rel)
             names.append(abs)
         elif repo.dirstate.state(abs) == '?':
-            ui.status('adding %s\n' % rel)
+            ui.status(_('adding %s\n') % rel)
             names.append(abs)
     repo.add(names)
 
 def addremove(ui, repo, *pats, **opts):
-    """add all new files, delete all missing files"""
+    """add all new files, delete all missing files
+
+    Add all new files and remove all missing files from the repository.
+
+    New files are ignored if they match any of the patterns in .hgignore. As
+    with add, these changes take effect at the next commit.
+    """
     add, remove = [], []
     for src, abs, rel, exact in walk(repo, pats, opts):
         if src == 'f' and repo.dirstate.state(abs) == '?':
             add.append(abs)
             if ui.verbose or not exact:
-                ui.status('adding ', rel, '\n')
+                ui.status(_('adding %s\n') % rel)
         if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
             remove.append(abs)
             if ui.verbose or not exact:
-                ui.status('removing ', rel, '\n')
+                ui.status(_('removing %s\n') % rel)
     repo.add(add)
     repo.remove(remove)
 
 def annotate(ui, repo, *pats, **opts):
-    """show changeset information per file line"""
+    """show changeset information per file line
+
+    List changes in files, showing the revision id responsible for each line
+
+    This command is useful to discover who did a change or when a change took
+    place.
+
+    Without the -a option, annotate will avoid processing files it
+    detects as binary. With -a, annotate will generate an annotation
+    anyway, probably with undesirable results.
+    """
     def getnode(rev):
         return short(repo.changelog.node(rev))
 
@@ -512,7 +538,7 @@
         return trimuser(ui, cl[1], rev, ucache)
 
     if not pats:
-        raise util.Abort('at least one file name or pattern required')
+        raise util.Abort(_('at least one file name or pattern required'))
 
     opmap = [['user', getname], ['number', str], ['changeset', getnode]]
     if not opts['user'] and not opts['changeset']:
@@ -527,12 +553,12 @@
 
     for src, abs, rel, exact in walk(repo, pats, opts):
         if abs not in mmap:
-            ui.warn("warning: %s is not in the repository!\n" % rel)
+            ui.warn(_("warning: %s is not in the repository!\n") % rel)
             continue
 
         f = repo.file(abs)
         if not opts['text'] and util.binary(f.read(mmap[abs])):
-            ui.write("%s: binary file\n" % rel)
+            ui.write(_("%s: binary file\n") % rel)
             continue
 
         lines = f.annotate(mmap[abs])
@@ -550,9 +576,22 @@
                 ui.write("%s: %s" % (" ".join(p), l[1]))
 
 def bundle(ui, repo, fname, dest="default-push", **opts):
-    """create a changegroup file"""
+    """create a changegroup file
+
+    Generate a compressed changegroup file collecting all changesets
+    not found in the other repository.
+
+    This file can then be transferred using conventional means and
+    applied to another repository with the unbundle command. This is
+    useful when native push and pull are not available or when
+    exporting an entire repository is undesirable. The standard file
+    extension is ".hg".
+
+    Unlike import/export, this exactly preserves all changeset
+    contents including permissions, rename data, and revision history.
+    """
     f = open(fname, "wb")
-    dest = ui.expandpath(dest)
+    dest = ui.expandpath(dest, repo.root)
     other = hg.repository(ui, dest)
     o = repo.findoutgoing(other)
     cg = repo.changegroup(o)
@@ -571,7 +610,19 @@
         raise
 
 def cat(ui, repo, file1, *pats, **opts):
-    """output the latest or given revisions of files"""
+    """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.
+
+    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
+    for the export command, with the following additions:
+
+    %s   basename of file being printed
+    %d   dirname of file being printed, or '.' if in repo root
+    %p   root-relative path name of file being printed
+    """
     mf = {}
     if opts['rev']:
         change = repo.changelog.read(repo.lookup(opts['rev']))
@@ -585,19 +636,34 @@
                 try:
                     n = r.lookup(rev)
                 except KeyError, inst:
-                    raise util.Abort('cannot find file %s in rev %s', rel, rev)
+                    raise util.Abort(_('cannot find file %s in rev %s'), rel, rev)
         else:
             n = r.tip()
         fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
         fp.write(r.read(n))
 
 def clone(ui, source, dest=None, **opts):
-    """make a copy of an existing repository"""
+    """make a copy of an existing repository
+
+    Create a copy of an existing repository in a new directory.
+
+    If no destination directory name is specified, it defaults to the
+    basename of the source.
+
+    The location of the source is added to the new repository's
+    .hg/hgrc file, as the default to be used for future pulls.
+
+    For efficiency, hardlinks are used for cloning whenever the source
+    and destination are on the same filesystem.  Some filesystems,
+    such as AFS, implement hardlinking incorrectly, but do not report
+    errors.  In these cases, use the --pull option to avoid
+    hardlinking.
+    """
     if dest is None:
         dest = os.path.basename(os.path.normpath(source))
 
     if os.path.exists(dest):
-        raise util.Abort("destination '%s' already exists", dest)
+        raise util.Abort(_("destination '%s' already exists"), dest)
 
     dest = os.path.realpath(dest)
 
@@ -649,7 +715,10 @@
         for f in files.split():
             src = os.path.join(source, ".hg", f)
             dst = os.path.join(dest, ".hg", f)
-            util.copyfiles(src, dst)
+            try:
+                util.copyfiles(src, dst)
+            except OSError, inst:
+                if inst.errno != errno.ENOENT: raise
 
         repo = hg.repository(ui, dest)
 
@@ -673,16 +742,22 @@
     d.close()
 
 def commit(ui, repo, *pats, **opts):
-    """commit the specified files or all outstanding changes"""
-    if opts['text']:
-        ui.warn("Warning: -t and --text is deprecated,"
-                " please use -m or --message instead.\n")
-    message = opts['message'] or opts['text']
+    """commit the specified files or all outstanding changes
+
+    Commit changes to the given files into the repository.
+
+    If a list of files is omitted, all changes reported by "hg status"
+    from the root of the repository will be commited.
+
+    The HGEDITOR or EDITOR environment variables are used to start an
+    editor to add a commit comment.
+    """
+    message = opts['message']
     logfile = opts['logfile']
 
     if message and logfile:
-        raise util.Abort('options --message and --logfile are mutually '
-                         'exclusive')
+        raise util.Abort(_('options --message and --logfile are mutually '
+                           'exclusive'))
     if not message and logfile:
         try:
             if logfile == '-':
@@ -690,7 +765,7 @@
             else:
                 message = open(logfile).read()
         except IOError, inst:
-            raise util.Abort("can't read commit message '%s': %s" %
+            raise util.Abort(_("can't read commit message '%s': %s") %
                              (logfile, inst.strerror))
 
     if opts['addremove']:
@@ -713,19 +788,20 @@
 
 def docopy(ui, repo, pats, opts):
     if not pats:
-        raise util.Abort('no source or destination specified')
+        raise util.Abort(_('no source or destination specified'))
     elif len(pats) == 1:
-        raise util.Abort('no destination specified')
+        raise util.Abort(_('no destination specified'))
     pats = list(pats)
     dest = pats.pop()
     sources = []
+    dir2dir = len(pats) == 1 and os.path.isdir(pats[0])
 
     def okaytocopy(abs, rel, exact):
-        reasons = {'?': 'is not managed',
-                   'a': 'has been marked for add'}
+        reasons = {'?': _('is not managed'),
+                   'a': _('has been marked for add')}
         reason = reasons.get(repo.dirstate.state(abs))
         if reason:
-            if exact: ui.warn('%s: not copying - file %s\n' % (rel, reason))
+            if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
         else:
             return True
 
@@ -733,7 +809,7 @@
         if okaytocopy(abs, rel, exact):
             sources.append((abs, rel, exact))
     if not sources:
-        raise util.Abort('no files to copy')
+        raise util.Abort(_('no files to copy'))
 
     cwd = repo.getcwd()
     absdest = util.canonpath(repo.root, cwd, dest)
@@ -741,36 +817,44 @@
     if os.path.exists(reldest):
         destisfile = not os.path.isdir(reldest)
     else:
-        destisfile = len(sources) == 1 or repo.dirstate.state(absdest) != '?'
+        destisfile = not dir2dir and (len(sources) == 1
+                                      or repo.dirstate.state(absdest) != '?')
+
+    if destisfile and len(sources) > 1:
+        raise util.Abort(_('with multiple sources, destination must be a '
+                           'directory'))
 
-    if destisfile:
-        if opts['parents']:
-            raise util.Abort('with --parents, destination must be a directory')
-        elif len(sources) > 1:
-            raise util.Abort('with multiple sources, destination must be a '
-                             'directory')
+    srcpfxlen = 0
+    if dir2dir:
+        srcpfx = util.pathto(cwd, util.canonpath(repo.root, cwd, pats[0]))
+        if os.path.exists(reldest):
+            srcpfx = os.path.split(srcpfx)[0]
+        if srcpfx:
+            srcpfx += os.sep
+        srcpfxlen = len(srcpfx)
+
     errs, copied = 0, []
     for abs, rel, exact in sources:
-        if opts['parents']:
-            mydest = os.path.join(dest, rel)
-        elif destisfile:
+        if destisfile:
             mydest = reldest
+        elif dir2dir:
+            mydest = os.path.join(dest, rel[srcpfxlen:])
         else:
             mydest = os.path.join(dest, os.path.basename(rel))
         myabsdest = util.canonpath(repo.root, cwd, mydest)
         myreldest = util.pathto(cwd, myabsdest)
         if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
-            ui.warn('%s: not overwriting - file already managed\n' % myreldest)
+            ui.warn(_('%s: not overwriting - file already managed\n') % myreldest)
             continue
         mydestdir = os.path.dirname(myreldest) or '.'
         if not opts['after']:
             try:
-                if opts['parents']: os.makedirs(mydestdir)
+                if dir2dir: os.makedirs(mydestdir)
                 elif not destisfile: os.mkdir(mydestdir)
             except OSError, inst:
                 if inst.errno != errno.EEXIST: raise
         if ui.verbose or not exact:
-            ui.status('copying %s to %s\n' % (rel, myreldest))
+            ui.status(_('copying %s to %s\n') % (rel, myreldest))
         if not opts['after']:
             try:
                 shutil.copyfile(rel, myreldest)
@@ -779,19 +863,34 @@
                 raise util.Abort(str(inst))
             except IOError, inst:
                 if inst.errno == errno.ENOENT:
-                    ui.warn('%s: deleted in working copy\n' % rel)
+                    ui.warn(_('%s: deleted in working copy\n') % rel)
                 else:
-                    ui.warn('%s: cannot copy - %s\n' % (rel, inst.strerror))
+                    ui.warn(_('%s: cannot copy - %s\n') % (rel, inst.strerror))
                 errs += 1
                 continue
         repo.copy(abs, myabsdest)
         copied.append((abs, rel, exact))
     if errs:
-        ui.warn('(consider using --after)\n')
+        ui.warn(_('(consider using --after)\n'))
     return errs, copied
 
 def copy(ui, repo, *pats, **opts):
-    """mark files as copied for the next commit"""
+    """mark files as copied for the next commit
+
+    Mark dest as having copies of source files.  If dest is a
+    directory, copies are put in that directory.  If dest is a file,
+    there can only be one source.
+
+    By default, this command copies the contents of files as they
+    stand in the working directory.  If invoked with --after, the
+    operation is recorded, but no copying is performed.
+
+    This command takes effect in the next commit.
+
+    NOTE: This command should be treated as experimental. While it
+    should properly record copied files, this information is not yet
+    fully used by merge, nor fully reported by log.
+    """
     errs, copied = docopy(ui, repo, pats, opts)
     return errs
 
@@ -816,22 +915,22 @@
     for f in dc:
         state = repo.dirstate.state(f)
         if state in "nr" and f not in m1:
-            ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
+            ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
             errors += 1
         if state in "a" and f in m1:
-            ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
+            ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
             errors += 1
         if state in "m" and f not in m1 and f not in m2:
-            ui.warn("%s in state %s, but not in either manifest\n" %
+            ui.warn(_("%s in state %s, but not in either manifest\n") %
                     (f, state))
             errors += 1
     for f in m1:
         state = repo.dirstate.state(f)
         if state not in "nrm":
-            ui.warn("%s in manifest1, but listed as state %s" % (f, state))
+            ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
             errors += 1
     if errors:
-        raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
+        raise util.Abort(_(".hg/dirstate inconsistent with current parent's manifest"))
 
 def debugconfig(ui):
     """show combined config settings from all hgrc files"""
@@ -842,6 +941,19 @@
     for section, name, value in ui.walkconfig():
         ui.write('%s.%s=%s\n' % (section, name, value))
 
+def debugsetparents(ui, repo, rev1, rev2=None):
+    """
+    manually set the parents of the current working directory
+
+    This is useful for writing repository conversion tools, but should
+    be used with care.
+    """
+
+    if not rev2:
+        rev2 = hex(nullid)
+
+    repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
+
 def debugstate(ui, repo):
     """show the contents of the current dirstate"""
     repo.dirstate.read()
@@ -854,7 +966,7 @@
                     time.strftime("%x %X",
                                   time.localtime(dc[file_][3])), file_))
     for f in repo.dirstate.copies:
-        ui.write("copy: %s -> %s\n" % (repo.dirstate.copies[f], f))
+        ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
 
 def debugdata(ui, file_, rev):
     """dump the contents of an data file revision"""
@@ -862,7 +974,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"""
@@ -902,9 +1014,9 @@
         n = r.tip()
     m = r.renamed(n)
     if m:
-        ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
+        ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
     else:
-        ui.write("not renamed\n")
+        ui.write(_("not renamed\n"))
 
 def debugwalk(ui, repo, *pats, **opts):
     """show how files match on given patterns"""
@@ -919,7 +1031,22 @@
         ui.write("%s\n" % line.rstrip())
 
 def diff(ui, repo, *pats, **opts):
-    """diff working directory (or selected files)"""
+    """diff working directory (or selected files)
+
+    Show differences between revisions for the specified files.
+
+    Differences between files are shown using the unified diff format.
+
+    When two revision arguments are given, then changes are shown
+    between those revisions. If only one revision is specified then
+    that revision is compared to the working directory, and, when no
+    revisions are specified, the working directory files are compared
+    to its parent.
+
+    Without the -a option, diff will avoid generating diffs of files
+    it detects as binary. With -a, diff will generate a diff anyway,
+    probably with undesirable results.
+    """
     node1, node2 = None, None
     revs = [repo.lookup(x) for x in opts['rev']]
 
@@ -928,7 +1055,7 @@
     if len(revs) > 1:
         node2 = revs[1]
     if len(revs) > 2:
-        raise util.Abort("too many revisions to diff")
+        raise util.Abort(_("too many revisions to diff"))
 
     fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
 
@@ -960,30 +1087,69 @@
         fp.close()
 
 def export(ui, repo, *changesets, **opts):
-    """dump the header and diffs for one or more changesets"""
+    """dump the header and diffs for one or more changesets
+
+    Print the changeset header and diffs for one or more revisions.
+
+    The information shown in the changeset header is: author,
+    changeset hash, parent and commit comment.
+
+    Output may be to a file, in which case the name of the file is
+    given using a format string.  The formatting rules are as follows:
+
+    %%   literal "%" character
+    %H   changeset hash (40 bytes of hexadecimal)
+    %N   number of patches being generated
+    %R   changeset revision number
+    %b   basename of the exporting repository
+    %h   short-form changeset hash (12 bytes of hexadecimal)
+    %n   zero-padded sequence number, starting at 1
+    %r   zero-padded changeset revision number
+
+    Without the -a option, export will avoid generating diffs of files
+    it detects as binary. With -a, export will generate a diff anyway,
+    probably with undesirable results.
+    """
     if not changesets:
-        raise util.Abort("export requires at least one changeset")
+        raise util.Abort(_("export requires at least one changeset"))
     seqno = 0
     revs = list(revrange(ui, repo, changesets))
     total = len(revs)
     revwidth = max(map(len, revs))
-    ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
+    ui.note(len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n"))
     for cset in revs:
         seqno += 1
         doexport(ui, repo, cset, seqno, total, revwidth, opts)
 
 def forget(ui, repo, *pats, **opts):
-    """don't add the specified files on the next commit"""
+    """don't add the specified files on the next commit
+
+    Undo an 'hg add' scheduled for the next commit.
+    """
     forget = []
     for src, abs, rel, exact in walk(repo, pats, opts):
         if repo.dirstate.state(abs) == 'a':
             forget.append(abs)
             if ui.verbose or not exact:
-                ui.status('forgetting ', rel, '\n')
+                ui.status(_('forgetting %s\n') % rel)
     repo.forget(forget)
 
 def grep(ui, repo, pattern, *pats, **opts):
-    """search for a pattern in specified files and revisions"""
+    """search for a pattern in specified files and revisions
+
+    Search revisions of files for a regular expression.
+
+    This command behaves differently than Unix grep.  It only accepts
+    Python/Perl regexps.  It searches repository history, not the
+    working directory.  It always prints the revision number in which
+    a match appears.
+
+    By default, grep only prints output for the first revision of a
+    file in which it finds a match.  To get it to print every revision
+    that contains a change in match status ("-" for a match that
+    becomes a non-match, or "+" for a non-match that becomes a match),
+    use the --all flag.
+    """
     reflags = 0
     if opts['ignore_case']:
         reflags |= re.I
@@ -1102,7 +1268,14 @@
     return (count == 0 and 1) or 0
 
 def heads(ui, repo, **opts):
-    """show current repository heads"""
+    """show current repository heads
+
+    Show all repository head changesets.
+
+    Repository "heads" are changesets that don't have children
+    changesets. They are where development generally takes place and
+    are the usual targets for update and merge operations.
+    """
     heads = repo.changelog.heads()
     br = None
     if opts['branches']:
@@ -1111,10 +1284,16 @@
         show_changeset(ui, repo, changenode=n, brinfo=br)
 
 def identify(ui, repo):
-    """print information about the working copy"""
+    """print information about the working copy
+    Print a short summary of the current state of the repo.
+
+    This summary identifies the repository state using one or two parent
+    hash identifiers, followed by a "+" if there are uncommitted changes
+    in the working directory, followed by a list of tags for this revision.
+    """
     parents = [p for p in repo.dirstate.parents() if p != nullid]
     if not parents:
-        ui.write("unknown\n")
+        ui.write(_("unknown\n"))
         return
 
     hexfunc = ui.verbose and hex or short
@@ -1133,22 +1312,39 @@
     ui.write("%s\n" % ' '.join(output))
 
 def import_(ui, repo, patch1, *patches, **opts):
-    """import an ordered set of patches"""
+    """import an ordered set of patches
+
+    Import a list of patches and commit them individually.
+
+    If there are outstanding changes in the working directory, import
+    will abort unless given the -f flag.
+
+    If a patch looks like a mail message (its first line starts with
+    "From " or looks like an RFC822 header), it will not be applied
+    unless the -f option is used.  The importer neither parses nor
+    discards mail headers, so use -f only to override the "mailness"
+    safety check, not to import a real mail message.
+    """
     patches = (patch1,) + patches
 
     if not opts['force']:
         (c, a, d, u) = repo.changes()
         if c or a or d:
-            raise util.Abort("outstanding uncommitted changes")
+            raise util.Abort(_("outstanding uncommitted changes"))
 
     d = opts["base"]
     strip = opts["strip"]
 
     mailre = re.compile(r'(?:From |[\w-]+:)')
-    diffre = re.compile(r'(?:diff -|--- .*\s+\w+ \w+ +\d+ \d+:\d+:\d+ \d+)')
+
+    # attempt to detect the start of a patch
+    # (this heuristic is borrowed from quilt)
+    diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
+                        'retrieving revision [0-9]+(\.[0-9]+)*$|' +
+                        '(---|\*\*\*)[ \t])')
 
     for patch in patches:
-        ui.status("applying %s\n" % patch)
+        ui.status(_("applying %s\n") % patch)
         pf = os.path.join(d, patch)
 
         message = []
@@ -1159,15 +1355,15 @@
             if (not message and not hgpatch and
                    mailre.match(line) and not opts['force']):
                 if len(line) > 35: line = line[:32] + '...'
-                raise util.Abort('first line looks like a '
-                                 'mail header: ' + line)
+                raise util.Abort(_('first line looks like a '
+                                   'mail header: ') + line)
             if diffre.match(line):
                 break
             elif hgpatch:
                 # parse values when importing the result of an hg export
                 if line.startswith("# User "):
                     user = line[7:]
-                    ui.debug('User: %s\n' % user)
+                    ui.debug(_('User: %s\n') % user)
                 elif not line.startswith("# ") and line:
                     message.append(line)
                     hgpatch = False
@@ -1179,10 +1375,10 @@
 
         # make sure message isn't empty
         if not message:
-            message = "imported patch %s\n" % patch
+            message = _("imported patch %s\n") % patch
         else:
             message = "%s\n" % '\n'.join(message)
-        ui.debug('message:\n%s\n' % message)
+        ui.debug(_('message:\n%s\n') % message)
 
         files = util.patch(strip, pf, ui)
 
@@ -1191,30 +1387,64 @@
         repo.commit(files, message, user)
 
 def incoming(ui, repo, source="default", **opts):
-    """show new changesets found in source"""
-    source = ui.expandpath(source)
+    """show new changesets found in source
+
+    Show new changesets found in the specified repo or the default
+    pull repo. These are the changesets that would be pulled if a pull
+    was requested.
+
+    Currently only local repositories are supported.
+    """
+    source = ui.expandpath(source, repo.root)
     other = hg.repository(ui, source)
     if not other.local():
-        raise util.Abort("incoming doesn't work for remote repositories yet")
+        raise util.Abort(_("incoming doesn't work for remote repositories yet"))
     o = repo.findincoming(other)
     if not o:
         return
     o = other.changelog.nodesbetween(o)[0]
+    if opts['newest_first']:
+        o.reverse()
     for n in o:
+        parents = [p for p in other.changelog.parents(n) if p != nullid]
+        if opts['no_merges'] and len(parents) == 2:
+            continue
         show_changeset(ui, other, changenode=n)
         if opts['patch']:
-            prev = other.changelog.parents(n)[0]
+            prev = (parents and parents[0]) or nullid
             dodiff(ui, ui, other, prev, n)
             ui.write("\n")
 
 def init(ui, dest="."):
-    """create a new repository in the given directory"""
+    """create a new repository in the given directory
+
+    Initialize a new repository in the given directory.  If the given
+    directory does not exist, it is created.
+
+    If no directory is given, the current directory is used.
+    """
     if not os.path.exists(dest):
         os.mkdir(dest)
     hg.repository(ui, dest, create=1)
 
 def locate(ui, repo, *pats, **opts):
-    """locate files matching specific patterns"""
+    """locate files matching specific patterns
+
+    Print all files under Mercurial control whose names match the
+    given patterns.
+
+    This command searches the current directory and its
+    subdirectories.  To search an entire repository, move to the root
+    of the repository.
+
+    If no patterns are given to match, this command prints all file
+    names.
+
+    If you want to feed the output of this command into the "xargs"
+    command, use the "-0" option to both this command and "xargs".
+    This will avoid the problem of "xargs" treating single filenames
+    that contain white space as multiple filenames.
+    """
     end = opts['print0'] and '\0' or '\n'
 
     for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
@@ -1226,7 +1456,15 @@
             ui.write(rel, end)
 
 def log(ui, repo, *pats, **opts):
-    """show revision history of entire repository or files"""
+    """show revision history of entire repository or files
+
+    Print the revision history of the specified files or the entire project.
+
+    By default this command outputs: changeset id and hash, tags,
+    parents, user, date and time, and a summary for each commit. The
+    -v switch adds some more detail, such as changed files, manifest
+    hashes or message signatures.
+    """
     class dui:
         # Implement and delegate some ui protocol.  Save hunks of
         # output for later display in the desired order.
@@ -1260,14 +1498,19 @@
             du = dui(ui)
         elif st == 'add':
             du.bump(rev)
+            changenode = repo.changelog.node(rev)
+            parents = [p for p in repo.changelog.parents(changenode)
+                       if p != nullid]
+            if opts['no_merges'] and len(parents) == 2:
+                 continue
+            if opts['only_merges'] and len(parents) != 2:
+                 continue
+
             br = None
-            if opts['branch']:
-                br = repo.branchlookup([repo.changelog.node(rev)])
-
             if opts['keyword']:
                 changes = repo.changelog.read(repo.changelog.node(rev))
                 miss = 0
-                for k in opts['keyword']:
+                for k in [kw.lower() for kw in opts['keyword']]:
                     if not (k in changes[1].lower() or
                             k in changes[4].lower() or
                             k in " ".join(changes[3][:20]).lower()):
@@ -1276,10 +1519,12 @@
                 if miss:
                     continue
 
+            if opts['branch']:
+                br = repo.branchlookup([repo.changelog.node(rev)])
+
             show_changeset(du, repo, rev, brinfo=br)
             if opts['patch']:
-                changenode = repo.changelog.node(rev)
-                prev, other = repo.changelog.parents(changenode)
+                prev = (parents and parents[0]) or nullid
                 dodiff(du, du, repo, prev, changenode, fns)
                 du.write("\n\n")
         elif st == 'iter':
@@ -1287,7 +1532,13 @@
                 ui.write(*args)
 
 def manifest(ui, repo, rev=None):
-    """output the latest or given revision of the project manifest"""
+    """output the latest or given revision of the project manifest
+
+    Print a list of version controlled files for the given revision.
+
+    The manifest is the list of files being version controlled. If no revision
+    is given then the tip is used.
+    """
     if rev:
         try:
             # assume all revision numbers are for changesets
@@ -1307,20 +1558,33 @@
         ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
 
 def outgoing(ui, repo, dest="default-push", **opts):
-    """show changesets not found in destination"""
-    dest = ui.expandpath(dest)
+    """show changesets not found in destination
+
+    Show changesets not found in the specified destination repo or the
+    default push repo. These are the changesets that would be pushed
+    if a push was requested.
+    """
+    dest = ui.expandpath(dest, repo.root)
     other = hg.repository(ui, dest)
     o = repo.findoutgoing(other)
     o = repo.changelog.nodesbetween(o)[0]
+    if opts['newest_first']:
+        o.reverse()
     for n in o:
+        parents = [p for p in repo.changelog.parents(n) if p != nullid]
+        if opts['no_merges'] and len(parents) == 2:
+            continue
         show_changeset(ui, repo, changenode=n)
         if opts['patch']:
-            prev = repo.changelog.parents(n)[0]
+            prev = (parents and parents[0]) or nullid
             dodiff(ui, ui, repo, prev, n)
             ui.write("\n")
 
 def parents(ui, repo, rev=None):
-    """show the parents of the working dir or revision"""
+    """show the parents of the working dir or revision
+
+    Print the working directory's parent revisions.
+    """
     if rev:
         p = repo.changelog.parents(repo.lookup(rev))
     else:
@@ -1331,7 +1595,14 @@
             show_changeset(ui, repo, changenode=n)
 
 def paths(ui, search=None):
-    """show definition of symbolic path names"""
+    """show definition of symbolic path names
+
+    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 /etc/mercurial/hgrc
+    and $HOME/.hgrc.  If run inside a repository, .hg/hgrc is used, too.
+    """
     try:
         repo = hg.repository(ui=ui)
     except hg.RepoError:
@@ -1342,16 +1613,35 @@
             if name == search:
                 ui.write("%s\n" % path)
                 return
-        ui.warn("not found!\n")
+        ui.warn(_("not found!\n"))
         return 1
     else:
         for name, path in ui.configitems("paths"):
             ui.write("%s = %s\n" % (name, path))
 
 def pull(ui, repo, source="default", **opts):
-    """pull changes from the specified source"""
-    source = ui.expandpath(source)
-    ui.status('pulling from %s\n' % (source))
+    """pull changes from the specified source
+
+    Pull changes from a remote repository to a local one.
+
+    This finds all changes from the repository at the specified path
+    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.  With SSH, paths are relative
+    to the remote user's home directory by default; use two slashes at
+    the start of a path to specify it as relative to the filesystem root.
+    """
+    source = ui.expandpath(source, repo.root)
+    ui.status(_('pulling from %s\n') % (source))
 
     if opts['ssh']:
         ui.setconfig("ui", "ssh", opts['ssh'])
@@ -1369,13 +1659,33 @@
         if opts['update']:
             return update(ui, repo)
         else:
-            ui.status("(run 'hg update' to get a working copy)\n")
+            ui.status(_("(run 'hg update' to get a working copy)\n"))
 
     return r
 
 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
-    """push changes to the specified destination"""
-    dest = ui.expandpath(dest)
+    """push changes to the specified destination
+
+    Push changes from the local repository to the given destination.
+
+    This is the symmetrical operation for pull. It helps to move
+    changes from the current repository to a different one. If the
+    destination is local this is identical to a pull in that directory
+    from the current one.
+
+    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:
+
+      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.
+    """
+    dest = ui.expandpath(dest, repo.root)
     ui.status('pushing to %s\n' % (dest))
 
     if ssh:
@@ -1388,10 +1698,16 @@
     return r
 
 def rawcommit(ui, repo, *flist, **rc):
-    "raw commit interface"
+    """raw commit interface
+
+    Lowlevel commit, for use in helper scripts.
+
+    This command is not intended to be used by normal users, as it is
+    primarily useful for importing from other SCMs.
+    """
     if rc['text']:
-        ui.warn("Warning: -t and --text is deprecated,"
-                " please use -m or --message instead.\n")
+        ui.warn(_("Warning: -t and --text is deprecated,"
+                  " please use -m or --message instead.\n"))
     message = rc['message'] or rc['text']
     if not message and rc['logfile']:
         try:
@@ -1399,7 +1715,7 @@
         except IOError:
             pass
     if not message and not rc['logfile']:
-        raise util.Abort("missing commit message")
+        raise util.Abort(_("missing commit message"))
 
     files = relpath(repo, list(flist))
     if rc['files']:
@@ -1413,49 +1729,83 @@
         raise util.Abort(str(inst))
 
 def recover(ui, repo):
-    """roll back an interrupted transaction"""
+    """roll back an interrupted transaction
+
+    Recover from an interrupted commit or pull.
+
+    This command tries to fix the repository status after an interrupted
+    operation. It should only be necessary when Mercurial suggests it.
+    """
     repo.recover()
 
 def remove(ui, repo, pat, *pats, **opts):
-    """remove the specified files on the next commit"""
+    """remove the specified files on the next commit
+
+    Schedule the indicated files for removal from the repository.
+
+    This command schedules the files to be removed at the next commit.
+    This only removes files from the current branch, not from the
+    entire project history.  If the files still exist in the working
+    directory, they will be deleted from it.
+    """
     names = []
     def okaytoremove(abs, rel, exact):
         c, a, d, u = repo.changes(files = [abs])
         reason = None
-        if c: reason = 'is modified'
-        elif a: reason = 'has been marked for add'
-        elif u: reason = 'is not managed'
+        if c: reason = _('is modified')
+        elif a: reason = _('has been marked for add')
+        elif u: reason = _('is not managed')
         if reason:
-            if exact: ui.warn('not removing %s: file %s\n' % (rel, reason))
+            if exact: ui.warn(_('not removing %s: file %s\n') % (rel, reason))
         else:
             return True
     for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
         if okaytoremove(abs, rel, exact):
-            if ui.verbose or not exact: ui.status('removing %s\n' % rel)
+            if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
             names.append(abs)
-    for name in names:
-        try:
-            os.unlink(name)
-        except OSError, inst:
-            if inst.errno != errno.ENOENT: raise
-    repo.remove(names)
+    repo.remove(names, unlink=True)
 
 def rename(ui, repo, *pats, **opts):
-    """rename files; equivalent of copy + remove"""
+    """rename files; equivalent of copy + remove
+
+    Mark dest as copies of sources; mark sources for deletion.  If
+    dest is a directory, copies are put in that directory.  If dest is
+    a file, there can only be one source.
+
+    By default, this command copies the contents of files as they
+    stand in the working directory.  If invoked with --after, the
+    operation is recorded, but no copying is performed.
+
+    This command takes effect in the next commit.
+
+    NOTE: This command should be treated as experimental. While it
+    should properly record rename files, this information is not yet
+    fully used by merge, nor fully reported by log.
+    """
     errs, copied = docopy(ui, repo, pats, opts)
     names = []
     for abs, rel, exact in copied:
-        if ui.verbose or not exact: ui.status('removing %s\n' % rel)
-        try:
-            os.unlink(rel)
-        except OSError, inst:
-            if inst.errno != errno.ENOENT: raise
+        if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
         names.append(abs)
-    repo.remove(names)
+    repo.remove(names, unlink=True)
     return errs
 
 def revert(ui, repo, *names, **opts):
-    """revert modified files or dirs back to their unmodified states"""
+    """revert modified files or dirs back to their unmodified states
+
+    Revert any uncommitted modifications made to the named files or
+    directories.  This restores the contents of the affected files to
+    an unmodified state.
+
+    If a file has been deleted, it is recreated.  If the executable
+    mode of a file was changed, it is reset.
+
+    If a directory is given, all files in that directory and its
+    subdirectories are reverted.
+
+    If no arguments are given, all files in the current directory and
+    its subdirectories are reverted.
+    """
     node = opts['rev'] and repo.lookup(opts['rev']) or \
            repo.dirstate.parents()[0]
     root = os.path.realpath(repo.root)
@@ -1494,25 +1844,42 @@
             chosen[relname] = 1
         return ret
 
+    (c, a, d, u) = repo.changes()
+    repo.forget(filter(choose, a))
+    repo.undelete(filter(choose, d))
+
     r = repo.update(node, False, True, choose, False)
     for n in relnames:
         if n not in chosen:
-            ui.warn('error: no matches for %s\n' % n)
+            ui.warn(_('error: no matches for %s\n') % n)
             r = 1
     sys.stdout.flush()
     return r
 
 def root(ui, repo):
-    """print the root (top) of the current working dir"""
+    """print the root (top) of the current working dir
+
+    Print the root directory of the current repository.
+    """
     ui.write(repo.root + "\n")
 
 def serve(ui, repo, **opts):
-    """export the repository via HTTP"""
+    """export the repository via HTTP
+
+    Start a local HTTP repository browser and pull server.
+
+    By default, the server logs accesses to stdout and errors to
+    stderr.  Use the "-A" and "-E" options to log to files.
+    """
 
     if opts["stdio"]:
         fin, fout = sys.stdin, sys.stdout
         sys.stdout = sys.stderr
 
+        # Prevent insertion/deletion of CRs
+        util.set_binary(fin)
+        util.set_binary(fout)
+
         def getarg():
             argline = fin.readline()[:-1]
             arg, l = argline.split()
@@ -1597,29 +1964,34 @@
             except socket.error:
                 pass
         if port != 80:
-            ui.status('listening at http://%s:%d/\n' % (addr, port))
+            ui.status(_('listening at http://%s:%d/\n') % (addr, port))
         else:
-            ui.status('listening at http://%s/\n' % addr)
+            ui.status(_('listening at http://%s/\n') % addr)
     httpd.serve_forever()
 
 def status(ui, repo, *pats, **opts):
-    '''show changed files in the working directory
+    """show changed files in the working directory
 
+    Show changed files in the working directory.  If no names are
+    given, all files are shown.  Otherwise, only files matching the
+    given names are shown.
+
+    The codes used to show the status of files are:
     M = modified
     A = added
     R = removed
     ? = not tracked
-    '''
+    """
 
     cwd = repo.getcwd()
     files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
     (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
                     for n in repo.changes(files=files, match=matchfn)]
 
-    changetypes = [('modified', 'M', c),
-                   ('added', 'A', a),
-                   ('removed', 'R', d),
-                   ('unknown', '?', u)]
+    changetypes = [(_('modified'), 'M', c),
+                   (_('added'), 'A', a),
+                   (_('removed'), 'R', d),
+                   (_('unknown'), '?', u)]
 
     end = opts['print0'] and '\0' or '\n'
 
@@ -1634,19 +2006,33 @@
             ui.write(format % f)
 
 def tag(ui, repo, name, rev=None, **opts):
-    """add a tag for the current tip or a given revision"""
+    """add a tag for the current tip or a given revision
+
+    Name a particular revision using <name>.
+
+    Tags are used to name particular revisions of the repository and are
+    very useful to compare different revision, to go back to significant
+    earlier versions or to mark branch points as releases, etc.
+
+    If no revision is given, the tip is used.
+
+    To facilitate version control, distribution, and merging of tags,
+    they are stored as a file named ".hgtags" which is managed
+    similarly to other project files and can be hand-edited if
+    necessary.
+    """
     if opts['text']:
-        ui.warn("Warning: -t and --text is deprecated,"
-                " please use -m or --message instead.\n")
+        ui.warn(_("Warning: -t and --text is deprecated,"
+                  " please use -m or --message instead.\n"))
     if name == "tip":
-        raise util.Abort("the name 'tip' is reserved")
+        raise util.Abort(_("the name 'tip' is reserved"))
     if rev:
         r = hex(repo.lookup(rev))
     else:
         r = hex(repo.changelog.tip())
 
     if name.find(revrangesep) >= 0:
-        raise util.Abort("'%s' cannot be used in a tag name" % revrangesep)
+        raise util.Abort(_("'%s' cannot be used in a tag name") % revrangesep)
 
     if opts['local']:
         repo.opener("localtags", "a").write("%s %s\n" % (r, name))
@@ -1655,22 +2041,27 @@
     (c, a, d, u) = repo.changes()
     for x in (c, a, d, u):
         if ".hgtags" in x:
-            raise util.Abort("working copy of .hgtags is changed "
-                             "(please commit .hgtags manually)")
+            raise util.Abort(_("working copy of .hgtags is changed "
+                               "(please commit .hgtags manually)"))
 
     repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
     if repo.dirstate.state(".hgtags") == '?':
         repo.add([".hgtags"])
 
     message = (opts['message'] or opts['text'] or
-               "Added tag %s for changeset %s" % (name, r))
+               _("Added tag %s for changeset %s") % (name, r))
     try:
         repo.commit([".hgtags"], message, opts['user'], opts['date'])
     except ValueError, inst:
         raise util.Abort(str(inst))
 
 def tags(ui, repo):
-    """list repository tags"""
+    """list repository tags
+
+    List the repository tags.
+
+    This lists both regular and local tags.
+    """
 
     l = repo.tagslist()
     l.reverse()
@@ -1682,22 +2073,28 @@
         ui.write("%-30s %s\n" % (t, r))
 
 def tip(ui, repo):
-    """show the tip revision"""
+    """show the tip revision
+
+    Show the tip revision.
+    """
     n = repo.changelog.tip()
     show_changeset(ui, repo, changenode=n)
 
 def unbundle(ui, repo, fname):
-    """apply a changegroup file"""
+    """apply a changegroup file
+
+    Apply a compressed changegroup file generated by the bundle
+    command.
+    """
     f = urllib.urlopen(fname)
 
     if f.read(4) != "HG10":
-        raise util.Abort("%s: not a Mercurial bundle file" % fname)
+        raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
 
     def bzgenerator(f):
         zd = bz2.BZ2Decompressor()
         for chunk in f:
             yield zd.decompress(chunk)
-        yield zd.flush()
 
     bzgen = bzgenerator(util.filechunkiter(f, 4096))
     repo.addchangegroup(util.chunkbuffer(bzgen))
@@ -1718,7 +2115,9 @@
     repo.undo()
 
 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
-    '''update or merge working directory
+    """update or merge working directory
+
+    Update the working directory to the specified revision.
 
     If there are no outstanding changes in the working directory and
     there is a linear relationship between the current version and the
@@ -1729,7 +2128,10 @@
     changed between either parent are marked as changed for the next
     commit and a commit must be performed before any further updates
     are allowed.
-    '''
+
+    By default, update will refuse to run if doing so would require
+    merging or discarding local changes.
+    """
     if branch:
         br = repo.branchlookup(branch=branch)
         found = []
@@ -1737,22 +2139,30 @@
             if branch in br[x]:
                 found.append(x)
         if len(found) > 1:
-            ui.warn("Found multiple heads for %s\n" % branch)
+            ui.warn(_("Found multiple heads for %s\n") % branch)
             for x in found:
                 show_changeset(ui, repo, changenode=x, brinfo=br)
             return 1
         if len(found) == 1:
             node = found[0]
-            ui.warn("Using head %s for branch %s\n" % (short(node), branch))
+            ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
         else:
-            ui.warn("branch %s not found\n" % (branch))
+            ui.warn(_("branch %s not found\n") % (branch))
             return 1
     else:
         node = node and repo.lookup(node) or repo.changelog.tip()
     return repo.update(node, allow=merge, force=clean)
 
 def verify(ui, repo):
-    """verify the integrity of the repository"""
+    """verify the integrity of the repository
+
+    Verify the integrity of the current repository.
+
+    This will perform an extensive check of the repository's
+    integrity, validating the hashes and checksums of each entry in
+    the changelog, manifest, and tracked files, as well as the
+    integrity of their crosslinks and indices.
+    """
     return repo.verify()
 
 # Command options and aliases are listed here, alphabetically
@@ -1760,244 +2170,249 @@
 table = {
     "^add":
         (add,
-         [('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search')],
+         [('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
          "hg add [OPTION]... [FILE]..."),
     "addremove":
         (addremove,
-         [('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search')],
+         [('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
          "hg addremove [OPTION]... [FILE]..."),
     "^annotate":
         (annotate,
-         [('r', 'rev', '', 'revision'),
-          ('a', 'text', None, 'treat all files as text'),
-          ('u', 'user', None, 'show user'),
-          ('n', 'number', None, 'show revision number'),
-          ('c', 'changeset', None, 'show changeset'),
-          ('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search')],
-         'hg annotate [OPTION]... FILE...'),
+         [('r', 'rev', '', _('annotate the specified revision')),
+          ('a', 'text', None, _('treat all files as text')),
+          ('u', 'user', None, _('list the author')),
+          ('n', 'number', None, _('list the revision number (default)')),
+          ('c', 'changeset', None, _('list the changeset')),
+          ('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         _('hg annotate [OPTION]... FILE...')),
     "bundle":
         (bundle,
          [],
-         'hg bundle FILE DEST'),
+         _('hg bundle FILE DEST')),
     "cat":
         (cat,
-         [('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search'),
-          ('o', 'output', "", 'output to file'),
-          ('r', 'rev', '', 'revision')],
-         'hg cat [OPTION]... FILE...'),
+         [('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns')),
+          ('o', 'output', "", _('print output to file with formatted name')),
+          ('r', 'rev', '', _('print the given revision'))],
+         _('hg cat [OPTION]... FILE...')),
     "^clone":
         (clone,
-         [('U', 'noupdate', None, 'skip update after cloning'),
-          ('e', 'ssh', "", 'ssh command'),
-          ('r', 'rev', [], 'a changeset you would like to have after cloning'),
-          ('', 'pull', None, 'use pull protocol to copy metadata'),
-          ('', 'remotecmd', "", 'remote hg command')],
-         'hg clone [OPTION]... SOURCE [DEST]'),
+         [('U', 'noupdate', None, _('do not update the new working directory')),
+          ('e', 'ssh', "", _('specify ssh command to use')),
+          ('', 'pull', None, _('use pull protocol to copy metadata')),
+          ('r', 'rev', [], _('a changeset you would like to have after cloning')),
+          ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
+         _('hg clone [OPTION]... SOURCE [DEST]')),
     "^commit|ci":
         (commit,
-         [('A', 'addremove', None, 'run add/remove during commit'),
-          ('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search'),
-          ('m', 'message', "", 'commit message'),
-          ('t', 'text', "", 'commit message (deprecated: use -m)'),
-          ('l', 'logfile', "", 'commit message file'),
-          ('d', 'date', "", 'date code'),
-          ('u', 'user', "", 'user')],
-         'hg commit [OPTION]... [FILE]...'),
+         [('A', 'addremove', None, _('run addremove during commit')),
+          ('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns')),
+          ('m', 'message', "", _('use <text> as commit message')),
+          ('l', 'logfile', "", _('read the commit message from <file>')),
+          ('d', 'date', "", _('record datecode as commit date')),
+          ('u', 'user', "", _('record user as commiter'))],
+         _('hg commit [OPTION]... [FILE]...')),
     "copy|cp": (copy,
-             [('I', 'include', [], 'include path in search'),
-              ('X', 'exclude', [], 'exclude path from search'),
-              ('A', 'after', None, 'record a copy after it has happened'),
-              ('f', 'force', None, 'replace destination if it exists'),
-              ('p', 'parents', None, 'append source path to dest')],
-             'hg copy [OPTION]... [SOURCE]... DEST'),
-    "debugancestor": (debugancestor, [], 'debugancestor INDEX REV1 REV2'),
-    "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
-    "debugconfig": (debugconfig, [], 'debugconfig'),
-    "debugstate": (debugstate, [], 'debugstate'),
-    "debugdata": (debugdata, [], 'debugdata FILE REV'),
-    "debugindex": (debugindex, [], 'debugindex FILE'),
-    "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
-    "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
+             [('I', 'include', [], _('include names matching the given patterns')),
+              ('X', 'exclude', [], _('exclude names matching the given patterns')),
+              ('A', 'after', None, _('record a copy that has already occurred')),
+              ('f', 'force', None, _('forcibly copy over an existing managed file'))],
+             _('hg copy [OPTION]... [SOURCE]... DEST')),
+    "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
+    "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
+    "debugconfig": (debugconfig, [], _('debugconfig')),
+    "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
+    "debugstate": (debugstate, [], _('debugstate')),
+    "debugdata": (debugdata, [], _('debugdata FILE REV')),
+    "debugindex": (debugindex, [], _('debugindex FILE')),
+    "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
+    "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
     "debugwalk":
         (debugwalk,
-         [('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search')],
-         'debugwalk [OPTION]... [FILE]...'),
+         [('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         _('debugwalk [OPTION]... [FILE]...')),
     "^diff":
         (diff,
-         [('r', 'rev', [], 'revision'),
-          ('a', 'text', None, 'treat all files as text'),
-          ('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search')],
-         'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
+         [('r', 'rev', [], _('revision')),
+          ('a', 'text', None, _('treat all files as text')),
+          ('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
     "^export":
         (export,
-         [('o', 'output', "", 'output to file'),
-          ('a', 'text', None, 'treat all files as text')],
+         [('o', 'output', "", _('print output to file with formatted name')),
+          ('a', 'text', None, _('treat all files as text'))],
          "hg export [-a] [-o OUTFILE] REV..."),
     "forget":
         (forget,
-         [('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search')],
+         [('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
          "hg forget [OPTION]... FILE..."),
     "grep":
         (grep,
-         [('0', 'print0', None, 'end fields with NUL'),
-          ('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'include path in search'),
-          ('', 'all', None, 'print all revisions with matches'),
-          ('i', 'ignore-case', None, 'ignore case when matching'),
-          ('l', 'files-with-matches', None, 'print names of files and revs with matches'),
-          ('n', 'line-number', None, 'print line numbers'),
-          ('r', 'rev', [], 'search in revision rev'),
-          ('u', 'user', None, 'print user who made change')],
+         [('0', 'print0', None, _('end fields with NUL')),
+          ('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('include names matching the given patterns')),
+          ('', 'all', None, _('print all revisions that match')),
+          ('i', 'ignore-case', None, _('ignore case when matching')),
+          ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
+          ('n', 'line-number', None, _('print matching line numbers')),
+          ('r', 'rev', [], _('search in given revision range')),
+          ('u', 'user', None, _('print user who committed change'))],
          "hg grep [OPTION]... PATTERN [FILE]..."),
     "heads":
         (heads,
-         [('b', 'branches', None, 'find branch info')],
-         'hg heads [-b]'),
-    "help": (help_, [], 'hg help [COMMAND]'),
-    "identify|id": (identify, [], 'hg identify'),
+         [('b', 'branches', None, _('find branch info'))],
+         _('hg heads [-b]')),
+    "help": (help_, [], _('hg help [COMMAND]')),
+    "identify|id": (identify, [], _('hg identify')),
     "import|patch":
         (import_,
-         [('p', 'strip', 1, 'path strip'),
-          ('f', 'force', None, 'skip check for outstanding changes'),
-          ('b', 'base', "", 'base path')],
+         [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
+                            _('meaning as the corresponding patch option')),
+          ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
+          ('b', 'base', "", _('base path'))],
          "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
     "incoming|in": (incoming,
-         [('p', 'patch', None, 'show patch')],
-         'hg incoming [-p] [SOURCE]'),
-    "^init": (init, [], 'hg init [DEST]'),
+         [('M', 'no-merges', None, _("do not show merges")),
+          ('p', 'patch', None, _('show patch')),
+          ('n', 'newest-first', None, _('show newest record first'))],
+         _('hg incoming [-p] [-n] [-M] [SOURCE]')),
+    "^init": (init, [], _('hg init [DEST]')),
     "locate":
         (locate,
-         [('r', 'rev', '', 'revision'),
-          ('0', 'print0', None, 'end filenames with NUL'),
-          ('f', 'fullpath', None, 'print complete paths'),
-          ('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search')],
-         'hg locate [OPTION]... [PATTERN]...'),
+         [('r', 'rev', '', _('search the repository as it stood at rev')),
+          ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
+          ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
+          ('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         _('hg locate [OPTION]... [PATTERN]...')),
     "^log|history":
         (log,
-         [('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search'),
-          ('b', 'branch', None, 'show branches'),
-          ('k', 'keyword', [], 'search for a keyword'),
-          ('r', 'rev', [], 'revision'),
-          ('p', 'patch', None, 'show patch')],
-         'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
-    "manifest": (manifest, [], 'hg manifest [REV]'),
+         [('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns')),
+          ('b', 'branch', None, _('show branches')),
+          ('k', 'keyword', [], _('search for a keyword')),
+          ('r', 'rev', [], _('show the specified revision or range')),
+          ('M', 'no-merges', None, _("do not show merges")),
+          ('m', 'only-merges', None, _("show only merges")),
+          ('p', 'patch', None, _('show patch'))],
+         _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
+    "manifest": (manifest, [], _('hg manifest [REV]')),
     "outgoing|out": (outgoing,
-         [('p', 'patch', None, 'show patch')],
-         'hg outgoing [-p] [DEST]'),
-    "parents": (parents, [], 'hg parents [REV]'),
-    "paths": (paths, [], 'hg paths [NAME]'),
+         [('M', 'no-merges', None, _("do not show merges")),
+          ('p', 'patch', None, _('show patch')),
+          ('n', 'newest-first', None, _('show newest record first'))],
+         _('hg outgoing [-p] [-n] [-M] [DEST]')),
+    "parents": (parents, [], _('hg parents [REV]')),
+    "paths": (paths, [], _('hg paths [NAME]')),
     "^pull":
         (pull,
-         [('u', 'update', None, 'update working directory'),
-          ('e', 'ssh', "", 'ssh command'),
-          ('', 'remotecmd', "", 'remote hg command'),
-          ('r', 'rev', [], 'a specific revision you would like to pull')],
-         'hg pull [-u] [-e FILE] [--remotecmd FILE] [-r rev]... [SOURCE]'),
+         [('u', 'update', None, _('update the working directory to tip after pull')),
+          ('e', 'ssh', "", _('specify ssh command to use')),
+          ('r', 'rev', [], _('a specific revision you would like to pull')),
+          ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
+         _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
     "^push":
         (push,
-         [('f', 'force', None, 'force push'),
-          ('e', 'ssh', "", 'ssh command'),
-          ('', 'remotecmd', "", 'remote hg command')],
-         'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
+         [('f', 'force', None, _('force push')),
+          ('e', 'ssh', "", _('specify ssh command to use')),
+          ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
+         _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
     "rawcommit":
         (rawcommit,
-         [('p', 'parent', [], 'parent'),
-          ('d', 'date', "", 'date code'),
-          ('u', 'user', "", 'user'),
-          ('F', 'files', "", 'file list'),
-          ('m', 'message', "", 'commit message'),
-          ('t', 'text', "", 'commit message (deprecated: use -m)'),
-          ('l', 'logfile', "", 'commit message file')],
-         'hg rawcommit [OPTION]... [FILE]...'),
-    "recover": (recover, [], "hg recover"),
+         [('p', 'parent', [], _('parent')),
+          ('d', 'date', "", _('date code')),
+          ('u', 'user', "", _('user')),
+          ('F', 'files', "", _('file list')),
+          ('m', 'message', "", _('commit message')),
+          ('t', 'text', "", _('commit message (deprecated: use -m)')),
+          ('l', 'logfile', "", _('commit message file'))],
+         _('hg rawcommit [OPTION]... [FILE]...')),
+    "recover": (recover, [], _("hg recover")),
     "^remove|rm": (remove,
-                   [('I', 'include', [], 'include path in search'),
-                    ('X', 'exclude', [], 'exclude path from search')],
-                   "hg remove [OPTION]... FILE..."),
+                   [('I', 'include', [], _('include names matching the given patterns')),
+                    ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+                   _("hg remove [OPTION]... FILE...")),
     "rename|mv": (rename,
-                  [('I', 'include', [], 'include path in search'),
-                   ('X', 'exclude', [], 'exclude path from search'),
-                   ('A', 'after', None, 'record a copy after it has happened'),
-                   ('f', 'force', None, 'replace destination if it exists'),
-                   ('p', 'parents', None, 'append source path to dest')],
-                  'hg rename [OPTION]... [SOURCE]... DEST'),
+                  [('I', 'include', [], _('include names matching the given patterns')),
+                   ('X', 'exclude', [], _('exclude names matching the given patterns')),
+                   ('A', 'after', None, _('record a rename that has already occurred')),
+                   ('f', 'force', None, _('forcibly copy over an existing managed file'))],
+                  _('hg rename [OPTION]... [SOURCE]... DEST')),
     "^revert":
         (revert,
-         [("n", "nonrecursive", None, "don't recurse into subdirs"),
-          ("r", "rev", "", "revision")],
-         "hg revert [-n] [-r REV] [NAME]..."),
-    "root": (root, [], "hg root"),
+         [("n", "nonrecursive", None, _("do not recurse into subdirectories")),
+          ("r", "rev", "", _("revision to revert to"))],
+         _("hg revert [-n] [-r REV] [NAME]...")),
+    "root": (root, [], _("hg root")),
     "^serve":
         (serve,
-         [('A', 'accesslog', '', 'access log file'),
-          ('E', 'errorlog', '', 'error log file'),
-          ('p', 'port', 0, 'listen port'),
-          ('a', 'address', '', 'interface address'),
-          ('n', 'name', "", 'repository name'),
-          ('', 'stdio', None, 'for remote clients'),
-          ('t', 'templates', "", 'template directory'),
-          ('', 'style', "", 'template style'),
-          ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
-         "hg serve [OPTION]..."),
+         [('A', 'accesslog', '', _('name of access log file to write to')),
+          ('E', 'errorlog', '', _('name of error log file to write to')),
+          ('p', 'port', 0, _('port to use (default: 8000)')),
+          ('a', 'address', '', _('address to use')),
+          ('n', 'name', "", _('name to show in web pages (default: working dir)')),
+          ('', 'stdio', None, _('for remote clients')),
+          ('t', 'templates', "", _('web templates to use')),
+          ('', 'style', "", _('template style to use')),
+          ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
+         _("hg serve [OPTION]...")),
     "^status":
         (status,
-         [('m', 'modified', None, 'show only modified files'),
-          ('a', 'added', None, 'show only added files'),
-          ('r', 'removed', None, 'show only removed files'),
-          ('u', 'unknown', None, 'show only unknown (not tracked) files'),
-          ('n', 'no-status', None, 'hide status prefix'),
-          ('0', 'print0', None, 'end filenames with NUL'),
-          ('I', 'include', [], 'include path in search'),
-          ('X', 'exclude', [], 'exclude path from search')],
-         "hg status [OPTION]... [FILE]..."),
+         [('m', 'modified', None, _('show only modified files')),
+          ('a', 'added', None, _('show only added files')),
+          ('r', 'removed', None, _('show only removed files')),
+          ('u', 'unknown', None, _('show only unknown (not tracked) files')),
+          ('n', 'no-status', None, _('hide status prefix')),
+          ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
+          ('I', 'include', [], _('include names matching the given patterns')),
+          ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+         _("hg status [OPTION]... [FILE]...")),
     "tag":
         (tag,
-         [('l', 'local', None, 'make the tag local'),
-          ('m', 'message', "", 'commit message'),
-          ('t', 'text', "", 'commit message (deprecated: use -m)'),
-          ('d', 'date', "", 'date code'),
-          ('u', 'user', "", 'user')],
-         'hg tag [OPTION]... NAME [REV]'),
-    "tags": (tags, [], 'hg tags'),
-    "tip": (tip, [], 'hg tip'),
+         [('l', 'local', None, _('make the tag local')),
+          ('m', 'message', "", _('message for tag commit log entry')),
+          ('t', 'text', "", _('commit message (deprecated: use -m)')),
+          ('d', 'date', "", _('record datecode as commit date')),
+          ('u', 'user', "", _('record user as commiter'))],
+         _('hg tag [OPTION]... NAME [REV]')),
+    "tags": (tags, [], _('hg tags')),
+    "tip": (tip, [], _('hg tip')),
     "unbundle":
         (unbundle,
          [],
-         'hg unbundle FILE'),
-    "undo": (undo, [], 'hg undo'),
+         _('hg unbundle FILE')),
+    "undo": (undo, [], _('hg undo')),
     "^update|up|checkout|co":
         (update,
-         [('b', 'branch', "", 'checkout the head of a specific branch'),
-          ('m', 'merge', None, 'allow merging of conflicts'),
-          ('C', 'clean', None, 'overwrite locally modified files')],
-         'hg update [-b TAG] [-m] [-C] [REV]'),
-    "verify": (verify, [], 'hg verify'),
-    "version": (show_version, [], 'hg version'),
+         [('b', 'branch', "", _('checkout the head of a specific branch')),
+          ('m', 'merge', None, _('allow merging of branches')),
+          ('C', 'clean', None, _('overwrite locally modified files'))],
+         _('hg update [-b TAG] [-m] [-C] [REV]')),
+    "verify": (verify, [], _('hg verify')),
+    "version": (show_version, [], _('hg version')),
 }
 
 globalopts = [
-    ('R', 'repository', "", 'repository root directory'),
-    ('', 'cwd', '', 'change working directory'),
-    ('y', 'noninteractive', None, 'run non-interactively'),
-    ('q', 'quiet', None, 'quiet mode'),
-    ('v', 'verbose', None, 'verbose mode'),
-    ('', 'debug', None, 'debug mode'),
-    ('', 'debugger', None, 'start debugger'),
-    ('', 'traceback', None, 'print traceback on exception'),
-    ('', 'time', None, 'time how long the command takes'),
-    ('', 'profile', None, 'profile'),
-    ('', 'version', None, 'output version information and exit'),
-    ('h', 'help', None, 'display help and exit'),
+    ('R', 'repository', "", _("repository root directory")),
+    ('', 'cwd', '', _("change working directory")),
+    ('y', 'noninteractive', None, _("do not prompt, assume 'yes' for any required answers")),
+    ('q', 'quiet', None, _("suppress output")),
+    ('v', 'verbose', None, _("enable additional output")),
+    ('', 'debug', None, _("enable debugging output")),
+    ('', 'debugger', None, _("start debugger")),
+    ('', 'traceback', None, _("print traceback on exception")),
+    ('', 'time', None, _("time how long the command takes")),
+    ('', 'profile', None, _("print command execution profile")),
+    ('', 'version', None, _("output version information and exit")),
+    ('h', 'help', None, _("display help and exit")),
 ]
 
 norepo = ("clone init version help debugancestor debugconfig debugdata"
@@ -2022,7 +2437,7 @@
 class ParseError(Exception):
     """Exception raised on errors in parsing the command line."""
 
-def parse(args):
+def parse(ui, args):
     options = {}
     cmdoptions = {}
 
@@ -2033,6 +2448,17 @@
 
     if args:
         cmd, args = args[0], args[1:]
+        defaults = ui.config("defaults", cmd)
+        if defaults:
+            # reparse with command defaults added
+            args = [cmd] + defaults.split() + args
+            try:
+                args = fancyopts.fancyopts(args, globalopts, options)
+            except fancyopts.getopt.GetoptError, inst:
+                raise ParseError(None, inst)
+
+            cmd, args = args[0], args[1:]
+
         i = find(cmd)[1]
         c = list(i[1])
     else:
@@ -2066,11 +2492,16 @@
     u = ui.ui()
     external = []
     for x in u.extensions():
+        def on_exception(Exception, inst):
+            u.warn(_("*** failed to import extension %s\n") % x[1])
+            u.warn("%s\n" % inst)
+            if "--traceback" in sys.argv[1:]:
+                traceback.print_exc()
         if x[1]:
             try:
                 mod = imp.load_source(x[0], x[1])
-            except:
-                u.warn("*** failed to import extension %s\n" % x[1])
+            except Exception, inst:
+                on_exception(Exception, inst)
                 continue
         else:
             def importh(name):
@@ -2081,8 +2512,8 @@
                 return mod
             try:
                 mod = importh(x[0])
-            except:
-                u.warn("failed to import extension %s\n" % x[0])
+            except Exception, inst:
+                on_exception(Exception, inst)
                 continue
 
         external.append(mod)
@@ -2090,21 +2521,21 @@
         cmdtable = getattr(x, 'cmdtable', {})
         for t in cmdtable:
             if t in table:
-                u.warn("module %s overrides %s\n" % (x.__name__, t))
+                u.warn(_("module %s overrides %s\n") % (x.__name__, t))
         table.update(cmdtable)
 
     try:
-        cmd, func, args, options, cmdoptions = parse(args)
+        cmd, func, args, options, cmdoptions = parse(u, args)
     except ParseError, inst:
         if inst.args[0]:
-            u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
+            u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
             help_(u, inst.args[0])
         else:
-            u.warn("hg: %s\n" % inst.args[1])
+            u.warn(_("hg: %s\n") % inst.args[1])
             help_(u, 'shortlist')
         sys.exit(-1)
     except UnknownCommand, inst:
-        u.warn("hg: unknown command '%s'\n" % inst.args[0])
+        u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
         help_(u, 'shortlist')
         sys.exit(1)
 
@@ -2117,7 +2548,7 @@
         s = get_times()
         def print_time():
             t = get_times()
-            u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
+            u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
                 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
         atexit.register(print_time)
 
@@ -2176,42 +2607,42 @@
                 traceback.print_exc()
             raise
     except hg.RepoError, inst:
-        u.warn("abort: ", inst, "!\n")
+        u.warn(_("abort: "), inst, "!\n")
     except revlog.RevlogError, inst:
-        u.warn("abort: ", inst, "!\n")
+        u.warn(_("abort: "), inst, "!\n")
     except SignalInterrupt:
-        u.warn("killed!\n")
+        u.warn(_("killed!\n"))
     except KeyboardInterrupt:
         try:
-            u.warn("interrupted!\n")
+            u.warn(_("interrupted!\n"))
         except IOError, inst:
             if inst.errno == errno.EPIPE:
                 if u.debugflag:
-                    u.warn("\nbroken pipe\n")
+                    u.warn(_("\nbroken pipe\n"))
             else:
                 raise
     except IOError, inst:
         if hasattr(inst, "code"):
-            u.warn("abort: %s\n" % inst)
+            u.warn(_("abort: %s\n") % inst)
         elif hasattr(inst, "reason"):
-            u.warn("abort: error: %s\n" % inst.reason[1])
+            u.warn(_("abort: error: %s\n") % inst.reason[1])
         elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
             if u.debugflag:
-                u.warn("broken pipe\n")
+                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)
+                u.warn(_("abort: %s\n") % inst.strerror)
         else:
             raise
     except OSError, inst:
         if hasattr(inst, "filename"):
-            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)
+            u.warn(_("abort: %s\n") % inst.strerror)
     except util.Abort, inst:
-        u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
+        u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
         sys.exit(1)
     except TypeError, inst:
         # was this an argument error?
@@ -2219,17 +2650,17 @@
         if len(tb) > 2: # no
             raise
         u.debug(inst, "\n")
-        u.warn("%s: invalid arguments\n" % cmd)
+        u.warn(_("%s: invalid arguments\n") % cmd)
         help_(u, cmd)
     except UnknownCommand, inst:
-        u.warn("hg: unknown command '%s'\n" % inst.args[0])
+        u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
         help_(u, 'shortlist')
     except SystemExit:
         # don't catch this in the catch-all below
         raise
     except:
-        u.warn("** unknown exception encountered, details follow\n")
-        u.warn("** report bug details to mercurial@selenic.com\n")
+        u.warn(_("** unknown exception encountered, details follow\n"))
+        u.warn(_("** report bug details to mercurial@selenic.com\n"))
         raise
 
     sys.exit(-1)
--- a/mercurial/dirstate.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/dirstate.py	Thu Oct 27 12:26:16 2005 -0700
@@ -9,6 +9,7 @@
 
 import struct, os
 from node import *
+from i18n import gettext as _
 from demandload import *
 demandload(globals(), "time bisect stat util re")
 
@@ -67,7 +68,7 @@
                     try:
                         syntax = syntaxes[s]
                     except KeyError:
-                        self.ui.warn("ignoring invalid syntax '%s'\n" % s)
+                        self.ui.warn(_("ignoring invalid syntax '%s'\n") % s)
                     continue
                 pat = syntax + line
                 for s in syntaxes.values():
@@ -117,6 +118,8 @@
             self.dirty = 1
 
     def setparents(self, p1, p2=nullid):
+        if not self.pl:
+            self.read()
         self.markdirty()
         self.pl = p1, p2
 
@@ -187,7 +190,7 @@
             try:
                 del self.map[f]
             except KeyError:
-                self.ui.warn("not in dirstate: %s!\n" % f)
+                self.ui.warn(_("not in dirstate: %s!\n") % f)
                 pass
 
     def clear(self):
@@ -268,6 +271,22 @@
     # directly by this function, but might be modified by your statmatch call.
     #
     def walkhelper(self, files, statmatch, dc):
+        def supported_type(f, st):
+            if stat.S_ISREG(st.st_mode):
+                return True
+            else:
+                kind = 'unknown'
+                if stat.S_ISCHR(st.st_mode): kind = _('character device')
+                elif stat.S_ISBLK(st.st_mode): kind = _('block device')
+                elif stat.S_ISFIFO(st.st_mode): kind = _('fifo')
+                elif stat.S_ISLNK(st.st_mode): kind = _('symbolic link')
+                elif stat.S_ISSOCK(st.st_mode): kind = _('socket')
+                elif stat.S_ISDIR(st.st_mode): kind = _('directory')
+                self.ui.warn(_('%s: unsupported file type (type is %s)\n') % (
+                    util.pathto(self.getcwd(), f),
+                    kind))
+                return False
+
         # recursion free walker, faster than os.walk.
         def findfiles(s):
             retfiles = []
@@ -290,9 +309,9 @@
                         ds = os.path.join(nd, f +'/')
                         if statmatch(ds, st):
                             work.append(p)
-                    else:
-                        if statmatch(np, st):
-                            yield util.pconvert(np)
+                    elif statmatch(np, st) and supported_type(np, st):
+                        yield util.pconvert(np)
+
 
         known = {'.hg': 1}
         def seen(fn):
@@ -315,27 +334,17 @@
                 sorted.sort()
                 for fl in sorted:
                     yield 'f', fl
-            elif stat.S_ISREG(st.st_mode):
+            else:
                 ff = util.normpath(ff)
                 if seen(ff):
                     continue
                 found = False
                 self.blockignore = True
-                if statmatch(ff, st):
+                if statmatch(ff, st) and supported_type(ff, st):
                     found = True
                 self.blockignore = False
                 if found:
                     yield 'f', ff
-            else:
-                kind = 'unknown'
-                if stat.S_ISCHR(st.st_mode): kind = 'character device'
-                elif stat.S_ISBLK(st.st_mode): kind = 'block device'
-                elif stat.S_ISFIFO(st.st_mode): kind = 'fifo'
-                elif stat.S_ISLNK(st.st_mode): kind = 'symbolic link'
-                elif stat.S_ISSOCK(st.st_mode): kind = 'socket'
-                self.ui.warn('%s: unsupported file type (type is %s)\n' % (
-                    util.pathto(self.getcwd(), ff),
-                    kind))
 
         # step two run through anything left in the dc hash and yield
         # if we haven't already seen it
@@ -368,8 +377,6 @@
                 if self.ignore(fn): return False
                 return match(fn)
 
-            if not stat.S_ISREG(s.st_mode):
-                return False
             c = dc.pop(fn, None)
             if c:
                 type, mode, size, time = c
--- a/mercurial/hgweb.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/hgweb.py	Thu Oct 27 12:26:16 2005 -0700
@@ -10,7 +10,9 @@
 from demandload import demandload
 demandload(globals(), "mdiff time re socket zlib errno ui hg ConfigParser")
 demandload(globals(), "zipfile tempfile StringIO tarfile BaseHTTPServer util")
+demandload(globals(), "mimetypes")
 from node import *
+from i18n import gettext as _
 
 def templatepath():
     for f in "templates", "../templates":
@@ -61,12 +63,20 @@
         return "/"
     return up + "/"
 
+def get_mtime(repo_path):
+    hg_path = os.path.join(repo_path, ".hg")
+    cl_path = os.path.join(hg_path, "00changelog.i")
+    if os.path.exists(os.path.join(cl_path)):
+        return os.stat(cl_path).st_mtime
+    else:
+        return os.stat(hg_path).st_mtime
+
 class hgrequest:
     def __init__(self, inp=None, out=None, env=None):
         self.inp = inp or sys.stdin
         self.out = out or sys.stdout
         self.env = env or os.environ
-        self.form = cgi.parse(self.inp, self.env)
+        self.form = cgi.parse(self.inp, self.env, keep_blank_values=1)
 
     def write(self, *things):
         for thing in things:
@@ -111,7 +121,7 @@
                 if m:
                     self.map[m.group(1)] = os.path.join(self.base, m.group(2))
                 else:
-                    raise LookupError("unknown map entry '%s'" % l)
+                    raise LookupError(_("unknown map entry '%s'") % l)
 
     def __call__(self, t, **map):
         m = self.defaults.copy()
@@ -154,6 +164,8 @@
 
 common_filters = {
     "escape": cgi.escape,
+    "strip": lambda x: x.strip(),
+    "rstrip": lambda x: x.rstrip(),
     "age": age,
     "date": lambda x: util.datestr(x),
     "addbreaks": nl2br,
@@ -176,9 +188,9 @@
         self.archives = 'zip', 'gz', 'bz2'
 
     def refresh(self):
-        s = os.stat(os.path.join(self.repo.root, ".hg", "00changelog.i"))
-        if s.st_mtime != self.mtime:
-            self.mtime = s.st_mtime
+        mtime = get_mtime(self.repo.root)
+        if mtime != self.mtime:
+            self.mtime = mtime
             self.repo = hg.repository(self.repo.ui, self.repo.root)
             self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10))
             self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10))
@@ -196,12 +208,14 @@
         if len(files) > self.maxfiles:
             yield self.t("fileellipses")
 
-    def parents(self, t1, nodes=[], rev=None,**args):
+    def parents(self, node, parents=[], rev=None, hide=False, **args):
         if not rev:
             rev = lambda x: ""
-        for node in nodes:
-            if node != nullid:
-                yield self.t(t1, node=hex(node), rev=rev(node), **args)
+        parents = [p for p in parents if p != nullid]
+        if hide and len(parents) == 1 and rev(parents[0]) == rev(node) - 1:
+            return
+        for p in parents:
+            yield dict(node=hex(p), rev=rev(p), **args)
 
     def showtag(self, t1, node=nullid, **args):
         for t in self.repo.nodetags(node):
@@ -290,7 +304,7 @@
             for label, rev in l:
                 yield {"label": label, "rev": rev}
 
-            yield {"label": "tip", "rev": ""}
+            yield {"label": "tip", "rev": "tip"}
 
         def changelist(**map):
             parity = (start - end) & 1
@@ -303,8 +317,8 @@
 
                 l.insert(0, {"parity": parity,
                              "author": changes[1],
-                             "parent": self.parents("changelogparent",
-                                                    cl.parents(n), cl.rev),
+                             "parent": self.parents(n, cl.parents(n), cl.rev,
+                                                    hide=True),
                              "changelogtag": self.showtag("changelogtag",n),
                              "manifest": hex(changes[0]),
                              "desc": changes[4],
@@ -364,8 +378,7 @@
                 yield self.t('searchentry',
                              parity=count & 1,
                              author=changes[1],
-                             parent=self.parents("changelogparent",
-                                                 cl.parents(n), cl.rev),
+                             parent=self.parents(n, cl.parents(n), cl.rev),
                              changelogtag=self.showtag("changelogtag",n),
                              manifest=hex(changes[0]),
                              desc=changes[4],
@@ -410,8 +423,7 @@
                      diff=diff,
                      rev=cl.rev(n),
                      node=nodeid,
-                     parent=self.parents("changesetparent",
-                                         cl.parents(n), cl.rev),
+                     parent=self.parents(n, cl.parents(n), cl.rev),
                      changesettag=self.showtag("changesettag",n),
                      manifest=hex(changes[0]),
                      author=changes[1],
@@ -443,8 +455,7 @@
                              "node": hex(cn),
                              "author": cs[1],
                              "date": cs[2],
-                             "parent": self.parents("filelogparent",
-                                                    fl.parents(n),
+                             "parent": self.parents(n, fl.parents(n),
                                                     fl.rev, file=f),
                              "desc": cs[4]})
                 parity = 1 - parity
@@ -465,6 +476,11 @@
         cs = cl.read(cn)
         mfn = cs[0]
 
+        mt = mimetypes.guess_type(f)[0]
+        rawtext = text
+        if util.binary(text):
+            text = "(binary:%s)" % mt
+
         def lines():
             for l, t in enumerate(text.splitlines(1)):
                 yield {"line": t,
@@ -476,13 +492,14 @@
                      filenode=node,
                      path=up(f),
                      text=lines(),
+                     raw=rawtext,
+                     mimetype=mt,
                      rev=changerev,
                      node=hex(cn),
                      manifest=hex(mfn),
                      author=cs[1],
                      date=cs[2],
-                     parent=self.parents("filerevparent",
-                                         fl.parents(n), fl.rev, file=f),
+                     parent=self.parents(n, fl.parents(n), fl.rev, file=f),
                      permissions=self.repo.manifest.readflags(mfn)[f])
 
     def fileannotate(self, f, node):
@@ -534,8 +551,7 @@
                      manifest=hex(mfn),
                      author=cs[1],
                      date=cs[2],
-                     parent=self.parents("fileannotateparent",
-                                         fl.parents(n), fl.rev, file=f),
+                     parent=self.parents(n, fl.parents(n), fl.rev, file=f),
                      permissions=self.repo.manifest.readflags(mfn)[f])
 
     def manifest(self, mnode, path):
@@ -639,8 +655,7 @@
                      filenode=hex(mf.get(file, nullid)),
                      node=changeset,
                      rev=self.repo.changelog.rev(n),
-                     parent=self.parents("filediffparent",
-                                         cl.parents(n), cl.rev),
+                     parent=self.parents(n, cl.parents(n), cl.rev),
                      diff=diff)
 
     def archive(self, req, cnode, type):
@@ -704,8 +719,32 @@
         def footer(**map):
             yield self.t("footer", **map)
 
+        def expand_form(form):
+            shortcuts = {
+                'cl': [('cmd', ['changelog']), ('rev', None)],
+                'cs': [('cmd', ['changeset']), ('node', None)],
+                'f': [('cmd', ['file']), ('filenode', None)],
+                'fl': [('cmd', ['filelog']), ('filenode', None)],
+                'fd': [('cmd', ['filediff']), ('node', None)],
+                'fa': [('cmd', ['annotate']), ('filenode', None)],
+                'mf': [('cmd', ['manifest']), ('manifest', None)],
+                'ca': [('cmd', ['archive']), ('node', None)],
+                'tags': [('cmd', ['tags'])],
+                'tip': [('cmd', ['changeset']), ('node', ['tip'])],
+            }
+
+            for k in shortcuts.iterkeys():
+                if form.has_key(k):
+                    for name, value in shortcuts[k]:
+                        if value is None:
+                            value = form[k]
+                        form[name] = value
+                    del form[k]
+
         self.refresh()
 
+        expand_form(req.form)
+
         t = self.repo.ui.config("web", "templates", templatepath())
         m = os.path.join(t, "map")
         style = self.repo.ui.config("web", "style", "")
@@ -843,7 +882,7 @@
 
         def __init__(self, *args, **kwargs):
             if self.address_family is None:
-                raise hg.RepoError('IPv6 not available on this system')
+                raise hg.RepoError(_('IPv6 not available on this system'))
             BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
 
     class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler):
@@ -960,9 +999,7 @@
                        .replace("//", "/"))
 
                 # update time with local timezone
-                d = (os.stat(os.path.join(path,
-                                          ".hg", "00changelog.d")).st_mtime,
-                     util.makedate()[1])
+                d = (get_mtime(path), util.makedate()[1])
 
                 yield dict(contact=(get("ui", "username") or # preferred
                                     get("web", "contact") or # deprecated
--- a/mercurial/httprepo.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/httprepo.py	Thu Oct 27 12:26:16 2005 -0700
@@ -7,6 +7,7 @@
 
 from node import *
 from remoterepo import *
+from i18n import gettext as _
 from demandload import *
 demandload(globals(), "hg os urllib urllib2 urlparse zlib util")
 
@@ -67,7 +68,7 @@
         return -1
 
     def do_cmd(self, cmd, **args):
-        self.ui.debug("sending %s command\n" % cmd)
+        self.ui.debug(_("sending %s command\n") % cmd)
         q = {"cmd": cmd}
         q.update(args)
         qs = urllib.urlencode(q)
@@ -79,13 +80,13 @@
         if not proto.startswith('application/mercurial') and \
                not proto.startswith('text/plain') and \
                not proto.startswith('application/hg-changegroup'):
-            raise hg.RepoError("'%s' does not appear to be an hg repository" %
+            raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
                                self.url)
 
         if proto.startswith('application/mercurial'):
             version = proto[22:]
             if float(version) > 0.1:
-                raise hg.RepoError("'%s' uses newer protocol %s" %
+                raise hg.RepoError(_("'%s' uses newer protocol %s") %
                                    (self.url, version))
 
         return resp
@@ -95,7 +96,7 @@
         try:
             return map(bin, d[:-1].split(" "))
         except:
-            self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
+            self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
             raise
 
     def branches(self, nodes):
@@ -105,7 +106,7 @@
             br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
             return br
         except:
-            self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
+            self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
             raise
 
     def between(self, pairs):
@@ -115,7 +116,7 @@
             p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
             return p
         except:
-            self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n")
+            self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
             raise
 
     def changegroup(self, nodes):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/i18n.py	Thu Oct 27 12:26:16 2005 -0700
@@ -0,0 +1,15 @@
+"""
+i18n.py - internationalization support for mercurial
+
+Copyright 2005 Matt Mackall <mpm@selenic.com>
+
+This software may be used and distributed according to the terms
+of the GNU General Public License, incorporated herein by reference.
+"""
+
+# the import from gettext is _really_ slow
+# for now we use a dummy function
+gettext = lambda x: x
+#import gettext
+#t = gettext.translation('hg', '/usr/share/locale', fallback=1)
+#gettext = t.gettext
--- a/mercurial/localrepo.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/localrepo.py	Thu Oct 27 12:26:16 2005 -0700
@@ -8,6 +8,7 @@
 import struct, os, util
 import filelog, manifest, changelog, dirstate, repo
 from node import *
+from i18n import gettext as _
 from demandload import *
 demandload(globals(), "re lock transaction tempfile stat mdiff errno")
 
@@ -18,12 +19,12 @@
             while not os.path.isdir(os.path.join(p, ".hg")):
                 oldp = p
                 p = os.path.dirname(p)
-                if p == oldp: raise repo.RepoError("no repo found")
+                if p == oldp: raise repo.RepoError(_("no repo found"))
             path = p
         self.path = os.path.join(path, ".hg")
 
         if not create and not os.path.isdir(self.path):
-            raise repo.RepoError("repository %s not found" % self.path)
+            raise repo.RepoError(_("repository %s not found") % self.path)
 
         self.root = os.path.abspath(path)
         self.ui = ui
@@ -48,7 +49,7 @@
     def hook(self, name, **args):
         s = self.ui.config("hooks", name)
         if s:
-            self.ui.note("running hook %s: %s\n" % (name, s))
+            self.ui.note(_("running hook %s: %s\n") % (name, s))
             old = {}
             for k, v in args.items():
                 k = k.upper()
@@ -68,7 +69,7 @@
                     del os.environ[k]
 
             if r:
-                self.ui.warn("abort: %s hook failed with status %d!\n" %
+                self.ui.warn(_("abort: %s hook failed with status %d!\n") %
                              (name, r))
                 return False
         return True
@@ -138,7 +139,7 @@
             try:
                 return self.changelog.lookup(key)
             except:
-                raise repo.RepoError("unknown revision '%s'" % key)
+                raise repo.RepoError(_("unknown revision '%s'") % key)
 
     def dev(self):
         return os.stat(self.path).st_dev
@@ -174,7 +175,7 @@
 
         for mf, cmd in self.encodepats:
             if mf(filename):
-                self.ui.debug("filtering %s through %s\n" % (filename, cmd))
+                self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
                 data = util.filter(data, cmd)
                 break
 
@@ -190,7 +191,7 @@
 
         for mf, cmd in self.decodepats:
             if mf(filename):
-                self.ui.debug("filtering %s through %s\n" % (filename, cmd))
+                self.ui.debug(_("filtering %s through %s\n") % (filename, cmd))
                 data = util.filter(data, cmd)
                 break
 
@@ -217,28 +218,28 @@
     def recover(self):
         lock = self.lock()
         if os.path.exists(self.join("journal")):
-            self.ui.status("rolling back interrupted transaction\n")
+            self.ui.status(_("rolling back interrupted transaction\n"))
             return transaction.rollback(self.opener, self.join("journal"))
         else:
-            self.ui.warn("no interrupted transaction available\n")
+            self.ui.warn(_("no interrupted transaction available\n"))
 
     def undo(self):
         lock = self.lock()
         if os.path.exists(self.join("undo")):
-            self.ui.status("rolling back last transaction\n")
+            self.ui.status(_("rolling back last transaction\n"))
             transaction.rollback(self.opener, self.join("undo"))
             self.dirstate = None
             util.rename(self.join("undo.dirstate"), self.join("dirstate"))
             self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
         else:
-            self.ui.warn("no undo information available\n")
+            self.ui.warn(_("no undo information available\n"))
 
     def lock(self, wait=1):
         try:
             return lock.lock(self.join("lock"), 0)
         except lock.LockHeld, inst:
             if wait:
-                self.ui.warn("waiting for lock held by %s\n" % inst.args[0])
+                self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0])
                 return lock.lock(self.join("lock"), wait)
             raise inst
 
@@ -326,7 +327,7 @@
                 elif s == 'r':
                     remove.append(f)
                 else:
-                    self.ui.warn("%s not tracked!\n" % f)
+                    self.ui.warn(_("%s not tracked!\n") % f)
         else:
             (c, a, d, u) = self.changes(match=match)
             commit = c + a
@@ -340,7 +341,7 @@
         m2 = self.manifest.read(c2[0])
 
         if not commit and not remove and not force and p2 == nullid:
-            self.ui.status("nothing changed\n")
+            self.ui.status(_("nothing changed\n"))
             return None
 
         if not self.hook("precommit"):
@@ -359,7 +360,7 @@
                 mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False))
                 t = self.wread(f)
             except IOError:
-                self.ui.warn("trouble committing %s!\n" % f)
+                self.ui.warn(_("trouble committing %s!\n") % f)
                 raise
 
             r = self.file(f)
@@ -369,7 +370,7 @@
             if cp:
                 meta["copy"] = cp
                 meta["copyrev"] = hex(m1.get(cp, m2.get(cp, nullid)))
-                self.ui.debug(" %s: copy %s:%s\n" % (f, cp, meta["copyrev"]))
+                self.ui.debug(_(" %s: copy %s:%s\n") % (f, cp, meta["copyrev"]))
                 fp1, fp2 = nullid, nullid
             else:
                 fp1 = m1.get(f, nullid)
@@ -520,40 +521,66 @@
         for f in list:
             p = self.wjoin(f)
             if not os.path.exists(p):
-                self.ui.warn("%s does not exist!\n" % f)
+                self.ui.warn(_("%s does not exist!\n") % f)
             elif not os.path.isfile(p):
-                self.ui.warn("%s not added: only files supported currently\n" % f)
+                self.ui.warn(_("%s not added: only files supported currently\n") % f)
             elif self.dirstate.state(f) in 'an':
-                self.ui.warn("%s already tracked!\n" % f)
+                self.ui.warn(_("%s already tracked!\n") % f)
             else:
                 self.dirstate.update([f], "a")
 
     def forget(self, list):
         for f in list:
             if self.dirstate.state(f) not in 'ai':
-                self.ui.warn("%s not added!\n" % f)
+                self.ui.warn(_("%s not added!\n") % f)
             else:
                 self.dirstate.forget([f])
 
-    def remove(self, list):
+    def remove(self, list, unlink=False):
+        if unlink:
+            for f in list:
+                try:
+                    util.unlink(self.wjoin(f))
+                except OSError, inst:
+                    if inst.errno != errno.ENOENT: raise
         for f in list:
             p = self.wjoin(f)
             if os.path.exists(p):
-                self.ui.warn("%s still exists!\n" % f)
+                self.ui.warn(_("%s still exists!\n") % f)
             elif self.dirstate.state(f) == 'a':
-                self.ui.warn("%s never committed!\n" % f)
+                self.ui.warn(_("%s never committed!\n") % f)
                 self.dirstate.forget([f])
             elif f not in self.dirstate:
-                self.ui.warn("%s not tracked!\n" % f)
+                self.ui.warn(_("%s not tracked!\n") % f)
             else:
                 self.dirstate.update([f], "r")
 
+    def undelete(self, list):
+        p = self.dirstate.parents()[0]
+        mn = self.changelog.read(p)[0]
+        mf = self.manifest.readflags(mn)
+        m = self.manifest.read(mn)
+        for f in list:
+            if self.dirstate.state(f) not in  "r":
+                self.ui.warn("%s not removed!\n" % f)
+            else:
+                t = self.file(f).read(m[f])
+                try:
+                    self.wwrite(f, t)
+                except IOError, e:
+                    if e.errno != errno.ENOENT:
+                        raise
+                    os.makedirs(os.path.dirname(self.wjoin(f)))
+                    self.wwrite(f, t)
+                util.set_exec(self.wjoin(f), mf[f])
+                self.dirstate.update([f], "n")
+
     def copy(self, source, dest):
         p = self.wjoin(dest)
         if not os.path.exists(p):
-            self.ui.warn("%s does not exist!\n" % dest)
+            self.ui.warn(_("%s does not exist!\n") % dest)
         elif not os.path.isfile(p):
-            self.ui.warn("copy failed: %s is not a file\n" % dest)
+            self.ui.warn(_("copy failed: %s is not a file\n") % dest)
         else:
             if self.dirstate.state(dest) == '?':
                 self.dirstate.update([dest], "a")
@@ -711,7 +738,7 @@
 
         # assume we're closer to the tip than the root
         # and start by examining the heads
-        self.ui.status("searching for changes\n")
+        self.ui.status(_("searching for changes\n"))
 
         if not heads:
             heads = remote.heads()
@@ -741,21 +768,21 @@
                 if n[0] in seen:
                     continue
 
-                self.ui.debug("examining %s:%s\n" % (short(n[0]), short(n[1])))
+                self.ui.debug(_("examining %s:%s\n") % (short(n[0]), short(n[1])))
                 if n[0] == nullid:
                     break
                 if n in seenbranch:
-                    self.ui.debug("branch already found\n")
+                    self.ui.debug(_("branch already found\n"))
                     continue
                 if n[1] and n[1] in m: # do we know the base?
-                    self.ui.debug("found incomplete branch %s:%s\n"
+                    self.ui.debug(_("found incomplete branch %s:%s\n")
                                   % (short(n[0]), short(n[1])))
                     search.append(n) # schedule branch range for scanning
                     seenbranch[n] = 1
                 else:
                     if n[1] not in seen and n[1] not in fetch:
                         if n[2] in m and n[3] in m:
-                            self.ui.debug("found new changeset %s\n" %
+                            self.ui.debug(_("found new changeset %s\n") %
                                           short(n[1]))
                             fetch[n[1]] = 1 # earliest unknown
                             base[n[2]] = 1 # latest known
@@ -770,14 +797,14 @@
 
             if r:
                 reqcnt += 1
-                self.ui.debug("request %d: %s\n" %
+                self.ui.debug(_("request %d: %s\n") %
                             (reqcnt, " ".join(map(short, r))))
                 for p in range(0, len(r), 10):
                     for b in remote.branches(r[p:p+10]):
-                        self.ui.debug("received %s:%s\n" %
+                        self.ui.debug(_("received %s:%s\n") %
                                       (short(b[0]), short(b[1])))
                         if b[0] in m:
-                            self.ui.debug("found base node %s\n" % short(b[0]))
+                            self.ui.debug(_("found base node %s\n") % short(b[0]))
                             base[b[0]] = 1
                         elif b[0] not in seen:
                             unknown.append(b)
@@ -791,15 +818,15 @@
             p = n[0]
             f = 1
             for i in l:
-                self.ui.debug("narrowing %d:%d %s\n" % (f, len(l), short(i)))
+                self.ui.debug(_("narrowing %d:%d %s\n") % (f, len(l), short(i)))
                 if i in m:
                     if f <= 2:
-                        self.ui.debug("found new branch changeset %s\n" %
+                        self.ui.debug(_("found new branch changeset %s\n") %
                                           short(p))
                         fetch[p] = 1
                         base[i] = 1
                     else:
-                        self.ui.debug("narrowed branch search to %s:%s\n"
+                        self.ui.debug(_("narrowed branch search to %s:%s\n")
                                       % (short(p), short(i)))
                         search.append((p, i))
                     break
@@ -808,15 +835,15 @@
         # sanity check our fetch list
         for f in fetch.keys():
             if f in m:
-                raise repo.RepoError("already have changeset " + short(f[:4]))
+                raise repo.RepoError(_("already have changeset ") + short(f[:4]))
 
         if base.keys() == [nullid]:
-            self.ui.warn("warning: pulling from an unrelated repository!\n")
+            self.ui.warn(_("warning: pulling from an unrelated repository!\n"))
 
-        self.ui.note("found new changesets starting at " +
+        self.ui.note(_("found new changesets starting at ") +
                      " ".join([short(f) for f in fetch]) + "\n")
 
-        self.ui.debug("%d total queries\n" % reqcnt)
+        self.ui.debug(_("%d total queries\n") % reqcnt)
 
         return fetch.keys()
 
@@ -825,7 +852,7 @@
             base = {}
             self.findincoming(remote, base, heads)
 
-        self.ui.debug("common changesets up to "
+        self.ui.debug(_("common changesets up to ")
                       + " ".join(map(short, base.keys())) + "\n")
 
         remain = dict.fromkeys(self.changelog.nodemap)
@@ -855,13 +882,13 @@
 
         # if we have an empty repo, fetch everything
         if self.changelog.tip() == nullid:
-            self.ui.status("requesting all changes\n")
+            self.ui.status(_("requesting all changes\n"))
             fetch = [nullid]
         else:
             fetch = self.findincoming(remote)
 
         if not fetch:
-            self.ui.status("no changes found\n")
+            self.ui.status(_("no changes found\n"))
             return 1
 
         if heads is None:
@@ -877,19 +904,19 @@
         heads = remote.heads()
         inc = self.findincoming(remote, base, heads)
         if not force and inc:
-            self.ui.warn("abort: unsynced remote changes!\n")
-            self.ui.status("(did you forget to sync? use push -f to force)\n")
+            self.ui.warn(_("abort: unsynced remote changes!\n"))
+            self.ui.status(_("(did you forget to sync? use push -f to force)\n"))
             return 1
 
         update = self.findoutgoing(remote, base)
         if not update:
-            self.ui.status("no changes found\n")
+            self.ui.status(_("no changes found\n"))
             return 1
         elif not force:
             if len(heads) < len(self.changelog.heads()):
-                self.ui.warn("abort: push creates new remote branches!\n")
-                self.ui.status("(did you forget to merge?" +
-                               " use push -f to force)\n")
+                self.ui.warn(_("abort: push creates new remote branches!\n"))
+                self.ui.status(_("(did you forget to merge?"
+                                 " use push -f to force)\n"))
                 return 1
 
         cg = self.changegroup(update)
@@ -1226,8 +1253,8 @@
             if l <= 4: return ""
             d = source.read(l - 4)
             if len(d) < l - 4:
-                raise repo.RepoError("premature EOF reading chunk" +
-                                     " (got %d bytes, expected %d)"
+                raise repo.RepoError(_("premature EOF reading chunk"
+                                       " (got %d bytes, expected %d)")
                                      % (len(d), l - 4))
             return d
 
@@ -1238,7 +1265,7 @@
                 yield c
 
         def csmap(x):
-            self.ui.debug("add changeset %s\n" % short(x))
+            self.ui.debug(_("add changeset %s\n") % short(x))
             return self.changelog.count()
 
         def revmap(x):
@@ -1252,7 +1279,7 @@
         oldheads = len(self.changelog.heads())
 
         # pull off the changeset group
-        self.ui.status("adding changesets\n")
+        self.ui.status(_("adding changesets\n"))
         co = self.changelog.tip()
         cn = self.changelog.addgroup(getgroup(), csmap, tr, 1) # unique
         cnr, cor = map(self.changelog.rev, (cn, co))
@@ -1261,16 +1288,16 @@
         changesets = cnr - cor
 
         # pull off the manifest group
-        self.ui.status("adding manifests\n")
+        self.ui.status(_("adding manifests\n"))
         mm = self.manifest.tip()
         mo = self.manifest.addgroup(getgroup(), revmap, tr)
 
         # process the files
-        self.ui.status("adding file changes\n")
+        self.ui.status(_("adding file changes\n"))
         while 1:
             f = getchunk()
             if not f: break
-            self.ui.debug("adding %s revisions\n" % f)
+            self.ui.debug(_("adding %s revisions\n") % f)
             fl = self.file(f)
             o = fl.count()
             n = fl.addgroup(getgroup(), revmap, tr)
@@ -1280,18 +1307,18 @@
         newheads = len(self.changelog.heads())
         heads = ""
         if oldheads and newheads > oldheads:
-            heads = " (+%d heads)" % (newheads - oldheads)
+            heads = _(" (+%d heads)") % (newheads - oldheads)
 
-        self.ui.status(("added %d changesets" +
-                        " with %d changes to %d files%s\n")
-                       % (changesets, revisions, files, heads))
+        self.ui.status(_("added %d changesets"
+                         " with %d changes to %d files%s\n")
+                         % (changesets, revisions, files, heads))
 
         tr.close()
 
         if changesets > 0:
             if not self.hook("changegroup",
                               node=hex(self.changelog.node(cor+1))):
-                self.ui.warn("abort: changegroup hook returned failure!\n")
+                self.ui.warn(_("abort: changegroup hook returned failure!\n"))
                 return 1
 
             for i in range(cor + 1, cnr + 1):
@@ -1303,7 +1330,7 @@
                moddirstate=True):
         pl = self.dirstate.parents()
         if not force and pl[1] != nullid:
-            self.ui.warn("aborting: outstanding uncommitted merges\n")
+            self.ui.warn(_("aborting: outstanding uncommitted merges\n"))
             return 1
 
         p1, p2 = pl[0], node
@@ -1326,10 +1353,10 @@
 
         # resolve the manifest to determine which files
         # we care about merging
-        self.ui.note("resolving manifests\n")
-        self.ui.debug(" force %s allow %s moddirstate %s linear %s\n" %
+        self.ui.note(_("resolving manifests\n"))
+        self.ui.debug(_(" force %s allow %s moddirstate %s linear %s\n") %
                       (force, allow, moddirstate, linear_path))
-        self.ui.debug(" ancestor %s local %s remote %s\n" %
+        self.ui.debug(_(" ancestor %s local %s remote %s\n") %
                       (short(man), short(m1n), short(m2n)))
 
         merge = {}
@@ -1375,7 +1402,7 @@
                     a = ma.get(f, nullid)
                     # are both different from the ancestor?
                     if n != a and m2[f] != a:
-                        self.ui.debug(" %s versions differ, resolve\n" % f)
+                        self.ui.debug(_(" %s versions differ, resolve\n") % f)
                         # merge executable bits
                         # "if we changed or they changed, change in merge"
                         a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
@@ -1386,7 +1413,7 @@
                     # is remote's version newer?
                     # or are we going back in time?
                     elif force or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
-                        self.ui.debug(" remote %s is newer, get\n" % f)
+                        self.ui.debug(_(" remote %s is newer, get\n") % f)
                         get[f] = m2[f]
                         s = 1
                 elif f in umap:
@@ -1395,60 +1422,60 @@
 
                 if not s and mfw[f] != mf2[f]:
                     if force:
-                        self.ui.debug(" updating permissions for %s\n" % f)
+                        self.ui.debug(_(" updating permissions for %s\n") % f)
                         util.set_exec(self.wjoin(f), mf2[f])
                     else:
                         a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
                         mode = ((a^b) | (a^c)) ^ a
                         if mode != b:
-                            self.ui.debug(" updating permissions for %s\n" % f)
+                            self.ui.debug(_(" updating permissions for %s\n") % f)
                             util.set_exec(self.wjoin(f), mode)
                 del m2[f]
             elif f in ma:
                 if n != ma[f]:
-                    r = "d"
+                    r = _("d")
                     if not force and (linear_path or allow):
                         r = self.ui.prompt(
-                            (" local changed %s which remote deleted\n" % f) +
-                            "(k)eep or (d)elete?", "[kd]", "k")
-                    if r == "d":
+                            (_(" local changed %s which remote deleted\n") % f) +
+                             _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
+                    if r == _("d"):
                         remove.append(f)
                 else:
-                    self.ui.debug("other deleted %s\n" % f)
+                    self.ui.debug(_("other deleted %s\n") % f)
                     remove.append(f) # other deleted it
             else:
                 # file is created on branch or in working directory
                 if force and f not in umap:
-                    self.ui.debug("remote deleted %s, clobbering\n" % f)
+                    self.ui.debug(_("remote deleted %s, clobbering\n") % f)
                     remove.append(f)
                 elif n == m1.get(f, nullid): # same as parent
                     if p2 == pa: # going backwards?
-                        self.ui.debug("remote deleted %s\n" % f)
+                        self.ui.debug(_("remote deleted %s\n") % f)
                         remove.append(f)
                     else:
-                        self.ui.debug("local modified %s, keeping\n" % f)
+                        self.ui.debug(_("local modified %s, keeping\n") % f)
                 else:
-                    self.ui.debug("working dir created %s, keeping\n" % f)
+                    self.ui.debug(_("working dir created %s, keeping\n") % f)
 
         for f, n in m2.iteritems():
             if choose and not choose(f): continue
             if f[0] == "/": continue
             if f in ma and n != ma[f]:
-                r = "k"
+                r = _("k")
                 if not force and (linear_path or allow):
                     r = self.ui.prompt(
-                        ("remote changed %s which local deleted\n" % f) +
-                        "(k)eep or (d)elete?", "[kd]", "k")
-                if r == "k": get[f] = n
+                        (_("remote changed %s which local deleted\n") % f) +
+                         _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
+                if r == _("k"): get[f] = n
             elif f not in ma:
-                self.ui.debug("remote created %s\n" % f)
+                self.ui.debug(_("remote created %s\n") % f)
                 get[f] = n
             else:
                 if force or p2 == pa: # going backwards?
-                    self.ui.debug("local deleted %s, recreating\n" % f)
+                    self.ui.debug(_("local deleted %s, recreating\n") % f)
                     get[f] = n
                 else:
-                    self.ui.debug("local deleted %s\n" % f)
+                    self.ui.debug(_("local deleted %s\n") % f)
 
         del mw, m1, m2, ma
 
@@ -1463,17 +1490,17 @@
             p1, p2 = p2, nullid
         else:
             if not allow:
-                self.ui.status("this update spans a branch" +
-                               " affecting the following files:\n")
+                self.ui.status(_("this update spans a branch"
+                                 " affecting the following files:\n"))
                 fl = merge.keys() + get.keys()
                 fl.sort()
                 for f in fl:
                     cf = ""
-                    if f in merge: cf = " (resolve)"
+                    if f in merge: cf = _(" (resolve)")
                     self.ui.status(" %s%s\n" % (f, cf))
-                self.ui.warn("aborting update spanning branches!\n")
-                self.ui.status("(use update -m to merge across branches" +
-                               " or -C to lose changes)\n")
+                self.ui.warn(_("aborting update spanning branches!\n"))
+                self.ui.status(_("(use update -m to merge across branches"
+                                 " or -C to lose changes)\n"))
                 return 1
             branch_merge = True
 
@@ -1485,7 +1512,7 @@
         files.sort()
         for f in files:
             if f[0] == "/": continue
-            self.ui.note("getting %s\n" % f)
+            self.ui.note(_("getting %s\n") % f)
             t = self.file(f).read(get[f])
             try:
                 self.wwrite(f, t)
@@ -1505,7 +1532,7 @@
         files = merge.keys()
         files.sort()
         for f in files:
-            self.ui.status("merging %s\n" % f)
+            self.ui.status(_("merging %s\n") % f)
             my, other, flag = merge[f]
             self.merge3(f, my, other)
             util.set_exec(self.wjoin(f), flag)
@@ -1525,14 +1552,13 @@
 
         remove.sort()
         for f in remove:
-            self.ui.note("removing %s\n" % f)
+            self.ui.note(_("removing %s\n") % f)
             try:
-                os.unlink(self.wjoin(f))
+                util.unlink(self.wjoin(f))
             except OSError, inst:
-                self.ui.warn("update failed to remove %s: %s!\n" % (f, inst))
-            # try removing directories that might now be empty
-            try: os.removedirs(os.path.dirname(self.wjoin(f)))
-            except: pass
+                if inst.errno != errno.ENOENT:
+                    self.ui.warn(_("update failed to remove %s: %s!\n") %
+                                 (f, inst.strerror))
         if moddirstate:
             if branch_merge:
                 self.dirstate.update(remove, 'r')
@@ -1556,15 +1582,15 @@
         b = temp("base", base)
         c = temp("other", other)
 
-        self.ui.note("resolving %s\n" % fn)
-        self.ui.debug("file %s: my %s other %s ancestor %s\n" %
+        self.ui.note(_("resolving %s\n") % fn)
+        self.ui.debug(_("file %s: my %s other %s ancestor %s\n") %
                               (fn, short(my), short(other), short(base)))
 
         cmd = (os.environ.get("HGMERGE") or self.ui.config("ui", "merge")
                or "hgmerge")
-        r = os.system("%s %s %s %s" % (cmd, a, b, c))
+        r = os.system('%s "%s" "%s" "%s"' % (cmd, a, b, c))
         if r:
-            self.ui.warn("merging %s failed!\n" % fn)
+            self.ui.warn(_("merging %s failed!\n") % fn)
 
         os.unlink(b)
         os.unlink(c)
@@ -1581,25 +1607,25 @@
             errors[0] += 1
 
         seen = {}
-        self.ui.status("checking changesets\n")
+        self.ui.status(_("checking changesets\n"))
         for i in range(self.changelog.count()):
             changesets += 1
             n = self.changelog.node(i)
             l = self.changelog.linkrev(n)
             if l != i:
-                err("incorrect link (%d) for changeset revision %d" % (l, i))
+                err(_("incorrect link (%d) for changeset revision %d") %(l, i))
             if n in seen:
-                err("duplicate changeset at revision %d" % i)
+                err(_("duplicate changeset at revision %d") % i)
             seen[n] = 1
 
             for p in self.changelog.parents(n):
                 if p not in self.changelog.nodemap:
-                    err("changeset %s has unknown parent %s" %
+                    err(_("changeset %s has unknown parent %s") %
                                  (short(n), short(p)))
             try:
                 changes = self.changelog.read(n)
             except Exception, inst:
-                err("unpacking changeset %s: %s" % (short(n), inst))
+                err(_("unpacking changeset %s: %s") % (short(n), inst))
 
             neededmanifests[changes[0]] = n
 
@@ -1607,55 +1633,55 @@
                 filelinkrevs.setdefault(f, []).append(i)
 
         seen = {}
-        self.ui.status("checking manifests\n")
+        self.ui.status(_("checking manifests\n"))
         for i in range(self.manifest.count()):
             n = self.manifest.node(i)
             l = self.manifest.linkrev(n)
 
             if l < 0 or l >= self.changelog.count():
-                err("bad manifest link (%d) at revision %d" % (l, i))
+                err(_("bad manifest link (%d) at revision %d") % (l, i))
 
             if n in neededmanifests:
                 del neededmanifests[n]
 
             if n in seen:
-                err("duplicate manifest at revision %d" % i)
+                err(_("duplicate manifest at revision %d") % i)
 
             seen[n] = 1
 
             for p in self.manifest.parents(n):
                 if p not in self.manifest.nodemap:
-                    err("manifest %s has unknown parent %s" %
+                    err(_("manifest %s has unknown parent %s") %
                         (short(n), short(p)))
 
             try:
                 delta = mdiff.patchtext(self.manifest.delta(n))
             except KeyboardInterrupt:
-                self.ui.warn("interrupted")
+                self.ui.warn(_("interrupted"))
                 raise
             except Exception, inst:
-                err("unpacking manifest %s: %s" % (short(n), inst))
+                err(_("unpacking manifest %s: %s") % (short(n), inst))
 
             ff = [ l.split('\0') for l in delta.splitlines() ]
             for f, fn in ff:
                 filenodes.setdefault(f, {})[bin(fn[:40])] = 1
 
-        self.ui.status("crosschecking files in changesets and manifests\n")
+        self.ui.status(_("crosschecking files in changesets and manifests\n"))
 
         for m,c in neededmanifests.items():
-            err("Changeset %s refers to unknown manifest %s" %
+            err(_("Changeset %s refers to unknown manifest %s") %
                 (short(m), short(c)))
         del neededmanifests
 
         for f in filenodes:
             if f not in filelinkrevs:
-                err("file %s in manifest but not in changesets" % f)
+                err(_("file %s in manifest but not in changesets") % f)
 
         for f in filelinkrevs:
             if f not in filenodes:
-                err("file %s in changeset but not in manifest" % f)
+                err(_("file %s in changeset but not in manifest") % f)
 
-        self.ui.status("checking files\n")
+        self.ui.status(_("checking files\n"))
         ff = filenodes.keys()
         ff.sort()
         for f in ff:
@@ -1669,15 +1695,15 @@
                 n = fl.node(i)
 
                 if n in seen:
-                    err("%s: duplicate revision %d" % (f, i))
+                    err(_("%s: duplicate revision %d") % (f, i))
                 if n not in filenodes[f]:
-                    err("%s: %d:%s not in manifests" % (f, i, short(n)))
+                    err(_("%s: %d:%s not in manifests") % (f, i, short(n)))
                 else:
                     del filenodes[f][n]
 
                 flr = fl.linkrev(n)
                 if flr not in filelinkrevs[f]:
-                    err("%s:%s points to unexpected changeset %d"
+                    err(_("%s:%s points to unexpected changeset %d")
                             % (f, short(n), flr))
                 else:
                     filelinkrevs[f].remove(flr)
@@ -1686,25 +1712,25 @@
                 try:
                     t = fl.read(n)
                 except Exception, inst:
-                    err("unpacking file %s %s: %s" % (f, short(n), inst))
+                    err(_("unpacking file %s %s: %s") % (f, short(n), inst))
 
                 # verify parents
                 (p1, p2) = fl.parents(n)
                 if p1 not in nodes:
-                    err("file %s:%s unknown parent 1 %s" %
+                    err(_("file %s:%s unknown parent 1 %s") %
                         (f, short(n), short(p1)))
                 if p2 not in nodes:
-                    err("file %s:%s unknown parent 2 %s" %
+                    err(_("file %s:%s unknown parent 2 %s") %
                             (f, short(n), short(p1)))
                 nodes[n] = 1
 
             # cross-check
             for node in filenodes[f]:
-                err("node %s in manifests not in %s" % (hex(node), f))
+                err(_("node %s in manifests not in %s") % (hex(node), f))
 
-        self.ui.status("%d files, %d changesets, %d total revisions\n" %
+        self.ui.status(_("%d files, %d changesets, %d total revisions\n") %
                        (files, changesets, revisions))
 
         if errors[0]:
-            self.ui.warn("%d integrity errors encountered!\n" % errors[0])
+            self.ui.warn(_("%d integrity errors encountered!\n") % errors[0])
             return 1
--- a/mercurial/manifest.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/manifest.py	Thu Oct 27 12:26:16 2005 -0700
@@ -7,6 +7,7 @@
 
 import sys, struct
 from revlog import *
+from i18n import gettext as _
 from demandload import *
 demandload(globals(), "bisect")
 
@@ -38,16 +39,6 @@
             self.read(node)
         return self.mapcache[2]
 
-    def diff(self, a, b):
-        # this is sneaky, as we're not actually using a and b
-        if self.listcache and self.addlist and self.listcache[0] == a:
-            d = mdiff.diff(self.listcache[1], self.addlist, 1)
-            if mdiff.patch(a, d) != b:
-                raise AssertionError("sortdiff failed!")
-            return d
-        else:
-            return mdiff.textdiff(a, b)
-
     def add(self, map, flags, transaction, link, p1=None, p2=None,
             changed=None):
         # directly generate the mdiff delta from the data collected during
@@ -144,7 +135,7 @@
                     end = bs
                     if w[1] == 1:
                         raise AssertionError(
-                            "failed to remove %s from manifest\n" % f)
+                            _("failed to remove %s from manifest\n") % f)
                 else:
                     # item is found, replace/delete the existing line
                     end = bs + 1
@@ -158,7 +149,7 @@
 
         text = "".join(self.addlist)
         if cachedelta and mdiff.patch(self.listcache[0], cachedelta) != text:
-            raise AssertionError("manifest delta failure\n")
+            raise AssertionError(_("manifest delta failure\n"))
         n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
         self.mapcache = (n, map, flags)
         self.listcache = (text, self.addlist)
--- a/mercurial/mdiff.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/mdiff.py	Thu Oct 27 12:26:16 2005 -0700
@@ -45,65 +45,6 @@
 
     return "".join(l)
 
-def sortdiff(a, b):
-    la = lb = 0
-    lena = len(a)
-    lenb = len(b)
-
-    while 1:
-        am, bm, = la, lb
-
-        # walk over matching lines
-        while lb < lenb and la < lena and a[la] == b[lb] :
-            la += 1
-            lb += 1
-
-        if la > am:
-            yield (am, bm, la - am) # return a match
-
-        # skip mismatched lines from b
-        while la < lena and lb < lenb and b[lb] < a[la]:
-            lb += 1
-
-        if lb >= lenb:
-            break
-
-        # skip mismatched lines from a
-        while la < lena and lb < lenb and b[lb] > a[la]:
-            la += 1
-
-        if la >= lena:
-            break
-
-    yield (lena, lenb, 0)
-
-def diff(a, b, sorted=0):
-    if not a:
-        s = "".join(b)
-        return s and (struct.pack(">lll", 0, 0, len(s)) + s)
-
-    bin = []
-    p = [0]
-    for i in a: p.append(p[-1] + len(i))
-
-    if sorted:
-        try:
-            d = sortdiff(a, b)
-        except:
-            raise
-    else:
-        d = difflib.SequenceMatcher(None, a, b).get_matching_blocks()
-    la = 0
-    lb = 0
-    for am, bm, size in d:
-        s = "".join(b[lb:bm])
-        if am > la or s:
-            bin.append(struct.pack(">lll", p[la], p[am], len(s)) + s)
-        la = am + size
-        lb = bm + size
-
-    return "".join(bin)
-
 def patchtext(bin):
     pos = 0
     t = []
@@ -119,5 +60,3 @@
 
 patches = mpatch.patches
 textdiff = bdiff.bdiff
-
-
--- a/mercurial/revlog.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/revlog.py	Thu Oct 27 12:26:16 2005 -0700
@@ -11,6 +11,7 @@
 """
 
 from node import *
+from i18n import gettext as _
 from demandload import demandload
 demandload(globals(), "binascii errno heapq mdiff sha struct zlib")
 
@@ -47,7 +48,7 @@
     if t == '\0': return bin
     if t == 'x': return zlib.decompress(bin)
     if t == 'u': return bin[1:]
-    raise RevlogError("unknown compression type %s" % t)
+    raise RevlogError(_("unknown compression type %s") % t)
 
 indexformat = ">4l20s20s20s"
 
@@ -97,6 +98,8 @@
     def __len__(self):
         return len(self.p.index)
     def load(self, pos):
+        if pos < 0:
+            pos += len(self.p.index)
         self.p.load(pos)
         return self.p.index[pos]
     def __getitem__(self, pos):
@@ -213,7 +216,7 @@
         try:
             return self.nodemap[node]
         except KeyError:
-            raise RevlogError('%s: no node %s' % (self.indexfile, hex(node)))
+            raise RevlogError(_('%s: no node %s') % (self.indexfile, hex(node)))
     def linkrev(self, node): return self.index[self.rev(node)][3]
     def parents(self, node):
         if node == nullid: return (nullid, nullid)
@@ -444,8 +447,8 @@
             for n in self.nodemap:
                 if hex(n).startswith(id):
                     c.append(n)
-            if len(c) > 1: raise KeyError("Ambiguous identifier")
-            if len(c) < 1: raise KeyError("No match found")
+            if len(c) > 1: raise RevlogError(_("Ambiguous identifier"))
+            if len(c) < 1: raise RevlogError(_("No match found"))
             return c[0]
 
         return None
@@ -507,7 +510,7 @@
         text = mdiff.patches(text, bins)
 
         if node != hash(text, p1, p2):
-            raise RevlogError("integrity check failed on %s:%d"
+            raise RevlogError(_("integrity check failed on %s:%d")
                           % (self.datafile, rev))
 
         self.cache = (node, rev, text)
@@ -776,7 +779,7 @@
             if node in self.nodemap:
                 # this can happen if two branches make the same change
                 # if unique:
-                #    raise RevlogError("already have %s" % hex(node[:4]))
+                #    raise RevlogError(_("already have %s") % hex(node[:4]))
                 chain = node
                 continue
             delta = chunk[80:]
@@ -785,7 +788,7 @@
                 # retrieve the parent revision of the delta chain
                 chain = p1
                 if not chain in self.nodemap:
-                    raise RevlogError("unknown base %s" % short(chain[:4]))
+                    raise RevlogError(_("unknown base %s") % short(chain[:4]))
 
             # full versions are inserted when the needed deltas become
             # comparable to the uncompressed text or when the previous
@@ -804,7 +807,7 @@
                 text = self.patches(text, [delta])
                 chk = self.addrevision(text, transaction, link, p1, p2)
                 if chk != node:
-                    raise RevlogError("consistency error adding group")
+                    raise RevlogError(_("consistency error adding group"))
                 measure = len(text)
             else:
                 e = (end, len(cdelta), self.base(t), link, p1, p2, node)
--- a/mercurial/sshrepo.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/sshrepo.py	Thu Oct 27 12:26:16 2005 -0700
@@ -7,6 +7,7 @@
 
 from node import *
 from remoterepo import *
+from i18n import gettext as _
 from demandload import *
 demandload(globals(), "hg os re stat")
 
@@ -17,7 +18,7 @@
 
         m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path)
         if not m:
-            raise hg.RepoError("couldn't parse destination %s" % path)
+            raise hg.RepoError(_("couldn't parse destination %s") % path)
 
         self.user = m.group(2)
         self.host = m.group(3)
@@ -41,7 +42,7 @@
             if size == 0: break
             l = self.pipee.readline()
             if not l: break
-            self.ui.status("remote: ", l)
+            self.ui.status(_("remote: "), l)
 
     def __del__(self):
         try:
@@ -49,7 +50,7 @@
             self.pipei.close()
             # read the error descriptor until EOF
             for l in self.pipee:
-                self.ui.status("remote: ", l)
+                self.ui.status(_("remote: "), l)
             self.pipee.close()
         except:
             pass
@@ -58,7 +59,7 @@
         return -1
 
     def do_cmd(self, cmd, **args):
-        self.ui.debug("sending %s command\n" % cmd)
+        self.ui.debug(_("sending %s command\n") % cmd)
         self.pipeo.write("%s\n" % cmd)
         for k, v in args.items():
             self.pipeo.write("%s %d\n" % (k, len(v)))
@@ -74,7 +75,7 @@
         try:
             l = int(l)
         except:
-            raise hg.RepoError("unexpected response '%s'" % l)
+            raise hg.RepoError(_("unexpected response '%s'") % l)
         return r.read(l)
 
     def lock(self):
@@ -89,7 +90,7 @@
         try:
             return map(bin, d[:-1].split(" "))
         except:
-            raise hg.RepoError("unexpected response '%s'" % (d[:400] + "..."))
+            raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
 
     def branches(self, nodes):
         n = " ".join(map(hex, nodes))
@@ -98,7 +99,7 @@
             br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
             return br
         except:
-            raise hg.RepoError("unexpected response '%s'" % (d[:400] + "..."))
+            raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
 
     def between(self, pairs):
         n = "\n".join(["-".join(map(hex, p)) for p in pairs])
@@ -107,7 +108,7 @@
             p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
             return p
         except:
-            raise hg.RepoError("unexpected response '%s'" % (d[:400] + "..."))
+            raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
 
     def changegroup(self, nodes):
         n = " ".join(map(hex, nodes))
@@ -117,7 +118,7 @@
     def addchangegroup(self, cg):
         d = self.call("addchangegroup")
         if d:
-            raise hg.RepoError("push refused: %s", d)
+            raise hg.RepoError(_("push refused: %s"), d)
 
         while 1:
             d = cg.read(4096)
--- a/mercurial/transaction.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/transaction.py	Thu Oct 27 12:26:16 2005 -0700
@@ -13,6 +13,7 @@
 
 import os
 import util
+from i18n import gettext as _
 
 class transaction:
     def __init__(self, report, opener, journal, after=None):
@@ -20,7 +21,7 @@
 
         # abort here if the journal already exists
         if os.path.exists(journal):
-            raise AssertionError("journal already exists - run hg recover")
+            raise AssertionError(_("journal already exists - run hg recover"))
 
         self.report = report
         self.opener = opener
@@ -58,17 +59,17 @@
     def abort(self):
         if not self.entries: return
 
-        self.report("transaction abort!\n")
+        self.report(_("transaction abort!\n"))
 
         for f, o in self.entries:
             try:
                 self.opener(f, "a").truncate(o)
             except:
-                self.report("failed to truncate %s\n" % f)
+                self.report(_("failed to truncate %s\n") % f)
 
         self.entries = []
 
-        self.report("rollback completed\n")
+        self.report(_("rollback completed\n"))
 
 def rollback(opener, file):
     for l in open(file).readlines():
--- a/mercurial/ui.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/ui.py	Thu Oct 27 12:26:16 2005 -0700
@@ -6,6 +6,7 @@
 # of the GNU General Public License, incorporated herein by reference.
 
 import os, ConfigParser
+from i18n import gettext as _
 from demandload import *
 demandload(globals(), "re socket sys util")
 
@@ -88,9 +89,12 @@
                 user = user[f+1:]
         return user
 
-    def expandpath(self, loc):
+    def expandpath(self, loc, root=""):
         paths = {}
         for name, path in self.configitems("paths"):
+            m = path.find("://")
+            if m == -1:
+                    path = os.path.join(root, path)
             paths[name] = path
 
         return paths.get(loc, loc)
@@ -114,7 +118,7 @@
             if re.match(pat, r):
                 return r
             else:
-                self.write("unrecognized response\n")
+                self.write(_("unrecognized response\n"))
     def status(self, *msg):
         if not self.quiet: self.write(*msg)
     def warn(self, *msg):
@@ -135,7 +139,7 @@
                   os.environ.get("EDITOR", "vi"))
 
         os.environ["HGUSER"] = self.username()
-        util.system("%s %s" % (editor, name), errprefix="edit failed")
+        util.system("%s %s" % (editor, name), errprefix=_("edit failed"))
 
         t = open(name).read()
         t = re.sub("(?m)^HG:.*\n", "", t)
--- a/mercurial/util.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/mercurial/util.py	Thu Oct 27 12:26:16 2005 -0700
@@ -11,6 +11,7 @@
 """
 
 import os, errno
+from i18n import gettext as _
 from demandload import *
 demandload(globals(), "re cStringIO shutil popen2 tempfile threading time")
 
@@ -46,7 +47,7 @@
         cmd = cmd.replace('INFILE', inname)
         cmd = cmd.replace('OUTFILE', outname)
         code = os.system(cmd)
-        if code: raise Abort("command '%s' failed: %s" %
+        if code: raise Abort(_("command '%s' failed: %s") %
                              (cmd, explain_exit(code)))
         return open(outname, 'rb').read()
     finally:
@@ -82,7 +83,7 @@
             files.setdefault(pf, 1)
     code = fp.close()
     if code:
-        raise Abort("patch command failed: %s" % explain_exit(code))
+        raise Abort(_("patch command failed: %s") % explain_exit(code)[0])
     return files.keys()
 
 def binary(s):
@@ -178,6 +179,16 @@
         raise Abort('%s not under root' % myname)
 
 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head=''):
+    return _matcher(canonroot, cwd, names, inc, exc, head, 'glob')
+
+def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head=''):
+    if os.name == 'nt':
+        dflt_pat = 'glob'
+    else:
+        dflt_pat = 'relpath'
+    return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat)
+
+def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat):
     """build a function to match a set of file patterns
 
     arguments:
@@ -207,12 +218,15 @@
     make head regex a rooted bool
     """
 
-    def patkind(name):
+    def patkind(name, dflt_pat='glob'):
         for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
             if name.startswith(prefix + ':'): return name.split(':', 1)
+        return dflt_pat, name
+
+    def contains_glob(name):
         for c in name:
-            if c in _globchars: return 'glob', name
-        return 'relpath', name
+            if c in _globchars: return True
+        return False
 
     def regex(kind, name, tail):
         '''convert a pattern into a regular expression'''
@@ -232,22 +246,36 @@
 
     def matchfn(pats, tail):
         """build a matching function from a set of patterns"""
-        if pats:
-            pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats])
-            return re.compile(pat).match
+        if not pats:
+            return
+        matches = []
+        for k, p in pats:
+            try:
+                pat = '(?:%s)' % regex(k, p, tail)
+                matches.append(re.compile(pat).match)
+            except re.error, inst:
+                raise Abort("invalid pattern: %s:%s" % (k, p))
+
+        def buildfn(text):
+            for m in matches:
+                r = m(text)
+                if r:
+                    return r
+
+        return buildfn
 
     def globprefix(pat):
         '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
         root = []
         for p in pat.split(os.sep):
-            if patkind(p)[0] == 'glob': break
+            if contains_glob(p): break
             root.append(p)
         return '/'.join(root)
 
     pats = []
     files = []
     roots = []
-    for kind, name in map(patkind, names):
+    for kind, name in [patkind(p, dflt_pat) for p in names]:
         if kind in ('glob', 'relpath'):
             name = canonpath(canonroot, cwd, name)
             if name == '':
@@ -296,6 +324,13 @@
         os.unlink(dst)
         os.rename(src, dst)
 
+def unlink(f):
+    """unlink and remove the directory if it is empty"""
+    os.unlink(f)
+    # try removing directories that might now be empty
+    try: os.removedirs(os.path.dirname(f))
+    except: pass
+
 def copyfiles(src, dst, hardlink=None):
     """Copy a directory tree using hardlinks if possible"""
 
@@ -365,13 +400,23 @@
     os_link = os.link
 else:
     def os_link(src, dst):
-        raise OSError(0, "Hardlinks not supported")
+        raise OSError(0, _("Hardlinks not supported"))
 
 # Platform specific variants
 if os.name == 'nt':
+    demandload(globals(), "msvcrt")
     nulldev = 'NUL:'
+    
+    try:
+        import win32api, win32process
+        filename = win32process.GetModuleFileNameEx(win32api.GetCurrentProcess(), 0)
+        systemrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
+        
+    except ImportError:
+        systemrc = r'c:\mercurial\mercurial.ini'
+        pass
 
-    rcpath = (r'c:\mercurial\mercurial.ini',
+    rcpath = (systemrc,
               os.path.join(os.path.expanduser('~'), 'mercurial.ini'))
 
     def parse_patch_output(output_line):
@@ -408,6 +453,9 @@
     def set_exec(f, mode):
         pass
 
+    def set_binary(fd):
+        msvcrt.setmode(fd.fileno(), os.O_BINARY)
+
     def pconvert(path):
         return path.replace("\\", "/")
 
@@ -421,7 +469,7 @@
     readlock = _readlock_file
 
     def explain_exit(code):
-        return "exited with status %d" % code, code
+        return _("exited with status %d") % code, code
 
 else:
     nulldev = '/dev/null'
@@ -454,6 +502,9 @@
         else:
             os.chmod(f, s & 0666)
 
+    def set_binary(fd):
+        pass
+
     def pconvert(path):
         return path
 
@@ -484,14 +535,14 @@
         """return a 2-tuple (desc, code) describing a process's status"""
         if os.WIFEXITED(code):
             val = os.WEXITSTATUS(code)
-            return "exited with status %d" % val, val
+            return _("exited with status %d") % val, val
         elif os.WIFSIGNALED(code):
             val = os.WTERMSIG(code)
-            return "killed by signal %d" % val, val
+            return _("killed by signal %d") % val, val
         elif os.WIFSTOPPED(code):
             val = os.WSTOPSIG(code)
-            return "stopped by signal %d" % val, val
-        raise ValueError("invalid exit code")
+            return _("stopped by signal %d") % val, val
+        raise ValueError(_("invalid exit code"))
 
 class chunkbuffer(object):
     """Allow arbitrary sized chunks of data to be efficiently read from an
@@ -504,7 +555,7 @@
         self.buf = ''
         self.targetsize = int(targetsize)
         if self.targetsize <= 0:
-            raise ValueError("targetsize must be greater than 0, was %d" %
+            raise ValueError(_("targetsize must be greater than 0, was %d") %
                              targetsize)
         self.iterempty = False
 
--- a/setup.py	Sun Oct 16 16:24:40 2005 -0700
+++ b/setup.py	Thu Oct 27 12:26:16 2005 -0700
@@ -6,6 +6,7 @@
 # './setup.py --help' for more options
 
 import glob
+import sys
 from distutils.core import setup, Extension
 from distutils.command.install_data import install_data
 
@@ -15,6 +16,20 @@
 try:
     import py2exe
 
+    # Help py2exe to find win32com.shell
+    try:
+        import modulefinder
+        import win32com
+        for p in win32com.__path__[1:]: # Take the path to win32comext
+            modulefinder.AddPackagePath("win32com", p)
+        pn = "win32com.shell"
+        __import__(pn)
+        m = sys.modules[pn]
+        for p in m.__path__[1:]:
+            modulefinder.AddPackagePath(pn, p)
+    except ImportError:
+        pass
+
     # Due to the use of demandload py2exe is not finding the modules.
     # packagescan.getmodules creates a list of modules included in
     # the mercurial package plus depdent modules.
@@ -34,6 +49,8 @@
             # Sets the 'includes' option with the list of needed modules
             if not self.includes:
                 self.includes = []
+            else:
+                self.includes = self.includes.split(',')
             self.includes += mercurial.packagescan.getmodules(self.build_lib,
                                                               'mercurial')
             self.includes += mercurial.packagescan.getmodules(self.build_lib,
--- a/templates/changelog.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/changelog.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -7,8 +7,8 @@
 
 <div class="buttons">
 <a href="?cmd=tags">tags</a>
-<a href="?cmd=manifest;manifest=#manifest#;path=/">manifest</a>
-<a type="application/rss+xml" href="?cmd=changelog;style=rss">rss</a>
+<a href="?mf=#manifest|short#;path=/">manifest</a>
+<a type="application/rss+xml" href="?style=rss">rss</a>
 </div>
 
 <h2>changelog for #repo|escape#</h2>
@@ -18,7 +18,7 @@
 <label for="search1">search:</label>
 <input type="hidden" name="cmd" value="changelog">
 <input name="rev" id="search1" type="text" size="30">
-navigate: <small>#changenav%naventry#</small>
+navigate: <small class="navigate">#changenav%naventry#</small>
 </p>
 </form>
 
@@ -29,7 +29,7 @@
 <label for="search2">search:</label>
 <input type="hidden" name="cmd" value="changelog">
 <input name="rev" id="search2" type="text" size="30">
-navigate: <small>#changenav%naventry#</small>
+navigate: <small class="navigate">#changenav%naventry#</small>
 </p>
 </form>
 
--- a/templates/changelogentry-rss.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/changelogentry-rss.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -1,7 +1,7 @@
 <item>
-    <title>#desc|firstline|escape#</title>
-    <link>#url#?cmd=changeset;node=#node#</link>
-    <description><![CDATA[#desc|escape|addbreaks#]]></description>
+    <title>#desc|strip|firstline|rstrip|escape#</title>
+    <link>#url#?cs=#node|short#</link>
+    <description><![CDATA[#desc|strip|escape|addbreaks#]]></description>
     <author>#author|obfuscate#</author>
     <pubDate>#date|rfc822date#</pubDate>
 </item>
--- a/templates/changelogentry.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/changelogentry.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -1,13 +1,13 @@
 <table class="changelogEntry parity#parity#">
  <tr>
   <th class="age" width="15%">#date|age# ago:</th>
-  <th class="firstline">#desc|firstline|escape#</th>
+  <th class="firstline">#desc|strip|firstline|escape#</th>
  </tr>
  <tr>
   <th class="changesetRev">changeset #rev#:</th>
-  <td class="changesetNode"><a href="?cmd=changeset;node=#node#">#node|short#</a></td>
+  <td class="changesetNode"><a href="?cs=#node|short#">#node|short#</a></td>
  </tr>
- #parent#
+ #parent%changelogparent#
  #changelogtag#
  <tr>
   <th class="author">author:</th>
@@ -18,7 +18,7 @@
   <td class="date">#date|date#</td>
  </tr>
  <tr>
-  <th class="files"><a href="?cmd=manifest;manifest=#manifest#;path=/">files</a>:</th>
+  <th class="files"><a href="?mf=#manifest|short#;path=/">files</a>:</th>
   <td class="files">#files#</td>
  </tr>
 </table>
--- a/templates/changeset-raw.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/changeset-raw.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -3,7 +3,7 @@
 # User #author#
 # Date #date|date#
 # Node ID #node#
-#parent#
+#parent%changesetparent#
 #desc#
 
 #diff#
--- a/templates/changeset.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/changeset.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -4,21 +4,21 @@
 <body>
 
 <div class="buttons">
-<a href="?cmd=changelog;rev=#rev#">changelog</a>
+<a href="?cl=#rev#">changelog</a>
 <a href="?cmd=tags">tags</a>
-<a href="?cmd=manifest;manifest=#manifest#;path=/">manifest</a>
-<a href="?cmd=changeset;node=#node#;style=raw">raw</a>
+<a href="?mf=#manifest|short#;path=/">manifest</a>
+<a href="?cs=#node|short#;style=raw">raw</a>
 #archives%archiveentry#
 </div>
 
-<h2>changeset: #desc|escape|firstline#</h2>
+<h2>changeset: #desc|strip|escape|firstline#</h2>
 
 <table id="changesetEntry">
 <tr>
  <th class="changeset">changeset #rev#:</th>
- <td class="changeset"><a href="?cmd=changeset;node=#node#">#node|short#</a></td>
+ <td class="changeset"><a href="?cs=#node|short#">#node|short#</a></td>
 </tr>
-#parent#
+#parent%changesetparent#
 #changesettag#
 <tr>
  <th class="author">author:</th>
@@ -32,7 +32,7 @@
  <td class="files">#files#</td></tr>
 <tr>
  <th class="description">description:</th>
- <td class="description">#desc|escape|addbreaks#</td>
+ <td class="description">#desc|strip|escape|addbreaks#</td>
 </tr>
 </table>
 
@@ -40,7 +40,6 @@
 #diff#
 </div>
 
-</body>
-</html>
+#footer#
 
 
--- a/templates/fileannotate.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/fileannotate.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -4,12 +4,12 @@
 <body>
 
 <div class="buttons">
-<a href="?cmd=changelog;rev=#rev#">changelog</a>
-<a href="?cmd=tags">tags</a>
-<a href="?cmd=changeset;node=#node#">changeset</a>
-<a href="?cmd=manifest;manifest=#manifest#;path=#path#">manifest</a>
-<a href="?cmd=file;file=#file#;filenode=#filenode#">file</a>
-<a href="?cmd=filelog;file=#file#;filenode=#filenode#">revisions</a>
+<a href="?cl=#rev#">changelog</a>
+<a href="?tags=">tags</a>
+<a href="?cs=#node|short#">changeset</a>
+<a href="?mf=#manifest|short#;path=#path#">manifest</a>
+<a href="?f=#filenode|short#;file=#file#">file</a>
+<a href="?fl=#filenode|short#;file=#file#">revisions</a>
 </div>
 
 <h2>Annotate #file#</h2>
@@ -17,8 +17,8 @@
 <table>
 <tr>
  <td class="metatag">changeset #rev#:</td>
- <td><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>
-#parent#
+ <td><a href="?cs=#node|short#">#node|short#</a></td></tr>
+#parent%fileannotateparent#
 <tr>
  <td class="metatag">author:</td>
  <td>#author|obfuscate#</td></tr>
--- a/templates/filediff.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/filediff.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -4,13 +4,13 @@
 <body>
 
 <div class="buttons">
-<a href="?cmd=changelog;rev=#rev#">changelog</a>
-<a href="?cmd=tags">tags</a>
-<a href="?cmd=changeset;node=#node#">changeset</a>
-<a href="?cmd=file;file=#file#;filenode=#filenode#">file</a>
-<a href="?cmd=filelog;file=#file#;filenode=#filenode#">revisions</a>
-<a href="?cmd=annotate;file=#file#;filenode=#filenode#">annotate</a>
-<a href="?cmd=filediff;file=#file#;node=#node#;style=raw">raw</a>
+<a href="?cl=#rev#">changelog</a>
+<a href="?tags=">tags</a>
+<a href="?cs=#node|short#">changeset</a>
+<a href="?f=#filenode|short#;file=#file#">file</a>
+<a href="?fl=#filenode|short#;file=#file#">revisions</a>
+<a href="?fa=#filenode|short#;file=#file#">annotate</a>
+<a href="?fd=#node|short#;file=#file#;style=raw">raw</a>
 </div>
 
 <h2>#file#</h2>
@@ -18,9 +18,9 @@
 <table id="filediffEntry">
 <tr>
  <th class="revision">revision #rev#:</th>
- <td class="revision"><a href="?cmd=changeset;node=#node#">#node|short#</a></td>
+ <td class="revision"><a href="?cs=#node|short#">#node|short#</a></td>
 </tr>
-#parent#
+#parent%filediffparent#
 </table>
 
 <div id="fileDiff">
--- a/templates/filelog.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/filelog.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -1,17 +1,17 @@
 #header#
 <title>#repo|escape#: #file# history</title>
 <link rel="alternate" type="application/rss+xml"
-   href="?cmd=filelog;file=#file#;filenode=0;style=rss" title="RSS feed for #repo|escape#:#file#">
+   href="?fl=0;file=#file#;style=rss" title="RSS feed for #repo|escape#:#file#">
 </head>
 </head>
 <body>
 
 <div class="buttons">
-<a href="?cmd=changelog">changelog</a>
-<a href="?cmd=tags">tags</a>
-<a href="?cmd=file;file=#file#;filenode=#filenode#">file</a>
-<a href="?cmd=annotate;file=#file#;filenode=#filenode#">annotate</a>
-<a type="application/rss+xml" href="?cmd=filelog;file=#file#;filenode=0;style=rss">rss</a>
+<a href="?cl=tip">changelog</a>
+<a href="?tags=">tags</a>
+<a href="?f=#filenode|short#;file=#file#">file</a>
+<a href="?fa=#filenode|short#;file=#file#">annotate</a>
+<a type="application/rss+xml" href="?fl=0;file=#file#;style=rss">rss</a>
 </div>
 
 <h2>#file# revision history</h2>
--- a/templates/filelogentry-rss.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/filelogentry-rss.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -1,7 +1,7 @@
 <item>
-    <title>#desc|firstline|escape#</title>
-    <link>#url#?cmd=file;file=#file#;filenode=#filenode#</link>
-    <description><![CDATA[#desc|escape|addbreaks#]]></description>
+    <title>#desc|strip|firstline|rstrip|escape#</title>
+    <link>#url#?f=#filenode|short#;file=#file#</link>
+    <description><![CDATA[#desc|strip|escape|addbreaks#]]></description>
     <author>#author|obfuscate#</author>
     <pubDate>#date|rfc822date#</pubDate>>
 </item>
--- a/templates/filelogentry.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/filelogentry.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -1,12 +1,12 @@
 <table class="parity#parity#" width="100%" cellspacing="0" cellpadding="0">
 <tr>
  <td align="right" width="15%"><b>#date|age# ago:&nbsp;</b></td>
- <td><b><a href="?cmd=changeset;node=#node#">#desc|firstline|escape#</a></b></td></tr>
+ <td><b><a href="?cs=#node|short#">#desc|strip|firstline|escape#</a></b></td></tr>
 <tr>
  <td align="right">revision #filerev#:&nbsp;</td>
- <td><a href="?cmd=file;file=#file#;filenode=#filenode#">#filenode|short#</a>
-<a href="?cmd=filediff;file=#file#;node=#node#">(diff)</a>
-<a href="?cmd=annotate;file=#file#;filenode=#filenode#">(annotate)</a>
+ <td><a href="?f=#filenode|short#;file=#file#">#filenode|short#</a>
+<a href="?fd=#node|short#;file=#file#">(diff)</a>
+<a href="?fa=#filenode|short#;file=#file#">(annotate)</a>
 </td></tr>
 <tr>
  <td align="right">author:&nbsp;</td>
--- a/templates/filerevision-raw.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/filerevision-raw.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -1,3 +1,4 @@
-#header#
-#text%fileline#
-#footer#
+Context-type: #mimetype#
+Content-disposition: filename=#file#
+
+#raw#
--- a/templates/filerevision.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/filerevision.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -4,13 +4,13 @@
 <body>
 
 <div class="buttons">
-<a href="?cmd=changelog;rev=#rev#">changelog</a>
-<a href="?cmd=tags">tags</a>
-<a href="?cmd=changeset;node=#node#">changeset</a>
-<a href="?cmd=manifest;manifest=#manifest#;path=#path#">manifest</a>
-<a href="?cmd=filelog;file=#file#;filenode=#filenode#">revisions</a>
-<a href="?cmd=annotate;file=#file#;filenode=#filenode#">annotate</a>
-<a href="?cmd=file;file=#file#;filenode=#filenode#;style=raw">raw</a>
+<a href="?cl=#rev#">changelog</a>
+<a href="?tags=">tags</a>
+<a href="?cs=#node|short#">changeset</a>
+<a href="?mf=#manifest|short#;path=#path#">manifest</a>
+<a href="?fl=#filenode|short#;file=#file#">revisions</a>
+<a href="?fa=#filenode|short#;file=#file#">annotate</a>
+<a href="?f=#filenode|short#;file=#file#;style=raw">raw</a>
 </div>
 
 <h2>#file#</h2>
@@ -18,8 +18,8 @@
 <table>
 <tr>
  <td class="metatag">changeset #rev#:</td>
- <td><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>
-#parent#
+ <td><a href="?cs=#node|short#">#node|short#</a></td></tr>
+#parent%filerevparent#
 <tr>
  <td class="metatag">author:</td>
  <td>#author|obfuscate#</td></tr>
--- a/templates/footer.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/footer.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -1,2 +1,7 @@
+<div class="logo">
+powered by<br/>
+<a href="http://www.selenic.com/mercurial/">mercurial</a>
+</div>
+
 </body>
 </html>
--- a/templates/header.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/header.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -21,6 +21,13 @@
   font-family: sans;
   font-weight: bold;
 }
+.navigate a {
+  background-color: #ccc;
+  padding: 2pt;
+  font-family: sans;
+  color: black;
+}
+
 .metatag {
   background-color: #888888;
   color: white;
@@ -30,6 +37,23 @@
 /* Common */
 pre { margin: 0; }
 
+.logo {
+  background-color: #333;
+  padding: 4pt;
+  margin: 8pt 0 8pt 8pt;
+  font-family: sans;
+  font-size: 60%;
+  color: white;
+  float: right;
+  clear: right;
+  text-align: left;
+}
+
+.logo a {
+  font-weight: bold;
+  font-size: 150%; 
+  color: #999;
+}
 
 /* Changelog entries */
 .changelogEntry { width: 100%; }
--- a/templates/manifest.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/manifest.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -4,9 +4,9 @@
 <body>
 
 <div class="buttons">
-<a href="?cmd=changelog;rev=#rev#">changelog</a>
-<a href="?cmd=tags">tags</a>
-<a href="?cmd=changeset;node=#node#">changeset</a>
+<a href="?cl=#rev#">changelog</a>
+<a href="?tags=">tags</a>
+<a href="?cs=#node|short#">changeset</a>
 </div>
 
 <h2>manifest for changeset #node|short#: #path#</h2>
@@ -14,7 +14,7 @@
 <table cellpadding="0" cellspacing="0">
 <tr class="parity1">
   <td><tt>drwxr-xr-x</tt>&nbsp;
-  <td><a href="?cmd=manifest;manifest=#manifest#;path=#up#">[up]</a>
+  <td><a href="?mf=#manifest|short#;path=#up#">[up]</a>
 #dentries%manifestdirentry#
 #fentries%manifestfileentry#
 </table>
--- a/templates/map	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/map	Thu Oct 27 12:26:16 2005 -0700
@@ -3,39 +3,39 @@
 footer = footer.tmpl
 search = search.tmpl
 changelog = changelog.tmpl
-naventry = "<a href="?cmd=changelog;rev=#rev#">#label#</a> "
-filedifflink = "<a href="?cmd=filediff;node=#node#;file=#file#">#file#</a> "
-filenodelink = "<a href="?cmd=file;filenode=#filenode#;file=#file#">#file#</a> "
+naventry = "<a href="?cl=#rev#">#label#</a> "
+filedifflink = "<a href="?fd=#node|short#;file=#file#">#file#</a> "
+filenodelink = "<a href="?f=#filenode|short#;file=#file#">#file#</a> "
 fileellipses = "..."
 changelogentry = changelogentry.tmpl
 searchentry = changelogentry.tmpl
 changeset = changeset.tmpl
 manifest = manifest.tmpl
 manifestdirentry = "<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td><a href="?cmd=manifest;manifest=#manifest#;path=#path#">#basename#/</a>"
-manifestfileentry = "<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td><a href="?cmd=file;filenode=#filenode#;file=#file#">#basename#</a>"
+manifestfileentry = "<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td><a href="?f=#filenode|short#;file=#file#">#basename#</a>"
 filerevision = filerevision.tmpl
 fileannotate = fileannotate.tmpl
 filediff = filediff.tmpl
 filelog = filelog.tmpl
 fileline = "<div class="parity#parity#"><span class="lineno">#linenumber#</span>#line|escape#</div>"
 filelogentry = filelogentry.tmpl
-annotateline = "<tr class="parity#parity#"><td class="annotate"><a href="?cmd=changeset;node=#node#">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>"
+annotateline = "<tr class="parity#parity#"><td class="annotate"><a href="?cs=#node|short#">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>"
 difflineplus = "<span class="plusline">#line|escape#</span>"
 difflineminus = "<span class="minusline">#line|escape#</span>"
 difflineat = "<span class="atline">#line|escape#</span>"
 diffline = "#line|escape#"
-changelogparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>"
-changesetparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#">#node|short#</a></td></tr>"
-filerevparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=file;file=#file#;filenode=#node#">#node|short#</a></td></tr>"
-fileannotateparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=annotate;file=#file#;filenode=#node#">#node|short#</a></td></tr>"
+changelogparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
+changesetparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
+filerevparent = "<tr><td class="metatag">parent:</td><td><a href="?f=#node|short#;file=#file#">#node|short#</a></td></tr>"
+fileannotateparent = "<tr><td class="metatag">parent:</td><td><a href="?fa=#filenode|short#;file=#file#">#node|short#</a></td></tr>"
 tags = tags.tmpl
-tagentry = "<li class="tagEntry parity#parity#"><span class="node">#node#</span> <a href="?cmd=changeset;node=#node#">#tag#</a></li>"
+tagentry = "<li class="tagEntry parity#parity#"><span class="node">#node#</span> <a href="?cs=#node|short#">#tag#</a></li>"
 diffblock = "<pre class="parity#parity#">#lines#</pre>"
 changelogtag = "<tr><th class="tag">tag:</th><td class="tag">#tag#</td></tr>"
 changesettag = "<tr><th class="tag">tag:</th><td class="tag">#tag#</td></tr>"
-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>#contact|obfuscate#</td><td>#lastupdate|age# ago</td><td><a href="#url#?cmd=changelog;style=rss">RSS</a></td></tr>"
+filediffparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cs=#node|short#">#node|short#</a></td></tr>"
+filelogparent = "<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="?f=#node|short#;file=#file#">#node|short#</a></td></tr>"
+indexentry = "<tr class="parity#parity#"><td><a href="#url#">#name#</a></td><td>#shortdesc#</td><td>#contact|obfuscate#</td><td>#lastupdate|age# ago</td><td><a href="#url#?cl=tip;style=rss">RSS</a></td></tr>"
 index = index.tmpl
-archiveentry = "<a href="?cmd=archive;node=#node#;type=#type#">#type#</a> "
+archiveentry = "<a href="?ca=#node|short#;type=#type#">#type#</a> "
 notfound = notfound.tmpl
--- a/templates/search.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/search.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -4,25 +4,29 @@
 <body>
 
 <div class="buttons">
-<a href="?cmd=changelog;rev=#rev#">changelog</a>
-<a href="?cmd=tags">tags</a>
-<a href="?cmd=manifest;manifest=#manifest#;path=/">manifest</a>
+<a href="?cl=tip">changelog</a>
+<a href="?tags=">tags</a>
+<a href="?mf=#manifest|short#;path=/">manifest</a>
 </div>
 
 <h2>searching for #query|escape#</h2>
 
 <form>
+<p>
 search:
 <input type="hidden" name="cmd" value="changelog">
 <input name="rev" type="text" width="30" value="#query|escape#">
+</p>
 </form>
 
 #entries#
 
 <form>
+<p>
 search:
 <input type="hidden" name="cmd" value="changelog">
-<input name="rev" type="text" width="30">
+<input name="rev" type="text" width="30" value="#query|escape#">
+</p>
 </form>
 
 #footer#
--- a/templates/tags.tmpl	Sun Oct 16 16:24:40 2005 -0700
+++ b/templates/tags.tmpl	Thu Oct 27 12:26:16 2005 -0700
@@ -4,8 +4,8 @@
 <body>
 
 <div class="buttons">
-<a href="?cmd=changelog;rev=#rev#">changelog</a>
-<a href="?cmd=manifest;manifest=#manifest#;path=/">manifest</a>
+<a href="?cl=tip">changelog</a>
+<a href="?mf=#manifest|short#;path=/">manifest</a>
 </div>
 
 <h2>tags:</h2>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-confused-revert	Thu Oct 27 12:26:16 2005 -0700
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+hg init
+echo foo > a
+hg add a
+hg commit -m "1" -d "0 0"
+
+echo bar > b
+hg add b
+hg remove a
+
+echo "%%% should show a removed and b added"
+hg status
+
+echo "reverting..."
+hg revert
+
+echo "%%% should show b unknown and a back to normal"
+hg status
+
+rm b
+
+hg co -C 0
+echo foo-a > a
+hg commit -m "2a" -d "0 0"
+
+hg co -C 0
+echo foo-b > a
+hg commit -m "2b" -d "0 0"
+
+HGMERGE=true hg update -m 1
+
+echo "%%% should show foo-b"
+cat a
+
+echo bar > b
+hg add b
+rm a
+hg remove a
+
+echo "%%% should show a removed and b added"
+hg status
+
+echo "reverting..."
+hg revert
+
+echo "%%% should show b unknown and a marked modified (merged)"
+hg status
+
+echo "%%% should show foo-b"
+cat a
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-confused-revert.out	Thu Oct 27 12:26:16 2005 -0700
@@ -0,0 +1,17 @@
+%%% should show a removed and b added
+A b
+R a
+reverting...
+%%% should show b unknown and a back to normal
+? b
+merging a
+%%% should show foo-b
+foo-b
+%%% should show a removed and b added
+A b
+R a
+reverting...
+%%% should show b unknown and a marked modified (merged)
+? b
+%%% should show foo-b
+foo-b
--- a/tests/test-help.out	Sun Oct 16 16:24:40 2005 -0700
+++ b/tests/test-help.out	Thu Oct 27 12:26:16 2005 -0700
@@ -124,33 +124,66 @@
 
 add the specified files on the next commit
 
+    Schedule files to be version controlled and added to the repository.
+
+    The files will be added to the repository at the next commit.
+
+    If no names are given, add all files in the current directory and
+    its subdirectories.
+
 options:
 
- -I --include  include path in search
- -X --exclude  exclude path from search
+ -I --include  include names matching the given patterns
+ -X --exclude  exclude names matching the given patterns
 hg add: option --skjdfks not recognized
 hg add [OPTION]... [FILE]...
 
 add the specified files on the next commit
 
+    Schedule files to be version controlled and added to the repository.
+
+    The files will be added to the repository at the next commit.
+
+    If no names are given, add all files in the current directory and
+    its subdirectories.
+
 options:
 
- -I --include  include path in search
- -X --exclude  exclude path from search
+ -I --include  include names matching the given patterns
+ -X --exclude  exclude names matching the given patterns
 hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...
 
 diff working directory (or selected files)
 
+    Show differences between revisions for the specified files.
+
+    Differences between files are shown using the unified diff format.
+
+    When two revision arguments are given, then changes are shown
+    between those revisions. If only one revision is specified then
+    that revision is compared to the working directory, and, when no
+    revisions are specified, the working directory files are compared
+    to its parent.
+
+    Without the -a option, diff will avoid generating diffs of files
+    it detects as binary. With -a, diff will generate a diff anyway,
+    probably with undesirable results.
+
 options:
 
  -r --rev      revision
  -a --text     treat all files as text
- -I --include  include path in search
- -X --exclude  exclude path from search
+ -I --include  include names matching the given patterns
+ -X --exclude  exclude names matching the given patterns
 hg status [OPTION]... [FILE]...
 
 show changed files in the working directory
 
+    Show changed files in the working directory.  If no names are
+    given, all files are shown.  Otherwise, only files matching the
+    given names are shown.
+
+    The codes used to show the status of files are:
     M = modified
     A = added
     R = removed
@@ -163,9 +196,9 @@
  -r --removed    show only removed files
  -u --unknown    show only unknown (not tracked) files
  -n --no-status  hide status prefix
- -0 --print0     end filenames with NUL
- -I --include    include path in search
- -X --exclude    exclude path from search
+ -0 --print0     end filenames with NUL, for use with xargs
+ -I --include    include names matching the given patterns
+ -X --exclude    exclude names matching the given patterns
 hg status [OPTION]... [FILE]...
 
 show changed files in the working directory
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-revert	Thu Oct 27 12:26:16 2005 -0700
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+hg init
+echo 123 > a
+echo 123 > c
+hg add a c
+hg commit -m "first" -d "0 0" a c
+echo 123 > b
+hg status
+echo 12 > c
+hg status
+hg add b
+hg status
+hg rm a
+hg status
+hg revert a
+hg status
+hg revert b
+hg status
+hg revert c
+hg status
+ls
+
+true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-revert.out	Thu Oct 27 12:26:16 2005 -0700
@@ -0,0 +1,16 @@
+? b
+M c
+? b
+M c
+A b
+M c
+A b
+R a
+M c
+A b
+M c
+? b
+? b
+a
+b
+c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-symlinks	Thu Oct 27 12:26:16 2005 -0700
@@ -0,0 +1,24 @@
+#!/bin/sh
+#Test bug regarding symlinks that showed up in hg 0.7
+#Author: Matthew Elder <sseses@gmail.com>
+
+#make and initialize repo
+hg init test; cd test;
+
+#make a file and a symlink
+touch foo; ln -s foo bar;
+
+#import with addremove -- symlink walking should _not_ screwup.
+hg addremove
+
+#commit -- the symlink should _not_ appear added to dir state
+hg commit -m 'initial'
+
+#add a new file so hg will let me commit again
+touch bomb
+
+#again, symlink should _not_ show up on dir state
+hg addremove
+
+#Assert screamed here before, should go by without consequence
+hg commit -m 'is there a bug?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-symlinks.out	Thu Oct 27 12:26:16 2005 -0700
@@ -0,0 +1,4 @@
+bar: unsupported file type (type is symbolic link)
+adding foo
+bar: unsupported file type (type is symbolic link)
+adding bomb
--- a/tests/test-update-reverse	Sun Oct 16 16:24:40 2005 -0700
+++ b/tests/test-update-reverse	Thu Oct 27 12:26:16 2005 -0700
@@ -7,7 +7,7 @@
 
 touch main
 hg add main
-hg commit -t "Added main" -d "0 0"
+hg commit -m "Added main" -d "0 0"
 hg checkout 0
 
 echo Main should be gone
--- a/tests/test-update-reverse.out	Sun Oct 16 16:24:40 2005 -0700
+++ b/tests/test-update-reverse.out	Thu Oct 27 12:26:16 2005 -0700
@@ -1,4 +1,3 @@
-Warning: -t and --text is deprecated, please use -m or --message instead.
 Main should be gone
 a
 changeset:   3:91ebc10ed028
--- a/tests/test-walk	Sun Oct 16 16:24:40 2005 -0700
+++ b/tests/test-walk	Thu Oct 27 12:26:16 2005 -0700
@@ -30,7 +30,7 @@
 hg debugwalk
 cd ..
 hg debugwalk -Ibeans
-hg debugwalk 'mammals/../beans/b*'
+hg debugwalk 'glob:mammals/../beans/b*'
 hg debugwalk '-X*/Procyonidae' mammals
 hg debugwalk path:mammals
 hg debugwalk ..
@@ -42,8 +42,8 @@
 hg debugwalk glob:\*
 hg debugwalk 're:.*[kb]$'
 hg debugwalk path:beans/black
-hg debugwalk beans 'beans/*'
-hg debugwalk 'j*'
+hg debugwalk beans 'glob:beans/*'
+hg debugwalk 'glob:j*'
 hg debugwalk NOEXIST
 mkfifo fifo
 hg debugwalk fifo