[PATCH] improved semantics for remove (issue438)

Dirkjan Ochtman dirkjan at ochtman.nl
Fri Mar 21 09:21:09 CDT 2008


# HG changeset patch
# User Dirkjan Ochtman <dirkjan at ochtman.nl>
# Date 1206107862 -3600
# Node ID fadd63aa67b27c3a222ca73661c98a5cc64b1bdb
# Parent  0750f11152febd2ff4ca7439957b77111d99cc63
improved semantics for remove (issue438)

- Added files are never deleted (only removed with --force).
- Modified files can only be removed with --force.
- With --keep, removals never delete the file.
- With --after, only deleted files are removed.

diff -r 0750f11152fe -r fadd63aa67b2 mercurial/commands.py
--- a/mercurial/commands.py	Fri Mar 21 14:52:24 2008 +0100
+++ b/mercurial/commands.py	Fri Mar 21 14:57:42 2008 +0100
@@ -2129,49 +2129,61 @@
 
     This only removes files from the current branch, not from the
     entire project history.  If the files still exist in the working
-    directory, they will be deleted from it.  If invoked with --after,
-    files are marked as removed, but not actually unlinked unless --force
-    is also given. Without exact file names, --after will only mark
-    files as removed if they are no longer in the working directory.
+    directory, they will be deleted from it, unless invoked with --keep.
+
+    --after can be used to remove files that have been deleted from disk.
+    --keep can be used to remove files from further revisions without deleting.
+
+    Added files can only be removed with the -f/--force option, and will never
+    be deleted. Modified files can only be removed with the -f/--force option.
 
     This command schedules the files to be removed at the next commit.
     To undo a remove before that, see hg revert.
+    """
 
-    Modified files and added files are not removed by default.  To
-    remove them, use the -f/--force option.
-    """
-    if not opts['after'] and not pats:
+    after, keep, force = opts.get('after'), opts.get('keep'), opts.get('force')
+    if not pats and not after:
         raise util.Abort(_('no files specified'))
+
     files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
-    exact = dict.fromkeys(files)
     mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
     modified, added, removed, deleted, unknown = mardu
+
     remove, forget = [], []
     for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
+
         reason = None
-        if abs in modified and not opts['force']:
-            reason = _('is modified (use -f to force removal)')
+        if abs in removed or abs in unknown:
+            continue
+
+        elif after and not keep and abs not in deleted:
+            reason = _('still exists (use without -A to remove)')
+
+        elif keep and not after and abs in deleted:
+            reason = _('already deleted (use without -k to remove)')
+
         elif abs in added:
-            if opts['force']:
+            if not force and not keep:
+                reason = _('has been marked for add (use -f to force removal)')
+            else:
                 forget.append(abs)
-                continue
-            reason = _('has been marked for add (use -f to force removal)')
-            exact = 1 # force the message
-        elif abs not in repo.dirstate:
-            reason = _('is not managed')
-        elif opts['after'] and not exact and abs not in deleted:
-            continue
-        elif abs in removed:
-            continue
+
+        elif abs in modified:
+            if not force and not keep:
+                reason = _('is modified (use -f to force removal)')
+            else:
+                remove.append(abs)
+
+        elif not reason:
+            remove.append(abs)
+
         if reason:
-            if exact:
-                ui.warn(_('not removing %s: file %s\n') % (rel, reason))
-        else:
-            if ui.verbose or not exact:
-                ui.status(_('removing %s\n') % rel)
-            remove.append(abs)
+            ui.warn(_('not removing %s: file %s\n') % (rel, reason))
+        elif ui.verbose or not exact:
+            ui.status(_('removing %s\n') % rel)
+
     repo.forget(forget)
-    repo.remove(remove, unlink=opts['force'] or not opts['after'])
+    repo.remove(remove, unlink=not keep and not after)
 
 def rename(ui, repo, *pats, **opts):
     """rename files; equivalent of copy + remove
@@ -3125,8 +3137,10 @@
     "recover": (recover, [], _('hg recover')),
     "^remove|rm":
         (remove,
-         [('A', 'after', None, _('record remove without deleting')),
-          ('f', 'force', None, _('remove file even if modified')),
+         [('A', 'after', None, _('record delete for missing files')),
+          ('k', 'keep', None, _('record remove without deleting')),
+          ('f', 'force', None,
+		  _('remove (and delete) file even if added or modified')),
          ] + walkopts,
          _('hg remove [OPTION]... FILE...')),
     "rename|mv":
diff -r 0750f11152fe -r fadd63aa67b2 tests/test-issue660
--- a/tests/test-issue660	Fri Mar 21 14:52:24 2008 +0100
+++ b/tests/test-issue660	Fri Mar 21 14:57:42 2008 +0100
@@ -19,7 +19,7 @@
 hg add a/a
 
 echo % removing shadow
-hg rm --after a
+hg rm -A a
 
 echo % should succeed - shadow removed
 hg add a/a
@@ -33,7 +33,7 @@
 hg add b
 
 echo % removing shadow
-hg rm --after b/b
+hg rm -A b/b
 
 echo % should succeed - shadow removed
 hg add b
@@ -76,7 +76,7 @@
 hg add d
 
 echo % removing shadow
-hg rm --after d/d/d
+hg rm -A d/d/d
 
 echo % should succeed - shadow removed
 hg add d
diff -r 0750f11152fe -r fadd63aa67b2 tests/test-remove
--- a/tests/test-remove	Fri Mar 21 14:52:24 2008 +0100
+++ b/tests/test-remove	Fri Mar 21 14:57:42 2008 +0100
@@ -3,16 +3,52 @@
 hg init a
 cd a
 echo a > foo
+
+echo % file not managed
+hg rm foo 
+
+hg add foo
+hg commit -m1
+
+echo % normal remove
 hg rm foo
-hg add foo
-hg commit -m 1 -d "1000000 0"
+hg st
+test -f foo && echo NOK foo still exists || echo OK foo was removed
+
+hg up -C
+echo % normal remove with after
+hg rm -A foo
+hg st
+test -f foo && echo OK foo still exists || echo NOK foo was removed
+
+hg up -C
+echo % normal remove with after + missing
+rm foo
+hg rm -A foo
+hg st
+test -f foo && echo NOK foo still exists || echo OK foo was removed
+
+hg up -C
+echo % normal remove with keep
+hg rm -k foo
+hg st
+test -f foo && echo OK foo still exists || echo NOK foo was removed
+
+hg up -C
+echo % no file specified
 hg remove
+
+echo % remove + revert
 rm foo
 hg remove foo
+hg st
 hg revert --all
+test -f foo && echo OK foo still exists || echo NOK foo was removed
+
 rm foo
-hg remove --after
-hg commit -m 2 -d "1000000 0"
+hg remove foo
+hg commit -m2
+
 hg export --nodates 0
 hg export --nodates 1
 hg log -p -r 0
@@ -20,26 +56,99 @@
 
 echo a > a
 hg add a
+echo % added files are not removed
 hg rm a
+test -f a && echo OK a still exists || echo NOK a was removed
+
+echo % no warning for added files if --keep
+hg rm -k a
+hg st
+
+echo % not even when --forced
 hg rm -f a
+test -f a && echo OK a still exists || echo NOK a was removed
+hg st
+
 echo b > b
 mkdir c
 echo d > c/d
-hg ci -A -m 3 -d "1000001 0"
-echo c >> b
-hg rm b
-hg rm -f b
-hg rm -A c/d
-hg st
-cat c/d
-hg revert c
-hg rm -A
-hg st
-hg rm -A c
-hg st
-rm c/d
+hg ci -Am3
+
+echo % rm -A without patterns
+rm b
 hg rm -A
 hg st
 
+hg up -C
+echo c >> b
+echo % modified files are not removed
+hg rm b
+test -f b && echo OK b still exists || echo NOK b was removed
+
+echo % no warning for modified files if --keep
+hg rm -k b
+hg st
+
+hg up -C
+echo c >> b
+echo % unless --forced
+hg rm -f b
+test -f b && echo NOK b still exists || echo OK b was removed
+
+echo % remove file without deleting it
+hg rm -k c/d
+test -f c/d && echo OK c/d still exists || echo NOK c/d was removed
+hg st
+cat c/d
+
+hg up -C
+echo % adding another file to dir
+echo e > c/e
+hg ci -Am4
+
+echo % rm on a dir
+hg rm c
+hg st
+
+hg up -C
+echo % rm -k on a dir
+hg rm -k c
+ls c
+hg st
+
+hg up -C
+echo % rm -A on a dir
+hg rm -A c
+ls c
+hg st
+
+hg up -C
+echo % rm -Ak on a dir
+hg rm -Ak c
+ls c
+hg st
+
+hg up -C
+echo % rm -A on a dir with missing
+rm c/e
+hg rm -A c
+ls c
+hg st
+
+hg up -C
+echo % rm -k on a dir with missing
+rm c/e
+hg rm -k c
+ls c
+hg st
+
+hg up -C
+echo % rm -Ak on a dir with missing
+rm c/e
+hg rm -Ak c
+ls c
+hg st
+
+echo % clone
 cd ..
 hg clone a b
diff -r 0750f11152fe -r fadd63aa67b2 tests/test-remove.out
--- a/tests/test-remove.out	Fri Mar 21 14:52:24 2008 +0100
+++ b/tests/test-remove.out	Fri Mar 21 14:57:42 2008 +0100
@@ -1,67 +1,153 @@
-not removing foo: file is not managed
+% file not managed
+% normal remove
+R foo
+OK foo was removed
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% normal remove with after
+not removing foo: file still exists (use without -A to remove)
+OK foo still exists
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% normal remove with after + missing
+R foo
+OK foo was removed
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% normal remove with keep
+R foo
+OK foo still exists
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% no file specified
 abort: no files specified
+% remove + revert
+R foo
 undeleting foo
-removing foo
+OK foo still exists
 # HG changeset patch
 # User test
-# Date 1000000 0
-# Node ID 8ba83d44753d6259db5ce6524974dd1174e90f47
+# Date 0 0
+# Node ID b51ca55c20354097ca299529d18b5cd356976ba2
 # Parent  0000000000000000000000000000000000000000
 1
 
-diff -r 000000000000 -r 8ba83d44753d foo
+diff -r 000000000000 -r b51ca55c2035 foo
 --- /dev/null
 +++ b/foo
 @@ -0,0 +1,1 @@
 +a
 # HG changeset patch
 # User test
-# Date 1000000 0
-# Node ID a1fce69c50d97881c5c014ab23f580f720c78678
-# Parent  8ba83d44753d6259db5ce6524974dd1174e90f47
+# Date 0 0
+# Node ID 451c12a24e5a7336921b8d93e280837d7c2b4fc1
+# Parent  b51ca55c20354097ca299529d18b5cd356976ba2
 2
 
-diff -r 8ba83d44753d -r a1fce69c50d9 foo
+diff -r b51ca55c2035 -r 451c12a24e5a foo
 --- a/foo
 +++ /dev/null
 @@ -1,1 +0,0 @@
 -a
-changeset:   0:8ba83d44753d
+changeset:   0:b51ca55c2035
 user:        test
-date:        Mon Jan 12 13:46:40 1970 +0000
+date:        Thu Jan 01 00:00:00 1970 +0000
 summary:     1
 
-diff -r 000000000000 -r 8ba83d44753d foo
+diff -r 000000000000 -r b51ca55c2035 foo
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/foo	Mon Jan 12 13:46:40 1970 +0000
++++ b/foo	Thu Jan 01 00:00:00 1970 +0000
 @@ -0,0 +1,1 @@
 +a
 
-changeset:   1:a1fce69c50d9
+changeset:   1:451c12a24e5a
 tag:         tip
 user:        test
-date:        Mon Jan 12 13:46:40 1970 +0000
+date:        Thu Jan 01 00:00:00 1970 +0000
 summary:     2
 
-diff -r 8ba83d44753d -r a1fce69c50d9 foo
---- a/foo	Mon Jan 12 13:46:40 1970 +0000
+diff -r b51ca55c2035 -r 451c12a24e5a foo
+--- a/foo	Thu Jan 01 00:00:00 1970 +0000
 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
 @@ -1,1 +0,0 @@
 -a
 
+% added files are not removed
 not removing a: file has been marked for add (use -f to force removal)
+OK a still exists
+% no warning for added files if --keep
+? a
+% not even when --forced
+OK a still exists
+? a
 adding a
 adding b
 adding c/d
+% rm -A without patterns
+not removing a: file still exists (use without -A to remove)
+not removing c/d: file still exists (use without -A to remove)
+removing b
+R b
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% modified files are not removed
 not removing b: file is modified (use -f to force removal)
+OK b still exists
+% no warning for modified files if --keep
+R b
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% unless --forced
+OK b was removed
+% remove file without deleting it
+OK c/d still exists
 R b
 R c/d
 d
-undeleting c/d
-R b
-R b
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% adding another file to dir
+adding c/e
+% rm on a dir
 removing c/d
-R b
+removing c/e
 R c/d
+R c/e
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% rm -k on a dir
+removing c/d
+removing c/e
+d
+e
+R c/d
+R c/e
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% rm -A on a dir
+not removing c/d: file still exists (use without -A to remove)
+not removing c/e: file still exists (use without -A to remove)
+d
+e
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% rm -Ak on a dir
+removing c/d
+removing c/e
+d
+e
+R c/d
+R c/e
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% rm -A on a dir with missing
+not removing c/d: file still exists (use without -A to remove)
+removing c/e
+d
+R c/e
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% rm -k on a dir with missing
+removing c/d
+not removing c/e: file already deleted (use without -k to remove)
+d
+R c/d
+! c/e
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% rm -Ak on a dir with missing
+removing c/d
+removing c/e
+d
+R c/d
+R c/e
+% clone
 updating working directory
-3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+4 files updated, 0 files merged, 0 files removed, 0 files unresolved


More information about the Mercurial-devel mailing list