mercurial/dirstate.py
changeset 13704 a464763e99f1
parent 13400 14f3795a5ed7
child 13728 15d1db2abfcb
--- a/mercurial/dirstate.py	Sun Mar 20 01:16:57 2011 +0100
+++ b/mercurial/dirstate.py	Sun Mar 20 17:41:09 2011 -0400
@@ -49,6 +49,7 @@
         self._rootdir = os.path.join(root, '')
         self._dirty = False
         self._dirtypl = False
+        self._lastnormal = set()        # files believed to be normal
         self._ui = ui
 
     @propertycache
@@ -285,6 +286,12 @@
         if f in self._copymap:
             del self._copymap[f]
 
+        # Right now, this file is clean: but if some code in this
+        # process modifies it without changing its size before the clock
+        # ticks over to the next second, then it won't be clean anymore.
+        # So make sure that status() will look harder at it.
+        self._lastnormal.add(f)
+
     def normallookup(self, f):
         '''Mark a file normal, but possibly dirty.'''
         if self._pl[1] != nullid and f in self._map:
@@ -308,6 +315,7 @@
         self._map[f] = ('n', 0, -1, -1)
         if f in self._copymap:
             del self._copymap[f]
+        self._lastnormal.discard(f)
 
     def otherparent(self, f):
         '''Mark as coming from the other parent, always dirty.'''
@@ -319,6 +327,7 @@
         self._map[f] = ('n', 0, -2, -1)
         if f in self._copymap:
             del self._copymap[f]
+        self._lastnormal.discard(f)
 
     def add(self, f):
         '''Mark a file added.'''
@@ -327,6 +336,7 @@
         self._map[f] = ('a', 0, -1, -1)
         if f in self._copymap:
             del self._copymap[f]
+        self._lastnormal.discard(f)
 
     def remove(self, f):
         '''Mark a file removed.'''
@@ -343,6 +353,7 @@
         self._map[f] = ('r', 0, size, 0)
         if size == 0 and f in self._copymap:
             del self._copymap[f]
+        self._lastnormal.discard(f)
 
     def merge(self, f):
         '''Mark a file merged.'''
@@ -352,6 +363,7 @@
         self._map[f] = ('m', s.st_mode, s.st_size, int(s.st_mtime))
         if f in self._copymap:
             del self._copymap[f]
+        self._lastnormal.discard(f)
 
     def forget(self, f):
         '''Forget a file.'''
@@ -361,6 +373,7 @@
             del self._map[f]
         except KeyError:
             self._ui.warn(_("not in dirstate: %s\n") % f)
+        self._lastnormal.discard(f)
 
     def _normalize(self, path, knownpath):
         norm_path = os.path.normcase(path)
@@ -640,6 +653,7 @@
         radd = removed.append
         dadd = deleted.append
         cadd = clean.append
+        lastnormal = self._lastnormal.__contains__
 
         lnkkind = stat.S_IFLNK
 
@@ -672,6 +686,18 @@
                 elif (time != int(st.st_mtime)
                       and (mode & lnkkind != lnkkind or self._checklink)):
                     ladd(fn)
+                elif lastnormal(fn):
+                    # If previously in this process we recorded that
+                    # this file is clean, think twice: intervening code
+                    # may have modified the file in the same second
+                    # without changing its size. So force caller to
+                    # check file contents. Because we're not updating
+                    # self._map, this only affects the current process.
+                    # That should be OK because this mainly affects
+                    # multiple commits in the same process, and each
+                    # commit by definition makes the committed files
+                    # clean.
+                    ladd(fn)
                 elif listclean:
                     cadd(fn)
             elif state == 'm':