Patchwork [rfc] merge: use separate lists for each action type

login
register
mail settings
Submitter Mads Kiilerich
Date Feb. 28, 2014, 12:53 a.m.
Message ID <7eb6a98f39554adb8cee.1393548826@mk-desktop>
Download mbox | patch
Permalink /patch/3801/
State Superseded
Commit 43eecb4e23f879f880dce8518a7afe3c868a9655
Headers show

Comments

Mads Kiilerich - Feb. 28, 2014, 12:53 a.m.
# HG changeset patch
# User Mads Kiilerich <madski@unity3d.com>
# Date 1393548524 -3600
#      Fri Feb 28 01:48:44 2014 +0100
# Node ID 7eb6a98f39554adb8ceecb64a26b38474a96a9f2
# Parent  433f05f1df32932ee94595c6b70b7125a26c7768
merge: use separate lists for each action type

This replaces the grand unified action list that had multiple action types as
tuples in one big list. That list was iterated multiple times just to find
actions of a specific type. This data model also made some code more
convoluted than necessary.

Instead we now store actions as a tuple of lists. Using multiple lists gives a
bit of cut'n'pasted code but also enables other optimizations.

This patch uses 'if True:' to preserve indentations and help reviewing. It also
limits the number of conflicts with other pending patches. It can trivially be
cleaned up later.

The changes to test output are due to changes in the ordering of debug output.
That is mainly because we now do the debug logging for files when we actually
process them. Files are also processed in a slightly different but still
correct order. It is now primarily ordered by action type, secondarily by
filename.
Matt Mackall - March 1, 2014, 12:01 a.m.
On Fri, 2014-02-28 at 01:53 +0100, Mads Kiilerich wrote:
> # HG changeset patch
> # User Mads Kiilerich <madski@unity3d.com>
> # Date 1393548524 -3600
> #      Fri Feb 28 01:48:44 2014 +0100
> # Node ID 7eb6a98f39554adb8ceecb64a26b38474a96a9f2
> # Parent  433f05f1df32932ee94595c6b70b7125a26c7768
> merge: use separate lists for each action type

I think I'd prefer going to a dict of lists, using the existing letter
scheme. I expect we'll be adding new types here, so the tuple usage will
be annoying to maintain.

Patch

diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py
+++ b/hgext/largefiles/overrides.py
@@ -374,14 +374,13 @@  def overridemanifestmerge(origfn, repo, 
     if overwrite:
         return actions
 
-    removes = set(a[0] for a in actions if a[1] == 'r')
-    processed = []
+    alist, dlist, drlist, elist, flist, glist, mlist, rlist, rdlist = actions
+    removes = set(a[0] for a in rlist)
 
-    for action in actions:
-        f, m, args, msg = action
-
+    newglist = []
+    for f, args, msg in glist:
         splitstandin = f and lfutil.splitstandin(f)
-        if (m == "g" and splitstandin is not None and
+        if (splitstandin is not None and
             splitstandin in p1 and splitstandin not in removes):
             # Case 1: normal file in the working copy, largefile in
             # the second parent
@@ -391,12 +390,11 @@  def overridemanifestmerge(origfn, repo, 
                     'use (l)argefile or keep (n)ormal file?'
                     '$$ &Largefile $$ &Normal file') % lfile
             if repo.ui.promptchoice(msg, 0) == 0:
-                processed.append((lfile, "r", None, msg))
-                processed.append((standin, "g", (p2.flags(standin),), msg))
+                rlist.append((lfile, None, msg))
+                newglist.append((standin, (p2.flags(standin),), msg))
             else:
-                processed.append((standin, "r", None, msg))
-        elif (m == "g" and
-            lfutil.standin(f) in p1 and lfutil.standin(f) not in removes):
+                rlist.append((standin, None, msg))
+        elif lfutil.standin(f) in p1 and lfutil.standin(f) not in removes:
             # Case 2: largefile in the working copy, normal file in
             # the second parent
             standin = lfutil.standin(f)
@@ -405,14 +403,15 @@  def overridemanifestmerge(origfn, repo, 
                     'keep (l)argefile or use (n)ormal file?'
                     '$$ &Largefile $$ &Normal file') % lfile
             if repo.ui.promptchoice(msg, 0) == 0:
-                processed.append((lfile, "r", None, msg))
+                rlist.append((lfile, None, msg))
             else:
-                processed.append((standin, "r", None, msg))
-                processed.append((lfile, "g", (p2.flags(lfile),), msg))
+                rlist.append((standin, None, msg))
+                newglist.append((lfile, (p2.flags(lfile),), msg))
         else:
-            processed.append(action)
+            newglist.append((f, args, msg))
+    glist[:] = newglist
 
-    return processed
+    return actions
 
 # Override filemerge to prompt the user about how they wish to merge
 # largefiles. This will handle identical edits without prompting the user.
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -128,58 +128,49 @@  def _forgetremoved(wctx, mctx, branchmer
     as removed.
     """
 
-    actions = []
-    state = branchmerge and 'r' or 'f'
+    rlist, flist = [], []
+    l = flist
+    if branchmerge:
+        l = rlist
     for f in wctx.deleted():
         if f not in mctx:
-            actions.append((f, state, None, "forget deleted"))
+            l.append((f, None, "forget deleted"))
 
     if not branchmerge:
         for f in wctx.removed():
             if f not in mctx:
-                actions.append((f, "f", None, "forget removed"))
+                flist.append((f, None, "forget removed"))
 
-    return actions
+    return rlist, flist
 
 def _checkcollision(repo, wmf, actions, prompts):
     # build provisional merged manifest up
     pmmf = set(wmf)
 
-    def addop(f, args):
+    alist, dlist, drlist, elist, flist, glist, mlist, rlist, rdlist = actions
+    # dr, e and rd are nop
+
+    for f, args, msg in alist:
         pmmf.add(f)
-    def removeop(f, args):
+    for f, args, msg in flist:
+        pmmf.add(f) # untracked file should be kept in working directory
+    for f, args, msg in glist:
+        pmmf.add(f)
+    for f, args, msg in rlist:
         pmmf.discard(f)
-    def nop(f, args):
-        pass
 
-    def renameop(f, args):
+    for f, args, msg in dlist:
         f2, fd, flags = args
         if f:
             pmmf.discard(f)
         pmmf.add(fd)
-    def mergeop(f, args):
+    for f, args, msg in mlist:
         f2, fa, fd, move = args
         if move:
             pmmf.discard(f)
         pmmf.add(fd)
 
     opmap = {
-        "a": addop,
-        "d": renameop,
-        "dr": nop,
-        "e": nop,
-        "f": addop, # untracked file should be kept in working directory
-        "g": addop,
-        "m": mergeop,
-        "r": removeop,
-        "rd": nop,
-    }
-    for f, m, args, msg in actions:
-        op = opmap.get(m)
-        assert op, m
-        op(f, args)
-
-    opmap = {
         "cd": addop,
         "dc": addop,
     }
@@ -208,7 +199,9 @@  def manifestmerge(repo, wctx, p2, pa, br
     """
 
     overwrite = force and not branchmerge
-    actions, copy, movewithdir = [], {}, {}
+    actions = [], [], [], [], [], [], [], [], []
+    alist, dlist, drlist, elist, flist, glist, mlist, rlist, rdlist = actions
+    copy, movewithdir = {}, {}
 
     followcopies = False
     if overwrite:
@@ -228,9 +221,9 @@  def manifestmerge(repo, wctx, p2, pa, br
         ret = copies.mergecopies(repo, wctx, p2, pa)
         copy, movewithdir, diverge, renamedelete = ret
         for of, fl in diverge.iteritems():
-            actions.append((of, "dr", (fl,), "divergent renames"))
+            drlist.append((of, (fl,), "divergent renames"))
         for of, fl in renamedelete.iteritems():
-            actions.append((of, "rd", (fl,), "rename and delete"))
+            rdlist.append((of, (fl,), "rename and delete"))
 
     repo.ui.note(_("resolving manifests\n"))
     repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
@@ -285,43 +278,43 @@  def manifestmerge(repo, wctx, p2, pa, br
                 pass # remote unchanged - keep local
             elif n1 == a and fl1 == fla: # local unchanged - use remote
                 if n1 == n2: # optimization: keep local content
-                    actions.append((f, "e", (fl2,), "update permissions"))
+                    elist.append((f, (fl2,), "update permissions"))
                 else:
-                    actions.append((f, "g", (fl2,), "remote is newer"))
+                    glist.append((f, (fl2,), "remote is newer"))
             elif nol and n2 == a: # remote only changed 'x'
-                actions.append((f, "e", (fl2,), "update permissions"))
+                elist.append((f, (fl2,), "update permissions"))
             elif nol and n1 == a: # local only changed 'x'
-                actions.append((f, "g", (fl1,), "remote is newer"))
+                glist.append((f, (fl1,), "remote is newer"))
             else: # both changed something
-                actions.append((f, "m", (f, fa, f, False), "versions differ"))
+                mlist.append((f, (f, fa, f, False), "versions differ"))
         elif f in copied: # files we'll deal with on m2 side
             pass
         elif n1 and f in movewithdir: # directory rename
             f2 = movewithdir[f]
-            actions.append((f, "d", (None, f2, fl1),
+            dlist.append((f, (None, f2, fl1),
                             "remote renamed directory to " + f2))
         elif n1 and f in copy:
             f2 = copy[f]
-            actions.append((f, "m", (f2, f2, f, False),
+            mlist.append((f, (f2, f2, f, False),
                             "local copied/moved to " + f2))
         elif n1 and f in ma: # clean, a different, no remote
             if n1 != ma[f]:
                 prompts.append((f, "cd")) # prompt changed/deleted
             elif n1[20:] == "a": # added, no remote
-                actions.append((f, "f", None, "remote deleted"))
+                flist.append((f, None, "remote deleted"))
             else:
-                actions.append((f, "r", None, "other deleted"))
+                rlist.append((f, None, "other deleted"))
         elif n2 and f in movewithdir:
             f2 = movewithdir[f]
-            actions.append((None, "d", (f, f2, fl2),
+            dlist.append((None, (f, f2, fl2),
                             "local renamed directory to " + f2))
         elif n2 and f in copy:
             f2 = copy[f]
             if f2 in m2:
-                actions.append((f2, "m", (f, f2, f, False),
+                mlist.append((f2, (f, f2, f, False),
                                 "remote copied to " + f))
             else:
-                actions.append((f2, "m", (f, f2, f, True),
+                mlist.append((f2, (f, f2, f, True),
                                 "remote moved to " + f))
         elif n2 and f not in ma:
             # local unknown, remote created: the logic is described by the
@@ -337,16 +330,16 @@  def manifestmerge(repo, wctx, p2, pa, br
             # Checking whether the files are different is expensive, so we
             # don't do that when we can avoid it.
             if force and not branchmerge:
-                actions.append((f, "g", (fl2,), "remote created"))
+                glist.append((f, (fl2,), "remote created"))
             else:
                 different = _checkunknownfile(repo, wctx, p2, f)
                 if force and branchmerge and different:
-                    actions.append((f, "m", (f, f, f, False), # f not in ma ...
+                    mlist.append((f, (f, f, f, False), # f not in ma ...
                                     "remote differs from untracked local"))
                 elif not force and different:
                     aborts.append((f, "ud"))
                 else:
-                    actions.append((f, "g", (fl2,), "remote created"))
+                    glist.append((f, (fl2,), "remote created"))
         elif n2 and n2 != ma[f]:
             different = _checkunknownfile(repo, wctx, p2, f)
             if not force and different:
@@ -374,29 +367,26 @@  def manifestmerge(repo, wctx, p2, pa, br
     for f, m in sorted(prompts):
         if m == "cd":
             if acceptremote:
-                actions.append((f, "r", None, "remote delete"))
+                rlist.append((f, None, "remote delete"))
             elif repo.ui.promptchoice(
                 _("local changed %s which remote deleted\n"
                   "use (c)hanged version or (d)elete?"
                   "$$ &Changed $$ &Delete") % f, 0):
-                actions.append((f, "r", None, "prompt delete"))
+                rlist.append((f, None, "prompt delete"))
             else:
-                actions.append((f, "a", None, "prompt keep"))
+                alist.append((f, None, "prompt keep"))
         elif m == "dc":
             if acceptremote:
-                actions.append((f, "g", (m2.flags(f),), "remote recreating"))
+                glist.append((f, (m2.flags(f),), "remote recreating"))
             elif repo.ui.promptchoice(
                 _("remote changed %s which local deleted\n"
                   "use (c)hanged version or leave (d)eleted?"
                   "$$ &Changed $$ &Deleted") % f, 0) == 0:
-                actions.append((f, "g", (m2.flags(f),), "prompt recreating"))
+                glist.append((f, (m2.flags(f),), "prompt recreating"))
         else: assert False, m
     return actions
 
-def actionkey(a):
-    return a[1] in "rf" and -1 or 0, a
-
-def getremove(repo, mctx, overwrite, args):
+def batchremove(repo, mctx, overwrite, args):
     """apply usually-non-interactive updates to the working directory
 
     mctx is the context to be merged into the working copy
@@ -406,13 +396,11 @@  def getremove(repo, mctx, overwrite, arg
     verbose = repo.ui.verbose
     unlink = util.unlinkpath
     wjoin = repo.wjoin
-    fctx = mctx.filectx
-    wwrite = repo.wwrite
     audit = repo.wopener.audit
     i = 0
     for arg in args:
         f = arg[0]
-        if arg[1] == 'r':
+        if True:
             if verbose:
                 repo.ui.note(_("removing %s\n") % f)
             audit(f)
@@ -421,10 +409,30 @@  def getremove(repo, mctx, overwrite, arg
             except OSError, inst:
                 repo.ui.warn(_("update failed to remove %s: %s!\n") %
                              (f, inst.strerror))
-        else:
+        if i == 100:
+            yield i, f
+            i = 0
+        i += 1
+    if i > 0:
+        yield i, f
+
+def batchget(repo, mctx, overwrite, args):
+    """apply usually-non-interactive updates to the working directory
+
+    mctx is the context to be merged into the working copy
+
+    yields tuples for progress updates
+    """
+    verbose = repo.ui.verbose
+    fctx = mctx.filectx
+    wwrite = repo.wwrite
+    i = 0
+    for arg in args:
+        f = arg[0]
+        if True:
             if verbose:
                 repo.ui.note(_("getting %s\n") % f)
-            wwrite(f, fctx(f).data(), arg[2][0])
+            wwrite(f, fctx(f).data(), arg[1][0])
         if i == 100:
             yield i, f
             i = 0
@@ -443,17 +451,20 @@  def applyupdates(repo, actions, wctx, mc
     describes how many files were affected by the update.
     """
 
-    updated, merged, removed, unresolved = 0, 0, 0, 0
+    updated, merged, removed, unresolved, numupdates, z = 0, 0, 0, 0, 0, 0
     ms = mergestate(repo)
     ms.reset(wctx.p1().node())
     moves = []
-    actions.sort(key=actionkey)
+
+    for l in actions:
+        l.sort()
+        numupdates += len(l)
+    alist, dlist, drlist, elist, flist, glist, mlist, rlist, rdlist = actions
 
     # prescan for merges
-    for a in actions:
-        f, m, args, msg = a
-        repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
-        if m == "m": # merge
+    for f, args, msg in mlist:
+        repo.ui.debug(" %s: %s -> m\n" % (f, msg))
+        if True:
             f2, fa, fd, move = args
             if fd == '.hgsubstate': # merged internally
                 continue
@@ -482,43 +493,39 @@  def applyupdates(repo, actions, wctx, mc
             audit(f)
             util.unlinkpath(repo.wjoin(f))
 
-    numupdates = len(actions)
-    workeractions = [a for a in actions if a[1] in 'gr']
-    updateactions = [a for a in workeractions if a[1] == 'g']
-    updated = len(updateactions)
-    removeactions = [a for a in workeractions if a[1] == 'r']
-    removed = len(removeactions)
-    actions = [a for a in actions if a[1] not in 'gr']
-
-    hgsub = [a[1] for a in workeractions if a[0] == '.hgsubstate']
-    if hgsub and hgsub[0] == 'r':
+    if util.any(a[0] == '.hgsubstate' for a in rlist):
         subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
 
-    z = 0
-    prog = worker.worker(repo.ui, 0.001, getremove, (repo, mctx, overwrite),
-                         removeactions)
-    for i, item in prog:
-        z += i
-        repo.ui.progress(_('updating'), z, item=item, total=numupdates,
-                         unit=_('files'))
-    prog = worker.worker(repo.ui, 0.001, getremove, (repo, mctx, overwrite),
-                         updateactions)
+    removed = len(rlist)
+    for f, args, msg in rlist: repo.ui.debug(" %s: %s -> r\n" % (f, msg))
+    prog = worker.worker(repo.ui, 0.001, batchremove, (repo, mctx, overwrite),
+                         rlist)
     for i, item in prog:
         z += i
         repo.ui.progress(_('updating'), z, item=item, total=numupdates,
                          unit=_('files'))
 
-    if hgsub and hgsub[0] == 'g':
+    updated = len(glist)
+    for f, args, msg in glist: repo.ui.debug(" %s: %s -> g\n" % (f, msg))
+    prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx, overwrite),
+                         glist)
+    for i, item in prog:
+        z += i
+        repo.ui.progress(_('updating'), z, item=item, total=numupdates,
+                         unit=_('files'))
+
+    if util.any(a[0] == '.hgsubstate' for a in glist):
         subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
 
     _updating = _('updating')
     _files = _('files')
     progress = repo.ui.progress
 
-    for i, a in enumerate(actions):
-        f, m, args, msg = a
-        progress(_updating, z + i + 1, item=f, total=numupdates, unit=_files)
-        if m == "m": # merge
+    if True:
+        # merge
+        for f, args, msg in mlist:
+            z += 1
+            progress(_updating, z, item=f, total=numupdates, unit=_files)
             f2, fa, fd, move = args
             if fd == '.hgsubstate': # subrepo states need updating
                 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
@@ -533,7 +540,12 @@  def applyupdates(repo, actions, wctx, mc
                     updated += 1
                 else:
                     merged += 1
-        elif m == "d": # directory rename
+
+        # directory rename
+        for f, args, msg in dlist:
+            repo.ui.debug(" %s: %s -> d\n" % (f, msg))
+            z += 1
+            progress(_updating, z, item=f, total=numupdates, unit=_files)
             f2, fd, flags = args
             if f:
                 repo.ui.note(_("moving %s to %s\n") % (f, fd))
@@ -544,23 +556,47 @@  def applyupdates(repo, actions, wctx, mc
                 repo.ui.note(_("getting %s to %s\n") % (f2, fd))
                 repo.wwrite(fd, mctx.filectx(f2).data(), flags)
             updated += 1
-        elif m == "dr": # divergent renames
+
+        # divergent renames
+        for f, args, msg in drlist:
+            repo.ui.debug(" %s: %s -> dr\n" % (f, msg))
+            z += 1
+            progress(_updating, z, item=f, total=numupdates, unit=_files)
             fl, = args
             repo.ui.warn(_("note: possible conflict - %s was renamed "
                            "multiple times to:\n") % f)
             for nf in fl:
                 repo.ui.warn(" %s\n" % nf)
-        elif m == "rd": # rename and delete
+
+        # rename and delete
+        for f, args, msg in rdlist:
+            repo.ui.debug(" %s: %s -> rd\n" % (f, msg))
+            z += 1
+            progress(_updating, z, item=f, total=numupdates, unit=_files)
             fl, = args
             repo.ui.warn(_("note: possible conflict - %s was deleted "
                            "and renamed to:\n") % f)
             for nf in fl:
                 repo.ui.warn(" %s\n" % nf)
-        elif m == "e": # exec
+
+        # exec
+        for f, args, msg in elist:
+            repo.ui.debug(" %s: %s -> e\n" % (f, msg))
+            z += 1
+            progress(_updating, z, item=f, total=numupdates, unit=_files)
             flags, = args
             audit(f)
             util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
             updated += 1
+
+        # forget (manifest only, fake it)
+        for f, args, msg in flist:
+            repo.ui.debug(" %s: %s -> f\n" % (f, msg))
+
+        # re-add (manifest only, fake it)
+        for f, args, msg in alist:
+            repo.ui.debug(" %s: %s -> a\n" % (f, msg))
+
     ms.commit()
     progress(_updating, None, total=numupdates, unit=_files)
 
@@ -569,38 +605,51 @@  def applyupdates(repo, actions, wctx, mc
 def calculateupdates(repo, tctx, mctx, ancestor, branchmerge, force, partial,
                      acceptremote=False):
     "Calculate the actions needed to merge mctx into tctx"
-    actions = []
-    actions += manifestmerge(repo, tctx, mctx,
+    actions = manifestmerge(repo, tctx, mctx,
                              ancestor,
                              branchmerge, force,
                              partial, acceptremote)
+    alist, dlist, drlist, elist, flist, glist, mlist, rlist, rdlist = actions
     if tctx.rev() is None:
-        actions += _forgetremoved(tctx, mctx, branchmerge)
+        newrlist, newflist = _forgetremoved(tctx, mctx, branchmerge)
+        rlist += newrlist
+        flist += newflist
     return actions
 
 def recordupdates(repo, actions, branchmerge):
     "record merge actions to the dirstate"
+    (alist, dlist, drlist, elist, flist, glist, mlist, rlist, rdlist) = actions
 
-    for a in actions:
-        f, m, args, msg = a
-        if m == "r": # remove
+    if True:
+        # forget (most come first)
+        for f, args, msg in flist:
+            repo.dirstate.drop(f)
+
+        # remove (most come first)
+        for f, args, msg in rlist:
             if branchmerge:
                 repo.dirstate.remove(f)
             else:
                 repo.dirstate.drop(f)
-        elif m == "a": # re-add
+
+        # re-add
+        for f, args, msg in alist:
             if not branchmerge:
                 repo.dirstate.add(f)
-        elif m == "f": # forget
-            repo.dirstate.drop(f)
-        elif m == "e": # exec change
+
+        # exec change
+        for f, args, msg in elist:
             repo.dirstate.normallookup(f)
-        elif m == "g": # get
+
+        # get
+        for f, args, msg in glist:
             if branchmerge:
                 repo.dirstate.otherparent(f)
             else:
                 repo.dirstate.normal(f)
-        elif m == "m": # merge
+
+        # merge
+        for f, args, msg in mlist:
             f2, fa, fd, move = args
             if branchmerge:
                 # We've done a branch merge, mark this file as merged
@@ -623,7 +672,9 @@  def recordupdates(repo, actions, branchm
                     repo.dirstate.normallookup(fd)
                 if move:
                     repo.dirstate.drop(f)
-        elif m == "d": # directory rename
+
+        # directory rename
+        for f, args, msg in dlist:
             f2, fd, flag = args
             if not f2 and f not in repo.dirstate:
                 # untracked file moved
diff --git a/tests/test-graft.t b/tests/test-graft.t
--- a/tests/test-graft.t
+++ b/tests/test-graft.t
@@ -159,9 +159,9 @@  Graft out of order, skipping a merge and
   resolving manifests
    branchmerge: True, force: True, partial: False
    ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
-   d: remote is newer -> g
    e: versions differ -> m
     preserving e for resolve of e
+   d: remote is newer -> g
   getting d
   updating: d 1/2 files (50.00%)
   updating: e 2/2 files (100.00%)
diff --git a/tests/test-issue672.t b/tests/test-issue672.t
--- a/tests/test-issue672.t
+++ b/tests/test-issue672.t
@@ -35,9 +35,9 @@  http://mercurial.selenic.com/bts/issue67
    branchmerge: True, force: False, partial: False
    ancestor: 81f4b099af3d, local: c64f439569a9+, remote: c12dcd37c90a
    1: other deleted -> r
-   1a: remote created -> g
   removing 1
   updating: 1 1/2 files (50.00%)
+   1a: remote created -> g
   getting 1a
   updating: 1a 2/2 files (100.00%)
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
diff --git a/tests/test-rebase-conflicts.t b/tests/test-rebase-conflicts.t
--- a/tests/test-rebase-conflicts.t
+++ b/tests/test-rebase-conflicts.t
@@ -219,9 +219,9 @@  Check that the right ancestors is used w
    branchmerge: False, force: True, partial: False
    ancestor: d79e2059b5c0+, local: d79e2059b5c0+, remote: 4bc80088dc6b
    f2.txt: other deleted -> r
-   f1.txt: remote created -> g
   removing f2.txt
   updating: f2.txt 1/2 files (50.00%)
+   f1.txt: remote created -> g
   getting f1.txt
   updating: f1.txt 2/2 files (100.00%)
    merge against 9:e31216eec445
@@ -254,9 +254,9 @@  Check that the right ancestors is used w
    branchmerge: False, force: False, partial: False
    ancestor: 2a7f09cac94c, local: 2a7f09cac94c+, remote: d79e2059b5c0
    f1.txt: other deleted -> r
-   f2.txt: remote created -> g
   removing f1.txt
   updating: f1.txt 1/2 files (50.00%)
+   f2.txt: remote created -> g
   getting f2.txt
   updating: f2.txt 2/2 files (100.00%)
   3 changesets found
diff --git a/tests/test-rename-dir-merge.t b/tests/test-rename-dir-merge.t
--- a/tests/test-rename-dir-merge.t
+++ b/tests/test-rename-dir-merge.t
@@ -41,15 +41,15 @@ 
    ancestor: f9b20c0d4c51, local: ce36d17b18fb+, remote: 397f8b00a740
    a/a: other deleted -> r
    a/b: other deleted -> r
-   a/c: remote renamed directory to b/c -> d
-   b/a: remote created -> g
-   b/b: remote created -> g
   removing a/a
   removing a/b
   updating: a/b 2/5 files (40.00%)
+   b/a: remote created -> g
+   b/b: remote created -> g
   getting b/a
   getting b/b
   updating: b/b 4/5 files (80.00%)
+   a/c: remote renamed directory to b/c -> d
   updating: a/c 5/5 files (100.00%)
   moving a/c to b/c (glob)
   3 files updated, 0 files merged, 2 files removed, 0 files unresolved
diff --git a/tests/test-rename-merge1.t b/tests/test-rename-merge1.t
--- a/tests/test-rename-merge1.t
+++ b/tests/test-rename-merge1.t
@@ -38,9 +38,8 @@ 
    ancestor: af1939970a1c, local: 044f8520aeeb+, remote: 85c198ef2f6c
    a: remote moved to b -> m
     preserving a for resolve of b
-   a2: divergent renames -> dr
+  removing a
    b2: remote created -> g
-  removing a
   getting b2
   updating: b2 1/3 files (33.33%)
   updating: a 2/3 files (66.67%)
@@ -48,6 +47,7 @@ 
   merging a and b to b
   my b@044f8520aeeb+ other b@85c198ef2f6c ancestor a@af1939970a1c
    premerge successful
+   a2: divergent renames -> dr
   updating: a2 3/3 files (100.00%)
   note: possible conflict - a2 was renamed multiple times to:
    c2
@@ -181,10 +181,10 @@  Check for issue3074
   resolving manifests
    branchmerge: True, force: False, partial: False
    ancestor: 19d7f95df299, local: 0084274f6b67+, remote: 5d32493049f0
-   file: rename and delete -> rd
    newfile: remote created -> g
   getting newfile
   updating: newfile 1/2 files (50.00%)
+   file: rename and delete -> rd
   updating: file 2/2 files (100.00%)
   note: possible conflict - file was deleted and renamed to:
    newfile
diff --git a/tests/test-rename-merge2.t b/tests/test-rename-merge2.t
--- a/tests/test-rename-merge2.t
+++ b/tests/test-rename-merge2.t
@@ -121,11 +121,11 @@  args:
   resolving manifests
    branchmerge: True, force: False, partial: False
    ancestor: 924404dff337, local: 86a2aa42fc76+, remote: f4db7e329e71
-   a: remote is newer -> g
    b: local copied/moved to a -> m
     preserving b for resolve of b
    rev: versions differ -> m
     preserving rev for resolve of rev
+   a: remote is newer -> g
   getting a
   updating: a 1/3 files (33.33%)
   updating: b 2/3 files (66.67%)
@@ -228,9 +228,9 @@  args:
   resolving manifests
    branchmerge: True, force: False, partial: False
    ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: 4ce40f5aca24
-   b: remote created -> g
    rev: versions differ -> m
     preserving rev for resolve of rev
+   b: remote created -> g
   getting b
   updating: b 1/2 files (50.00%)
   updating: rev 2/2 files (100.00%)
@@ -285,12 +285,12 @@  args:
   resolving manifests
    branchmerge: True, force: False, partial: False
    ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: bdb19105162a
-   a: other deleted -> r
-   b: remote created -> g
    rev: versions differ -> m
     preserving rev for resolve of rev
+   a: other deleted -> r
   removing a
   updating: a 1/3 files (33.33%)
+   b: remote created -> g
   getting b
   updating: b 2/3 files (66.67%)
   updating: rev 3/3 files (100.00%)
@@ -378,20 +378,20 @@  m "um a c" "um x c" "      " "10 do merg
   resolving manifests
    branchmerge: True, force: False, partial: False
    ancestor: 924404dff337, local: 02963e448370+, remote: fe905ef2c33e
-   a: divergent renames -> dr
-   c: remote created -> g
    rev: versions differ -> m
     preserving rev for resolve of rev
+   c: remote created -> g
   getting c
   updating: c 1/3 files (33.33%)
-  updating: a 2/3 files (66.67%)
+  updating: rev 2/3 files (66.67%)
+  picked tool 'python ../merge' for rev (binary False symlink False)
+  merging rev
+  my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
+   a: divergent renames -> dr
+  updating: a 3/3 files (100.00%)
   note: possible conflict - a was renamed multiple times to:
    b
    c
-  updating: rev 3/3 files (100.00%)
-  picked tool 'python ../merge' for rev (binary False symlink False)
-  merging rev
-  my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
   1 files updated, 1 files merged, 0 files removed, 0 files unresolved
   (branch merge, don't forget to commit)
   --------------
@@ -440,11 +440,11 @@  m "um a c" "um x c" "      " "10 do merg
   resolving manifests
    branchmerge: True, force: False, partial: False
    ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
-   a: other deleted -> r
    b: versions differ -> m
     preserving b for resolve of b
    rev: versions differ -> m
     preserving rev for resolve of rev
+   a: other deleted -> r
   removing a
   updating: a 1/3 files (33.33%)
   updating: b 2/3 files (66.67%)
@@ -472,11 +472,11 @@  m "um a c" "um x c" "      " "10 do merg
   resolving manifests
    branchmerge: True, force: False, partial: False
    ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
-   a: remote is newer -> g
    b: versions differ -> m
     preserving b for resolve of b
    rev: versions differ -> m
     preserving rev for resolve of rev
+   a: remote is newer -> g
   getting a
   updating: a 1/3 files (33.33%)
   updating: b 2/3 files (66.67%)
@@ -505,11 +505,11 @@  m "um a c" "um x c" "      " "10 do merg
   resolving manifests
    branchmerge: True, force: False, partial: False
    ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
-   a: other deleted -> r
    b: versions differ -> m
     preserving b for resolve of b
    rev: versions differ -> m
     preserving rev for resolve of rev
+   a: other deleted -> r
   removing a
   updating: a 1/3 files (33.33%)
   updating: b 2/3 files (66.67%)
@@ -537,11 +537,11 @@  m "um a c" "um x c" "      " "10 do merg
   resolving manifests
    branchmerge: True, force: False, partial: False
    ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
-   a: remote is newer -> g
    b: versions differ -> m
     preserving b for resolve of b
    rev: versions differ -> m
     preserving rev for resolve of rev
+   a: remote is newer -> g
   getting a
   updating: a 1/3 files (33.33%)
   updating: b 2/3 files (66.67%)
@@ -602,11 +602,11 @@  m "um a c" "um x c" "      " "10 do merg
    ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
   remote changed a which local deleted
   use (c)hanged version or leave (d)eleted? c
-   a: prompt recreating -> g
    b: versions differ -> m
     preserving b for resolve of b
    rev: versions differ -> m
     preserving rev for resolve of rev
+   a: prompt recreating -> g
   getting a
   updating: a 1/3 files (33.33%)
   updating: b 2/3 files (66.67%)
@@ -637,20 +637,19 @@  m "um a c" "um x c" "      " "10 do merg
    ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
   local changed a which remote deleted
   use (c)hanged version or (d)elete? c
-   a: prompt keep -> a
    b: versions differ -> m
     preserving b for resolve of b
    rev: versions differ -> m
     preserving rev for resolve of rev
-  updating: a 1/3 files (33.33%)
-  updating: b 2/3 files (66.67%)
+  updating: b 1/3 files (33.33%)
   picked tool 'python ../merge' for b (binary False symlink False)
   merging b
   my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
-  updating: rev 3/3 files (100.00%)
+  updating: rev 2/3 files (66.67%)
   picked tool 'python ../merge' for rev (binary False symlink False)
   merging rev
   my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
+   a: prompt keep -> a
   0 files updated, 2 files merged, 0 files removed, 0 files unresolved
   (branch merge, don't forget to commit)
   --------------
@@ -746,9 +745,9 @@  m "nm a b" "um x a" "      " "22 get a, 
    ancestor: 924404dff337, local: 02963e448370+, remote: 2b958612230f
    b: local copied/moved to a -> m
     preserving b for resolve of b
-   c: remote created -> g
    rev: versions differ -> m
     preserving rev for resolve of rev
+   c: remote created -> g
   getting c
   updating: c 1/3 files (33.33%)
   updating: b 2/3 files (66.67%)
@@ -854,8 +853,8 @@  8  f  (f)  f   f   "remote differs from 
     preserving 6/g for resolve of 6/g
    7/f: remote differs from untracked local -> m
     preserving 7/f for resolve of 7/f
+  removing 4/f
    8/f: prompt recreating -> g
-  removing 4/f
   getting 8/f
   $ hg mani
   0/f
diff --git a/tests/test-up-local-change.t b/tests/test-up-local-change.t
--- a/tests/test-up-local-change.t
+++ b/tests/test-up-local-change.t
@@ -67,9 +67,9 @@ 
   resolving manifests
    branchmerge: False, force: False, partial: False
    ancestor: 1e71731e6fbb, local: 1e71731e6fbb+, remote: c19d34741b0a
-   b: other deleted -> r
    a: versions differ -> m
     preserving a for resolve of a
+   b: other deleted -> r
   removing b
   updating: b 1/2 files (50.00%)
   updating: a 2/2 files (100.00%)
diff --git a/tests/test-update-reverse.t b/tests/test-update-reverse.t
--- a/tests/test-update-reverse.t
+++ b/tests/test-update-reverse.t
@@ -70,10 +70,10 @@ 
    ancestor: 91ebc10ed028+, local: 91ebc10ed028+, remote: 71a760306caf
    side1: other deleted -> r
    side2: other deleted -> r
-   main: remote created -> g
   removing side1
   removing side2
   updating: side2 2/3 files (66.67%)
+   main: remote created -> g
   getting main
   updating: main 3/3 files (100.00%)
   1 files updated, 0 files merged, 2 files removed, 0 files unresolved