diff --git a/mercurial/cext/parsers.c b/mercurial/cext/parsers.c --- a/mercurial/cext/parsers.c +++ b/mercurial/cext/parsers.c @@ -29,6 +29,8 @@ static const char *const versionerrortext = "Python minor version mismatch"; +static const int dirstate_v1_from_p2 = -2; + static PyObject *dict_new_presized(PyObject *self, PyObject *args) { Py_ssize_t expected_size; @@ -164,9 +166,19 @@ static PyObject *dirstatetuple_get_merge } }; +static PyObject *dirstatetuple_get_from_p2(dirstateTupleObject *self) +{ + if (self->size == dirstate_v1_from_p2) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +}; + static PyGetSetDef dirstatetuple_getset[] = { {"state", (getter)dirstatetuple_get_state, NULL, "state", NULL}, {"merged", (getter)dirstatetuple_get_merged, NULL, "merged", NULL}, + {"from_p2", (getter)dirstatetuple_get_from_p2, NULL, "from_p2", NULL}, {NULL} /* Sentinel */ }; diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -393,7 +393,7 @@ class dirstate(object): copies[f] = source self.normallookup(f) # Also fix up otherparent markers - elif s.state == b'n' and s[2] == FROM_P2: + elif s.state == b'n' and s.from_p2: source = self._map.copymap.get(f) if source: copies[f] = source @@ -531,16 +531,18 @@ class dirstate(object): # being removed, restore that state. entry = self._map.get(f) if entry is not None: - if entry.state == b'r' and entry[2] in (NONNORMAL, FROM_P2): + if entry.state == b'r' and ( + entry[2] == NONNORMAL or entry.from_p2 + ): source = self._map.copymap.get(f) if entry[2] == NONNORMAL: self.merge(f) - elif entry[2] == FROM_P2: + elif entry.from_p2: self.otherparent(f) if source: self.copy(source, f) return - if entry.merged or entry.state == b'n' and entry[2] == FROM_P2: + if entry.merged or entry.state == b'n' and entry.from_p2: return self._addpath(f, b'n', 0, possibly_dirty=True) self._map.copymap.pop(f, None) @@ -1336,7 +1338,7 @@ class dirstate(object): (size != st.st_size and size != st.st_size & _rangemask) or ((mode ^ st.st_mode) & 0o100 and checkexec) ) - or size == FROM_P2 # other parent + or t.from_p2 or fn in copymap ): if stat.S_ISLNK(st.st_mode) and size != st.st_size: diff --git a/mercurial/dirstatemap.py b/mercurial/dirstatemap.py --- a/mercurial/dirstatemap.py +++ b/mercurial/dirstatemap.py @@ -173,7 +173,7 @@ class dirstatemap(object): # backup the previous state if entry.merged: # merge size = NONNORMAL - elif entry[0] == b'n' and entry[2] == FROM_P2: # other parent + elif entry[0] == b'n' and entry.from_p2: size = FROM_P2 self.otherparentset.add(f) if size == 0: diff --git a/mercurial/pure/parsers.py b/mercurial/pure/parsers.py --- a/mercurial/pure/parsers.py +++ b/mercurial/pure/parsers.py @@ -33,6 +33,10 @@ stringio = pycompat.bytesio _decompress = zlib.decompress +# a special value used internally for `size` if the file come from the other parent +FROM_P2 = -2 + + class dirstatetuple(object): """represent a dirstate entry @@ -87,6 +91,14 @@ class dirstatetuple(object): """ return self._state == b'm' + @property + def from_p2(self): + """True if the file have been fetched from p2 during the current merge + + Should only be set if a merge is in progress in the dirstate + """ + return self._size == FROM_P2 + def v1_state(self): """return a "state" suitable for v1 serialization""" return self._state