merge uses wrong ancestor (and consequently does the wrong thing)

Mads Kiilerich mads at kiilerich.com
Mon Oct 6 13:35:21 CDT 2008


(Changing to mercurial-devel)

Stefan Ring wrote:
> I already tried that; it doesn't help at all. The merge tool is 
> invoked with the wrong ancestor.

Indeed. You are absolutely right.

As far as I can see a root of the problem is that because of 
content-hash-indexing then any combination of file content and parents 
will only be stored once in the fileindex. When the same file content 
accidentially occurs twice with the same parents then 
revlog._addrevision will find node in nodemap and reuse it. But the 
reused revlog will have the wrong "link", causing linkrev to return the 
first node which in this case is wrong and causes the wrong(?) base to 
be used.

The existence of revlog.linkrev indicates that the revlog is assumed to 
be a bijective mapping between (content,p1,p2) and "link", but the reuse 
of nodes indicates that the reverse mapping can't be relied on?

The solutution to this issue seems to be to not use linkrev. Instead 
merge.mergestate could keep track of the parent revision in  instead of 
trying to look it up - perhaps something like below? It seems to work 
for me ...

And THEN we have a case where premerge saves/hurts us ;-)

/Mads


diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -56,7 +56,7 @@
     def mark(self, dfile, state):
         self._state[dfile][0] = state
         self._write()
-    def resolve(self, dfile, wctx, octx):
+    def resolve(self, dfile, wctx, octx, actx):
         if self[dfile] == 'r':
             return 0
         state, hash, lfile, afile, anode, ofile, flags = self._state[dfile]
@@ -64,7 +64,7 @@
         self._repo.wwrite(dfile, f.read(), flags)
         fcd = wctx[dfile]
         fco = octx[ofile]
-        fca = self._repo.filectx(afile, fileid=anode)
+        fca = actx[afile]
         r = filemerge.filemerge(self._repo, self._local, lfile, fcd, 
fco, fca)
         if not r:
             self.mark(dfile, 'r')
@@ -269,7 +269,7 @@
         return 1
     return cmp(a1, a2)
 
-def applyupdates(repo, action, wctx, mctx):
+def applyupdates(repo, action, wctx, mctx, actx):
     "apply the merge action list to the working directory"
 
     updated, merged, removed, unresolved = 0, 0, 0, 0
@@ -286,7 +286,7 @@
             repo.ui.debug(_("preserving %s for resolve of %s\n") % (f, fd))
             fcl = wctx[f]
             fco = mctx[f2]
-            fca = fcl.ancestor(fco) or repo.filectx(f, fileid=nullrev)
+            fca = fcl.ancestor(fco) or repo.filectx(f, fileid=nullrev) 
# FIXME???
             ms.add(fcl, fco, fca, fd, flags)
             if f != fd and move:
                 moves.append(f)
@@ -315,7 +315,7 @@
             removed += 1
         elif m == "m": # merge
             f2, fd, flags, move = a[2:]
-            r = ms.resolve(fd, wctx, mctx)
+            r = ms.resolve(fd, wctx, mctx, actx)
             if r > 0:
                 unresolved += 1
             else:
@@ -485,7 +485,7 @@
         if not partial:
             repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
 
-        stats = applyupdates(repo, action, wc, p2)
+        stats = applyupdates(repo, action, wc, p2, pa)
 
         if not partial:
             recordupdates(repo, action, branchmerge)



More information about the Mercurial-devel mailing list