changeset 48075:a660d8a53267

dirstate: use a new `drop_merge_data` in `setparent` What is happening in this `setparent` loop is that we remove all `merge` related information when the dirstate is moved out of a `merge` situation. So instead of shuffling state to get them where we want, we simply add a method on the DirstateItem to do drop the information we want dropped. Differential Revision: https://phab.mercurial-scm.org/D11506
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 22 Sep 2021 17:46:29 +0200
parents 5d68c4eedd66
children 060cd909439f
files mercurial/cext/parsers.c mercurial/dirstatemap.py mercurial/pure/parsers.py
diffstat 3 files changed, 44 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/cext/parsers.c	Wed Sep 22 15:17:12 2021 +0200
+++ b/mercurial/cext/parsers.c	Wed Sep 22 17:46:29 2021 +0200
@@ -515,6 +515,27 @@
 	Py_RETURN_NONE;
 }
 
+static PyObject *dirstate_item_drop_merge_data(dirstateItemObject *self)
+{
+	if (dirstate_item_c_merged(self) || dirstate_item_c_from_p2(self)) {
+		if (dirstate_item_c_merged(self)) {
+			self->flags |= dirstate_flag_p1_tracked;
+		} else {
+			self->flags &= ~dirstate_flag_p1_tracked;
+		}
+		self->flags &=
+		    ~(dirstate_flag_merged | dirstate_flag_clean_p1 |
+		      dirstate_flag_clean_p2 | dirstate_flag_p2_tracked);
+		self->flags |= dirstate_flag_possibly_dirty;
+		self->mode = 0;
+		self->mtime = 0;
+		/* size = None on the python size turn into size = NON_NORMAL
+		 * when accessed. So the next line is currently required, but a
+		 * some future clean up would be welcome. */
+		self->size = dirstate_v1_nonnormal;
+	}
+	Py_RETURN_NONE;
+}
 static PyMethodDef dirstate_item_methods[] = {
     {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
      "return a \"state\" suitable for v1 serialization"},
@@ -551,6 +572,8 @@
      "mark a file as \"tracked\""},
     {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
      "mark a file as \"untracked\""},
+    {"drop_merge_data", (PyCFunction)dirstate_item_drop_merge_data, METH_NOARGS,
+     "remove all \"merge-only\" from a DirstateItem"},
     {NULL} /* Sentinel */
 };
 
--- a/mercurial/dirstatemap.py	Wed Sep 22 15:17:12 2021 +0200
+++ b/mercurial/dirstatemap.py	Wed Sep 22 17:46:29 2021 +0200
@@ -441,26 +441,11 @@
                     continue
 
                 # Discard "merged" markers when moving away from a merge state
-                if s.merged:
-                    source = self.copymap.get(f)
+                if s.merged or s.from_p2:
+                    source = self.copymap.pop(f, None)
                     if source:
                         copies[f] = source
-                    self.reset_state(
-                        f,
-                        wc_tracked=True,
-                        p1_tracked=True,
-                        possibly_dirty=True,
-                    )
-                # Also fix up otherparent markers
-                elif s.from_p2:
-                    source = self.copymap.get(f)
-                    if source:
-                        copies[f] = source
-                    self.reset_state(
-                        f,
-                        p1_tracked=False,
-                        wc_tracked=True,
-                    )
+                    s.drop_merge_data()
         return copies
 
     def read(self):
--- a/mercurial/pure/parsers.py	Wed Sep 22 15:17:12 2021 +0200
+++ b/mercurial/pure/parsers.py	Wed Sep 22 17:46:29 2021 +0200
@@ -263,6 +263,24 @@
         self._size = None
         self._mtime = None
 
+    def drop_merge_data(self):
+        """remove all "merge-only" from a DirstateItem
+
+        This is to be call by the dirstatemap code when the second parent is dropped
+        """
+        if not (self.merged or self.from_p2):
+            return
+        self._p1_tracked = self.merged  # why is this not already properly set ?
+
+        self._merged = False
+        self._clean_p1 = False
+        self._clean_p2 = False
+        self._p2_tracked = False
+        self._possibly_dirty = True
+        self._mode = None
+        self._size = None
+        self._mtime = None
+
     @property
     def mode(self):
         return self.v1_mode()