changeset 1253:a45e717c61a8

Add rename/mv command. This is the logical equivalent of copy and remove, and is in fact implemented as such. It doesn't use the remove command directly.
author Bryan O'Sullivan <bos@serpentine.com>
date Wed, 14 Sep 2005 16:34:22 -0700
parents 94f38724283f
children e6560042b7b8
files doc/hg.1.txt mercurial/commands.py tests/test-help.out
diffstat 3 files changed, 59 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/doc/hg.1.txt	Wed Sep 14 16:31:03 2005 -0700
+++ b/doc/hg.1.txt	Wed Sep 14 16:34:22 2005 -0700
@@ -173,13 +173,15 @@
     stand in the working directory.  If invoked with --after, the
     operation is recorded, but no copying is performed.
 
-    This command takes effect for the next commit.
+    This command takes effect in the next commit.
 
     Options:
     -A, --after        record a copy that has already occurred
     -f, --force        forcibly copy over an existing managed file
     -p, --parents      append source path to dest
     
+    aliases: cp
+
 diff [-a] [-r revision] [-r revision] [files ...]::
     Show differences between revisions for the specified files.
 
@@ -448,6 +450,24 @@
 
     aliases: rm
 
+rename <source ...> <dest>::
+    Mark dest as copies of sources; mark sources for deletion.  If
+    dest is a directory, copies are put in that directory.  If dest is
+    a file, there can only be one source.
+
+    By default, this command copies the contents of files as they
+    stand in the working directory.  If invoked with --after, the
+    operation is recorded, but no copying is performed.
+
+    This command takes effect in the next commit.
+
+    Options:
+    -A, --after        record a rename that has already occurred
+    -f, --force        forcibly copy over an existing managed file
+    -p, --parents      append source path to dest
+
+    aliases: mv
+
 revert [names ...]::
     Revert any uncommitted modifications made to the named files or
     directories.  This restores the contents of the affected files to
--- a/mercurial/commands.py	Wed Sep 14 16:31:03 2005 -0700
+++ b/mercurial/commands.py	Wed Sep 14 16:34:22 2005 -0700
@@ -696,8 +696,7 @@
     except ValueError, inst:
         raise util.Abort(str(inst))
 
-def copy(ui, repo, *pats, **opts):
-    """mark files as copied for the next commit"""
+def docopy(ui, repo, pats, opts):
     if not pats:
         raise util.Abort('no source or destination specified')
     elif len(pats) == 1:
@@ -735,7 +734,7 @@
         elif len(sources) > 1:
             raise util.Abort('with multiple sources, destination must be a '
                              'directory')
-    errs = 0
+    errs, copied = 0, []
     for abs, rel, exact in sources:
         if opts['parents']:
             mydest = os.path.join(dest, rel)
@@ -763,6 +762,8 @@
                 n = repo.manifest.tip()
                 mf = repo.manifest.readflags(n)
                 util.set_exec(myreldest, util.is_exec(rel, mf[abs]))
+            except shutil.Error, inst:
+                raise util.Abort(str(inst))
             except IOError, inst:
                 if inst.errno == errno.ENOENT:
                     ui.warn('%s: deleted in working copy\n' % rel)
@@ -771,8 +772,14 @@
                 errs += 1
                 continue
         repo.copy(abs, myabsdest)
+        copied.append((abs, rel, exact))
     if errs:
-        ui.warn('(consider using --after to record failed copies)\n')
+        ui.warn('(consider using --after)\n')
+    return errs, copied
+
+def copy(ui, repo, *pats, **opts):
+    """mark files as copied for the next commit"""
+    errs, copied = docopy(ui, repo, pats, opts)
     return errs
 
 def debugcheckstate(ui, repo):
@@ -1390,14 +1397,14 @@
         reason = None
         if c: reason = 'is modified'
         elif a: reason = 'has been marked for add'
-        elif u: reason = 'not managed'
+        elif u: reason = 'is not managed'
         if reason and exact:
             ui.warn('not removing %s: file %s\n' % (rel, reason))
         else:
             return True
     for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
         if okaytoremove(abs, rel, exact):
-            if not exact: ui.status('removing %s\n' % rel)
+            if ui.verbose or not exact: ui.status('removing %s\n' % rel)
             names.append(abs)
     for name in names:
         try:
@@ -1406,6 +1413,20 @@
             if inst.errno != errno.ENOENT: raise
     repo.remove(names)
 
+def rename(ui, repo, *pats, **opts):
+    """rename files; equivalent of copy + remove"""
+    errs, copied = docopy(ui, repo, pats, opts)
+    names = []
+    for abs, rel, exact in copied:
+        if ui.verbose or not exact: ui.status('removing %s\n' % rel)
+        try:
+            os.unlink(rel)
+        except OSError, inst:
+            if inst.errno != errno.ENOENT: raise
+        names.append(abs)
+    repo.remove(names)
+    return errs
+
 def revert(ui, repo, *names, **opts):
     """revert modified files or dirs back to their unmodified states"""
     node = opts['rev'] and repo.lookup(opts['rev']) or \
@@ -1823,7 +1844,7 @@
           ('f', 'force', None, 'skip check for outstanding changes'),
           ('b', 'base', "", 'base path')],
          "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
-    "incoming|in": (incoming, 
+    "incoming|in": (incoming,
          [('p', 'patch', None, 'show patch')],
          'hg incoming [-p] [SOURCE]'),
     "^init": (init, [], 'hg init [DEST]'),
@@ -1844,7 +1865,7 @@
           ('p', 'patch', None, 'show patch')],
          'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
     "manifest": (manifest, [], 'hg manifest [REV]'),
-    "outgoing|out": (outgoing, 
+    "outgoing|out": (outgoing,
          [('p', 'patch', None, 'show patch')],
          'hg outgoing [-p] [DEST]'),
     "parents": (parents, [], 'hg parents [REV]'),
@@ -1876,6 +1897,13 @@
                    [('I', 'include', [], 'include path in search'),
                     ('X', 'exclude', [], 'exclude path from search')],
                    "hg remove [OPTION]... FILE..."),
+    "rename|mv": (rename,
+                  [('I', 'include', [], 'include path in search'),
+                   ('X', 'exclude', [], 'exclude path from search'),
+                   ('A', 'after', None, 'record a copy after it has happened'),
+                   ('f', 'force', None, 'replace destination if it exists'),
+                   ('p', 'parents', None, 'append source path to dest')],
+                  'hg rename [OPTION]... [SOURCE]... DEST'),
     "^revert":
         (revert,
          [("n", "nonrecursive", None, "don't recurse into subdirs"),
--- a/tests/test-help.out	Wed Sep 14 16:31:03 2005 -0700
+++ b/tests/test-help.out	Wed Sep 14 16:34:22 2005 -0700
@@ -65,6 +65,7 @@
  rawcommit   raw commit interface
  recover     roll back an interrupted transaction
  remove      remove the specified files on the next commit
+ rename      rename files; equivalent of copy + remove
  revert      revert modified files or dirs back to their unmodified states
  root        print the root (top) of the current working dir
  serve       export the repository via HTTP
@@ -106,6 +107,7 @@
  rawcommit   raw commit interface
  recover     roll back an interrupted transaction
  remove      remove the specified files on the next commit
+ rename      rename files; equivalent of copy + remove
  revert      revert modified files or dirs back to their unmodified states
  root        print the root (top) of the current working dir
  serve       export the repository via HTTP