changeset 2690:e9ecc45795e8

merge with crew
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Thu, 27 Jul 2006 12:34:02 +0200
parents 489c3bacce96 (current diff) aa7ddbc1262c (diff)
children accadcb4e4b5
files MANIFEST.in
diffstat 60 files changed, 573 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsigs
+++ b/.hgsigs
@@ -1,1 +1,2 @@
 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
+2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
--- a/.hgtags
+++ b/.hgtags
@@ -11,3 +11,4 @@ 979c049974485125e1f9357f6bbe9c1b548a64c3
 3a56574f329a368d645853e0f9e09472aee62349 0.8
 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
+2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
--- a/contrib/macosx/Welcome.html
+++ b/contrib/macosx/Welcome.html
@@ -5,13 +5,73 @@
   <meta http-equiv="Content-Style-Type" content="text/css">
   <title></title>
   <style type="text/css">
-    p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
+    p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica}
     p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
   </style>
 </head>
 <body>
 <p class="p1">This is a prepackaged release of <a href="http://www.selenic.com/mercurial">Mercurial</a> for Mac OS X.</p>
 <p class="p2"><br></p>
-<p class="p1">It is based on Mercurial 0.9.</p>
+<p class="p1">It is based on Mercurial 0.9.1</p>
+<br>
+<pre>
+Release Notes
+-------------
+
+2006-07-24  v0.9.1
+
+Major changes between Mercurial 0.9 and 0.9.1:
+
+ New features:
+ - You can now configure your 'hgweb' server to let remote users
+   'push' changes over http.
+ - You can now 'import' a patch in a mail message by saving the mail
+   message, and importing it.  This works for patches sent either
+   inline or as attachments.
+ - The 'diff' command now accepts '-rA:B' syntax as a synonym for
+   '-r A -r B', and adds '-b' and '-B' options.
+
+ New contributions and extensions:
+ - The 'acl' extension lets you lock down parts of a repository
+   against incoming changes
+ - The 'extdiff' extension lets you run your favourite graphical
+   change viewer
+ - Comprehensive integration with the 'vim' editor
+ - A restricted shell for 'ssh'-hosted repositories
+ - An importer for 'darcs' repositories
+
+ New hooks added:
+ - 'preupdate' is run before an update or merge in the working
+   directory.
+ - 'update' is run after an update or merge in the working
+   directory.
+
+ Behaviour changes:
+ - NOTE: Mercurial as installed by the Windows binary
+   installer no longer performs automatic line-ending conversion for
+   Unix/Linux compatibility.  To re-enable this feature, edit your
+   'mercurial.ini' file after you upgrade.
+ - The Windows binary installer now automatically adds 'hg' to your
+   '%PATH%'.
+ - The 'backout' command now runs an editor by default, to let you
+   modify the commit message for a backed-out changeset.
+ - An earlier problem with parsing of tags has been fixed.
+   This makes tag parsing slower but more reliable.
+
+ Memory usage and performance improvements:
+ - The 'remove' command has been rewritten to be hundreds of times
+   faster in large repositories.
+ - It is now possible to 'clone' a repository very quickly over a
+   LAN, if the server is configured to allow it.  See the new 'server'
+   section in the 'hgrc' documentation.
+
+ Other changes of note:
+ - Mercurial will now print help for an extension if you type 'hg
+   help EXT_NAME'.
+ - The usual array of bug fixes and documentation improvements.
+ - The integrated web server is now more WSGI-compliant.
+ - Work has begun to solidify Mercurial's API for use by third-party
+   packages.
+</pre>
 </body>
 </html>
--- a/contrib/mercurial.el
+++ b/contrib/mercurial.el
@@ -380,7 +380,9 @@ Handle frickin' frackin' gratuitous even
   (save-excursion
     (while hg-prev-buffer
       (set-buffer hg-prev-buffer))
-    (let ((path (or default (buffer-file-name) default-directory)))
+    (let ((path (or default
+                    (buffer-file-name)
+                    (expand-file-name default-directory))))
       (if (or (not path) current-prefix-arg)
           (expand-file-name
            (eval (list* 'read-file-name
@@ -972,7 +974,8 @@ With a prefix argument, prompt for the p
       (cd (hg-root path)))
     (when update
       (with-current-buffer buf
-	(set (make-local-variable 'backup-inhibited) nil)
+        (when (local-variable-p 'backup-inhibited)
+          (kill-local-variable 'backup-inhibited))
 	(hg-mode-line)))))
 
 (defun hg-incoming (&optional repo)
--- a/contrib/win32/ReadMe.html
+++ b/contrib/win32/ReadMe.html
@@ -14,7 +14,7 @@
   </head>
 
   <body>
-    <h1>Mercurial version 0.9 for Windows</h1>
+    <h1>Mercurial version 0.9.1 for Windows</h1>
 
     <p>Welcome to Mercurial for Windows!</p>
 
--- a/contrib/win32/mercurial.iss
+++ b/contrib/win32/mercurial.iss
@@ -4,7 +4,7 @@
 [Setup]
 AppCopyright=Copyright 2005, 2006 Matt Mackall and others
 AppName=Mercurial
-AppVerName=Mercurial version 0.9
+AppVerName=Mercurial version 0.9.1
 InfoAfterFile=contrib/win32/postinstall.txt
 LicenseFile=COPYING
 ShowLanguageDialog=yes
@@ -14,10 +14,10 @@ AppSupportURL=http://www.selenic.com/mer
 AppUpdatesURL=http://www.selenic.com/mercurial
 AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}
 AppContact=mercurial@selenic.com
-OutputBaseFilename=Mercurial-0.9
+OutputBaseFilename=Mercurial-0.9.1
 DefaultDirName={sd}\Mercurial
 SourceDir=C:\hg\hg-release
-VersionInfoVersion=0.9
+VersionInfoVersion=0.9.1
 VersionInfoDescription=Mercurial distributed SCM
 VersionInfoCopyright=Copyright 2005, 2006 Matt Mackall and others
 VersionInfoCompany=Matt Mackall and others
--- a/contrib/win32/postinstall.txt
+++ b/contrib/win32/postinstall.txt
@@ -7,6 +7,62 @@ file that comes with this package.
 Release Notes
 -------------
 
+2006-07-24  v0.9.1
+
+Major changes between Mercurial 0.9 and 0.9.1:
+
+ New features:
+ - You can now configure your 'hgweb' server to let remote users
+   'push' changes over http.
+ - You can now 'import' a patch in a mail message by saving the mail
+   message, and importing it.  This works for patches sent either
+   inline or as attachments.
+ - The 'diff' command now accepts '-rA:B' syntax as a synonym for
+   '-r A -r B', and adds '-b' and '-B' options.
+
+ New contributions and extensions:
+ - The 'acl' extension lets you lock down parts of a repository
+   against incoming changes
+ - The 'extdiff' extension lets you run your favourite graphical
+   change viewer
+ - Comprehensive integration with the 'vim' editor
+ - A restricted shell for 'ssh'-hosted repositories
+ - An importer for 'darcs' repositories
+
+ New hooks added:
+ - 'preupdate' is run before an update or merge in the working
+   directory.
+ - 'update' is run after an update or merge in the working
+   directory.
+
+ Behaviour changes:
+ - NOTE: Mercurial as installed by the Windows binary
+   installer no longer performs automatic line-ending conversion for
+   Unix/Linux compatibility.  To re-enable this feature, edit your
+   'mercurial.ini' file after you upgrade.
+ - The Windows binary installer now automatically adds 'hg' to your
+   '%PATH%'.
+ - The 'backout' command now runs an editor by default, to let you
+   modify the commit message for a backed-out changeset.
+ - An earlier problem with parsing of tags has been fixed.
+   This makes tag parsing slower but more reliable.
+
+ Memory usage and performance improvements:
+ - The 'remove' command has been rewritten to be hundreds of times
+   faster in large repositories.
+ - It is now possible to 'clone' a repository very quickly over a
+   LAN, if the server is configured to allow it.  See the new 'server'
+   section in the 'hgrc' documentation.
+
+ Other changes of note:
+ - Mercurial will now print help for an extension if you type 'hg
+   help EXT_NAME'.
+ - The usual array of bug fixes and documentation improvements.
+ - The integrated web server is now more WSGI-compliant.
+ - Work has begun to solidify Mercurial's API for use by third-party
+   packages.
+
+
 2006-05-10  v0.9
 
 * Major changes between Mercurial 0.8.1 and 0.9:
--- a/doc/hgrc.5.txt
+++ b/doc/hgrc.5.txt
@@ -138,9 +138,16 @@ email::
   from;;
     Optional.  Email address to use in "From" header and SMTP envelope
     of outgoing messages.
+  to;;
+    Optional.  Email address(es) of recipient(s).
+  cc;;
+    Optional.  Email address(es) to send carbon copies to.
+  bcc;;
+    Optional.  Email address(es) to send blind carbon copies to.
+    Cannot be set interactively.
   method;;
     Optional.  Method to use to send email messages.  If value is
-    "smtp" (default), use SMTP (see section "[mail]" for
+    "smtp" (default), use SMTP (see section "[smtp]" for
     configuration).  Otherwise, use as name of program to run that
     acts like sendmail (takes "-f" option for sender, list of
     recipients on command line, message on stdin).  Normally, setting
@@ -194,7 +201,8 @@ hooks::
 
   changegroup;;
     Run after a changegroup has been added via push, pull or
-    unbundle. ID of the first new changeset is in $HG_NODE.
+    unbundle. ID of the first new changeset is in $HG_NODE.  URL from
+    which changes came is in $HG_URL.
   commit;;
     Run after a changeset has been created in the local repository.
     ID of the newly created changeset is in $HG_NODE.  Parent
@@ -202,7 +210,7 @@ hooks::
   incoming;;
     Run after a changeset has been pulled, pushed, or unbundled into
     the local repository.  The ID of the newly arrived changeset is in
-    $HG_NODE.
+    $HG_NODE.  URL that was source of changes came is in $HG_URL.
   outgoing;;
     Run after sending changes from local repository to another.  ID of
     first changeset sent is in $HG_NODE.  Source of operation is in
@@ -210,7 +218,8 @@ hooks::
   prechangegroup;;
     Run before a changegroup is added via push, pull or unbundle.
     Exit status 0 allows the changegroup to proceed.  Non-zero status
-    will cause the push, pull or unbundle to fail.
+    will cause the push, pull or unbundle to fail.  URL from which
+    changes will come is in $HG_URL.
   precommit;;
     Run before starting a local commit.  Exit status 0 allows the
     commit to proceed.  Non-zero status will cause the commit to fail.
@@ -236,7 +245,8 @@ hooks::
     before accepting them.  Passed the ID of the first new changeset
     in $HG_NODE.  Exit status 0 allows the transaction to commit.
     Non-zero status will cause the transaction to be rolled back and
-    the push, pull or unbundle will fail.
+    the push, pull or unbundle will fail.  URL that was source of
+    changes is in $HG_URL.
   pretxncommit;;
     Run after a changeset has been created but the transaction not yet
     committed.  Changeset is visible to hook program.  This lets you
@@ -440,6 +450,9 @@ web::
   push_ssl;;
     Whether to require that inbound pushes be transported over SSL to
     prevent password sniffing.  Default is true.
+  stripes;;
+    How many lines a "zebra stripe" should span in multiline output.
+    Default is 1; set to 0 to disable.
   style;;
     Which template map style to use.
   templates;;
--- a/hgext/extdiff.py
+++ b/hgext/extdiff.py
@@ -22,6 +22,9 @@
 #   cmd.vdiff = kdiff3
 #   # add new command called meld, runs meld (no need to name twice)
 #   cmd.meld =
+#   # add new command called vimdiff, runs gvimdiff with DirDiff plugin
+#   #(see http://www.vim.org/scripts/script.php?script_id=102)
+#   cmd.vimdiff = LC_ALL=C gvim -f '+bdel 1 2' '+ execute "DirDiff ".argv(0)." ".argv(1)'
 #
 # you can use -I/-X and list of file or directory names like normal
 # "hg diff" command. extdiff makes snapshots of only needed files, so
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -852,6 +852,8 @@ class queue:
         else:
             start = self.series.index(patch) + 1
         for p in self.series[start:]:
+            if self.ui.verbose:
+                self.ui.write("%d " % self.series.index(p))
             self.ui.write("%s\n" % p)
 
     def qseries(self, repo, missing=None):
@@ -999,8 +1001,11 @@ class queue:
 
     def appliedname(self, index):
         p = self.applied[index]
+        pname = p.split(':')[1]
         if not self.ui.verbose:
-            p = p.split(':')[1]
+            p = pname
+        else:
+            p = str(self.series.index(pname)) + " " + p
         return p
 
     def top(self, repo):
@@ -1015,7 +1020,10 @@ class queue:
         if end == len(self.series):
             self.ui.write("All patches applied\n")
         else:
-            self.ui.write(self.series[end] + '\n')
+            p = self.series[end]
+            if self.ui.verbose:
+                self.ui.write("%d " % self.series.index(p))
+            self.ui.write(p + '\n')
 
     def prev(self, repo):
         if len(self.applied) > 1:
@@ -1272,6 +1280,30 @@ def version(ui, q=None):
 
 def reposetup(ui, repo):
     repomap[repo] = queue(ui, repo.join(""))
+    oldtags = repo.tags
+
+    def qtags():
+        if repo.tagscache:
+            return repo.tagscache
+
+        tagscache = oldtags()
+
+        q = repomap[repo]
+        if len(q.applied) == 0:
+            return tagscache
+
+        mqtags = [patch.split(':') for patch in q.applied]
+        mqtags.append((mqtags[-1][0], 'qtip'))
+        mqtags.append((mqtags[0][0], 'qbase'))
+        for patch in mqtags:
+            if patch[1] in tagscache:
+                repo.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
+            else:
+                tagscache[patch[1]] = revlog.bin(patch[0])
+
+        return tagscache
+
+    repo.tags = qtags
 
 cmdtable = {
     "qapplied": (applied, [], 'hg qapplied [PATCH]'),
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -38,6 +38,7 @@
 # from = My Name <my@email>
 # to = recipient1, recipient2, ...
 # cc = cc1, cc2, ...
+# bcc = bcc1, bcc2, ...
 
 from mercurial.demandload import *
 demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
@@ -185,6 +186,10 @@ def patchbomb(ui, repo, *revs, **opts):
     to = getaddrs('to', 'To')
     cc = getaddrs('cc', 'Cc', '')
 
+    bcc = opts['bcc'] or (ui.config('email', 'bcc') or
+                          ui.config('patchbomb', 'bcc') or '').split(',')
+    bcc = [a.strip() for a in bcc if a.strip()]
+
     if len(patches) > 1:
         ui.write(_('\nWrite the introductory message for the patch series.\n\n'))
 
@@ -240,7 +245,8 @@ def patchbomb(ui, repo, *revs, **opts):
         start_time += 1
         m['From'] = sender
         m['To'] = ', '.join(to)
-        if cc: m['Cc'] = ', '.join(cc)
+        if cc: m['Cc']  = ', '.join(cc)
+        if bcc: m['Bcc'] = ', '.join(bcc)
         if opts['test']:
             ui.status('Displaying ', m['Subject'], ' ...\n')
             fp = os.popen(os.getenv('PAGER', 'more'), 'w')
@@ -261,12 +267,13 @@ def patchbomb(ui, repo, *revs, **opts):
             fp.close()
         else:
             ui.status('Sending ', m['Subject'], ' ...\n')
-            mail.sendmail(sender, to + cc, m.as_string(0))
+            mail.sendmail(sender, to + bcc + cc, m.as_string(0))
 
 cmdtable = {
     'email':
     (patchbomb,
-     [('c', 'cc', [], 'email addresses of copy recipients'),
+     [('', 'bcc', [], 'email addresses of blind copy recipients'),
+      ('c', 'cc', [], 'email addresses of copy recipients'),
       ('d', 'diffstat', None, 'add diffstat output to messages'),
       ('f', 'from', '', 'email address of sender'),
       ('', 'plain', None, 'omit hg patch header'),
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -159,6 +159,10 @@ class bundlefilelog(bundlerevlog, filelo
 class bundlerepository(localrepo.localrepository):
     def __init__(self, ui, path, bundlename):
         localrepo.localrepository.__init__(self, ui, path)
+
+        self._url = 'bundle:' + bundlename
+        if path: self._url += '+' + path
+
         self.tempfile = None
         self.bundlefile = open(bundlename, "rb")
         header = self.bundlefile.read(6)
@@ -208,6 +212,9 @@ class bundlerepository(localrepo.localre
             for c in changegroup.chunkiter(self.bundlefile):
                 pass
 
+    def url(self):
+        return self._url
+
     def dev(self):
         return -1
 
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2614,37 +2614,44 @@ def serve(ui, repo, **opts):
 def status(ui, repo, *pats, **opts):
     """show changed files in the working directory
 
-    Show changed files in the repository.  If names are
-    given, only files that match are shown.
+    Show status of files in the repository.  If names are given, only
+    files that match are shown.  Files that are clean or ignored, are
+    not listed unless -c (clean), -i (ignored) or -A is given.
 
     The codes used to show the status of files are:
     M = modified
     A = added
     R = removed
+    C = clean
     ! = deleted, but still tracked
     ? = not tracked
     I = ignored (not shown by default)
       = the previous added file was copied from here
     """
 
-    show_ignored = opts['ignored'] and True or False
+    all = opts['all']
+    
     files, matchfn, anypats = matchpats(repo, pats, opts)
     cwd = (pats and repo.getcwd()) or ''
-    modified, added, removed, deleted, unknown, ignored = [
+    modified, added, removed, deleted, unknown, ignored, clean = [
         [util.pathto(cwd, x) for x in n]
-        for n in repo.changes(files=files, match=matchfn,
-                              show_ignored=show_ignored)]
-
-    changetypes = [('modified', 'M', modified),
+        for n in repo.status(files=files, match=matchfn,
+                             list_ignored=all or opts['ignored'],
+                             list_clean=all or opts['clean'])]
+
+    changetypes = (('modified', 'M', modified),
                    ('added', 'A', added),
                    ('removed', 'R', removed),
                    ('deleted', '!', deleted),
                    ('unknown', '?', unknown),
-                   ('ignored', 'I', ignored)]
+                   ('ignored', 'I', ignored))
+
+    explicit_changetypes = changetypes + (('clean', 'C', clean),)
 
     end = opts['print0'] and '\0' or '\n'
 
-    for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
+    for opt, char, changes in ([ct for ct in explicit_changetypes
+                                if all or opts[ct[0]]]
                                or changetypes):
         if opts['no_status']:
             format = "%%s%s" % end
@@ -2653,7 +2660,7 @@ def status(ui, repo, *pats, **opts):
 
         for f in changes:
             ui.write(format % f)
-            if (opts.get('copies') and not opts.get('no_status')
+            if ((all or opts.get('copies')) and not opts.get('no_status')
                 and opt == 'added' and repo.dirstate.copies.has_key(f)):
                 ui.write('  %s%s' % (repo.dirstate.copies[f], end))
 
@@ -2756,7 +2763,8 @@ def unbundle(ui, repo, fname, **opts):
         raise util.Abort(_("%s: unknown bundle compression type")
                          % fname)
     gen = generator(util.filechunkiter(f, 4096))
-    modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle')
+    modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
+                                   'bundle:' + fname)
     return postincoming(ui, repo, modheads, opts['update'])
 
 def undo(ui, repo):
@@ -3144,10 +3152,12 @@ table = {
          _('hg serve [OPTION]...')),
     "^status|st":
         (status,
-         [('m', 'modified', None, _('show only modified files')),
+         [('A', 'all', None, _('show status of all files')),
+          ('m', 'modified', None, _('show only modified files')),
           ('a', 'added', None, _('show only added files')),
           ('r', 'removed', None, _('show only removed files')),
           ('d', 'deleted', None, _('show only deleted (but tracked) files')),
+          ('c', 'clean', None, _('show only files without changes')),
           ('u', 'unknown', None, _('show only unknown (not tracked) files')),
           ('i', 'ignored', None, _('show ignored files')),
           ('n', 'no-status', None, _('hide status prefix')),
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -344,6 +344,10 @@ class dirstate(object):
     # directly by this function, but might be modified by your statmatch call.
     #
     def walkhelper(self, files, statmatch, dc, badmatch=None):
+        # self.root may end with a path separator when self.root == '/'
+        common_prefix_len = len(self.root)
+        if not self.root.endswith('/'):
+            common_prefix_len += 1
         # recursion free walker, faster than os.walk.
         def findfiles(s):
             work = [s]
@@ -352,7 +356,7 @@ class dirstate(object):
                 names = os.listdir(top)
                 names.sort()
                 # nd is the top of the repository dir tree
-                nd = util.normpath(top[len(self.root) + 1:])
+                nd = util.normpath(top[common_prefix_len:])
                 if nd == '.':
                     nd = ''
                 else:
@@ -434,15 +438,16 @@ class dirstate(object):
             if not seen(k) and (statmatch(k, None)):
                 yield 'm', k, None
 
-    def changes(self, files=None, match=util.always, show_ignored=None):
+    def status(self, files=None, match=util.always, list_ignored=False,
+               list_clean=False):
         lookup, modified, added, unknown, ignored = [], [], [], [], []
-        removed, deleted = [], []
+        removed, deleted, clean = [], [], []
 
-        for src, fn, st in self.statwalk(files, match, ignored=show_ignored):
+        for src, fn, st in self.statwalk(files, match, ignored=list_ignored):
             try:
                 type_, mode, size, time = self[fn]
             except KeyError:
-                if show_ignored and self.ignore(fn):
+                if list_ignored and self.ignore(fn):
                     ignored.append(fn)
                 else:
                     unknown.append(fn)
@@ -473,6 +478,8 @@ class dirstate(object):
                     modified.append(fn)
                 elif time != st.st_mtime:
                     lookup.append(fn)
+                elif list_clean:
+                    clean.append(fn)
             elif type_ == 'm':
                 modified.append(fn)
             elif type_ == 'a':
@@ -480,4 +487,5 @@ class dirstate(object):
             elif type_ == 'r':
                 removed.append(fn)
 
-        return (lookup, modified, added, removed, deleted, unknown, ignored)
+        return (lookup, modified, added, removed, deleted, unknown, ignored,
+                clean)
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -37,6 +37,7 @@ class hgweb(object):
         self.mtime = -1
         self.reponame = name
         self.archives = 'zip', 'gz', 'bz2'
+        self.stripecount = 1
         self.templatepath = self.repo.ui.config("web", "templates",
                                                 templater.templatepath())
 
@@ -46,6 +47,8 @@ class hgweb(object):
             self.mtime = mtime
             self.repo = hg.repository(self.repo.ui, self.repo.root)
             self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10))
+            self.stripecount = int(self.repo.ui.config("web", "stripes", 1))
+            self.maxshortchanges = int(self.repo.ui.config("web", "maxshortchanges", 60))
             self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10))
             self.allowpull = self.repo.ui.configbool("web", "allowpull", True)
 
@@ -158,7 +161,7 @@ class hgweb(object):
                             ignorewsamount=ignorewsamount,
                             ignoreblanklines=ignoreblanklines), f, tn)
 
-    def changelog(self, pos):
+    def changelog(self, pos, shortlog=False):
         def changenav(**map):
             def seq(factor, maxchanges=None):
                 if maxchanges:
@@ -173,8 +176,9 @@ class hgweb(object):
 
             l = []
             last = 0
-            for f in seq(1, self.maxchanges):
-                if f < self.maxchanges or f <= last:
+            maxchanges = shortlog and self.maxshortchanges or self.maxchanges
+            for f in seq(1, maxchanges):
+                if f < maxchanges or f <= last:
                     continue
                 if f > count:
                     break
@@ -219,14 +223,15 @@ class hgweb(object):
             for e in l:
                 yield e
 
+        maxchanges = shortlog and self.maxshortchanges or self.maxchanges
         cl = self.repo.changelog
         mf = cl.read(cl.tip())[0]
         count = cl.count()
-        start = max(0, pos - self.maxchanges + 1)
-        end = min(count, start + self.maxchanges)
+        start = max(0, pos - maxchanges + 1)
+        end = min(count, start + maxchanges)
         pos = end - 1
 
-        yield self.t('changelog',
+        yield self.t(shortlog and 'shortlog' or 'changelog',
                      changenav=changenav,
                      manifest=hex(mf),
                      rev=pos, changesets=count, entries=changelist,
@@ -265,7 +270,7 @@ class hgweb(object):
                 hn = hex(n)
 
                 yield self.t('searchentry',
-                             parity=count & 1,
+                             parity=self.stripes(count),
                              author=changes[1],
                              parent=self.siblings(cl.parents(n), cl.rev),
                              child=self.siblings(cl.children(n), cl.rev),
@@ -376,7 +381,7 @@ class hgweb(object):
             for l, t in enumerate(text.splitlines(1)):
                 yield {"line": t,
                        "linenumber": "% 6d" % (l + 1),
-                       "parity": l & 1}
+                       "parity": self.stripes(l)}
 
         yield self.t("filerevision",
                      file=f,
@@ -409,7 +414,7 @@ class hgweb(object):
         mfn = cs[0]
 
         def annotate(**map):
-            parity = 1
+            parity = 0
             last = None
             for r, l in fl.annotate(n):
                 try:
@@ -489,10 +494,10 @@ class hgweb(object):
                 yield {"file": full,
                        "manifest": mnode,
                        "filenode": hex(fnode),
-                       "parity": parity,
+                       "parity": self.stripes(parity),
                        "basename": f,
                        "permissions": mff[full]}
-                parity = 1 - parity
+                parity += 1
 
         def dirlist(**map):
             parity = 0
@@ -503,11 +508,11 @@ class hgweb(object):
                 if fnode:
                     continue
 
-                yield {"parity": parity,
+                yield {"parity": self.stripes(parity),
                        "path": os.path.join(path, f),
                        "manifest": mnode,
                        "basename": f[:-1]}
-                parity = 1 - parity
+                parity += 1
 
         yield self.t("manifest",
                      manifest=mnode,
@@ -530,12 +535,12 @@ class hgweb(object):
             parity = 0
             for k,n in i:
                 if notip and k == "tip": continue
-                yield {"parity": parity,
+                yield {"parity": self.stripes(parity),
                        "tag": k,
                        "tagmanifest": hex(cl.read(n)[0]),
                        "date": cl.read(n)[2],
                        "node": hex(n)}
-                parity = 1 - parity
+                parity += 1
 
         yield self.t("tags",
                      manifest=hex(mf),
@@ -565,12 +570,12 @@ class hgweb(object):
                 t = c[2]
 
                 yield self.t("tagentry",
-                             parity = parity,
+                             parity = self.stripes(parity),
                              tag = k,
                              node = hex(n),
                              date = t,
                              tagmanifest = hex(m))
-                parity = 1 - parity
+                parity += 1
 
         def changelist(**map):
             parity = 0
@@ -609,7 +614,8 @@ class hgweb(object):
                  lastchange = (0, 0), # FIXME
                  manifest = hex(mf),
                  tags = tagentries,
-                 shortlog = changelist)
+                 shortlog = changelist,
+                 archives=self.archivelist("tip"))
 
     def filediff(self, file, changeset):
         cl = self.repo.changelog
@@ -689,6 +695,7 @@ class hgweb(object):
         def expand_form(form):
             shortcuts = {
                 'cl': [('cmd', ['changelog']), ('rev', None)],
+                'sl': [('cmd', ['shortlog']), ('rev', None)],
                 'cs': [('cmd', ['changeset']), ('node', None)],
                 'f': [('cmd', ['file']), ('filenode', None)],
                 'fl': [('cmd', ['filelog']), ('filenode', None)],
@@ -752,6 +759,13 @@ class hgweb(object):
         else:
             req.write(self.t("error"))
 
+    def stripes(self, parity):
+        "make horizontal stripes for easier reading"
+        if self.stripecount:
+            return (1 + parity / self.stripecount) & 1
+        else:
+            return 0
+
     def do_changelog(self, req):
         hi = self.repo.changelog.count() - 1
         if req.form.has_key('rev'):
@@ -764,6 +778,18 @@ class hgweb(object):
 
         req.write(self.changelog(hi))
 
+    def do_shortlog(self, req):
+        hi = self.repo.changelog.count() - 1
+        if req.form.has_key('rev'):
+            hi = req.form['rev'][0]
+            try:
+                hi = self.repo.changelog.rev(self.repo.lookup(hi))
+            except hg.RepoError:
+                req.write(self.search(hi)) # XXX redirect to 404 page?
+                return
+
+        req.write(self.changelog(hi, shortlog = True))
+
     def do_changeset(self, req):
         req.write(self.changeset(req.form['node'][0]))
 
@@ -895,9 +921,13 @@ class hgweb(object):
         # require ssl by default, auth info cannot be sniffed and
         # replayed
         ssl_req = self.repo.ui.configbool('web', 'push_ssl', True)
-        if ssl_req and not req.env.get('HTTPS'):
-            bail(_('ssl required\n'))
-            return
+        if ssl_req:
+            if not req.env.get('HTTPS'):
+                bail(_('ssl required\n'))
+                return
+            proto = 'https'
+        else:
+            proto = 'http'
 
         # do not allow push unless explicitly allowed
         if not self.check_perm(req, 'push', False):
@@ -943,7 +973,9 @@ class hgweb(object):
                 sys.stdout = cStringIO.StringIO()
 
                 try:
-                    ret = self.repo.addchangegroup(fp, 'serve')
+                    url = 'remote:%s:%s' % (proto,
+                                            req.env.get('REMOTE_HOST', ''))
+                    ret = self.repo.addchangegroup(fp, 'serve', url)
                 finally:
                     val = sys.stdout.getvalue()
                     sys.stdout = old_stdout
--- a/mercurial/httprepo.py
+++ b/mercurial/httprepo.py
@@ -115,6 +115,7 @@ else:
 
 class httprepository(remoterepository):
     def __init__(self, ui, path):
+        self.path = path
         self.caps = None
         scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
         if query or frag:
@@ -124,8 +125,8 @@ class httprepository(remoterepository):
         host, port, user, passwd = netlocsplit(netloc)
 
         # urllib cannot handle URLs with embedded user or passwd
-        self.url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
-                                        urlpath, '', ''))
+        self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
+                                         urlpath, '', ''))
         self.ui = ui
 
         proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
@@ -189,6 +190,9 @@ class httprepository(remoterepository):
         opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
         urllib2.install_opener(opener)
 
+    def url(self):
+        return self.path
+
     # look up capabilities only when needed
 
     def get_caps(self):
@@ -213,7 +217,7 @@ class httprepository(remoterepository):
         q = {"cmd": cmd}
         q.update(args)
         qs = urllib.urlencode(q)
-        cu = "%s?%s" % (self.url, qs)
+        cu = "%s?%s" % (self._url, qs)
         try:
             resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
         except urllib2.HTTPError, inst:
@@ -234,13 +238,13 @@ class httprepository(remoterepository):
                not proto.startswith('text/plain') and \
                not proto.startswith('application/hg-changegroup'):
             raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
-                               self.url)
+                               self._url)
 
         if proto.startswith('application/mercurial'):
             version = proto[22:]
             if float(version) > 0.1:
                 raise hg.RepoError(_("'%s' uses newer protocol %s") %
-                                   (self.url, version))
+                                   (self._url, version))
 
         return resp
 
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -83,6 +83,9 @@ class localrepository(repo.repository):
 
         self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root)
 
+    def url(self):
+        return 'file:' + self.root
+
     def hook(self, name, throw=False, **args):
         def callhook(hname, funcname):
             '''call python hook. hook is callable object, looked up as
@@ -658,9 +661,9 @@ class localrepository(repo.repository):
             for src, fn in self.dirstate.walk(files, match, badmatch=badmatch):
                 yield src, fn
 
-    def changes(self, node1=None, node2=None, files=[], match=util.always,
-                wlock=None, show_ignored=None):
-        """return changes between two nodes or node and working directory
+    def status(self, node1=None, node2=None, files=[], match=util.always,
+                wlock=None, list_ignored=False, list_clean=False):
+        """return status of files between two nodes or node and working directory
 
         If node1 is None, use the first dirstate parent instead.
         If node2 is None, compare node1 with working directory.
@@ -679,7 +682,9 @@ class localrepository(repo.repository):
                     del mf[fn]
             return mf
 
-        modified, added, removed, deleted, unknown, ignored = [],[],[],[],[],[]
+        modified, added, removed, deleted, unknown = [], [], [], [], []
+        ignored, clean = [], []
+
         compareworking = False
         if not node1 or (not node2 and node1 == self.dirstate.parents()[0]):
             compareworking = True
@@ -697,8 +702,9 @@ class localrepository(repo.repository):
                     wlock = self.wlock(wait=0)
                 except lock.LockException:
                     wlock = None
-            lookup, modified, added, removed, deleted, unknown, ignored = (
-                self.dirstate.changes(files, match, show_ignored))
+            (lookup, modified, added, removed, deleted, unknown,
+             ignored, clean) = self.dirstate.status(files, match,
+                                                    list_ignored, list_clean)
 
             # are we comparing working dir against its parent?
             if compareworking:
@@ -721,12 +727,11 @@ class localrepository(repo.repository):
                         del mf2[f]
         else:
             # we are comparing two revisions
-            deleted, unknown, ignored = [], [], []
             mf2 = mfmatches(node2)
 
         if not compareworking:
             # flush lists from dirstate before comparing manifests
-            modified, added = [], []
+            modified, added, clean = [], [], []
 
             # make sure to sort the files so we talk to the disk in a
             # reasonable order
@@ -736,6 +741,8 @@ class localrepository(repo.repository):
                 if mf1.has_key(fn):
                     if mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1)):
                         modified.append(fn)
+                    elif list_clean:
+                        clean.append(fn)
                     del mf1[fn]
                 else:
                     added.append(fn)
@@ -743,12 +750,19 @@ class localrepository(repo.repository):
             removed = mf1.keys()
 
         # sort and return results:
-        for l in modified, added, removed, deleted, unknown, ignored:
+        for l in modified, added, removed, deleted, unknown, ignored, clean:
             l.sort()
-        if show_ignored is None:
-            return (modified, added, removed, deleted, unknown)
+        return (modified, added, removed, deleted, unknown, ignored, clean)
+
+    def changes(self, node1=None, node2=None, files=[], match=util.always,
+                wlock=None, list_ignored=False, list_clean=False):
+        '''DEPRECATED - use status instead'''
+        marduit = self.status(node1, node2, files, match, wlock,
+                              list_ignored, list_clean)
+        if list_ignored:
+            return marduit[:-1]
         else:
-            return (modified, added, removed, deleted, unknown, ignored)
+            return marduit[:-2]
 
     def add(self, list, wlock=None):
         if not wlock:
@@ -1174,7 +1188,7 @@ class localrepository(repo.repository):
             cg = remote.changegroup(fetch, 'pull')
         else:
             cg = remote.changegroupsubset(fetch, heads, 'pull')
-        return self.addchangegroup(cg, 'pull')
+        return self.addchangegroup(cg, 'pull', remote.url())
 
     def push(self, remote, force=False, revs=None):
         # there are two ways to push to remote repo:
@@ -1230,7 +1244,7 @@ class localrepository(repo.repository):
         ret = self.prepush(remote, force, revs)
         if ret[0] is not None:
             cg, remote_heads = ret
-            return remote.addchangegroup(cg, 'push')
+            return remote.addchangegroup(cg, 'push', self.url())
         return ret[1]
 
     def push_unbundle(self, remote, force, revs):
@@ -1583,7 +1597,7 @@ class localrepository(repo.repository):
 
         return util.chunkbuffer(gengroup())
 
-    def addchangegroup(self, source, srctype):
+    def addchangegroup(self, source, srctype, url):
         """add changegroup to repo.
         returns number of heads modified or added + 1."""
 
@@ -1597,7 +1611,7 @@ class localrepository(repo.repository):
         if not source:
             return 0
 
-        self.hook('prechangegroup', throw=True, source=srctype)
+        self.hook('prechangegroup', throw=True, source=srctype, url=url)
 
         changesets = files = revisions = 0
 
@@ -1664,17 +1678,18 @@ class localrepository(repo.repository):
 
         if changesets > 0:
             self.hook('pretxnchangegroup', throw=True,
-                      node=hex(self.changelog.node(cor+1)), source=srctype)
+                      node=hex(self.changelog.node(cor+1)), source=srctype,
+                      url=url)
 
         tr.close()
 
         if changesets > 0:
             self.hook("changegroup", node=hex(self.changelog.node(cor+1)),
-                      source=srctype)
+                      source=srctype, url=url)
 
             for i in range(cor + 1, cnr + 1):
                 self.hook("incoming", node=hex(self.changelog.node(i)),
-                          source=srctype)
+                          source=srctype, url=url)
 
         return newheads - oldheads + 1
 
--- a/mercurial/sshrepo.py
+++ b/mercurial/sshrepo.py
@@ -13,7 +13,7 @@ demandload(globals(), "hg os re stat uti
 
 class sshrepository(remoterepository):
     def __init__(self, ui, path, create=0):
-        self.url = path
+        self._url = path
         self.ui = ui
 
         m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path)
@@ -48,6 +48,9 @@ class sshrepository(remoterepository):
 
         self.validate_repo(ui, sshcmd, args, remotecmd)
 
+    def url(self):
+        return self._url
+
     def validate_repo(self, ui, sshcmd, args, remotecmd):
         cmd = '%s %s "%s -R %s serve --stdio"'
         cmd = cmd % (sshcmd, args, remotecmd, self.path)
@@ -180,7 +183,7 @@ class sshrepository(remoterepository):
             return 1
         return int(r)
 
-    def addchangegroup(self, cg, source):
+    def addchangegroup(self, cg, source, url):
         d = self.call("addchangegroup")
         if d:
             raise hg.RepoError(_("push refused: %s") % d)
--- a/mercurial/sshserver.py
+++ b/mercurial/sshserver.py
@@ -117,9 +117,13 @@ class sshserver(object):
             return
 
         self.respond("")
-        r = self.repo.addchangegroup(self.fin, 'serve')
+        r = self.repo.addchangegroup(self.fin, 'serve', self.client_url())
         self.respond(str(r))
 
+    def client_url(self):
+        client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
+        return 'remote:ssh:' + client
+        
     def do_unbundle(self):
         their_heads = self.getarg()[1].split()
 
@@ -159,7 +163,7 @@ class sshserver(object):
                 # push can proceed
 
                 fp.seek(0)
-                r = self.repo.addchangegroup(fp, 'serve')
+                r = self.repo.addchangegroup(fp, 'serve', self.client_url())
                 self.respond(str(r))
             finally:
                 if not was_locked:
--- a/mercurial/statichttprepo.py
+++ b/mercurial/statichttprepo.py
@@ -30,6 +30,7 @@ def opener(base):
 
 class statichttprepository(localrepo.localrepository):
     def __init__(self, ui, path):
+        self._url = path
         self.path = (path + "/.hg")
         self.ui = ui
         self.revlogversion = 0
@@ -41,6 +42,9 @@ class statichttprepository(localrepo.loc
         self.encodepats = None
         self.decodepats = None
 
+    def url(self):
+        return 'static-' + self._url
+
     def dev(self):
         return -1
 
--- a/templates/changelog-gitweb.tmpl
+++ b/templates/changelog-gitweb.tmpl
@@ -20,7 +20,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | changelog | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;rev=#rev#;style=gitweb">shortlog</a> | changelog | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>#archives%archiveentry#<br/>
 <br/>
 #changenav%naventry#<br/>
 </div>
--- a/templates/changelog.tmpl
+++ b/templates/changelog.tmpl
@@ -6,6 +6,7 @@
 <body>
 
 <div class="buttons">
+<a href="?sl=#rev#">shortlog</a>
 <a href="?cmd=tags">tags</a>
 <a href="?mf=#manifest|short#;path=/">manifest</a>
 #archives%archiveentry#
--- a/templates/changeset-gitweb.tmpl
+++ b/templates/changeset-gitweb.tmpl
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;rev=#rev#;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a> | changeset | <a href="?cmd=changeset;node=#node#;style=raw">raw</a> #archives%archiveentry#<br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;rev=#rev#;style=gitweb">shortlog</a> | <a href="?cmd=changelog;rev=#rev#;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a> | changeset | <a href="?cmd=changeset;node=#node#;style=raw">raw</a> #archives%archiveentry#<br/>
 </div>
 
 <div>
--- a/templates/changeset.tmpl
+++ b/templates/changeset.tmpl
@@ -5,6 +5,7 @@
 
 <div class="buttons">
 <a href="?cl=#rev#">changelog</a>
+<a href="?sl=#rev#">shortlog</a>
 <a href="?cmd=tags">tags</a>
 <a href="?mf=#manifest|short#;path=/">manifest</a>
 <a href="?cs=#node|short#;style=raw">raw</a>
--- a/templates/error-gitweb.tmpl
+++ b/templates/error-gitweb.tmpl
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/>
 </div>
 
 <div>
--- a/templates/fileannotate-gitweb.tmpl
+++ b/templates/fileannotate-gitweb.tmpl
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | annotate | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | annotate | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/>
 </div>
 
 <div class="title">#file|escape#</div>
--- a/templates/fileannotate.tmpl
+++ b/templates/fileannotate.tmpl
@@ -5,6 +5,7 @@
 
 <div class="buttons">
 <a href="?cl=#rev#">changelog</a>
+<a href="?sl=#rev#">shortlog</a>
 <a href="?tags=">tags</a>
 <a href="?cs=#node|short#">changeset</a>
 <a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a>
--- a/templates/filediff.tmpl
+++ b/templates/filediff.tmpl
@@ -5,6 +5,7 @@
 
 <div class="buttons">
 <a href="?cl=#rev#">changelog</a>
+<a href="?sl=#rev#">shortlog</a>
 <a href="?tags=">tags</a>
 <a href="?cs=#node|short#">changeset</a>
 <a href="?f=#filenode|short#;file=#file|urlescape#">file</a>
--- a/templates/filelog-gitweb.tmpl
+++ b/templates/filelog-gitweb.tmpl
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | revisions | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?fl=#filenode|short#;file=#file|urlescape#;style=rss">rss</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | revisions | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?fl=#filenode|short#;file=#file|urlescape#;style=rss">rss</a><br/>
 </div>
 
 <div class="title" >#file|urlescape#</div>
--- a/templates/filelog.tmpl
+++ b/templates/filelog.tmpl
@@ -8,6 +8,7 @@
 
 <div class="buttons">
 <a href="?cl=tip">changelog</a>
+<a href="?sl=tip">shortlog</a>
 <a href="?tags=">tags</a>
 <a href="?f=#filenode|short#;file=#file|urlescape#">file</a>
 <a href="?fa=#filenode|short#;file=#file|urlescape#">annotate</a>
--- a/templates/filerevision-gitweb.tmpl
+++ b/templates/filerevision-gitweb.tmpl
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?mf=#manifest|short#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | file | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?mf=#manifest|short#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | file | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=gitweb">annotate</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/>
 </div>
 
 <div class="title">#file|escape#</div>
--- a/templates/filerevision.tmpl
+++ b/templates/filerevision.tmpl
@@ -5,6 +5,7 @@
 
 <div class="buttons">
 <a href="?cl=#rev#">changelog</a>
+<a href="?sl=#rev#">shortlog</a>
 <a href="?tags=">tags</a>
 <a href="?cs=#node|short#">changeset</a>
 <a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a>
--- a/templates/manifest-gitweb.tmpl
+++ b/templates/manifest-gitweb.tmpl
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | manifest | <a href="?cs=#node|short#;style=gitweb">changeset</a> #archives%archiveentry#<br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | manifest | <a href="?cs=#node|short#;style=gitweb">changeset</a> #archives%archiveentry#<br/>
 </div>
 
 <div class="title" >#path|escape#</div>
--- a/templates/manifest.tmpl
+++ b/templates/manifest.tmpl
@@ -5,6 +5,7 @@
 
 <div class="buttons">
 <a href="?cl=#rev#">changelog</a>
+<a href="?sl=#rev#">shortlog</a>
 <a href="?tags=">tags</a>
 <a href="?cs=#node|short#">changeset</a>
 #archives%archiveentry#
--- a/templates/map
+++ b/templates/map
@@ -3,7 +3,10 @@ header = header.tmpl
 footer = footer.tmpl
 search = search.tmpl
 changelog = changelog.tmpl
+shortlog = shortlog.tmpl
+shortlogentry = shortlogentry.tmpl
 naventry = '<a href="?cl=#rev#">#label|escape#</a> '
+navshortentry = '<a href="?sl=#rev#">#label|escape#</a> '
 filedifflink = '<a href="?fd=#node|short#;file=#file|urlescape#">#file|escape#</a> '
 filenodelink = '<a href="?f=#filenode|short#;file=#file|urlescape#">#file|escape#</a> '
 fileellipses = '...'
--- a/templates/search-gitweb.tmpl
+++ b/templates/search-gitweb.tmpl
@@ -1,6 +1,6 @@
 #header#
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | log | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/>
 </div>
 
 <h2>searching for #query|escape#</h2>
--- a/templates/search.tmpl
+++ b/templates/search.tmpl
@@ -5,6 +5,7 @@
 
 <div class="buttons">
 <a href="?cl=tip">changelog</a>
+<a href="?sl=tip">shortlog</a>
 <a href="?tags=">tags</a>
 <a href="?mf=#manifest|short#;path=/">manifest</a>
 </div>
--- a/templates/shortlog-gitweb.tmpl
+++ b/templates/shortlog-gitweb.tmpl
@@ -1,13 +1,32 @@
 #header#
+<title>#repo|escape#: Shortlog</title>
+<link rel="alternate" type="application/rss+xml"
+   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
+</head>
+<body>
 
+<div class="page_header">
+<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / shortlog
+</div>
+
+<form action="#">
+<div class="search">
+<input type="hidden" name="repo" value="#repo|escape#"  />
+<input type="hidden" name="style" value="gitweb"  />
+<input type="hidden" name="cmd" value="changelog"  />
+<input type="text" name="rev"  />
+</div>
+</form>
+</div>
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">log</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/>
+<a href="?cmd=summary;style=gitweb">summary</a> | shortlog | <a href="?cmd=changelog;rev=#rev#;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>#archives%archiveentry#<br/>
+<br/>
 
-#changenav%naventry#<br/>
+#changenav%navshortentry#<br/>
 </div>
 
 <table cellspacing="0">
-#entries#
+#entries%shortlogentry#
 </table>
 
 #footer#
new file mode 100644
--- /dev/null
+++ b/templates/shortlog.tmpl
@@ -0,0 +1,38 @@
+#header#
+<title>#repo|escape#: shortlog</title>
+<link rel="alternate" type="application/rss+xml"
+   href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#">
+</head>
+<body>
+
+<div class="buttons">
+<a href="?cl=#rev#">changelog</a>
+<a href="?cmd=tags">tags</a>
+<a href="?mf=#manifest|short#;path=/">manifest</a>
+#archives%archiveentry#
+<a type="application/rss+xml" href="?style=rss">rss</a>
+</div>
+
+<h2>shortlog for #repo|escape#</h2>
+
+<form action="#">
+<p>
+<label for="search1">search:</label>
+<input type="hidden" name="cmd" value="changelog">
+<input name="rev" id="search1" type="text" size="30">
+navigate: <small class="navigate">#changenav%navshortentry#</small>
+</p>
+</form>
+
+#entries%shortlogentry#
+
+<form action="#">
+<p>
+<label for="search2">search:</label>
+<input type="hidden" name="cmd" value="changelog">
+<input name="rev" id="search2" type="text" size="30">
+navigate: <small class="navigate">#changenav%navshortentry#</small>
+</p>
+</form>
+
+#footer#
new file mode 100644
--- /dev/null
+++ b/templates/shortlogentry.tmpl
@@ -0,0 +1,7 @@
+<table class="slogEntry parity#parity#">
+ <tr>
+  <td class="age">#date|age#</td>
+  <td class="author">#author|obfuscate#</td>
+  <td class="node"><a href="?cs=#node|short#">#desc|strip|firstline|escape#</a></td>
+ </tr>
+</table>
--- a/templates/static/style.css
+++ b/templates/static/style.css
@@ -57,6 +57,12 @@ pre { margin: 0; }
 .logEntry th.age, .logEntry th.firstline { font-weight: bold; }
 .logEntry th.firstline { text-align: left; width: inherit; }
 
+/* Shortlog entries */
+.slogEntry { width: 100%; font-size: smaller; }
+.slogEntry .age { width: 7%; }
+.slogEntry td { font-weight: normal; text-align: left; vertical-align: top; }
+.slogEntry td.author { width: 35%; }
+
 /* Tag entries */
 #tagEntries { list-style: none; margin: 0; padding: 0; }
 #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; }
--- a/templates/summary-gitweb.tmpl
+++ b/templates/summary-gitweb.tmpl
@@ -9,7 +9,8 @@
 <a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / summary
 </div>
 <div class="page_nav">
-summary | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a><br/>
+summary | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>#archives%archiveentry#
+<br/>
 </div>
 
 <div class="title">&nbsp;</div>
--- a/templates/tags-gitweb.tmpl
+++ b/templates/tags-gitweb.tmpl
@@ -10,7 +10,7 @@
 </div>
 
 <div class="page_nav">
-<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | tags | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>
+<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=shortlog;style=gitweb">shortlog</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | tags | <a href="?cmd=manifest;manifest=#manifest#;path=/;style=gitweb">manifest</a>
 <br/>
 </div>
 
--- a/templates/tags.tmpl
+++ b/templates/tags.tmpl
@@ -7,6 +7,7 @@
 
 <div class="buttons">
 <a href="?cl=tip">changelog</a>
+<a href="?sl=tip">shortlog</a>
 <a href="?mf=#manifest|short#;path=/">manifest</a>
 <a type="application/rss+xml" href="?cmd=tags;style=rss">rss</a>
 </div>
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -25,7 +25,7 @@ parser = optparse.OptionParser("%prog [o
 parser.add_option("-v", "--verbose", action="store_true",
     help="output verbose messages")
 parser.add_option("-t", "--timeout", type="int",
-    help="output verbose messages")
+    help="kill errant tests after TIMEOUT seconds")
 parser.add_option("-c", "--cover", action="store_true",
     help="print a test coverage report")
 parser.add_option("-s", "--cover_stdlib", action="store_true",
--- a/tests/test-bundle
+++ b/tests/test-bundle
@@ -38,6 +38,8 @@ rm -rf empty
 hg init empty
 cd empty
 hg -R bundle://../full.hg log
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc
 #doesn't work (yet ?)
 #hg -R bundle://../full.hg verify
 hg pull bundle://../full.hg
--- a/tests/test-bundle.out
+++ b/tests/test-bundle.out
@@ -81,6 +81,7 @@ user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     0.0
 
+changegroup: u=bundle:../full.hg
 pulling from bundle://../full.hg
 requesting all changes
 adding changesets
--- a/tests/test-help.out
+++ b/tests/test-help.out
@@ -185,13 +185,15 @@ hg status [OPTION]... [FILE]...
 
 show changed files in the working directory
 
-    Show changed files in the repository.  If names are
-    given, only files that match are shown.
+    Show status of files in the repository.  If names are given, only
+    files that match are shown.  Files that are clean or ignored, are
+    not listed unless -c (clean), -i (ignored) or -A is given.
 
     The codes used to show the status of files are:
     M = modified
     A = added
     R = removed
+    C = clean
     ! = deleted, but still tracked
     ? = not tracked
     I = ignored (not shown by default)
@@ -201,10 +203,12 @@ aliases: st
 
 options:
 
+ -A --all        show status of all files
  -m --modified   show only modified files
  -a --added      show only added files
  -r --removed    show only removed files
  -d --deleted    show only deleted (but tracked) files
+ -c --clean      show only files without changes
  -u --unknown    show only unknown (not tracked) files
  -i --ignored    show ignored files
  -n --no-status  hide status prefix
--- a/tests/test-hook
+++ b/tests/test-hook
@@ -17,9 +17,9 @@ cd ../b
 
 # changegroup hooks can see env vars
 echo '[hooks]' > .hg/hgrc
-echo 'prechangegroup = echo prechangegroup hook' >> .hg/hgrc
-echo 'changegroup = echo changegroup hook: n=$HG_NODE' >> .hg/hgrc
-echo 'incoming = echo incoming hook: n=$HG_NODE' >> .hg/hgrc
+echo 'prechangegroup = echo prechangegroup hook: u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc
+echo 'changegroup = echo changegroup hook: n=$HG_NODE u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc
+echo 'incoming = echo incoming hook: n=$HG_NODE u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc
 
 # pretxncommit and commit hooks can see both parents of merge
 cd ../a
--- a/tests/test-hook.out
+++ b/tests/test-hook.out
@@ -22,11 +22,11 @@ pretxncommit hook: n=4c52fb2e402287dd5dc
 3:4c52fb2e4022
 commit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2
 commit hook b
-prechangegroup hook
-changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2
-incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2
-incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb
-incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321
+prechangegroup hook: u=file:
+changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
+incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file:
+incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb u=file:
+incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 u=file:
 pulling from ../a
 searching for changes
 adding changesets
--- a/tests/test-http
+++ b/tests/test-http
@@ -4,22 +4,31 @@ hg init test
 cd test
 echo foo>foo
 hg commit -A -d '0 0' -m 1
-hg --config server.uncompressed=True serve -p 20059 -d --pid-file=hg1.pid
-cat hg1.pid >> $DAEMON_PIDS
-hg serve -p 20060 -d --pid-file=hg2.pid
-cat hg2.pid >> $DAEMON_PIDS
+hg --config server.uncompressed=True serve -p 20059 -d --pid-file=../hg1.pid
+hg serve -p 20060 -d --pid-file=../hg2.pid
 cd ..
+cat hg1.pid hg2.pid >> $DAEMON_PIDS
 
 echo % clone via stream
 http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \
   sed -e 's/[0-9][0-9.]*/XXX/g'
-cd copy
-hg verify
+hg verify -R copy
 
 echo % try to clone via stream, should use pull instead
 http_proxy= hg clone --uncompressed http://localhost:20060/ copy2
 
 echo % clone via pull
 http_proxy= hg clone http://localhost:20059/ copy-pull
+hg verify -R copy-pull
+
+cd test
+echo bar > bar
+hg commit -A -d '1 0' -m 2
+cd ..
+
+echo % pull
 cd copy-pull
-hg verify
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc
+hg pull
+cd ..
--- a/tests/test-http.out
+++ b/tests/test-http.out
@@ -28,3 +28,13 @@ checking manifests
 crosschecking files in changesets and manifests
 checking files
 1 files, 1 changesets, 1 total revisions
+adding bar
+% pull
+changegroup: u=http://localhost:20059/
+pulling from http://localhost:20059/
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+(run 'hg update' to get a working copy)
--- a/tests/test-push-http
+++ b/tests/test-push-http
@@ -36,13 +36,19 @@ kill `cat hg.pid`
 
 echo % expect success
 echo 'allow_push = *' >> .hg/hgrc
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup: u=$HG_URL >> $HGTMP/urls' >> .hg/hgrc
 hg serve -p 20059 -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
 hg --cwd ../test2 push http://localhost:20059/
 kill `cat hg.pid`
 hg rollback
 
+sed 's/\(remote:http.*\):.*/\1/' $HGTMP/urls
+
 echo % expect authorization error: all users denied
+echo '[web]' > .hg/hgrc
+echo 'push_ssl = false' >> .hg/hgrc
 echo 'deny_push = *' >> .hg/hgrc
 hg serve -p 20059 -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
--- a/tests/test-push-http.out
+++ b/tests/test-push-http.out
@@ -20,6 +20,7 @@ adding manifests
 adding file changes
 added 1 changesets with 1 changes to 1 files
 rolling back last transaction
+changegroup: u=remote:http
 % expect authorization error: all users denied
 pushing to http://localhost:20059/
 searching for changes
--- a/tests/test-ssh
+++ b/tests/test-ssh
@@ -17,6 +17,8 @@ if [ ! -x dummyssh ] ; then
 	exit -1
 fi
 
+SSH_CLIENT='127.0.0.1 1 2'
+export SSH_CLIENT
 echo Got arguments 1:$1 2:$2 3:$3 4:$4 5:$5 >> dummylog
 $2
 EOF
@@ -29,6 +31,8 @@ echo this > foo
 hg ci -A -m "init" -d "1000000 0" foo
 echo '[server]' > .hg/hgrc
 echo 'uncompressed = True' >> .hg/hgrc
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup in remote: u=$HG_URL >> ../dummylog' >> .hg/hgrc
 
 cd ..
 
@@ -46,6 +50,9 @@ echo "# verify"
 cd local
 hg verify
 
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup in local: u=$HG_URL >> ../dummylog' >> .hg/hgrc
+
 echo "# empty default pull"
 hg paths
 hg pull -e ../dummyssh
--- a/tests/test-ssh.out
+++ b/tests/test-ssh.out
@@ -83,5 +83,7 @@ Got arguments 1:user@dummy 2:hg -R remot
 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
 Got arguments 1:user@dummy 2:hg -R local serve --stdio 3: 4: 5:
 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
+changegroup in remote: u=remote:ssh:127.0.0.1
 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5:
+changegroup in remote: u=remote:ssh:127.0.0.1
--- a/tests/test-static-http
+++ b/tests/test-static-http
@@ -37,6 +37,14 @@ http_proxy= hg clone static-http://local
 cd local
 hg verify
 cat bar
+
+cd ../remote
+echo baz > quux
+hg commit -A -mtest2 -d '100000000 0'
+
+cd ../local
+echo '[hooks]' >> .hg/hgrc
+echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc
 http_proxy= hg pull
 
 kill $!
--- a/tests/test-static-http.out
+++ b/tests/test-static-http.out
@@ -19,6 +19,12 @@ crosschecking files in changesets and ma
 checking files
 1 files, 1 changesets, 1 total revisions
 foo
+adding quux
+changegroup: u=static-http://localhost:20059/remote
 pulling from static-http://localhost:20059/remote
 searching for changes
-no changes found
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+(run 'hg update' to get a working copy)
--- a/tests/test-status
+++ b/tests/test-status
@@ -35,3 +35,8 @@ hg status modified added removed deleted
 hg copy modified copied
 echo "hg status -C:"
 hg status -C
+
+echo "hg status -t:"
+hg status -t
+echo "hg status -A:"
+hg status -A
--- a/tests/test-status.out
+++ b/tests/test-status.out
@@ -108,3 +108,50 @@ A copied
 R removed
 ! deleted
 ? unknown
+hg status -t:
+hg status: option -t not recognized
+hg status [OPTION]... [FILE]...
+
+show changed files in the working directory
+
+    Show status of files in the repository.  If names are given, only
+    files that match are shown.  Files that are clean or ignored, are
+    not listed unless -c (clean), -i (ignored) or -A is given.
+
+    The codes used to show the status of files are:
+    M = modified
+    A = added
+    R = removed
+    C = clean
+    ! = deleted, but still tracked
+    ? = not tracked
+    I = ignored (not shown by default)
+      = the previous added file was copied from here
+
+aliases: st
+
+options:
+
+ -A --all        show status of all files
+ -m --modified   show only modified files
+ -a --added      show only added files
+ -r --removed    show only removed files
+ -d --deleted    show only deleted (but tracked) files
+ -c --clean      show only files without changes
+ -u --unknown    show only unknown (not tracked) files
+ -i --ignored    show ignored files
+ -n --no-status  hide status prefix
+ -C --copies     show source of copied files
+ -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 -A:
+A added
+A copied
+  modified
+R removed
+! deleted
+? unknown
+I ignored
+C .hgignore
+C modified