hg status not showing empty dirs out of dirstate

Andrea Arcangeli andrea at suse.de
Sat Jun 17 09:42:00 CDT 2006


Given the general dislike for the feature, I now minimized it to be a
really low overhead and opt-in as requested, while still allowing people
to see leftover garbage to be able to verify if the distclean scripts
are cleaning up everything (I had garbage in my trees and I was a bit
annoyed that there was absolutely now way to find it reliably, despite
even CVS is perfectly capable of showing me if I've leftover/unknown
dirs in the tree ;).

The trick to cleanup a tree is now like this:

	hg status -nu | xargs rm # this get rid of the untracked files
	hg status -nuU | xargs rmdir # this get rid of the untracked dirs

The second command should be run multiple times until rmdir fails saying
that there is no dir left to delete (i.e. until no output is returned
from hg).

This isn't as good as I would liked but any other approach is more
heavyweight either in performance or ram utilization, and so probably
it would be overdesign. This is already enough to cleanup leftover
garbage directories in the working tree if people cares to write correct
cleanup scripts without having to clone or archive the tree that is a
much more inefficient way of checking it.

# HG changeset patch
# User andrea at suse.de
# Date 1150553218 -7200
# Node ID fcbfa4d0e0d7847ba12f543338c940ae68c19296
# Parent  dbeaa43691214bc0fffad6fbeceaa47b31b5dcc0
add --unknown_dirs

diff -r dbeaa4369121 -r fcbfa4d0e0d7 mercurial/commands.py
--- a/mercurial/commands.py	Sun Jun 04 17:08:02 2006 -0700
+++ b/mercurial/commands.py	Sat Jun 17 16:06:58 2006 +0200
@@ -2550,12 +2550,14 @@ def status(ui, repo, *pats, **opts):
     """
 
     show_ignored = opts['ignored'] and True or False
+    show_unknown_dirs = opts['unknown_dirs'] and True or False
     files, matchfn, anypats = matchpats(repo, pats, opts)
     cwd = (pats and repo.getcwd()) or ''
     modified, added, removed, deleted, unknown, ignored = [
         [util.pathto(cwd, x) for x in n]
         for n in repo.changes(files=files, match=matchfn,
-                              show_ignored=show_ignored)]
+                              show_ignored=show_ignored,
+                              show_unknown_dirs=show_unknown_dirs)]
 
     changetypes = [('modified', 'M', modified),
                    ('added', 'A', added),
@@ -3068,6 +3070,7 @@ table = {
           ('r', 'removed', None, _('show only removed files')),
           ('d', 'deleted', None, _('show only deleted (but tracked) files')),
           ('u', 'unknown', None, _('show only unknown (not tracked) files')),
+          ('U', 'unknown_dirs', None, _('include untracked dirs in the unknown list')),
           ('i', 'ignored', None, _('show ignored files')),
           ('n', 'no-status', None, _('hide status prefix')),
           ('0', 'print0', None,
diff -r dbeaa4369121 -r fcbfa4d0e0d7 mercurial/dirstate.py
--- a/mercurial/dirstate.py	Sun Jun 04 17:08:02 2006 -0700
+++ b/mercurial/dirstate.py	Sat Jun 17 16:06:58 2006 +0200
@@ -330,7 +330,9 @@ class dirstate(object):
     # is one of:
     # 'f' the file was found in the directory tree
     # 'm' the file was only in the dirstate and not in the tree
-    # and st is the stat result if the file was found in the directory.
+    #     and st is the stat result if the file was found in the directory.
+    # 'd' the directory is unknown (i.e. empty), so it has to be leftover garbage
+    #     that would otherwise go unnoticed
     #
     # dc is an optional arg for the current dirstate.  dc is not modified
     # directly by this function, but might be modified by your statmatch call.
@@ -355,6 +357,9 @@ class dirstate(object):
                     if hg < len(names) and names[hg] == '.hg':
                         if os.path.isdir(os.path.join(top, '.hg')):
                             continue
+                if not names:
+                    yield 'd', nd, st
+                    continue
                 for f in names:
                     np = util.pconvert(os.path.join(nd, f))
                     if seen(np):
@@ -426,7 +431,8 @@ 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 changes(self, files=None, match=util.always, show_ignored=None,
+                show_unknown_dirs=None):
         lookup, modified, added, unknown, ignored = [], [], [], [], []
         removed, deleted = [], []
 
@@ -437,7 +443,8 @@ class dirstate(object):
                 if show_ignored and self.ignore(fn):
                     ignored.append(fn)
                 else:
-                    unknown.append(fn)
+                    if src != 'd' or show_unknown_dirs:
+                        unknown.append(fn)
                 continue
             if src == 'm':
                 nonexistent = True
diff -r dbeaa4369121 -r fcbfa4d0e0d7 mercurial/localrepo.py
--- a/mercurial/localrepo.py	Sun Jun 04 17:08:02 2006 -0700
+++ b/mercurial/localrepo.py	Sat Jun 17 16:06:58 2006 +0200
@@ -596,7 +596,7 @@ class localrepository(object):
                 yield src, fn
 
     def changes(self, node1=None, node2=None, files=[], match=util.always,
-                wlock=None, show_ignored=None):
+                wlock=None, show_ignored=None, show_unknown_dirs=None):
         """return changes between two nodes or node and working directory
 
         If node1 is None, use the first dirstate parent instead.
@@ -630,7 +630,7 @@ class localrepository(object):
                 except lock.LockException:
                     wlock = None
             lookup, modified, added, removed, deleted, unknown, ignored = (
-                self.dirstate.changes(files, match, show_ignored))
+                self.dirstate.changes(files, match, show_ignored, show_unknown_dirs))
 
             # are we comparing working dir against its parent?
             if not node1:


More information about the Mercurial mailing list