diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -1050,7 +1050,7 @@ class queue: for f in m: repo.dirstate.normal(f) for f in mm: - repo.dirstate.normaldirty(f) + repo.dirstate.normallookup(f) for f in forget: repo.dirstate.forget(f) diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -202,18 +202,24 @@ class dirstate(object): self._incpath(f) def normal(self, f): - 'mark a file normal' + 'mark a file normal and clean' self._dirty = True s = os.lstat(self._join(f)) self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime) if self._copymap.has_key(f): del self._copymap[f] - def normaldirty(self, f): + def normallookup(self, f): 'mark a file normal, but possibly dirty' self._dirty = True - s = os.lstat(self._join(f)) - self._map[f] = ('n', s.st_mode, -1, -1) + self._map[f] = ('n', 0, -1, -1) + if f in self._copymap: + del self._copymap[f] + + def normaldirty(self, f): + 'mark a file normal, but dirty' + self._dirty = True + self._map[f] = ('n', 0, -2, -1) if f in self._copymap: del self._copymap[f] @@ -523,6 +529,7 @@ class dirstate(object): st = lstat(_join(fn)) if (size >= 0 and (size != st.st_size or (mode ^ st.st_mode) & 0100) + or size == -2 or fn in self._copymap): madd(fn) elif time != int(st.st_mtime): diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -998,7 +998,7 @@ class localrepository(repo.repository): elif self.dirstate[f] in 'amn': self.ui.warn(_("%s already tracked!\n") % f) elif self.dirstate[f] == 'r': - self.dirstate.normaldirty(f) + self.dirstate.normallookup(f) else: self.dirstate.add(f) finally: diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -543,7 +543,7 @@ def recordupdates(repo, action, branchme # of that file some time in the past. Thus our # merge will appear as a normal local file # modification. - repo.dirstate.normaldirty(fd) + repo.dirstate.normallookup(fd) if move: repo.dirstate.forget(f) elif m == "d": # directory rename diff --git a/tests/test-issue522 b/tests/test-issue522 new file mode 100755 --- /dev/null +++ b/tests/test-issue522 @@ -0,0 +1,31 @@ +#!/bin/sh + +# In the merge below, the file "foo" has the same contents in both +# parents, but if we look at the file-level history, we'll notice that +# the version in p1 is an ancestor of the version in p2. This test +# makes sure that we'll use the version from p2 in the manifest of the +# merge revision. + +hg init repo +cd repo + +echo foo > foo +hg ci -d '0 0' -qAm 'add foo' + +echo bar >> foo +hg ci -d '0 0' -m 'change foo' + +hg backout -d '0 0' -r tip -m 'backout changed foo' + +hg up -C 0 +touch bar +hg ci -d '0 0' -qAm 'add bar' + +hg merge --debug +hg debugstate | grep foo +hg st -A foo +hg ci -d '0 0' -m 'merge' + +hg manifest --debug | grep foo +hg debugindex .hg/store/data/foo.i + diff --git a/tests/test-issue522.out b/tests/test-issue522.out new file mode 100644 --- /dev/null +++ b/tests/test-issue522.out @@ -0,0 +1,17 @@ +reverting foo +changeset 2:4d9e78aaceee backs out changeset 1:b515023e500e +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +resolving manifests + overwrite None partial False + ancestor bbd179dfa0a7 local 71766447bdbb+ remote 4d9e78aaceee + foo: remote is newer -> g +getting foo +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +n 0 -2 unset foo +M foo +c6fc755d7e68f49f880599da29f15add41f42f5a 644 foo + rev offset length base linkrev nodeid p1 p2 + 0 0 5 0 0 2ed2a3912a0b 000000000000 000000000000 + 1 5 9 1 1 6f4310b00b9a 2ed2a3912a0b 000000000000 + 2 14 5 2 2 c6fc755d7e68 6f4310b00b9a 000000000000