mercurial/merge.py
changeset 21545 43eecb4e23f8
parent 21524 47b97d9af27e
child 21551 bde505f47141
equal deleted inserted replaced
21541:6062593d8b06 21545:43eecb4e23f8
   329     If we're merging, and the other revision has removed a file
   329     If we're merging, and the other revision has removed a file
   330     that is not present in the working directory, we need to mark it
   330     that is not present in the working directory, we need to mark it
   331     as removed.
   331     as removed.
   332     """
   332     """
   333 
   333 
   334     actions = []
   334     ractions = []
   335     state = branchmerge and 'r' or 'f'
   335     factions = xactions = []
       
   336     if branchmerge:
       
   337         xactions = ractions
   336     for f in wctx.deleted():
   338     for f in wctx.deleted():
   337         if f not in mctx:
   339         if f not in mctx:
   338             actions.append((f, state, None, "forget deleted"))
   340             xactions.append((f, None, "forget deleted"))
   339 
   341 
   340     if not branchmerge:
   342     if not branchmerge:
   341         for f in wctx.removed():
   343         for f in wctx.removed():
   342             if f not in mctx:
   344             if f not in mctx:
   343                 actions.append((f, "f", None, "forget removed"))
   345                 factions.append((f, None, "forget removed"))
   344 
   346 
   345     return actions
   347     return ractions, factions
   346 
   348 
   347 def _checkcollision(repo, wmf, actions):
   349 def _checkcollision(repo, wmf, actions):
   348     # build provisional merged manifest up
   350     # build provisional merged manifest up
   349     pmmf = set(wmf)
   351     pmmf = set(wmf)
   350 
   352 
   351     def addop(f, args):
   353     if actions:
   352         pmmf.add(f)
   354         # k, dr, e and rd are no-op
   353     def removeop(f, args):
   355         for m in 'a', 'f', 'g', 'cd', 'dc':
   354         pmmf.discard(f)
   356             for f, args, msg in actions[m]:
   355     def nop(f, args):
   357                 pmmf.add(f)
   356         pass
   358         for f, args, msg in actions['r']:
   357 
   359             pmmf.discard(f)
   358     def renamemoveop(f, args):
   360         for f, args, msg in actions['dm']:
   359         f2, flags = args
   361             f2, flags = args
   360         pmmf.discard(f2)
   362             pmmf.discard(f2)
   361         pmmf.add(f)
   363             pmmf.add(f)
   362     def renamegetop(f, args):
   364         for f, args, msg in actions['dg']:
   363         f2, flags = args
   365             f2, flags = args
   364         pmmf.add(f)
   366             pmmf.add(f)
   365     def mergeop(f, args):
   367         for f, args, msg in actions['m']:
   366         f1, f2, fa, move, anc = args
   368             f1, f2, fa, move, anc = args
   367         if move:
   369             if move:
   368             pmmf.discard(f1)
   370                 pmmf.discard(f1)
   369         pmmf.add(f)
   371             pmmf.add(f)
   370 
       
   371     opmap = {
       
   372         "a": addop,
       
   373         "dm": renamemoveop,
       
   374         "dg": renamegetop,
       
   375         "dr": nop,
       
   376         "e": nop,
       
   377         "k": nop,
       
   378         "f": addop, # untracked file should be kept in working directory
       
   379         "g": addop,
       
   380         "m": mergeop,
       
   381         "r": removeop,
       
   382         "rd": nop,
       
   383         "cd": addop,
       
   384         "dc": addop,
       
   385     }
       
   386     for f, m, args, msg in actions:
       
   387         op = opmap.get(m)
       
   388         assert op, m
       
   389         op(f, args)
       
   390 
   372 
   391     # check case-folding collision in provisional merged manifest
   373     # check case-folding collision in provisional merged manifest
   392     foldmap = {}
   374     foldmap = {}
   393     for f in sorted(pmmf):
   375     for f in sorted(pmmf):
   394         fold = util.normcase(f)
   376         fold = util.normcase(f)
   405     branchmerge and force are as passed in to update
   387     branchmerge and force are as passed in to update
   406     partial = function to filter file lists
   388     partial = function to filter file lists
   407     acceptremote = accept the incoming changes without prompting
   389     acceptremote = accept the incoming changes without prompting
   408     """
   390     """
   409 
   391 
   410     actions, copy, movewithdir = [], {}, {}
   392     actions = dict((m, []) for m in 'a f g cd dc r dm dg m dr e rd k'.split())
       
   393     copy, movewithdir = {}, {}
   411 
   394 
   412     # manifests fetched in order are going to be faster, so prime the caches
   395     # manifests fetched in order are going to be faster, so prime the caches
   413     [x.manifest() for x in
   396     [x.manifest() for x in
   414      sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
   397      sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
   415 
   398 
   416     if followcopies:
   399     if followcopies:
   417         ret = copies.mergecopies(repo, wctx, p2, pa)
   400         ret = copies.mergecopies(repo, wctx, p2, pa)
   418         copy, movewithdir, diverge, renamedelete = ret
   401         copy, movewithdir, diverge, renamedelete = ret
   419         for of, fl in diverge.iteritems():
   402         for of, fl in diverge.iteritems():
   420             actions.append((of, "dr", (fl,), "divergent renames"))
   403             actions['dr'].append((of, (fl,), "divergent renames"))
   421         for of, fl in renamedelete.iteritems():
   404         for of, fl in renamedelete.iteritems():
   422             actions.append((of, "rd", (fl,), "rename and delete"))
   405             actions['rd'].append((of, (fl,), "rename and delete"))
   423 
   406 
   424     repo.ui.note(_("resolving manifests\n"))
   407     repo.ui.note(_("resolving manifests\n"))
   425     repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
   408     repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
   426                   % (bool(branchmerge), bool(force), bool(partial)))
   409                   % (bool(branchmerge), bool(force), bool(partial)))
   427     repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
   410     repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
   469                 # Note: f as default is wrong - we can't really make a 3-way
   452                 # Note: f as default is wrong - we can't really make a 3-way
   470                 # merge without an ancestor file.
   453                 # merge without an ancestor file.
   471             fla = ma.flags(fa)
   454             fla = ma.flags(fa)
   472             nol = 'l' not in fl1 + fl2 + fla
   455             nol = 'l' not in fl1 + fl2 + fla
   473             if n2 == a and fl2 == fla:
   456             if n2 == a and fl2 == fla:
   474                 actions.append((f, "k", (), "keep")) # remote unchanged
   457                 actions['k'].append((f, (), "keep")) # remote unchanged
   475             elif n1 == a and fl1 == fla: # local unchanged - use remote
   458             elif n1 == a and fl1 == fla: # local unchanged - use remote
   476                 if n1 == n2: # optimization: keep local content
   459                 if n1 == n2: # optimization: keep local content
   477                     actions.append((f, "e", (fl2,), "update permissions"))
   460                     actions['e'].append((f, (fl2,), "update permissions"))
   478                 else:
   461                 else:
   479                     actions.append((f, "g", (fl2,), "remote is newer"))
   462                     actions['g'].append((f, (fl2,), "remote is newer"))
   480             elif nol and n2 == a: # remote only changed 'x'
   463             elif nol and n2 == a: # remote only changed 'x'
   481                 actions.append((f, "e", (fl2,), "update permissions"))
   464                 actions['e'].append((f, (fl2,), "update permissions"))
   482             elif nol and n1 == a: # local only changed 'x'
   465             elif nol and n1 == a: # local only changed 'x'
   483                 actions.append((f, "g", (fl1,), "remote is newer"))
   466                 actions['g'].append((f, (fl1,), "remote is newer"))
   484             else: # both changed something
   467             else: # both changed something
   485                 actions.append((f, "m", (f, f, fa, False, pa.node()),
   468                 actions['m'].append((f, (f, f, fa, False, pa.node()),
   486                                "versions differ"))
   469                                "versions differ"))
   487         elif f in copied: # files we'll deal with on m2 side
   470         elif f in copied: # files we'll deal with on m2 side
   488             pass
   471             pass
   489         elif n1 and f in movewithdir: # directory rename, move local
   472         elif n1 and f in movewithdir: # directory rename, move local
   490             f2 = movewithdir[f]
   473             f2 = movewithdir[f]
   491             actions.append((f2, "dm", (f, fl1),
   474             actions['dm'].append((f2, (f, fl1),
   492                             "remote directory rename - move from " + f))
   475                             "remote directory rename - move from " + f))
   493         elif n1 and f in copy:
   476         elif n1 and f in copy:
   494             f2 = copy[f]
   477             f2 = copy[f]
   495             actions.append((f, "m", (f, f2, f2, False, pa.node()),
   478             actions['m'].append((f, (f, f2, f2, False, pa.node()),
   496                             "local copied/moved from " + f2))
   479                             "local copied/moved from " + f2))
   497         elif n1 and f in ma: # clean, a different, no remote
   480         elif n1 and f in ma: # clean, a different, no remote
   498             if n1 != ma[f]:
   481             if n1 != ma[f]:
   499                 if acceptremote:
   482                 if acceptremote:
   500                     actions.append((f, "r", None, "remote delete"))
   483                     actions['r'].append((f, None, "remote delete"))
   501                 else:
   484                 else:
   502                     actions.append((f, "cd", None, "prompt changed/deleted"))
   485                     actions['cd'].append((f, None, "prompt changed/deleted"))
   503             elif n1[20:] == "a": # added, no remote
   486             elif n1[20:] == "a": # added, no remote
   504                 actions.append((f, "f", None, "remote deleted"))
   487                 actions['f'].append((f, None, "remote deleted"))
   505             else:
   488             else:
   506                 actions.append((f, "r", None, "other deleted"))
   489                 actions['r'].append((f, None, "other deleted"))
   507         elif n2 and f in movewithdir:
   490         elif n2 and f in movewithdir:
   508             f2 = movewithdir[f]
   491             f2 = movewithdir[f]
   509             actions.append((f2, "dg", (f, fl2),
   492             actions['dg'].append((f2, (f, fl2),
   510                             "local directory rename - get from " + f))
   493                             "local directory rename - get from " + f))
   511         elif n2 and f in copy:
   494         elif n2 and f in copy:
   512             f2 = copy[f]
   495             f2 = copy[f]
   513             if f2 in m2:
   496             if f2 in m2:
   514                 actions.append((f, "m", (f2, f, f2, False, pa.node()),
   497                 actions['m'].append((f, (f2, f, f2, False, pa.node()),
   515                                 "remote copied from " + f2))
   498                                 "remote copied from " + f2))
   516             else:
   499             else:
   517                 actions.append((f, "m", (f2, f, f2, True, pa.node()),
   500                 actions['m'].append((f, (f2, f, f2, True, pa.node()),
   518                                 "remote moved from " + f2))
   501                                 "remote moved from " + f2))
   519         elif n2 and f not in ma:
   502         elif n2 and f not in ma:
   520             # local unknown, remote created: the logic is described by the
   503             # local unknown, remote created: the logic is described by the
   521             # following table:
   504             # following table:
   522             #
   505             #
   528             #   y         y           y      |   merge
   511             #   y         y           y      |   merge
   529             #
   512             #
   530             # Checking whether the files are different is expensive, so we
   513             # Checking whether the files are different is expensive, so we
   531             # don't do that when we can avoid it.
   514             # don't do that when we can avoid it.
   532             if force and not branchmerge:
   515             if force and not branchmerge:
   533                 actions.append((f, "g", (fl2,), "remote created"))
   516                 actions['g'].append((f, (fl2,), "remote created"))
   534             else:
   517             else:
   535                 different = _checkunknownfile(repo, wctx, p2, f)
   518                 different = _checkunknownfile(repo, wctx, p2, f)
   536                 if force and branchmerge and different:
   519                 if force and branchmerge and different:
   537                     # FIXME: This is wrong - f is not in ma ...
   520                     # FIXME: This is wrong - f is not in ma ...
   538                     actions.append((f, "m", (f, f, f, False, pa.node()),
   521                     actions['m'].append((f, (f, f, f, False, pa.node()),
   539                                     "remote differs from untracked local"))
   522                                     "remote differs from untracked local"))
   540                 elif not force and different:
   523                 elif not force and different:
   541                     aborts.append((f, "ud"))
   524                     aborts.append((f, "ud"))
   542                 else:
   525                 else:
   543                     actions.append((f, "g", (fl2,), "remote created"))
   526                     actions['g'].append((f, (fl2,), "remote created"))
   544         elif n2 and n2 != ma[f]:
   527         elif n2 and n2 != ma[f]:
   545             different = _checkunknownfile(repo, wctx, p2, f)
   528             different = _checkunknownfile(repo, wctx, p2, f)
   546             if not force and different:
   529             if not force and different:
   547                 aborts.append((f, "ud"))
   530                 aborts.append((f, "ud"))
   548             else:
   531             else:
   549                 # if different: old untracked f may be overwritten and lost
   532                 # if different: old untracked f may be overwritten and lost
   550                 if acceptremote:
   533                 if acceptremote:
   551                     actions.append((f, "g", (m2.flags(f),),
   534                     actions['g'].append((f, (m2.flags(f),),
   552                                    "remote recreating"))
   535                                    "remote recreating"))
   553                 else:
   536                 else:
   554                     actions.append((f, "dc", (m2.flags(f),),
   537                     actions['dc'].append((f, (m2.flags(f),),
   555                                    "prompt deleted/changed"))
   538                                    "prompt deleted/changed"))
   556 
   539 
   557     for f, m in sorted(aborts):
   540     for f, m in sorted(aborts):
   558         if m == "ud":
   541         if m == "ud":
   559             repo.ui.warn(_("%s: untracked file differs\n") % f)
   542             repo.ui.warn(_("%s: untracked file differs\n") % f)
   564 
   547 
   565     if not util.checkcase(repo.path):
   548     if not util.checkcase(repo.path):
   566         # check collision between files only in p2 for clean update
   549         # check collision between files only in p2 for clean update
   567         if (not branchmerge and
   550         if (not branchmerge and
   568             (force or not wctx.dirty(missing=True, branch=False))):
   551             (force or not wctx.dirty(missing=True, branch=False))):
   569             _checkcollision(repo, m2, [])
   552             _checkcollision(repo, m2, None)
   570         else:
   553         else:
   571             _checkcollision(repo, m1, actions)
   554             _checkcollision(repo, m1, actions)
   572 
   555 
   573     return actions
   556     return actions
   574 
       
   575 actionpriority = dict((m, p) for p, m in enumerate(
       
   576     ['r', 'f', 'g', 'a', 'k', 'm', 'dm', 'dg', 'dr', 'cd', 'dc', 'rd', 'e']))
       
   577 
       
   578 def actionkey(a):
       
   579     return actionpriority[a[1]], a
       
   580 
   557 
   581 def batchremove(repo, actions):
   558 def batchremove(repo, actions):
   582     """apply removes to the working directory
   559     """apply removes to the working directory
   583 
   560 
   584     yields tuples for progress updates
   561     yields tuples for progress updates
   586     verbose = repo.ui.verbose
   563     verbose = repo.ui.verbose
   587     unlink = util.unlinkpath
   564     unlink = util.unlinkpath
   588     wjoin = repo.wjoin
   565     wjoin = repo.wjoin
   589     audit = repo.wopener.audit
   566     audit = repo.wopener.audit
   590     i = 0
   567     i = 0
   591     for f, m, args, msg in actions:
   568     for f, args, msg in actions:
   592         repo.ui.debug(" %s: %s -> r\n" % (f, msg))
   569         repo.ui.debug(" %s: %s -> r\n" % (f, msg))
   593         if True:
   570         if True:
   594             if verbose:
   571             if verbose:
   595                 repo.ui.note(_("removing %s\n") % f)
   572                 repo.ui.note(_("removing %s\n") % f)
   596             audit(f)
   573             audit(f)
   615     """
   592     """
   616     verbose = repo.ui.verbose
   593     verbose = repo.ui.verbose
   617     fctx = mctx.filectx
   594     fctx = mctx.filectx
   618     wwrite = repo.wwrite
   595     wwrite = repo.wwrite
   619     i = 0
   596     i = 0
   620     for f, m, args, msg in actions:
   597     for f, args, msg in actions:
   621         repo.ui.debug(" %s: %s -> g\n" % (f, msg))
   598         repo.ui.debug(" %s: %s -> g\n" % (f, msg))
   622         if True:
   599         if True:
   623             if verbose:
   600             if verbose:
   624                 repo.ui.note(_("getting %s\n") % f)
   601                 repo.ui.note(_("getting %s\n") % f)
   625             wwrite(f, fctx(f).data(), args[0])
   602             wwrite(f, fctx(f).data(), args[0])
   642 
   619 
   643     updated, merged, removed, unresolved = 0, 0, 0, 0
   620     updated, merged, removed, unresolved = 0, 0, 0, 0
   644     ms = mergestate(repo)
   621     ms = mergestate(repo)
   645     ms.reset(wctx.p1().node(), mctx.node())
   622     ms.reset(wctx.p1().node(), mctx.node())
   646     moves = []
   623     moves = []
   647     actions.sort(key=actionkey)
   624     for m, l in actions.items():
       
   625         l.sort()
   648 
   626 
   649     # prescan for merges
   627     # prescan for merges
   650     for a in actions:
   628     for f, args, msg in actions['m']:
   651         f, m, args, msg = a
   629         if True:
   652         if m == "m": # merge
       
   653             f1, f2, fa, move, anc = args
   630             f1, f2, fa, move, anc = args
   654             if f == '.hgsubstate': # merged internally
   631             if f == '.hgsubstate': # merged internally
   655                 continue
   632                 continue
   656             repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
   633             repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
   657             fcl = wctx[f1]
   634             fcl = wctx[f1]
   675         if os.path.lexists(repo.wjoin(f)):
   652         if os.path.lexists(repo.wjoin(f)):
   676             repo.ui.debug("removing %s\n" % f)
   653             repo.ui.debug("removing %s\n" % f)
   677             audit(f)
   654             audit(f)
   678             util.unlinkpath(repo.wjoin(f))
   655             util.unlinkpath(repo.wjoin(f))
   679 
   656 
   680     numupdates = len([a for a in actions if a[1] != 'k'])
   657     numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
   681     workeractions = [a for a in actions if a[1] in 'gr']
   658 
   682     updateactions = [a for a in workeractions if a[1] == 'g']
   659     if [a for a in actions['r'] if a[0] == '.hgsubstate']:
   683     updated = len(updateactions)
       
   684     removeactions = [a for a in workeractions if a[1] == 'r']
       
   685     removed = len(removeactions)
       
   686     actions = [a for a in actions if a[1] not in 'gr']
       
   687 
       
   688     hgsub = [a[1] for a in workeractions if a[0] == '.hgsubstate']
       
   689     if hgsub and hgsub[0] == 'r':
       
   690         subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
   660         subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
   691 
   661 
   692     # remove in parallel (must come first)
   662     # remove in parallel (must come first)
   693     z = 0
   663     z = 0
   694     prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), removeactions)
   664     prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
   695     for i, item in prog:
   665     for i, item in prog:
   696         z += i
   666         z += i
   697         progress(_updating, z, item=item, total=numupdates, unit=_files)
   667         progress(_updating, z, item=item, total=numupdates, unit=_files)
       
   668     removed = len(actions['r'])
   698 
   669 
   699     # get in parallel
   670     # get in parallel
   700     prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), updateactions)
   671     prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
   701     for i, item in prog:
   672     for i, item in prog:
   702         z += i
   673         z += i
   703         progress(_updating, z, item=item, total=numupdates, unit=_files)
   674         progress(_updating, z, item=item, total=numupdates, unit=_files)
   704 
   675     updated = len(actions['g'])
   705     if hgsub and hgsub[0] == 'g':
   676 
       
   677     if [a for a in actions['g'] if a[0] == '.hgsubstate']:
   706         subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
   678         subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
   707 
   679 
   708     for f, m, args, msg in actions:
   680     if True:
   709 
   681 
   710         # forget (manifest only, just log it) (must come first)
   682         # forget (manifest only, just log it) (must come first)
   711         if m == "f":
   683         for f, args, msg in actions['f']:
   712             repo.ui.debug(" %s: %s -> f\n" % (f, msg))
   684             repo.ui.debug(" %s: %s -> f\n" % (f, msg))
   713             z += 1
   685             z += 1
   714             progress(_updating, z, item=f, total=numupdates, unit=_files)
   686             progress(_updating, z, item=f, total=numupdates, unit=_files)
   715 
   687 
   716         # re-add (manifest only, just log it)
   688         # re-add (manifest only, just log it)
   717         elif m == "a":
   689         for f, args, msg in actions['a']:
   718             repo.ui.debug(" %s: %s -> a\n" % (f, msg))
   690             repo.ui.debug(" %s: %s -> a\n" % (f, msg))
   719             z += 1
   691             z += 1
   720             progress(_updating, z, item=f, total=numupdates, unit=_files)
   692             progress(_updating, z, item=f, total=numupdates, unit=_files)
   721 
   693 
   722         # keep (noop, just log it)
   694         # keep (noop, just log it)
   723         elif m == "k":
   695         for f, args, msg in actions['k']:
   724             repo.ui.debug(" %s: %s -> k\n" % (f, msg))
   696             repo.ui.debug(" %s: %s -> k\n" % (f, msg))
   725             # no progress
   697             # no progress
   726 
   698 
   727         # merge
   699         # merge
   728         elif m == "m":
   700         for f, args, msg in actions['m']:
   729             repo.ui.debug(" %s: %s -> m\n" % (f, msg))
   701             repo.ui.debug(" %s: %s -> m\n" % (f, msg))
   730             z += 1
   702             z += 1
   731             progress(_updating, z, item=f, total=numupdates, unit=_files)
   703             progress(_updating, z, item=f, total=numupdates, unit=_files)
   732             f1, f2, fa, move, anc = args
   704             f1, f2, fa, move, anc = args
   733             if f == '.hgsubstate': # subrepo states need updating
   705             if f == '.hgsubstate': # subrepo states need updating
   743                     updated += 1
   715                     updated += 1
   744                 else:
   716                 else:
   745                     merged += 1
   717                     merged += 1
   746 
   718 
   747         # directory rename, move local
   719         # directory rename, move local
   748         elif m == "dm":
   720         for f, args, msg in actions['dm']:
   749             repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
   721             repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
   750             z += 1
   722             z += 1
   751             progress(_updating, z, item=f, total=numupdates, unit=_files)
   723             progress(_updating, z, item=f, total=numupdates, unit=_files)
   752             f0, flags = args
   724             f0, flags = args
   753             repo.ui.note(_("moving %s to %s\n") % (f0, f))
   725             repo.ui.note(_("moving %s to %s\n") % (f0, f))
   755             repo.wwrite(f, wctx.filectx(f0).data(), flags)
   727             repo.wwrite(f, wctx.filectx(f0).data(), flags)
   756             util.unlinkpath(repo.wjoin(f0))
   728             util.unlinkpath(repo.wjoin(f0))
   757             updated += 1
   729             updated += 1
   758 
   730 
   759         # local directory rename, get
   731         # local directory rename, get
   760         elif m == "dg":
   732         for f, args, msg in actions['dg']:
   761             repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
   733             repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
   762             z += 1
   734             z += 1
   763             progress(_updating, z, item=f, total=numupdates, unit=_files)
   735             progress(_updating, z, item=f, total=numupdates, unit=_files)
   764             f0, flags = args
   736             f0, flags = args
   765             repo.ui.note(_("getting %s to %s\n") % (f0, f))
   737             repo.ui.note(_("getting %s to %s\n") % (f0, f))
   766             repo.wwrite(f, mctx.filectx(f0).data(), flags)
   738             repo.wwrite(f, mctx.filectx(f0).data(), flags)
   767             updated += 1
   739             updated += 1
   768 
   740 
   769         # divergent renames
   741         # divergent renames
   770         elif m == "dr":
   742         for f, args, msg in actions['dr']:
   771             repo.ui.debug(" %s: %s -> dr\n" % (f, msg))
   743             repo.ui.debug(" %s: %s -> dr\n" % (f, msg))
   772             z += 1
   744             z += 1
   773             progress(_updating, z, item=f, total=numupdates, unit=_files)
   745             progress(_updating, z, item=f, total=numupdates, unit=_files)
   774             fl, = args
   746             fl, = args
   775             repo.ui.warn(_("note: possible conflict - %s was renamed "
   747             repo.ui.warn(_("note: possible conflict - %s was renamed "
   776                            "multiple times to:\n") % f)
   748                            "multiple times to:\n") % f)
   777             for nf in fl:
   749             for nf in fl:
   778                 repo.ui.warn(" %s\n" % nf)
   750                 repo.ui.warn(" %s\n" % nf)
   779 
   751 
   780         # rename and delete
   752         # rename and delete
   781         elif m == "rd":
   753         for f, args, msg in actions['rd']:
   782             repo.ui.debug(" %s: %s -> rd\n" % (f, msg))
   754             repo.ui.debug(" %s: %s -> rd\n" % (f, msg))
   783             z += 1
   755             z += 1
   784             progress(_updating, z, item=f, total=numupdates, unit=_files)
   756             progress(_updating, z, item=f, total=numupdates, unit=_files)
   785             fl, = args
   757             fl, = args
   786             repo.ui.warn(_("note: possible conflict - %s was deleted "
   758             repo.ui.warn(_("note: possible conflict - %s was deleted "
   787                            "and renamed to:\n") % f)
   759                            "and renamed to:\n") % f)
   788             for nf in fl:
   760             for nf in fl:
   789                 repo.ui.warn(" %s\n" % nf)
   761                 repo.ui.warn(" %s\n" % nf)
   790 
   762 
   791         # exec
   763         # exec
   792         elif m == "e":
   764         for f, args, msg in actions['e']:
   793             repo.ui.debug(" %s: %s -> e\n" % (f, msg))
   765             repo.ui.debug(" %s: %s -> e\n" % (f, msg))
   794             z += 1
   766             z += 1
   795             progress(_updating, z, item=f, total=numupdates, unit=_files)
   767             progress(_updating, z, item=f, total=numupdates, unit=_files)
   796             flags, = args
   768             flags, = args
   797             audit(f)
   769             audit(f)
   816         repo.ui.status(
   788         repo.ui.status(
   817             _("note: merging %s and %s using bids from ancestors %s\n") %
   789             _("note: merging %s and %s using bids from ancestors %s\n") %
   818             (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
   790             (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
   819 
   791 
   820         # Call for bids
   792         # Call for bids
   821         fbids = {} # mapping filename to list af action bids
   793         fbids = {} # mapping filename to bids (action method to list af actions)
   822         for ancestor in ancestors:
   794         for ancestor in ancestors:
   823             repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
   795             repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
   824             actions = manifestmerge(repo, wctx, mctx, ancestor,
   796             actions = manifestmerge(repo, wctx, mctx, ancestor,
   825                                     branchmerge, force,
   797                                     branchmerge, force,
   826                                     partial, acceptremote, followcopies)
   798                                     partial, acceptremote, followcopies)
   827             for a in sorted(actions, key=lambda a: (a[1], a)):
   799             for m, l in sorted(actions.items()):
   828                 f, m, args, msg = a
   800                 for a in l:
   829                 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
   801                     f, args, msg = a
   830                 if f in fbids:
   802                     repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
   831                     fbids[f].append(a)
   803                     if f in fbids:
   832                 else:
   804                         d = fbids[f]
   833                     fbids[f] = [a]
   805                         if m in d:
       
   806                             d[m].append(a)
       
   807                         else:
       
   808                             d[m] = [a]
       
   809                     else:
       
   810                         fbids[f] = {m: [a]}
   834 
   811 
   835         # Pick the best bid for each file
   812         # Pick the best bid for each file
   836         repo.ui.note(_('\nauction for merging merge bids\n'))
   813         repo.ui.note(_('\nauction for merging merge bids\n'))
   837         actions = []
   814         actions = dict((m, []) for m in actions.keys())
   838         for f, bidsl in sorted(fbids.items()):
   815         for f, bids in sorted(fbids.items()):
       
   816             # bids is a mapping from action method to list af actions
   839             # Consensus?
   817             # Consensus?
   840             a0 = bidsl[0]
   818             if len(bids) == 1: # all bids are the same kind of method
   841             if util.all(a == a0 for a in bidsl[1:]): # len(bidsl) is > 1
   819                 m, l = bids.items()[0]
   842                 repo.ui.note(" %s: consensus for %s\n" % (f, a0[1]))
   820                 if util.all(a == l[0] for a in l[1:]): # len(bids) is > 1
   843                 actions.append(a0)
   821                     repo.ui.note(" %s: consensus for %s\n" % (f, m))
   844                 continue
   822                     actions[m].append(l[0])
   845             # Group bids by kind of action
   823                     continue
   846             bids = {}
       
   847             for a in bidsl:
       
   848                 m = a[1]
       
   849                 if m in bids:
       
   850                     bids[m].append(a)
       
   851                 else:
       
   852                     bids[m] = [a]
       
   853             # If keep is an option, just do it.
   824             # If keep is an option, just do it.
   854             if "k" in bids:
   825             if "k" in bids:
   855                 repo.ui.note(" %s: picking 'keep' action\n" % f)
   826                 repo.ui.note(" %s: picking 'keep' action\n" % f)
   856                 actions.append(bids["k"][0])
   827                 actions['k'].append(bids["k"][0])
   857                 continue
   828                 continue
   858             # If all gets agree [how could they not?], just do it.
   829             # If there are gets and they all agree [how could they not?], do it.
   859             if "g" in bids:
   830             if "g" in bids:
   860                 ga0 = bids["g"][0]
   831                 ga0 = bids["g"][0]
   861                 if util.all(a == ga0 for a in bids["g"][1:]):
   832                 if util.all(a == ga0 for a in bids["g"][1:]):
   862                     repo.ui.note(" %s: picking 'get' action\n" % f)
   833                     repo.ui.note(" %s: picking 'get' action\n" % f)
   863                     actions.append(ga0)
   834                     actions['g'].append(ga0)
   864                     continue
   835                     continue
   865             # TODO: Consider other simple actions such as mode changes
   836             # TODO: Consider other simple actions such as mode changes
   866             # Handle inefficient democrazy.
   837             # Handle inefficient democrazy.
   867             repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
   838             repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
   868             for _f, m, args, msg in bidsl:
   839             for m, l in sorted(bids.items()):
   869                 repo.ui.note('  %s -> %s\n' % (msg, m))
   840                 for _f, args, msg in l:
       
   841                     repo.ui.note('  %s -> %s\n' % (msg, m))
   870             # Pick random action. TODO: Instead, prompt user when resolving
   842             # Pick random action. TODO: Instead, prompt user when resolving
   871             a0 = bidsl[0]
   843             m, l = bids.items()[0]
   872             repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
   844             repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
   873                          (f, a0[1]))
   845                          (f, m))
   874             actions.append(a0)
   846             actions[m].append(l[0])
   875             continue
   847             continue
   876         repo.ui.note(_('end of auction\n\n'))
   848         repo.ui.note(_('end of auction\n\n'))
   877 
   849 
   878     # Filter out prompts.
       
   879     newactions, prompts = [], []
       
   880     for a in actions:
       
   881         if a[1] in ("cd", "dc"):
       
   882             prompts.append(a)
       
   883         else:
       
   884             newactions.append(a)
       
   885     # Prompt and create actions. TODO: Move this towards resolve phase.
   850     # Prompt and create actions. TODO: Move this towards resolve phase.
   886     for f, m, args, msg in sorted(prompts):
   851     if True:
   887         if m == "cd":
   852         for f, args, msg in actions['cd']:
   888             if repo.ui.promptchoice(
   853             if repo.ui.promptchoice(
   889                 _("local changed %s which remote deleted\n"
   854                 _("local changed %s which remote deleted\n"
   890                   "use (c)hanged version or (d)elete?"
   855                   "use (c)hanged version or (d)elete?"
   891                   "$$ &Changed $$ &Delete") % f, 0):
   856                   "$$ &Changed $$ &Delete") % f, 0):
   892                 newactions.append((f, "r", None, "prompt delete"))
   857                 actions['r'].append((f, None, "prompt delete"))
   893             else:
   858             else:
   894                 newactions.append((f, "a", None, "prompt keep"))
   859                 actions['a'].append((f, None, "prompt keep"))
   895         elif m == "dc":
   860         del actions['cd'][:]
       
   861 
       
   862         for f, args, msg in actions['dc']:
   896             flags, = args
   863             flags, = args
   897             if repo.ui.promptchoice(
   864             if repo.ui.promptchoice(
   898                 _("remote changed %s which local deleted\n"
   865                 _("remote changed %s which local deleted\n"
   899                   "use (c)hanged version or leave (d)eleted?"
   866                   "use (c)hanged version or leave (d)eleted?"
   900                   "$$ &Changed $$ &Deleted") % f, 0) == 0:
   867                   "$$ &Changed $$ &Deleted") % f, 0) == 0:
   901                 newactions.append((f, "g", (flags,), "prompt recreating"))
   868                 actions['g'].append((f, (flags,), "prompt recreating"))
   902         else: assert False, m
   869         del actions['dc'][:]
   903 
   870 
   904     if wctx.rev() is None:
   871     if wctx.rev() is None:
   905         newactions += _forgetremoved(wctx, mctx, branchmerge)
   872         ractions, factions = _forgetremoved(wctx, mctx, branchmerge)
   906 
   873         actions['r'].extend(ractions)
   907     return newactions
   874         actions['f'].extend(factions)
       
   875 
       
   876     return actions
   908 
   877 
   909 def recordupdates(repo, actions, branchmerge):
   878 def recordupdates(repo, actions, branchmerge):
   910     "record merge actions to the dirstate"
   879     "record merge actions to the dirstate"
   911 
   880     if True:
   912     for f, m, args, msg in actions:
       
   913 
       
   914         # remove (must come first)
   881         # remove (must come first)
   915         if m == "r": # remove
   882         for f, args, msg in actions['r']:
   916             if branchmerge:
   883             if branchmerge:
   917                 repo.dirstate.remove(f)
   884                 repo.dirstate.remove(f)
   918             else:
   885             else:
   919                 repo.dirstate.drop(f)
   886                 repo.dirstate.drop(f)
   920 
   887 
   921         # forget (must come first)
   888         # forget (must come first)
   922         elif m == "f":
   889         for f, args, msg in actions['f']:
   923             repo.dirstate.drop(f)
   890             repo.dirstate.drop(f)
   924 
   891 
   925         # re-add
   892         # re-add
   926         elif m == "a":
   893         for f, args, msg in actions['a']:
   927             if not branchmerge:
   894             if not branchmerge:
   928                 repo.dirstate.add(f)
   895                 repo.dirstate.add(f)
   929 
   896 
   930         # exec change
   897         # exec change
   931         elif m == "e":
   898         for f, args, msg in actions['e']:
   932             repo.dirstate.normallookup(f)
   899             repo.dirstate.normallookup(f)
   933 
   900 
   934         # keep
   901         # keep
   935         elif m == "k":
   902         for f, args, msg in actions['k']:
   936             pass
   903             pass
   937 
   904 
   938         # get
   905         # get
   939         elif m == "g":
   906         for f, args, msg in actions['g']:
   940             if branchmerge:
   907             if branchmerge:
   941                 repo.dirstate.otherparent(f)
   908                 repo.dirstate.otherparent(f)
   942             else:
   909             else:
   943                 repo.dirstate.normal(f)
   910                 repo.dirstate.normal(f)
   944 
   911 
   945         # merge
   912         # merge
   946         elif m == "m":
   913         for f, args, msg in actions['m']:
   947             f1, f2, fa, move, anc = args
   914             f1, f2, fa, move, anc = args
   948             if branchmerge:
   915             if branchmerge:
   949                 # We've done a branch merge, mark this file as merged
   916                 # We've done a branch merge, mark this file as merged
   950                 # so that we properly record the merger later
   917                 # so that we properly record the merger later
   951                 repo.dirstate.merge(f)
   918                 repo.dirstate.merge(f)
   966                     repo.dirstate.normallookup(f)
   933                     repo.dirstate.normallookup(f)
   967                 if move:
   934                 if move:
   968                     repo.dirstate.drop(f1)
   935                     repo.dirstate.drop(f1)
   969 
   936 
   970         # directory rename, move local
   937         # directory rename, move local
   971         elif m == "dm":
   938         for f, args, msg in actions['dm']:
   972             f0, flag = args
   939             f0, flag = args
   973             if f0 not in repo.dirstate:
   940             if f0 not in repo.dirstate:
   974                 # untracked file moved
   941                 # untracked file moved
   975                 continue
   942                 continue
   976             if branchmerge:
   943             if branchmerge:
   980             else:
   947             else:
   981                 repo.dirstate.normal(f)
   948                 repo.dirstate.normal(f)
   982                 repo.dirstate.drop(f0)
   949                 repo.dirstate.drop(f0)
   983 
   950 
   984         # directory rename, get
   951         # directory rename, get
   985         elif m == "dg":
   952         for f, args, msg in actions['dg']:
   986             f0, flag = args
   953             f0, flag = args
   987             if branchmerge:
   954             if branchmerge:
   988                 repo.dirstate.add(f)
   955                 repo.dirstate.add(f)
   989                 repo.dirstate.copy(f0, f)
   956                 repo.dirstate.copy(f0, f)
   990             else:
   957             else: