[PATCH] remove: add --keep-dirs option to disable removing empty directories

jonny.dee at gmx.net jonny.dee at gmx.net
Fri Aug 28 19:31:31 CDT 2009

# HG changeset patch
# User Jonny Dee <jonny.dee at gmx.net>
# Date 1251504955 -7200
# Node ID 34a07e4df72be5cd59bd3acddcf193f9ebab16ca
# Parent  3a78bbc5766064b0338859b25e183ea9514f4ec3
remove: add --keep-dirs option to disable removing empty directories.

Mercurial normally deletes empty directories when removing files
would leave them empty. This patch will add a new option --keep-dirs
to the 'remove' command which, when specified on command line, will
make Mercurial keep local empty directories.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2374,6 +2374,9 @@
       -A     W  W  W  R
       -Af    R  R  R  R
+    Mercurial normally deletes empty directories when removing files
+    would leave them empty. Pass --keep-dirs to disable this.
     This command schedules the files to be removed at the next commit.
     To undo a remove before that, see hg revert.
@@ -2410,7 +2413,8 @@
             ui.status(_('removing %s\n') % m.rel(f))
-    repo.remove(remove, unlink=not after)
+    keepdirs = opts.get('keep_dirs', None)
+    repo.remove(remove, unlink=not after, keepdirs=keepdirs)
 def rename(ui, repo, *pats, **opts):
     """rename files; equivalent of copy + remove
@@ -3456,6 +3460,8 @@
          [('A', 'after', None, _('record delete for missing files')),
           ('f', 'force', None,
            _('remove (and delete) file even if added or modified')),
+          ('', 'keep-dirs', None,
+           _('do not delete empty directories')),
          ] + walkopts,
          _('[OPTION]... FILE...')),
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1098,11 +1098,11 @@
-    def remove(self, list, unlink=False):
+    def remove(self, list, unlink=False, keepdirs=None):
         if unlink:
             for f in list:
-                    util.unlink(self.wjoin(f))
+                    util.unlink(self.wjoin(f), keepdirs)
                 except OSError, inst:
                     if inst.errno != errno.ENOENT:
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -445,14 +445,15 @@
         os.rename(src, dst)
-def unlink(f):
+def unlink(f, keepdirs=None):
     """unlink and remove the directory if it is empty"""
     # try removing directories that might now be empty
-    try:
-        os.removedirs(os.path.dirname(f))
-    except OSError:
-        pass
+    if not keepdirs:
+        try:
+            os.removedirs(os.path.dirname(f))
+        except OSError:
+            pass
 def copyfile(src, dest):
     "copy a file, preserving mode and atime/mtime"
diff --git a/tests/test-debugcomplete.out b/tests/test-debugcomplete.out
--- a/tests/test-debugcomplete.out
+++ b/tests/test-debugcomplete.out
@@ -175,7 +175,7 @@
 parents: rev, style, template
 pull: update, force, rev, ssh, remotecmd
 push: force, rev, ssh, remotecmd
-remove: after, force, include, exclude
+remove: after, force, keep-dirs, include, exclude
 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, include, exclude
 update: clean, check, date, rev
diff --git a/tests/test-remove b/tests/test-remove
--- a/tests/test-remove
+++ b/tests/test-remove
@@ -108,3 +108,16 @@
 echo % dir, options -Af
 rm test/bar
 remove -Af test
+mkdir test/subdir
+echo ab > test/subdir/foobar
+hg ci -Am3
+echo % dir, options --keep-dirs
+# using remove() does not help here because the generated output does
+# not list (empty) directories.
+hg rm --keep-dirs test
+hg st
+find . -name .hg -prune -o -print | sort
+hg up -C
diff --git a/tests/test-remove.out b/tests/test-remove.out
--- a/tests/test-remove.out
+++ b/tests/test-remove.out
@@ -111,3 +111,16 @@
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+adding test/subdir/foobar
+% dir, options --keep-dirs
+removing test/bar
+removing test/foo
+removing test/subdir/foobar
+R test/bar
+R test/foo
+R test/subdir/foobar
+3 files updated, 0 files merged, 0 files removed, 0 files unresolved

More information about the Mercurial-devel mailing list