merge: introduce mergestate
authorMatt Mackall <mpm@selenic.com>
Thu, 10 Apr 2008 15:02:24 -0500
changeset 6512 368a4ec603cc
parent 6511 5c1bb5750558
child 6514 3d73b870b3ae
merge: introduce mergestate
mercurial/filemerge.py
mercurial/merge.py
tests/test-convert-hg-source.out
tests/test-copy-move-merge.out
tests/test-double-merge.out
tests/test-dumprevlog.out
tests/test-issue612.out
tests/test-issue672.out
tests/test-merge-commit.out
tests/test-merge-remove.out
tests/test-merge10.out
tests/test-merge7.out
tests/test-merge9.out
tests/test-rename-merge1.out
tests/test-rename-merge2.out
tests/test-up-local-change.out
--- a/mercurial/filemerge.py	Thu Apr 10 14:25:50 2008 +0200
+++ b/mercurial/filemerge.py	Thu Apr 10 15:02:24 2008 -0500
@@ -5,7 +5,7 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-from node import nullrev
+from node import nullrev, short
 from i18n import _
 import util, os, tempfile, simplemerge, re, filecmp
 
@@ -99,13 +99,14 @@
             if newdata != data:
                 open(file, "wb").write(newdata)
 
-def filemerge(repo, fw, fd, fo, wctx, mctx):
+def filemerge(repo, mynode, orig, fcd, fco, fca):
     """perform a 3-way merge in the working directory
 
-    fw = original filename in the working directory
-    fd = destination filename in the working directory
-    fo = filename in other parent
-    wctx, mctx = working and merge changecontexts
+    mynode = parent node before merge
+    orig = original local filename before merge
+    fco = other file context
+    fca = ancestor file context
+    fcd = local file context for current/destination file
     """
 
     def temp(prefix, ctx):
@@ -123,23 +124,21 @@
         except IOError:
             return False
 
-    fco = mctx.filectx(fo)
-    if not fco.cmp(wctx.filectx(fd).data()): # files identical?
+    if not fco.cmp(fcd.data()): # files identical?
         return None
 
     ui = repo.ui
-    fcm = wctx.filectx(fw)
-    fca = fcm.ancestor(fco) or repo.filectx(fw, fileid=nullrev)
-    binary = isbin(fcm) or isbin(fco) or isbin(fca)
-    symlink = fcm.islink() or fco.islink()
-    tool, toolpath = _picktool(repo, ui, fw, binary, symlink)
+    fd = fcd.path()
+    binary = isbin(fcd) or isbin(fco) or isbin(fca)
+    symlink = fcd.islink() or fco.islink()
+    tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
     ui.debug(_("picked tool '%s' for %s (binary %s symlink %s)\n") %
-               (tool, fw, binary, symlink))
+               (tool, fd, binary, symlink))
 
     if not tool:
         tool = "internal:local"
         if ui.prompt(_(" no tool found to merge %s\n"
-                       "keep (l)ocal or take (o)ther?") % fw,
+                       "keep (l)ocal or take (o)ther?") % fd,
                      _("[lo]"), _("l")) != _("l"):
             tool = "internal:other"
     if tool == "internal:local":
@@ -158,11 +157,12 @@
     back = a + ".orig"
     util.copyfile(a, back)
 
-    if fw != fo:
-        repo.ui.status(_("merging %s and %s\n") % (fw, fo))
+    if orig != fco.path():
+        repo.ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
     else:
-        repo.ui.status(_("merging %s\n") % fw)
-    repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca))
+        repo.ui.status(_("merging %s\n") % fd)
+
+    repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcd, fco, fca))
 
     # do we attempt to simplemerge first?
     if _toolbool(ui, tool, "premerge", not (binary or symlink)):
@@ -176,9 +176,9 @@
         util.copyfile(back, a) # restore from backup and try again
 
     env = dict(HG_FILE=fd,
-               HG_MY_NODE=str(wctx.parents()[0]),
-               HG_OTHER_NODE=str(mctx),
-               HG_MY_ISLINK=fcm.islink(),
+               HG_MY_NODE=short(mynode),
+               HG_OTHER_NODE=str(fco.changectx()),
+               HG_MY_ISLINK=fcd.islink(),
                HG_OTHER_ISLINK=fco.islink(),
                HG_BASE_ISLINK=fca.islink())
 
@@ -194,7 +194,7 @@
         r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env)
 
     if not r and _toolbool(ui, tool, "checkconflicts"):
-        if re.match("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcm.data()):
+        if re.match("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data()):
             r = 1
 
     if not r and _toolbool(ui, tool, "checkchanged"):
--- a/mercurial/merge.py	Thu Apr 10 14:25:50 2008 +0200
+++ b/mercurial/merge.py	Thu Apr 10 15:02:24 2008 -0500
@@ -5,9 +5,45 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-from node import nullid, nullrev
+from node import nullid, nullrev, hex
 from i18n import _
-import errno, util, os, filemerge, copies
+import errno, util, os, filemerge, copies, sha, shutil
+
+class mergestate(object):
+    '''track 3-way merge state of individual files'''
+    def __init__(self, repo):
+        self._repo = repo
+        self._state = {}
+        self._data = {}
+    def reset(self, node):
+        self._local = node
+        shutil.rmtree(self._repo.join("merge"), True)
+    def add(self, fcl, fco, fca, fd, flags):
+        hash = sha.sha(fcl.path()).hexdigest()
+        self._repo.opener("merge/" + hash, "w").write(fcl.data())
+        self._state[fd] = 'u'
+        self._data[fd] = (hash, fcl.path(), fca.path(), hex(fca.filenode()),
+                          fco.path(), flags)
+    def __contains__(self, dfile):
+        return dfile in self._state
+    def __getitem__(self, dfile):
+        return self._state[dfile]
+    def mark(self, dfile, state):
+        self._state[dfile] = state
+    def resolve(self, dfile, wctx, octx):
+        if self[dfile] == 'r':
+            return 0
+        hash, lfile, afile, anode, ofile, flags = self._data[dfile]
+        f = self._repo.opener("merge/" + hash)
+        self._repo.wwrite(dfile, f.read(), flags)
+        fcd = wctx[dfile]
+        fco = octx[ofile]
+        fca = self._repo.filectx(afile, fileid=anode)
+        r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca)
+        if not r:
+            util.set_flags(self._repo.wjoin(dfile), flags)
+            self.mark(dfile, 'r')
+        return r
 
 def _checkunknown(wctx, mctx):
     "check for collisions between unknown files and files in mctx"
@@ -202,14 +238,29 @@
 
     updated, merged, removed, unresolved = 0, 0, 0, 0
     action.sort()
-    # prescan for copy/renames
+
+    ms = mergestate(repo)
+    ms.reset(wctx.parents()[0].node())
+    moves = []
+
+    # prescan for merges
     for a in action:
         f, m = a[:2]
         if m == 'm': # merge
             f2, fd, flags, move = a[2:]
-            if f != fd:
-                repo.ui.debug(_("copying %s to %s\n") % (f, fd))
-                repo.wwrite(fd, repo.wread(f), flags)
+            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)
+            ms.add(fcl, fco, fca, fd, flags)
+            if f != fd and move:
+                moves.append(f)
+
+    # remove renamed files after safely stored
+    for f in moves:
+        if util.lexists(repo.wjoin(f)):
+            repo.ui.debug(_("removing %s\n") % f)
+            os.unlink(repo.wjoin(f))
 
     audit_path = util.path_auditor(repo.root)
 
@@ -229,7 +280,7 @@
             removed += 1
         elif m == "m": # merge
             f2, fd, flags, move = a[2:]
-            r = filemerge.filemerge(repo, f, fd, f2, wctx, mctx)
+            r = ms.resolve(fd, wctx, mctx)
             if r > 0:
                 unresolved += 1
             else:
@@ -237,10 +288,6 @@
                     updated += 1
                 else:
                     merged += 1
-            util.set_flags(repo.wjoin(fd), flags)
-            if f != fd and move and util.lexists(repo.wjoin(f)):
-                repo.ui.debug(_("removing %s\n") % f)
-                os.unlink(repo.wjoin(f))
         elif m == "g": # get
             flags = a[2]
             repo.ui.note(_("getting %s\n") % f)
--- a/tests/test-convert-hg-source.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-convert-hg-source.out	Thu Apr 10 15:02:24 2008 -0500
@@ -1,9 +1,9 @@
 created new head
-merging baz and foo
+merging baz and foo to baz
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
-merging foo and baz
+merging foo and baz to baz
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 created new head
--- a/tests/test-copy-move-merge.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-copy-move-merge.out	Thu Apr 10 15:02:24 2008 -0500
@@ -12,16 +12,16 @@
   checking for directory renames
  a: remote moved to c -> m
  a: remote moved to b -> m
-copying a to b
-copying a to c
-picked tool 'internal:merge' for a (binary False symlink False)
-merging a and b
-my a@fb3948d97f07+ other b@40da226db0f0 ancestor a@583c7b748052
+preserving a for resolve of b
+preserving a for resolve of c
+removing a
+picked tool 'internal:merge' for b (binary False symlink False)
+merging a and b to b
+my b@fb3948d97f07+ other b@40da226db0f0 ancestor a@583c7b748052
  premerge successful
-removing a
-picked tool 'internal:merge' for a (binary False symlink False)
-merging a and c
-my a@fb3948d97f07+ other c@40da226db0f0 ancestor a@583c7b748052
+picked tool 'internal:merge' for c (binary False symlink False)
+merging a and c to c
+my c@fb3948d97f07+ other c@40da226db0f0 ancestor a@583c7b748052
  premerge successful
 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
--- a/tests/test-double-merge.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-double-merge.out	Thu Apr 10 15:02:24 2008 -0500
@@ -10,10 +10,11 @@
   checking for directory renames
  foo: versions differ -> m
  foo: remote copied to bar -> m
-copying foo to bar
-picked tool 'internal:merge' for foo (binary False symlink False)
-merging foo and bar
-my foo@2092631ce82b+ other bar@7731dad1c2b9 ancestor foo@310fd17130da
+preserving foo for resolve of bar
+preserving foo for resolve of foo
+picked tool 'internal:merge' for bar (binary False symlink False)
+merging foo and bar to bar
+my bar@2092631ce82b+ other bar@7731dad1c2b9 ancestor foo@310fd17130da
  premerge successful
 picked tool 'internal:merge' for foo (binary False symlink False)
 merging foo
--- a/tests/test-dumprevlog.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-dumprevlog.out	Thu Apr 10 15:02:24 2008 -0500
@@ -34,9 +34,9 @@
 -end-
 dumprevlog done
 undumping:
-.hg/store/data/a.i
+.hg/store/00changelog.i
 .hg/store/00manifest.i
-.hg/store/00changelog.i
+.hg/store/data/a.i
 undumping done
 checking changesets
 checking manifests
--- a/tests/test-issue612.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-issue612.out	Thu Apr 10 15:02:24 2008 -0500
@@ -3,7 +3,7 @@
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 created new head
 ? src/a.o
-merging src/a.c and source/a.c
+merging src/a.c and source/a.c to source/a.c
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 M source/a.c
--- a/tests/test-issue672.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-issue672.out	Thu Apr 10 15:02:24 2008 -0500
@@ -30,8 +30,9 @@
    1a -> 1 *
   checking for directory renames
  1a: local moved to 1 -> m
+preserving 1a for resolve of 1a
 picked tool 'internal:merge' for 1a (binary False symlink False)
-merging 1a and 1
+merging 1a and 1 to 1a
 my 1a@ac7575e3c052+ other 1@746e9549ea96 ancestor 1@81f4b099af3d
  premerge successful
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
@@ -47,11 +48,11 @@
    1a -> 1 *
   checking for directory renames
  1: remote moved to 1a -> m
-copying 1 to 1a
-picked tool 'internal:merge' for 1 (binary False symlink False)
-merging 1 and 1a
-my 1@746e9549ea96+ other 1a@ac7575e3c052 ancestor 1@81f4b099af3d
+preserving 1 for resolve of 1a
+removing 1
+picked tool 'internal:merge' for 1a (binary False symlink False)
+merging 1 and 1a to 1a
+my 1a@746e9549ea96+ other 1a@ac7575e3c052 ancestor 1@81f4b099af3d
  premerge successful
-removing 1
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
--- a/tests/test-merge-commit.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-merge-commit.out	Thu Apr 10 15:02:24 2008 -0500
@@ -1,6 +1,6 @@
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 created new head
-merging bar and foo
+merging bar and foo to bar
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 % contents of bar should be line0 line1 line2
@@ -27,6 +27,7 @@
  ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 7d3b554bfdf1
   searching for copies back to rev 1
  bar: versions differ -> m
+preserving bar for resolve of bar
 picked tool 'internal:merge' for bar (binary False symlink False)
 merging bar
 my bar@2d2f9a22c82b+ other bar@7d3b554bfdf1 ancestor bar@0a3ab4856510
@@ -49,7 +50,7 @@
 adding file changes
 added 3 changesets with 3 changes to 2 files (+1 heads)
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-merging foo and bar
+merging foo and bar to bar
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 % contents of bar should be line0 line1 line2
@@ -76,6 +77,7 @@
  ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 96ab80c60897
   searching for copies back to rev 1
  bar: versions differ -> m
+preserving bar for resolve of bar
 picked tool 'internal:merge' for bar (binary False symlink False)
 merging bar
 my bar@2d2f9a22c82b+ other bar@96ab80c60897 ancestor bar@0a3ab4856510
--- a/tests/test-merge-remove.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-merge-remove.out	Thu Apr 10 15:02:24 2008 -0500
@@ -1,5 +1,5 @@
 created new head
-merging foo1 and foo
+merging foo1 and foo to foo1
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 n   0         -2 bar
--- a/tests/test-merge10.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-merge10.out	Thu Apr 10 15:02:24 2008 -0500
@@ -8,7 +8,7 @@
 added 1 changesets with 1 changes to 1 files (+1 heads)
 (run 'hg heads' to see heads, 'hg merge' to merge)
 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
-merging testdir/subdir/a and testdir/a
+merging testdir/subdir/a and testdir/a to testdir/subdir/a
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 M testdir/subdir/a
--- a/tests/test-merge7.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-merge7.out	Thu Apr 10 15:02:24 2008 -0500
@@ -26,6 +26,7 @@
  ancestor faaea63e63a9 local 451c744aabcc+ remote a070d41e8360
   searching for copies back to rev 1
  test.txt: versions differ -> m
+preserving test.txt for resolve of test.txt
 picked tool 'internal:merge' for test.txt (binary False symlink False)
 merging test.txt
 my test.txt@451c744aabcc+ other test.txt@a070d41e8360 ancestor test.txt@faaea63e63a9
--- a/tests/test-merge9.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-merge9.out	Thu Apr 10 15:02:24 2008 -0500
@@ -5,7 +5,7 @@
 created new head
 merging bar
 merging bar failed!
-merging foo and baz
+merging foo and baz to baz
 1 files updated, 1 files merged, 0 files removed, 1 files unresolved
 There are unresolved merges, you can redo the full merge using:
   hg update -C 2
@@ -13,7 +13,7 @@
 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
 merging bar
 merging bar failed!
-merging baz and foo
+merging baz and foo to baz
 1 files updated, 1 files merged, 0 files removed, 1 files unresolved
 There are unresolved merges, you can redo the full merge using:
   hg update -C 1
--- a/tests/test-rename-merge1.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-rename-merge1.out	Thu Apr 10 15:02:24 2008 -0500
@@ -19,12 +19,12 @@
  a2: divergent renames -> dr
  a: remote moved to b -> m
  b2: remote created -> g
-copying a to b
-picked tool 'internal:merge' for a (binary False symlink False)
-merging a and b
-my a@f26ec4fc3fa3+ other b@8e765a822af2 ancestor a@af1939970a1c
+preserving a for resolve of b
+removing a
+picked tool 'internal:merge' for b (binary False symlink False)
+merging a and b to b
+my b@f26ec4fc3fa3+ other b@8e765a822af2 ancestor a@af1939970a1c
  premerge successful
-removing a
 warning: detected divergent renames of a2 to:
  c2
  b2
--- a/tests/test-rename-merge2.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-rename-merge2.out	Thu Apr 10 15:02:24 2008 -0500
@@ -13,10 +13,11 @@
   checking for directory renames
  rev: versions differ -> m
  a: remote copied to b -> m
-copying a to b
-picked tool 'python ../merge' for a (binary False symlink False)
-merging a and b
-my a@e300d1c794ec+ other b@735846fee2d7 ancestor a@924404dff337
+preserving a for resolve of b
+preserving rev for resolve of rev
+picked tool 'python ../merge' for b (binary False symlink False)
+merging a and b to b
+my b@e300d1c794ec+ other b@735846fee2d7 ancestor a@924404dff337
  premerge successful
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
@@ -45,9 +46,11 @@
  a: remote is newer -> g
  b: local copied to a -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 getting a
 picked tool 'python ../merge' for b (binary False symlink False)
-merging b and a
+merging b and a to b
 my b@ac809aeed39a+ other a@f4db7e329e71 ancestor a@924404dff337
  premerge successful
 picked tool 'python ../merge' for rev (binary False symlink False)
@@ -76,12 +79,13 @@
   checking for directory renames
  rev: versions differ -> m
  a: remote moved to b -> m
-copying a to b
-picked tool 'python ../merge' for a (binary False symlink False)
-merging a and b
-my a@e300d1c794ec+ other b@e03727d2d66b ancestor a@924404dff337
+preserving a for resolve of b
+preserving rev for resolve of rev
+removing a
+picked tool 'python ../merge' for b (binary False symlink False)
+merging a and b to b
+my b@e300d1c794ec+ other b@e03727d2d66b ancestor a@924404dff337
  premerge successful
-removing a
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
 my rev@e300d1c794ec+ other rev@e03727d2d66b ancestor rev@924404dff337
@@ -107,8 +111,10 @@
   checking for directory renames
  b: local moved to a -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
-merging b and a
+merging b and a to b
 my b@ecf3cb2a4219+ other a@f4db7e329e71 ancestor a@924404dff337
  premerge successful
 picked tool 'python ../merge' for rev (binary False symlink False)
@@ -136,6 +142,7 @@
   checking for directory renames
  rev: versions differ -> m
  b: remote created -> g
+preserving rev for resolve of rev
 getting b
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
@@ -161,6 +168,7 @@
    b -> a 
   checking for directory renames
  rev: versions differ -> m
+preserving rev for resolve of rev
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
 my rev@ac809aeed39a+ other rev@97c705ade336 ancestor rev@924404dff337
@@ -187,6 +195,7 @@
  a: other deleted -> r
  rev: versions differ -> m
  b: remote created -> g
+preserving rev for resolve of rev
 removing a
 getting b
 picked tool 'python ../merge' for rev (binary False symlink False)
@@ -212,6 +221,7 @@
    b -> a 
   checking for directory renames
  rev: versions differ -> m
+preserving rev for resolve of rev
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
 my rev@ecf3cb2a4219+ other rev@97c705ade336 ancestor rev@924404dff337
@@ -231,6 +241,8 @@
   searching for copies back to rev 1
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
 my b@ec03c2ca8642+ other b@79cc6877a3b7 ancestor a@924404dff337
@@ -262,6 +274,7 @@
  a: divergent renames -> dr
  rev: versions differ -> m
  c: remote created -> g
+preserving rev for resolve of rev
 warning: detected divergent renames of a to:
  b
  c
@@ -286,6 +299,8 @@
   searching for copies back to rev 1
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
 my b@ac809aeed39a+ other b@af30c7647fc7 ancestor b@000000000000
@@ -310,6 +325,8 @@
  a: other deleted -> r
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 removing a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -334,6 +351,8 @@
  a: remote is newer -> g
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 getting a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -359,6 +378,8 @@
  a: other deleted -> r
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 removing a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -383,6 +404,8 @@
  a: remote is newer -> g
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 getting a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -407,6 +430,8 @@
   searching for copies back to rev 1
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
 my b@0b76e65c8289+ other b@735846fee2d7 ancestor b@000000000000
@@ -431,6 +456,8 @@
  b: versions differ -> m
  rev: versions differ -> m
  a: prompt recreating -> g
+preserving b for resolve of b
+preserving rev for resolve of rev
 getting a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -455,6 +482,8 @@
   searching for copies back to rev 1
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
 my b@0b76e65c8289+ other b@e03727d2d66b ancestor b@000000000000
@@ -483,11 +512,12 @@
   checking for directory renames
  rev: versions differ -> m
  a: remote moved to b -> m
-copying a to b
-picked tool 'python ../merge' for a (binary False symlink False)
-merging a and b
-my a@e300d1c794ec+ other b@79cc6877a3b7 ancestor a@924404dff337
+preserving a for resolve of b
+preserving rev for resolve of rev
 removing a
+picked tool 'python ../merge' for b (binary False symlink False)
+merging a and b to b
+my b@e300d1c794ec+ other b@79cc6877a3b7 ancestor a@924404dff337
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
 my rev@e300d1c794ec+ other rev@79cc6877a3b7 ancestor rev@924404dff337
@@ -513,8 +543,10 @@
   checking for directory renames
  b: local moved to a -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
-merging b and a
+merging b and a to b
 my b@ec03c2ca8642+ other a@f4db7e329e71 ancestor a@924404dff337
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
@@ -544,8 +576,10 @@
  b: local moved to a -> m
  rev: versions differ -> m
  c: remote created -> g
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
-merging b and a
+merging b and a to b
 my b@ecf3cb2a4219+ other a@2b958612230f ancestor a@924404dff337
  premerge successful
 getting c
--- a/tests/test-up-local-change.out	Thu Apr 10 14:25:50 2008 +0200
+++ b/tests/test-up-local-change.out	Thu Apr 10 15:02:24 2008 -0500
@@ -23,6 +23,7 @@
    b
  a: versions differ -> m
  b: remote created -> g
+preserving a for resolve of a
 picked tool 'true' for a (binary False symlink False)
 merging a
 my a@33aaa84a386b+ other a@802f095af299 ancestor a@33aaa84a386b
@@ -60,6 +61,7 @@
    b
  a: versions differ -> m
  b: remote created -> g
+preserving a for resolve of a
 picked tool 'true' for a (binary False symlink False)
 merging a
 my a@33aaa84a386b+ other a@802f095af299 ancestor a@33aaa84a386b
@@ -113,6 +115,8 @@
   searching for copies back to rev 1
  a: versions differ -> m
  b: versions differ -> m
+preserving a for resolve of a
+preserving b for resolve of b
 picked tool 'true' for a (binary False symlink False)
 merging a
 my a@802f095af299+ other a@030602aee63d ancestor a@33aaa84a386b