Mercurial > public > mercurial-scm > hg
comparison mercurial/merge.py @ 21128:f4014f646f71
merge: with merge.preferancestor=*, run an auction with bids from ancestors
The basic idea is to do the merge planning with all the available ancestors,
consider the resulting actions as "bids", make an "auction" and
automatically pick the most favourable action for each file.
This implements the basic functionality and will only consider "keep" and
"get" actions. The heuristics for picking the best action can be tweaked later
on.
By default it will only pass ctx.ancestor as the single ancestor to
calculateupdates. The code path for merging with a single ancestor is not
changed.
author | Mads Kiilerich <madski@unity3d.com> |
---|---|
date | Fri, 28 Feb 2014 02:52:32 +0100 |
parents | 0d67fccc0d43 |
children | 1ce131b3221e |
comparison
equal
deleted
inserted
replaced
21127:69402eb72115 | 21128:f4014f646f71 |
---|---|
721 | 721 |
722 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial, | 722 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial, |
723 acceptremote, followcopies): | 723 acceptremote, followcopies): |
724 "Calculate the actions needed to merge mctx into wctx using ancestors" | 724 "Calculate the actions needed to merge mctx into wctx using ancestors" |
725 | 725 |
726 ancestor = ancestors[0] | 726 if len(ancestors) == 1: # default |
727 | 727 actions = manifestmerge(repo, wctx, mctx, ancestors[0], |
728 actions = manifestmerge(repo, wctx, mctx, | 728 branchmerge, force, |
729 ancestor, | 729 partial, acceptremote, followcopies) |
730 branchmerge, force, | 730 |
731 partial, acceptremote, followcopies) | 731 else: # only when merge.preferancestor=* - experimentalish code |
732 # Call for bids | |
733 fbids = {} # mapping filename to list af action bids | |
734 for ancestor in ancestors: | |
735 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor) | |
736 actions = manifestmerge(repo, wctx, mctx, ancestor, | |
737 branchmerge, force, | |
738 partial, acceptremote, followcopies) | |
739 for a in sorted(actions): | |
740 repo.ui.debug(' %s: %s\n' % (a[0], a[1])) | |
741 f = a[0] | |
742 if f in fbids: | |
743 fbids[f].append(a) | |
744 else: | |
745 fbids[f] = [a] | |
746 | |
747 # Pick the best bid for each file | |
748 repo.ui.note(_('\nauction for merging merge bids\n')) | |
749 actions = [] | |
750 for f, bidsl in sorted(fbids.items()): | |
751 # Consensus? | |
752 a0 = bidsl[0] | |
753 if util.all(a == a0 for a in bidsl[1:]): # len(bidsl) is > 1 | |
754 repo.ui.note(" %s: consensus for %s\n" % (f, a0[1])) | |
755 actions.append(a0) | |
756 continue | |
757 # Group bids by kind of action | |
758 bids = {} | |
759 for a in bidsl: | |
760 m = a[1] | |
761 if m in bids: | |
762 bids[m].append(a) | |
763 else: | |
764 bids[m] = [a] | |
765 # If keep is an option, just do it. | |
766 if "k" in bids: | |
767 repo.ui.note(" %s: picking 'keep' action\n" % f) | |
768 actions.append(bids["k"][0]) | |
769 continue | |
770 # If all gets agree [how could they not?], just do it. | |
771 if "g" in bids: | |
772 ga0 = bids["g"][0] | |
773 if util.all(a == ga0 for a in bids["g"][1:]): | |
774 repo.ui.note(" %s: picking 'get' action\n" % f) | |
775 actions.append(ga0) | |
776 continue | |
777 # TODO: Consider other simple actions such as mode changes | |
778 # Handle inefficient democrazy. | |
779 repo.ui.note(_(' %s: multiple merge bids:\n') % (f, m)) | |
780 for a in bidsl: | |
781 repo.ui.note(' %s: %s\n' % (f, a[1])) | |
782 # Pick random action. TODO: Instead, prompt user when resolving | |
783 a0 = bidsl[0] | |
784 repo.ui.warn(_(' %s: ambiguous merge - picked %s action)\n') % | |
785 (f, a0[1])) | |
786 actions.append(a0) | |
787 continue | |
788 repo.ui.note(_('end of auction\n\n')) | |
732 | 789 |
733 # Filter out prompts. | 790 # Filter out prompts. |
734 newactions, prompts = [], [] | 791 newactions, prompts = [], [] |
735 for a in actions: | 792 for a in actions: |
736 if a[1] in ("cd", "dc"): | 793 if a[1] in ("cd", "dc"): |
924 | 981 |
925 overwrite = force and not branchmerge | 982 overwrite = force and not branchmerge |
926 | 983 |
927 p2 = repo[node] | 984 p2 = repo[node] |
928 if pas[0] is None: | 985 if pas[0] is None: |
929 pas = [p1.ancestor(p2)] | 986 if repo.ui.config("merge", "preferancestor") == '*': |
987 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node()) | |
988 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])] | |
989 else: | |
990 pas = [p1.ancestor(p2)] | |
930 | 991 |
931 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2) | 992 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2) |
932 | 993 |
933 ### check phase | 994 ### check phase |
934 if not overwrite and len(pl) > 1: | 995 if not overwrite and len(pl) > 1: |