comparison mercurial/merge.py @ 23638:09be050ca98c

merge: let bid merge work on the file->action dict By moving the conversion from the file->action dict after the bid merge code, bid merge can be simplified a little. A few tests are affected by this change. Where we used to iterate over the actions first in order of the action type ('g', 'r', etc.) [1], we now iterate in order of filename. This difference affects the order of debug log statements. [1] And then in the non-deterministic order of files in the manifest dictionary (the order returned from manifest.diff()).
author Martin von Zweigbergk <martinvonz@google.com>
date Thu, 11 Dec 2014 20:56:53 -0800
parents 13f53a2aa342
children 35c724903157
comparison
equal deleted inserted replaced
23637:13f53a2aa342 23638:09be050ca98c
523 else: assert False, m 523 else: assert False, m
524 if aborts: 524 if aborts:
525 raise util.Abort(_("untracked files in working directory differ " 525 raise util.Abort(_("untracked files in working directory differ "
526 "from files in requested revision")) 526 "from files in requested revision"))
527 527
528 # Convert to dictionary-of-lists format
529 actionbyfile = actions
530 actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
531 for f, (m, args, msg) in actionbyfile.iteritems():
532 actions[m].append((f, args, msg))
533
534 return actions, diverge, renamedelete 528 return actions, diverge, renamedelete
535 529
536 def _resolvetrivial(repo, wctx, mctx, ancestor, actions): 530 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
537 """Resolves false conflicts where the nodeid changed but the content 531 """Resolves false conflicts where the nodeid changed but the content
538 remained the same.""" 532 remained the same."""
581 acceptremote, followcopies) 575 acceptremote, followcopies)
582 if diverge is None: # and renamedelete is None. 576 if diverge is None: # and renamedelete is None.
583 # Arbitrarily pick warnings from first iteration 577 # Arbitrarily pick warnings from first iteration
584 diverge = diverge1 578 diverge = diverge1
585 renamedelete = renamedelete1 579 renamedelete = renamedelete1
586 for m, l in sorted(actions.items()): 580 for f, a in sorted(actions.iteritems()):
587 for a in l: 581 m, args, msg = a
588 f, args, msg = a 582 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
589 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m)) 583 if f in fbids:
590 if f in fbids: 584 d = fbids[f]
591 d = fbids[f] 585 if m in d:
592 if m in d: 586 d[m].append(a)
593 d[m].append(a)
594 else:
595 d[m] = [a]
596 else: 587 else:
597 fbids[f] = {m: [a]} 588 d[m] = [a]
589 else:
590 fbids[f] = {m: [a]}
598 591
599 # Pick the best bid for each file 592 # Pick the best bid for each file
600 repo.ui.note(_('\nauction for merging merge bids\n')) 593 repo.ui.note(_('\nauction for merging merge bids\n'))
601 actions = dict((m, []) for m in actions.keys()) 594 actions = {}
602 for f, bids in sorted(fbids.items()): 595 for f, bids in sorted(fbids.items()):
603 # bids is a mapping from action method to list af actions 596 # bids is a mapping from action method to list af actions
604 # Consensus? 597 # Consensus?
605 if len(bids) == 1: # all bids are the same kind of method 598 if len(bids) == 1: # all bids are the same kind of method
606 m, l = bids.items()[0] 599 m, l = bids.items()[0]
607 if util.all(a == l[0] for a in l[1:]): # len(bids) is > 1 600 if util.all(a == l[0] for a in l[1:]): # len(bids) is > 1
608 repo.ui.note(" %s: consensus for %s\n" % (f, m)) 601 repo.ui.note(" %s: consensus for %s\n" % (f, m))
609 actions[m].append(l[0]) 602 actions[f] = l[0]
610 continue 603 continue
611 # If keep is an option, just do it. 604 # If keep is an option, just do it.
612 if 'k' in bids: 605 if 'k' in bids:
613 repo.ui.note(" %s: picking 'keep' action\n" % f) 606 repo.ui.note(" %s: picking 'keep' action\n" % f)
614 actions['k'].append(bids['k'][0]) 607 actions[f] = bids['k'][0]
615 continue 608 continue
616 # If there are gets and they all agree [how could they not?], do it. 609 # If there are gets and they all agree [how could they not?], do it.
617 if 'g' in bids: 610 if 'g' in bids:
618 ga0 = bids['g'][0] 611 ga0 = bids['g'][0]
619 if util.all(a == ga0 for a in bids['g'][1:]): 612 if util.all(a == ga0 for a in bids['g'][1:]):
620 repo.ui.note(" %s: picking 'get' action\n" % f) 613 repo.ui.note(" %s: picking 'get' action\n" % f)
621 actions['g'].append(ga0) 614 actions[f] = ga0
622 continue 615 continue
623 # TODO: Consider other simple actions such as mode changes 616 # TODO: Consider other simple actions such as mode changes
624 # Handle inefficient democrazy. 617 # Handle inefficient democrazy.
625 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f) 618 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
626 for m, l in sorted(bids.items()): 619 for m, l in sorted(bids.items()):
628 repo.ui.note(' %s -> %s\n' % (msg, m)) 621 repo.ui.note(' %s -> %s\n' % (msg, m))
629 # Pick random action. TODO: Instead, prompt user when resolving 622 # Pick random action. TODO: Instead, prompt user when resolving
630 m, l = bids.items()[0] 623 m, l = bids.items()[0]
631 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') % 624 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
632 (f, m)) 625 (f, m))
633 actions[m].append(l[0]) 626 actions[f] = l[0]
634 continue 627 continue
635 repo.ui.note(_('end of auction\n\n')) 628 repo.ui.note(_('end of auction\n\n'))
629
630 # Convert to dictionary-of-lists format
631 actionbyfile = actions
632 actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
633 for f, (m, args, msg) in actionbyfile.iteritems():
634 actions[m].append((f, args, msg))
636 635
637 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions) 636 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
638 637
639 if wctx.rev() is None: 638 if wctx.rev() is None:
640 ractions, factions = _forgetremoved(wctx, mctx, branchmerge) 639 ractions, factions = _forgetremoved(wctx, mctx, branchmerge)