mercurial/dirstate.py
changeset 47592 0f5c203eb5ab
parent 47591 3d8b639bfbaa
child 47593 f927ad5a4e2c
--- a/mercurial/dirstate.py	Thu Jul 08 10:05:23 2021 +0200
+++ b/mercurial/dirstate.py	Sat Jul 10 23:31:51 2021 +0200
@@ -72,6 +72,17 @@
         vfs.unlink(tmpname)
 
 
+def requires_parents_change(func):
+    def wrap(self, *args, **kwargs):
+        if not self.pendingparentchange():
+            msg = 'calling `%s` outside of a parentchange context'
+            msg %= func.__name__
+            raise error.ProgrammingError(msg)
+        return func(self, *args, **kwargs)
+
+    return wrap
+
+
 @interfaceutil.implementer(intdirstate.idirstate)
 class dirstate(object):
     def __init__(
@@ -440,6 +451,44 @@
     def copies(self):
         return self._map.copymap
 
+    @requires_parents_change
+    def update_file_reference(
+        self,
+        filename,
+        p1_tracked,
+    ):
+        """Set a file as tracked in the parent (or not)
+
+        This is to be called when adjust the dirstate to a new parent after an history
+        rewriting operation.
+
+        It should not be called during a merge (p2 != nullid) and only within
+        a `with dirstate.parentchange():` context.
+        """
+        if self.in_merge:
+            msg = b'update_file_reference should not be called when merging'
+            raise error.ProgrammingError(msg)
+        entry = self._map.get(filename)
+        if entry is None:
+            wc_tracked = False
+        else:
+            wc_tracked = entry.tracked
+        if p1_tracked and wc_tracked:
+            # the underlying reference might have changed, we will have to
+            # check it.
+            self.normallookup(filename)
+        elif not (p1_tracked or wc_tracked):
+            # the file is no longer relevant to anyone
+            self._drop(filename)
+        elif (not p1_tracked) and wc_tracked:
+            if not entry.added:
+                self._add(filename)
+        elif p1_tracked and not wc_tracked:
+            if entry is None or not entry.removed:
+                self._remove(filename)
+        else:
+            assert False, 'unreachable'
+
     def _addpath(
         self,
         f,