Merge with mpm
authorBryan O'Sullivan <bos@serpentine.com>
Fri, 07 Dec 2007 21:46:08 -0800
changeset 5629 1db1c7c1eb5e
parent 5628 71179daf6941 (current diff)
parent 5620 652f57de3ccf (diff)
child 5630 44482de04767
Merge with mpm
--- a/contrib/churn.py	Fri Dec 07 18:19:16 2007 -0600
+++ b/contrib/churn.py	Fri Dec 07 21:46:08 2007 -0800
@@ -125,6 +125,7 @@
         ui.note("rev %d: %d lines by %s\n" % (rev, lines, who))
 
         if progress:
+            nr_revs = max(nr_revs, 1)
             if int(100.0*(cur_rev - 1)/nr_revs) < int(100.0*cur_rev/nr_revs):
                 ui.write("%d%%.." % (int(100.0*cur_rev/nr_revs),))
                 sys.stdout.flush()
@@ -144,6 +145,7 @@
         return s[0:l]
 
     def graph(n, maximum, width, char):
+        maximum = max(1, maximum)
         n = int(n * width / float(maximum))
 
         return char * (n)
@@ -178,6 +180,8 @@
     ordered = stats.items()
     ordered.sort(lambda x, y: cmp(y[1], x[1]))
 
+    if not ordered:
+        return
     maximum = ordered[0][1]
 
     width = get_tty_width()
--- a/doc/hg.1.txt	Fri Dec 07 18:19:16 2007 -0600
+++ b/doc/hg.1.txt	Fri Dec 07 21:46:08 2007 -0800
@@ -89,13 +89,15 @@
     A range acts as a closed interval.  This means that a range of 3:5
     gives 3, 4 and 5.  Similarly, a range of 4:2 gives 4, 3, and 2.
 
+dot=.
+
 FILES
 -----
- .hgignore::
+ repo/.hgignore::
     This file contains regular expressions (one per line) that describe file
     names that should be ignored by hg. For details, see hgignore(5).
 
- .hgtags::
+ repo/.hgtags::
     This file contains changeset hash values and text tag names (one of each
     separated by spaces) that correspond to tagged versions of the repository
     contents.
--- a/mercurial/bdiff.c	Fri Dec 07 18:19:16 2007 -0600
+++ b/mercurial/bdiff.c	Fri Dec 07 21:46:08 2007 -0800
@@ -245,7 +245,7 @@
 
 	/* allocate and fill arrays */
 	t = equatelines(a, an, b, bn);
-	pos = (struct pos *)calloc((bn>0)?bn:1, sizeof(struct pos));
+	pos = (struct pos *)calloc(bn ? bn : 1, sizeof(struct pos));
 	/* we can't have more matches than lines in the shorter file */
 	l.head = l.base = (struct hunk *)malloc(sizeof(struct hunk) *
 	                                        ((an<bn ? an:bn) + 1));
--- a/mercurial/cmdutil.py	Fri Dec 07 18:19:16 2007 -0600
+++ b/mercurial/cmdutil.py	Fri Dec 07 21:46:08 2007 -0800
@@ -8,7 +8,7 @@
 from node import *
 from i18n import _
 import os, sys, bisect, stat
-import mdiff, bdiff, util, templater, patch
+import mdiff, bdiff, util, templater, patch, errno
 
 revrangesep = ':'
 
@@ -286,6 +286,206 @@
             if not dry_run:
                 repo.copy(old, new)
 
+def copy(ui, repo, pats, opts, rename=False):
+    # called with the repo lock held
+    #
+    # hgsep => pathname that uses "/" to separate directories
+    # ossep => pathname that uses os.sep to separate directories
+    cwd = repo.getcwd()
+    targets = {}
+    after = opts.get("after")
+    dryrun = opts.get("dry_run")
+
+    def walkpat(pat):
+        srcs = []
+        for tag, abs, rel, exact in walk(repo, [pat], opts, globbed=True):
+            state = repo.dirstate[abs]
+            if state in '?r':
+                if exact and state == '?':
+                    ui.warn(_('%s: not copying - file is not managed\n') % rel)
+                if exact and state == 'r':
+                    ui.warn(_('%s: not copying - file has been marked for'
+                              ' remove\n') % rel)
+                continue
+            # abs: hgsep
+            # rel: ossep
+            srcs.append((abs, rel, exact))
+        return srcs
+
+    # abssrc: hgsep
+    # relsrc: ossep
+    # otarget: ossep
+    def copyfile(abssrc, relsrc, otarget, exact):
+        abstarget = util.canonpath(repo.root, cwd, otarget)
+        reltarget = repo.pathto(abstarget, cwd)
+        target = repo.wjoin(abstarget)
+        src = repo.wjoin(abssrc)
+        state = repo.dirstate[abstarget]
+
+        # check for collisions
+        prevsrc = targets.get(abstarget)
+        if prevsrc is not None:
+            ui.warn(_('%s: not overwriting - %s collides with %s\n') %
+                    (reltarget, repo.pathto(abssrc, cwd),
+                     repo.pathto(prevsrc, cwd)))
+            return
+
+        # check for overwrites
+        exists = os.path.exists(target)
+        if (not after and exists or after and state in 'mn'):
+            if not opts['force']:
+                ui.warn(_('%s: not overwriting - file exists\n') %
+                        reltarget)
+                return
+
+        if after:
+            if not exists:
+                return
+        elif not dryrun:
+            try:
+                if exists:
+                    os.unlink(target)
+                targetdir = os.path.dirname(target) or '.'
+                if not os.path.isdir(targetdir):
+                    os.makedirs(targetdir)
+                util.copyfile(src, target)
+            except IOError, inst:
+                if inst.errno == errno.ENOENT:
+                    ui.warn(_('%s: deleted in working copy\n') % relsrc)
+                else:
+                    ui.warn(_('%s: cannot copy - %s\n') %
+                            (relsrc, inst.strerror))
+                    return True # report a failure
+
+        if ui.verbose or not exact:
+            action = rename and "moving" or "copying"
+            ui.status(_('%s %s to %s\n') % (action, relsrc, reltarget))
+
+        targets[abstarget] = abssrc
+
+        # fix up dirstate
+        origsrc = repo.dirstate.copied(abssrc) or abssrc
+        if abstarget == origsrc: # copying back a copy?
+            if state not in 'mn' and not dryrun:
+                repo.dirstate.normallookup(abstarget)
+        else:
+            if repo.dirstate[origsrc] == 'a':
+                if not ui.quiet:
+                    ui.warn(_("%s has not been committed yet, so no copy "
+                              "data will be stored for %s.\n")
+                            % (repo.pathto(origsrc, cwd), reltarget))
+                if abstarget not in repo.dirstate and not dryrun:
+                    repo.add([abstarget])
+            elif not dryrun:
+                repo.copy(origsrc, abstarget)
+
+        if rename and not dryrun:
+            repo.remove([abssrc], True)
+
+    # pat: ossep
+    # dest ossep
+    # srcs: list of (hgsep, hgsep, ossep, bool)
+    # return: function that takes hgsep and returns ossep
+    def targetpathfn(pat, dest, srcs):
+        if os.path.isdir(pat):
+            abspfx = util.canonpath(repo.root, cwd, pat)
+            abspfx = util.localpath(abspfx)
+            if destdirexists:
+                striplen = len(os.path.split(abspfx)[0])
+            else:
+                striplen = len(abspfx)
+            if striplen:
+                striplen += len(os.sep)
+            res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
+        elif destdirexists:
+            res = lambda p: os.path.join(dest,
+                                         os.path.basename(util.localpath(p)))
+        else:
+            res = lambda p: dest
+        return res
+
+    # pat: ossep
+    # dest ossep
+    # srcs: list of (hgsep, hgsep, ossep, bool)
+    # return: function that takes hgsep and returns ossep
+    def targetpathafterfn(pat, dest, srcs):
+        if util.patkind(pat, None)[0]:
+            # a mercurial pattern
+            res = lambda p: os.path.join(dest,
+                                         os.path.basename(util.localpath(p)))
+        else:
+            abspfx = util.canonpath(repo.root, cwd, pat)
+            if len(abspfx) < len(srcs[0][0]):
+                # A directory. Either the target path contains the last
+                # component of the source path or it does not.
+                def evalpath(striplen):
+                    score = 0
+                    for s in srcs:
+                        t = os.path.join(dest, util.localpath(s[0])[striplen:])
+                        if os.path.exists(t):
+                            score += 1
+                    return score
+
+                abspfx = util.localpath(abspfx)
+                striplen = len(abspfx)
+                if striplen:
+                    striplen += len(os.sep)
+                if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
+                    score = evalpath(striplen)
+                    striplen1 = len(os.path.split(abspfx)[0])
+                    if striplen1:
+                        striplen1 += len(os.sep)
+                    if evalpath(striplen1) > score:
+                        striplen = striplen1
+                res = lambda p: os.path.join(dest,
+                                             util.localpath(p)[striplen:])
+            else:
+                # a file
+                if destdirexists:
+                    res = lambda p: os.path.join(dest,
+                                        os.path.basename(util.localpath(p)))
+                else:
+                    res = lambda p: dest
+        return res
+
+
+    pats = util.expand_glob(pats)
+    if not pats:
+        raise util.Abort(_('no source or destination specified'))
+    if len(pats) == 1:
+        raise util.Abort(_('no destination specified'))
+    dest = pats.pop()
+    destdirexists = os.path.isdir(dest)
+    if not destdirexists:
+        if len(pats) > 1 or util.patkind(pats[0], None)[0]:
+            raise util.Abort(_('with multiple sources, destination must be an '
+                               'existing directory'))
+        if dest.endswith(os.sep) or os.altsep and dest.endswith(os.altsep):
+            raise util.Abort(_('destination %s is not a directory') % dest)
+
+    tfn = targetpathfn
+    if after:
+        tfn = targetpathafterfn
+    copylist = []
+    for pat in pats:
+        srcs = walkpat(pat)
+        if not srcs:
+            continue
+        copylist.append((tfn(pat, dest, srcs), srcs))
+    if not copylist:
+        raise util.Abort(_('no files to copy'))
+
+    errors = 0
+    for targetpath, srcs in copylist:
+        for abssrc, relsrc, exact in srcs:
+            if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
+                errors += 1
+
+    if errors:
+        ui.warn(_('(consider using --after)\n'))
+
+    return errors
+
 def service(opts, parentfn=None, initfn=None, runfn=None):
     '''Run a command as a service.'''
 
--- a/mercurial/commands.py	Fri Dec 07 18:19:16 2007 -0600
+++ b/mercurial/commands.py	Fri Dec 07 21:46:08 2007 -0800
@@ -194,6 +194,11 @@
     if op2 != nullid:
         raise util.Abort(_('outstanding uncommitted merge'))
     node = repo.lookup(rev)
+
+    a = repo.changelog.ancestor(op1, node)
+    if a != node:
+        raise util.Abort(_('cannot back out change on a different branch'))
+
     p1, p2 = repo.changelog.parents(node)
     if p1 == nullid:
         raise util.Abort(_('cannot back out a change with no parents'))
@@ -210,6 +215,7 @@
         if opts['parent']:
             raise util.Abort(_('cannot use --parent on non-merge changeset'))
         parent = p1
+
     hg.clean(repo, node, show_stats=False)
     revert_opts = opts.copy()
     revert_opts['date'] = None
@@ -432,204 +438,6 @@
                            force_editor=opts.get('force_editor'))
     cmdutil.commit(ui, repo, commitfunc, pats, opts)
 
-def docopy(ui, repo, pats, opts):
-    # called with the repo lock held
-    #
-    # hgsep => pathname that uses "/" to separate directories
-    # ossep => pathname that uses os.sep to separate directories
-    cwd = repo.getcwd()
-    errors = 0
-    copied = []
-    targets = {}
-
-    # abs: hgsep
-    # rel: ossep
-    # return: hgsep
-    def okaytocopy(abs, rel, exact):
-        reasons = {'?': _('is not managed'),
-                   'r': _('has been marked for remove')}
-        state = repo.dirstate[abs]
-        reason = reasons.get(state)
-        if reason:
-            if exact:
-                ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
-        else:
-            if state == 'a':
-                origsrc = repo.dirstate.copied(abs)
-                if origsrc is not None:
-                    return origsrc
-            return abs
-
-    # origsrc: hgsep
-    # abssrc: hgsep
-    # relsrc: ossep
-    # otarget: ossep
-    def copy(origsrc, abssrc, relsrc, otarget, exact):
-        abstarget = util.canonpath(repo.root, cwd, otarget)
-        reltarget = repo.pathto(abstarget, cwd)
-        prevsrc = targets.get(abstarget)
-        src = repo.wjoin(abssrc)
-        target = repo.wjoin(abstarget)
-        if prevsrc is not None:
-            ui.warn(_('%s: not overwriting - %s collides with %s\n') %
-                    (reltarget, repo.pathto(abssrc, cwd),
-                     repo.pathto(prevsrc, cwd)))
-            return
-        if (not opts['after'] and os.path.exists(target) or
-            opts['after'] and repo.dirstate[abstarget] in 'mn'):
-            if not opts['force']:
-                ui.warn(_('%s: not overwriting - file exists\n') %
-                        reltarget)
-                return
-            if not opts['after'] and not opts.get('dry_run'):
-                os.unlink(target)
-        if opts['after']:
-            if not os.path.exists(target):
-                return
-        else:
-            targetdir = os.path.dirname(target) or '.'
-            if not os.path.isdir(targetdir) and not opts.get('dry_run'):
-                os.makedirs(targetdir)
-            try:
-                restore = repo.dirstate[abstarget] == 'r'
-                if restore and not opts.get('dry_run'):
-                    repo.undelete([abstarget])
-                try:
-                    if not opts.get('dry_run'):
-                        util.copyfile(src, target)
-                    restore = False
-                finally:
-                    if restore:
-                        repo.remove([abstarget])
-            except IOError, inst:
-                if inst.errno == errno.ENOENT:
-                    ui.warn(_('%s: deleted in working copy\n') % relsrc)
-                else:
-                    ui.warn(_('%s: cannot copy - %s\n') %
-                            (relsrc, inst.strerror))
-                    errors += 1
-                    return
-        if ui.verbose or not exact:
-            ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
-        targets[abstarget] = abssrc
-        if abstarget != origsrc:
-            if repo.dirstate[origsrc] == 'a':
-                if not ui.quiet:
-                    ui.warn(_("%s has not been committed yet, so no copy "
-                              "data will be stored for %s.\n")
-                            % (repo.pathto(origsrc, cwd), reltarget))
-                if abstarget not in repo.dirstate and not opts.get('dry_run'):
-                    repo.add([abstarget])
-            elif not opts.get('dry_run'):
-                repo.copy(origsrc, abstarget)
-        copied.append((abssrc, relsrc, exact))
-
-    # pat: ossep
-    # dest ossep
-    # srcs: list of (hgsep, hgsep, ossep, bool)
-    # return: function that takes hgsep and returns ossep
-    def targetpathfn(pat, dest, srcs):
-        if os.path.isdir(pat):
-            abspfx = util.canonpath(repo.root, cwd, pat)
-            abspfx = util.localpath(abspfx)
-            if destdirexists:
-                striplen = len(os.path.split(abspfx)[0])
-            else:
-                striplen = len(abspfx)
-            if striplen:
-                striplen += len(os.sep)
-            res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
-        elif destdirexists:
-            res = lambda p: os.path.join(dest,
-                                         os.path.basename(util.localpath(p)))
-        else:
-            res = lambda p: dest
-        return res
-
-    # pat: ossep
-    # dest ossep
-    # srcs: list of (hgsep, hgsep, ossep, bool)
-    # return: function that takes hgsep and returns ossep
-    def targetpathafterfn(pat, dest, srcs):
-        if util.patkind(pat, None)[0]:
-            # a mercurial pattern
-            res = lambda p: os.path.join(dest,
-                                         os.path.basename(util.localpath(p)))
-        else:
-            abspfx = util.canonpath(repo.root, cwd, pat)
-            if len(abspfx) < len(srcs[0][0]):
-                # A directory. Either the target path contains the last
-                # component of the source path or it does not.
-                def evalpath(striplen):
-                    score = 0
-                    for s in srcs:
-                        t = os.path.join(dest, util.localpath(s[0])[striplen:])
-                        if os.path.exists(t):
-                            score += 1
-                    return score
-
-                abspfx = util.localpath(abspfx)
-                striplen = len(abspfx)
-                if striplen:
-                    striplen += len(os.sep)
-                if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
-                    score = evalpath(striplen)
-                    striplen1 = len(os.path.split(abspfx)[0])
-                    if striplen1:
-                        striplen1 += len(os.sep)
-                    if evalpath(striplen1) > score:
-                        striplen = striplen1
-                res = lambda p: os.path.join(dest,
-                                             util.localpath(p)[striplen:])
-            else:
-                # a file
-                if destdirexists:
-                    res = lambda p: os.path.join(dest,
-                                        os.path.basename(util.localpath(p)))
-                else:
-                    res = lambda p: dest
-        return res
-
-
-    pats = util.expand_glob(pats)
-    if not pats:
-        raise util.Abort(_('no source or destination specified'))
-    if len(pats) == 1:
-        raise util.Abort(_('no destination specified'))
-    dest = pats.pop()
-    destdirexists = os.path.isdir(dest)
-    if not destdirexists:
-        if len(pats) > 1 or util.patkind(pats[0], None)[0]:
-            raise util.Abort(_('with multiple sources, destination must be an '
-                               'existing directory'))
-        if dest.endswith(os.sep) or os.altsep and dest.endswith(os.altsep):
-            raise util.Abort(_('destination %s is not a directory') % dest)
-    if opts['after']:
-        tfn = targetpathafterfn
-    else:
-        tfn = targetpathfn
-    copylist = []
-    for pat in pats:
-        srcs = []
-        for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts,
-                                                       globbed=True):
-            origsrc = okaytocopy(abssrc, relsrc, exact)
-            if origsrc:
-                srcs.append((origsrc, abssrc, relsrc, exact))
-        if not srcs:
-            continue
-        copylist.append((tfn(pat, dest, srcs), srcs))
-    if not copylist:
-        raise util.Abort(_('no files to copy'))
-
-    for targetpath, srcs in copylist:
-        for origsrc, abssrc, relsrc, exact in srcs:
-            copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
-
-    if errors:
-        ui.warn(_('(consider using --after)\n'))
-    return errors, copied
-
 def copy(ui, repo, *pats, **opts):
     """mark files as copied for the next commit
 
@@ -646,10 +454,9 @@
     """
     wlock = repo.wlock(False)
     try:
-        errs, copied = docopy(ui, repo, pats, opts)
+        return cmdutil.copy(ui, repo, pats, opts)
     finally:
         del wlock
-    return errs
 
 def debugancestor(ui, index, rev1, rev2):
     """find the ancestor revision of two revisions in a given index"""
@@ -2254,20 +2061,15 @@
     """
     wlock = repo.wlock(False)
     try:
-        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)
-            names.append(abs)
-        if not opts.get('dry_run'):
-            repo.remove(names, True)
-        return errs
+        return cmdutil.copy(ui, repo, pats, opts, rename=True)
     finally:
         del wlock
 
 def revert(ui, repo, *pats, **opts):
-    """revert files or dirs to their states as of some revision
+    """restore individual files or dirs to an earlier state
+
+    (use update -r to check out earlier revisions, revert does not
+    change the working dir parents)
 
     With no revision specified, revert the named files or directories
     to the contents they had in the parent of the working directory.
@@ -2276,12 +2078,9 @@
     working directory has two parents, you must explicitly specify the
     revision to revert to.
 
-    Modified files are saved with a .orig suffix before reverting.
-    To disable these backups, use --no-backup.
-
     Using the -r option, revert the given files or directories to their
     contents as of a specific revision. This can be helpful to "roll
-    back" some or all of a change that should not have been committed.
+    back" some or all of an earlier  change.
 
     Revert modifies the working directory.  It does not commit any
     changes, or change the parent of the working directory.  If you
@@ -2295,6 +2094,9 @@
     If names are given, all files matching the names are reverted.
 
     If no arguments are given, no files are reverted.
+
+    Modified files are saved with a .orig suffix before reverting.
+    To disable these backups, use --no-backup.
     """
 
     if opts["date"]:
@@ -2445,10 +2247,12 @@
         del wlock
 
 def rollback(ui, repo):
-    """roll back the last transaction in this repository
-
-    Roll back the last transaction in this repository, restoring the
-    project to its state prior to the transaction.
+    """roll back the last transaction
+
+    This command should be used with care. There is only one level of
+    rollback, and there is no way to undo a rollback. It will also
+    restore the dirstate at the time of the last transaction, losing
+    any dirstate changes since that time.
 
     Transactions are used to encapsulate the effects of all commands
     that create new changesets or propagate existing changesets into a
@@ -2461,11 +2265,6 @@
       push (with this repository as destination)
       unbundle
 
-    This command should be used with care. There is only one level of
-    rollback, and there is no way to undo a rollback. It will also
-    restore the dirstate at the time of the last transaction, which
-    may lose subsequent dirstate changes.
-
     This command is not intended for use on public repositories. Once
     changes are visible for pull by other users, rolling a transaction
     back locally is ineffective (someone else may already have pulled
@@ -3068,7 +2867,7 @@
     "recover": (recover, [], _('hg recover')),
     "^remove|rm":
         (remove,
-         [('A', 'after', None, _('record remove that has already occurred')),
+         [('A', 'after', None, _('record remove without deleting')),
           ('f', 'force', None, _('remove file even if modified')),
          ] + walkopts,
          _('hg remove [OPTION]... FILE...')),
@@ -3079,7 +2878,7 @@
            _('forcibly copy over an existing managed file')),
          ] + walkopts + dryrunopts,
          _('hg rename [OPTION]... SOURCE... DEST')),
-    "^revert":
+    "revert":
         (revert,
          [('a', 'all', None, _('revert all changes when no arguments given')),
           ('d', 'date', '', _('tipmost revision matching date')),
--- a/mercurial/hg.py	Fri Dec 07 18:19:16 2007 -0600
+++ b/mercurial/hg.py	Fri Dec 07 21:46:08 2007 -0800
@@ -173,8 +173,15 @@
             src_store = os.path.realpath(src_repo.spath)
             if not os.path.exists(dest):
                 os.mkdir(dest)
-            dest_path = os.path.realpath(os.path.join(dest, ".hg"))
-            os.mkdir(dest_path)
+            try:
+                dest_path = os.path.realpath(os.path.join(dest, ".hg"))
+                os.mkdir(dest_path)
+            except OSError, inst:
+                if inst.errno == errno.EEXIST:
+                    dir_cleanup.close()
+                    raise util.Abort(_("destination '%s' already exists")
+                                     % dest)
+                raise
             if src_repo.spath != src_repo.path:
                 # XXX racy
                 dummy_changelog = os.path.join(dest_path, "00changelog.i")
@@ -203,7 +210,14 @@
             dest_repo = repository(ui, dest)
 
         else:
-            dest_repo = repository(ui, dest, create=True)
+            try:
+                dest_repo = repository(ui, dest, create=True)
+            except OSError, inst:
+                if inst.errno == errno.EEXIST:
+                    dir_cleanup.close()
+                    raise util.Abort(_("destination '%s' already exists")
+                                     % dest)
+                raise
 
             revs = None
             if rev:
--- a/mercurial/merge.py	Fri Dec 07 18:19:16 2007 -0600
+++ b/mercurial/merge.py	Fri Dec 07 21:46:08 2007 -0800
@@ -609,7 +609,10 @@
             try:
                 node = repo.branchtags()[wc.branch()]
             except KeyError:
-                raise util.Abort(_("branch %s not found") % wc.branch())
+                if wc.branch() == "default": # no default branch!
+                    node = repo.lookup("tip") # update to tip
+                else:
+                    raise util.Abort(_("branch %s not found") % wc.branch())
         overwrite = force and not branchmerge
         forcemerge = force and branchmerge
         pl = wc.parents()
--- a/tests/test-backout	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-backout	Fri Dec 07 21:46:08 2007 -0800
@@ -37,6 +37,22 @@
 hg backout -d '3 0' --merge tip
 cat a 2>/dev/null || echo cat: a: No such file or directory
 
+echo '# across branch'
+cd ..
+hg init branch
+cd branch
+echo a > a
+hg ci -Am0 -d '0 0'
+echo b > b
+hg ci -Am1 -d '0 0'
+hg co -C 0
+# should fail
+hg backout -d '0 0' 1
+echo c > c
+hg ci -Am2 -d '0 0'
+# should fail
+hg backout -d '0 0' 1
+
 echo '# backout with merge'
 cd ..
 hg init merge
--- a/tests/test-backout.out	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-backout.out	Fri Dec 07 21:46:08 2007 -0800
@@ -15,6 +15,13 @@
 removing a
 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
 cat: a: No such file or directory
+# across branch
+adding a
+adding b
+0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+abort: cannot back out change on a different branch
+adding c
+abort: cannot back out change on a different branch
 # backout with merge
 adding a
 reverting a
--- a/tests/test-globalopts.out	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-globalopts.out	Fri Dec 07 21:46:08 2007 -0800
@@ -175,8 +175,8 @@
  recover      roll back an interrupted transaction
  remove       remove the specified files on the next commit
  rename       rename files; equivalent of copy + remove
- revert       revert files or dirs to their states as of some revision
- rollback     roll back the last transaction in this repository
+ revert       restore individual files or dirs to an earlier state
+ rollback     roll back the last transaction
  root         print the root (top) of the current working dir
  serve        export the repository via HTTP
  showconfig   show combined config settings from all hgrc files
@@ -227,8 +227,8 @@
  recover      roll back an interrupted transaction
  remove       remove the specified files on the next commit
  rename       rename files; equivalent of copy + remove
- revert       revert files or dirs to their states as of some revision
- rollback     roll back the last transaction in this repository
+ revert       restore individual files or dirs to an earlier state
+ rollback     roll back the last transaction
  root         print the root (top) of the current working dir
  serve        export the repository via HTTP
  showconfig   show combined config settings from all hgrc files
--- a/tests/test-help.out	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-help.out	Fri Dec 07 21:46:08 2007 -0800
@@ -15,7 +15,6 @@
  pull       pull changes from the specified source
  push       push changes to the specified destination
  remove     remove the specified files on the next commit
- revert     revert files or dirs to their states as of some revision
  serve      export the repository via HTTP
  status     show changed files in the working directory
  update     update working directory
@@ -34,7 +33,6 @@
  pull       pull changes from the specified source
  push       push changes to the specified destination
  remove     remove the specified files on the next commit
- revert     revert files or dirs to their states as of some revision
  serve      export the repository via HTTP
  status     show changed files in the working directory
  update     update working directory
@@ -75,8 +73,8 @@
  recover      roll back an interrupted transaction
  remove       remove the specified files on the next commit
  rename       rename files; equivalent of copy + remove
- revert       revert files or dirs to their states as of some revision
- rollback     roll back the last transaction in this repository
+ revert       restore individual files or dirs to an earlier state
+ rollback     roll back the last transaction
  root         print the root (top) of the current working dir
  serve        export the repository via HTTP
  showconfig   show combined config settings from all hgrc files
@@ -123,8 +121,8 @@
  recover      roll back an interrupted transaction
  remove       remove the specified files on the next commit
  rename       rename files; equivalent of copy + remove
- revert       revert files or dirs to their states as of some revision
- rollback     roll back the last transaction in this repository
+ revert       restore individual files or dirs to an earlier state
+ rollback     roll back the last transaction
  root         print the root (top) of the current working dir
  serve        export the repository via HTTP
  showconfig   show combined config settings from all hgrc files
@@ -276,7 +274,6 @@
  pull       pull changes from the specified source
  push       push changes to the specified destination
  remove     remove the specified files on the next commit
- revert     revert files or dirs to their states as of some revision
  serve      export the repository via HTTP
  status     show changed files in the working directory
  update     update working directory
@@ -300,7 +297,6 @@
  pull       pull changes from the specified source
  push       push changes to the specified destination
  remove     remove the specified files on the next commit
- revert     revert files or dirs to their states as of some revision
  serve      export the repository via HTTP
  status     show changed files in the working directory
  update     update working directory
--- a/tests/test-issue612.out	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-issue612.out	Fri Dec 07 21:46:08 2007 -0800
@@ -1,6 +1,5 @@
 adding src/a.c
-copying src/a.c to source/a.c
-removing src/a.c
+moving src/a.c to source/a.c
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 ? src/a.o
 merging src/a.c and source/a.c
--- a/tests/test-rename-after-merge	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-rename-after-merge	Fri Dec 07 21:46:08 2007 -0800
@@ -24,6 +24,7 @@
 echo % merge repositories
 hg pull ../t2
 hg merge
+hg st
 
 echo % rename b as c
 hg mv b c
--- a/tests/test-rename-after-merge.out	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-rename-after-merge.out	Fri Dec 07 21:46:08 2007 -0800
@@ -14,7 +14,9 @@
 (run 'hg heads' to see heads, 'hg merge' to merge)
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
+M b
 % rename b as c
 A c
 R b
 % rename back c as b
+M b
--- a/tests/test-rename-dir-merge	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-rename-dir-merge	Fri Dec 07 21:46:08 2007 -0800
@@ -7,9 +7,7 @@
 mkdir a
 echo foo > a/a
 echo bar > a/b
-
-hg add a
-hg ci -m "0" -d "0 0"
+hg ci -Am "0" -d "0 0"
 
 hg co -C 0
 hg mv a b
@@ -17,6 +15,7 @@
 
 hg co -C 0
 echo baz > a/c
+echo quux > a/d
 hg add a/c
 hg ci -m "2 add a/c" -d "0 0"
 
--- a/tests/test-rename-dir-merge.out	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-rename-dir-merge.out	Fri Dec 07 21:46:08 2007 -0800
@@ -1,10 +1,8 @@
 adding a/a
 adding a/b
 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
-copying a/a to b/a
-copying a/b to b/b
-removing a/a
-removing a/b
+moving a/a to b/a
+moving a/b to b/b
 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
 resolving manifests
  overwrite None partial False
@@ -12,6 +10,7 @@
   searching for copies back to rev 1
   unmatched files in local:
    a/c
+   a/d
   unmatched files in other:
    b/a
    b/b
@@ -21,6 +20,8 @@
   checking for directory renames
   dir a/ -> b/
   file a/c -> b/c
+  file a/d -> b/d
+ a/d: remote renamed directory to b/d -> d
  a/c: remote renamed directory to b/c -> d
  a/b: other deleted -> r
  a/a: other deleted -> r
@@ -29,11 +30,12 @@
 removing a/a
 removing a/b
 moving a/c to b/c
+moving a/d to b/d
 getting b/a
 getting b/b
-3 files updated, 0 files merged, 2 files removed, 0 files unresolved
+4 files updated, 0 files merged, 2 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
-a/* b/a b/b b/c
+a/* b/a b/b b/c b/d
 M b/a
 M b/b
 A b/c
@@ -41,6 +43,7 @@
 R a/a
 R a/b
 R a/c
+? b/d
 b/c renamed from a/c:354ae8da6e890359ef49ade27b68bbc361f3ca88
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
 resolving manifests
@@ -50,6 +53,7 @@
   unmatched files in local:
    b/a
    b/b
+   b/d
   unmatched files in other:
    a/c
   all copies found (* = to merge, ! = divergent):
@@ -62,7 +66,8 @@
 getting a/c to b/c
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
-a/* b/a b/b b/c
+a/* b/a b/b b/c b/d
 A b/c
   a/c
+? b/d
 b/c renamed from a/c:354ae8da6e890359ef49ade27b68bbc361f3ca88
--- a/tests/test-rename-dir-merge2.out	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-rename-dir-merge2.out	Fri Dec 07 21:46:08 2007 -0800
@@ -1,7 +1,6 @@
 adding a/f
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-copying a/f to b/f
-removing a/f
+moving a/f to b/f
 adding a/aa/g
 pulling from ../r2
 searching for changes
--- a/tests/test-rename.out	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-rename.out	Fri Dec 07 21:46:08 2007 -0800
@@ -29,14 +29,10 @@
 R d2/b
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 # rename directory d1 as d3
-copying d1/a to d3/a
-copying d1/b to d3/b
-copying d1/ba to d3/ba
-copying d1/d11/a1 to d3/d11/a1
-removing d1/a
-removing d1/b
-removing d1/ba
-removing d1/d11/a1
+moving d1/a to d3/a
+moving d1/b to d3/b
+moving d1/ba to d3/ba
+moving d1/d11/a1 to d3/d11/a1
 A d3/a
   d1/a
 A d3/b
@@ -51,14 +47,10 @@
 R d1/d11/a1
 4 files updated, 0 files merged, 4 files removed, 0 files unresolved
 # rename --after directory d1 as d3
-copying d1/a to d3/a
-copying d1/b to d3/b
-copying d1/ba to d3/ba
-copying d1/d11/a1 to d3/d11/a1
-removing d1/a
-removing d1/b
-removing d1/ba
-removing d1/d11/a1
+moving d1/a to d3/a
+moving d1/b to d3/b
+moving d1/ba to d3/ba
+moving d1/d11/a1 to d3/d11/a1
 A d3/a
   d1/a
 A d3/b
@@ -73,37 +65,29 @@
 R d1/d11/a1
 4 files updated, 0 files merged, 4 files removed, 0 files unresolved
 # move a directory using a relative path
-copying ../d1/d11/a1 to d3/d11/a1
-removing ../d1/d11/a1
+moving ../d1/d11/a1 to d3/d11/a1
 A d2/d3/d11/a1
   d1/d11/a1
 R d1/d11/a1
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 # move --after a directory using a relative path
-copying ../d1/d11/a1 to d3/d11/a1
-removing ../d1/d11/a1
+moving ../d1/d11/a1 to d3/d11/a1
 A d2/d3/d11/a1
   d1/d11/a1
 R d1/d11/a1
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 # move directory d1/d11 to an existing directory d2 (removes empty d1)
-copying d1/d11/a1 to d2/d11/a1
-removing d1/d11/a1
+moving d1/d11/a1 to d2/d11/a1
 A d2/d11/a1
   d1/d11/a1
 R d1/d11/a1
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 # move directories d1 and d2 to a new directory d3
-copying d1/a to d3/d1/a
-copying d1/b to d3/d1/b
-copying d1/ba to d3/d1/ba
-copying d1/d11/a1 to d3/d1/d11/a1
-copying d2/b to d3/d2/b
-removing d1/a
-removing d1/b
-removing d1/ba
-removing d1/d11/a1
-removing d2/b
+moving d1/a to d3/d1/a
+moving d1/b to d3/d1/b
+moving d1/ba to d3/d1/ba
+moving d1/d11/a1 to d3/d1/d11/a1
+moving d2/b to d3/d2/b
 A d3/d1/a
   d1/a
 A d3/d1/b
@@ -121,16 +105,11 @@
 R d2/b
 5 files updated, 0 files merged, 5 files removed, 0 files unresolved
 # move --after directories d1 and d2 to a new directory d3
-copying d1/a to d3/d1/a
-copying d1/b to d3/d1/b
-copying d1/ba to d3/d1/ba
-copying d1/d11/a1 to d3/d1/d11/a1
-copying d2/b to d3/d2/b
-removing d1/a
-removing d1/b
-removing d1/ba
-removing d1/d11/a1
-removing d2/b
+moving d1/a to d3/d1/a
+moving d1/b to d3/d1/b
+moving d1/ba to d3/d1/ba
+moving d1/d11/a1 to d3/d1/d11/a1
+moving d2/b to d3/d2/b
 A d3/d1/a
   d1/a
 A d3/d1/b
@@ -150,8 +129,7 @@
 # move everything under directory d1 to existing directory d2, do not
 # overwrite existing files (d2/b)
 d2/b: not overwriting - file exists
-copying d1/d11/a1 to d2/d11/a1
-removing d1/d11/a1
+moving d1/d11/a1 to d2/d11/a1
 A d2/a
   d1/a
 A d2/ba
@@ -173,14 +151,10 @@
 # directory
 abort: with multiple sources, destination must be an existing directory
 # move every file under d1 to d2/d21 (glob)
-copying d1/a to d2/d21/a
-copying d1/b to d2/d21/b
-copying d1/ba to d2/d21/ba
-copying d1/d11/a1 to d2/d21/a1
-removing d1/a
-removing d1/b
-removing d1/ba
-removing d1/d11/a1
+moving d1/a to d2/d21/a
+moving d1/b to d2/d21/b
+moving d1/ba to d2/d21/ba
+moving d1/d11/a1 to d2/d21/a1
 A d2/d21/a
   d1/a
 A d2/d21/a1
@@ -195,10 +169,8 @@
 R d1/d11/a1
 4 files updated, 0 files merged, 4 files removed, 0 files unresolved
 # move --after some files under d1 to d2/d21 (glob)
-copying d1/a to d2/d21/a
-copying d1/d11/a1 to d2/d21/a1
-removing d1/a
-removing d1/d11/a1
+moving d1/a to d2/d21/a
+moving d1/d11/a1 to d2/d21/a1
 A d2/d21/a
   d1/a
 A d2/d21/a1
@@ -207,10 +179,8 @@
 R d1/d11/a1
 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
 # move every file under d1 starting with an 'a' to d2/d21 (regexp)
-copying d1/a to d2/d21/a
-copying d1/d11/a1 to d2/d21/a1
-removing d1/a
-removing d1/d11/a1
+moving d1/a to d2/d21/a
+moving d1/d11/a1 to d2/d21/a1
 A d2/d21/a
   d1/a
 A d2/d21/a1
@@ -233,9 +203,8 @@
 R d1/ba
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 # do not copy more than one source file to the same destination file
-copying d1/d11/a1 to d3/d11/a1
+moving d1/d11/a1 to d3/d11/a1
 d3/b: not overwriting - d2/b collides with d1/b
-removing d1/d11/a1
 A d3/a
   d1/a
 A d3/b
@@ -250,14 +219,10 @@
 R d1/d11/a1
 4 files updated, 0 files merged, 4 files removed, 0 files unresolved
 # move a whole subtree with "hg rename ."
-copying a to ../d3/d1/a
-copying b to ../d3/d1/b
-copying ba to ../d3/d1/ba
-copying d11/a1 to ../d3/d1/d11/a1
-removing a
-removing b
-removing ba
-removing d11/a1
+moving a to ../d3/d1/a
+moving b to ../d3/d1/b
+moving ba to ../d3/d1/ba
+moving d11/a1 to ../d3/d1/d11/a1
 A d3/d1/a
   d1/a
 A d3/d1/b
@@ -272,14 +237,10 @@
 R d1/d11/a1
 4 files updated, 0 files merged, 4 files removed, 0 files unresolved
 # move a whole subtree with "hg rename --after ."
-copying a to ../d3/a
-copying b to ../d3/b
-copying ba to ../d3/ba
-copying d11/a1 to ../d3/d11/a1
-removing a
-removing b
-removing ba
-removing d11/a1
+moving a to ../d3/a
+moving b to ../d3/b
+moving ba to ../d3/ba
+moving d11/a1 to ../d3/d11/a1
 A d3/a
   d1/a
 A d3/b
@@ -294,14 +255,10 @@
 R d1/d11/a1
 4 files updated, 0 files merged, 4 files removed, 0 files unresolved
 # move the parent tree with "hg rename .."
-copying ../a to ../../d3/a
-copying ../b to ../../d3/b
-copying ../ba to ../../d3/ba
-copying a1 to ../../d3/d11/a1
-removing ../a
-removing ../b
-removing ../ba
-removing a1
+moving ../a to ../../d3/a
+moving ../b to ../../d3/b
+moving ../ba to ../../d3/ba
+moving a1 to ../../d3/d11/a1
 A d3/a
   d1/a
 A d3/b
@@ -316,12 +273,9 @@
 R d1/d11/a1
 4 files updated, 0 files merged, 4 files removed, 0 files unresolved
 # skip removed files
-copying d1/a to d3/a
-copying d1/ba to d3/ba
-copying d1/d11/a1 to d3/d11/a1
-removing d1/a
-removing d1/ba
-removing d1/d11/a1
+moving d1/a to d3/a
+moving d1/ba to d3/ba
+moving d1/d11/a1 to d3/d11/a1
 A d3/a
   d1/a
 A d3/ba
--- a/tests/test-strict.out	Fri Dec 07 18:19:16 2007 -0600
+++ b/tests/test-strict.out	Fri Dec 07 21:46:08 2007 -0800
@@ -18,7 +18,6 @@
  pull       pull changes from the specified source
  push       push changes to the specified destination
  remove     remove the specified files on the next commit
- revert     revert files or dirs to their states as of some revision
  serve      export the repository via HTTP
  status     show changed files in the working directory
  update     update working directory