comparison mercurial/merge.py @ 45274:0e18861f96ab

merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API) Earlier, manifestmerge() and calculateupdates() returns a tuple of three things. I wanted to add one more thing to return value. Introducing a special class which represents results of a merge will help understand better and also ease adding new return values. Differential Revision: https://phab.mercurial-scm.org/D8799
author Pulkit Goyal <7895pulkit@gmail.com>
date Thu, 23 Jul 2020 18:03:14 +0530
parents 4f71d1a99e45
children 8e8d513941b4
comparison
equal deleted inserted replaced
45270:c8655782ef19 45274:0e18861f96ab
538 raise error.Abort( 538 raise error.Abort(
539 _(b'conflict in file \'%s\' is outside narrow clone') % f 539 _(b'conflict in file \'%s\' is outside narrow clone') % f
540 ) 540 )
541 541
542 542
543 class mergeresult(object):
544 ''''An object representing result of merging manifests.
545
546 It has information about what actions need to be performed on dirstate
547 mapping of divergent renames and other such cases. '''
548
549 def __init__(self, actions, diverge, renamedelete):
550 """
551 actions: dict of filename as keys and action related info as values
552 diverge: mapping of source name -> list of dest name for
553 divergent renames
554 renamedelete: mapping of source name -> list of destinations for files
555 deleted on one side and renamed on other.
556 """
557
558 self._actions = actions
559 self._diverge = diverge
560 self._renamedelete = renamedelete
561
562 @property
563 def actions(self):
564 return self._actions
565
566 @property
567 def diverge(self):
568 return self._diverge
569
570 @property
571 def renamedelete(self):
572 return self._renamedelete
573
574 def setactions(self, actions):
575 self._actions = actions
576
577
543 def manifestmerge( 578 def manifestmerge(
544 repo, 579 repo,
545 wctx, 580 wctx,
546 p2, 581 p2,
547 pa, 582 pa,
557 592
558 branchmerge and force are as passed in to update 593 branchmerge and force are as passed in to update
559 matcher = matcher to filter file lists 594 matcher = matcher to filter file lists
560 acceptremote = accept the incoming changes without prompting 595 acceptremote = accept the incoming changes without prompting
561 596
562 Returns: 597 Returns an object of mergeresult class
563
564 actions: dict of filename as keys and action related info as values
565 diverge: mapping of source name -> list of dest name for divergent renames
566 renamedelete: mapping of source name -> list of destinations for files
567 deleted on one side and renamed on other.
568 """ 598 """
569 if matcher is not None and matcher.always(): 599 if matcher is not None and matcher.always():
570 matcher = None 600 matcher = None
571 601
572 # manifests fetched in order are going to be faster, so prime the caches 602 # manifests fetched in order are going to be faster, so prime the caches
843 _filternarrowactions(narrowmatch, branchmerge, actions) 873 _filternarrowactions(narrowmatch, branchmerge, actions)
844 874
845 renamedelete = branch_copies1.renamedelete 875 renamedelete = branch_copies1.renamedelete
846 renamedelete.update(branch_copies2.renamedelete) 876 renamedelete.update(branch_copies2.renamedelete)
847 877
848 return actions, diverge, renamedelete 878 return mergeresult(actions, diverge, renamedelete)
849 879
850 880
851 def _resolvetrivial(repo, wctx, mctx, ancestor, actions): 881 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
852 """Resolves false conflicts where the nodeid changed but the content 882 """Resolves false conflicts where the nodeid changed but the content
853 remained the same.""" 883 remained the same."""
889 perform for merging two manifests. If there are multiple ancestors, uses bid 919 perform for merging two manifests. If there are multiple ancestors, uses bid
890 merge if enabled. 920 merge if enabled.
891 921
892 Also filters out actions which are unrequired if repository is sparse. 922 Also filters out actions which are unrequired if repository is sparse.
893 923
894 Returns same 3 element tuple as manifestmerge(). 924 Returns mergeresult object same as manifestmerge().
895 """ 925 """
896 # Avoid cycle. 926 # Avoid cycle.
897 from . import sparse 927 from . import sparse
898 928
899 if len(ancestors) == 1: # default 929 if len(ancestors) == 1: # default
900 actions, diverge, renamedelete = manifestmerge( 930 mresult = manifestmerge(
901 repo, 931 repo,
902 wctx, 932 wctx,
903 mctx, 933 mctx,
904 ancestors[0], 934 ancestors[0],
905 branchmerge, 935 branchmerge,
906 force, 936 force,
907 matcher, 937 matcher,
908 acceptremote, 938 acceptremote,
909 followcopies, 939 followcopies,
910 ) 940 )
911 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce) 941 _checkunknownfiles(repo, wctx, mctx, force, mresult.actions, mergeforce)
912 942
913 else: # only when merge.preferancestor=* - the default 943 else: # only when merge.preferancestor=* - the default
914 repo.ui.note( 944 repo.ui.note(
915 _(b"note: merging %s and %s using bids from ancestors %s\n") 945 _(b"note: merging %s and %s using bids from ancestors %s\n")
916 % ( 946 % (
925 {} 955 {}
926 ) # mapping filename to bids (action method to list af actions) 956 ) # mapping filename to bids (action method to list af actions)
927 diverge, renamedelete = None, None 957 diverge, renamedelete = None, None
928 for ancestor in ancestors: 958 for ancestor in ancestors:
929 repo.ui.note(_(b'\ncalculating bids for ancestor %s\n') % ancestor) 959 repo.ui.note(_(b'\ncalculating bids for ancestor %s\n') % ancestor)
930 actions, diverge1, renamedelete1 = manifestmerge( 960 mresult1 = manifestmerge(
931 repo, 961 repo,
932 wctx, 962 wctx,
933 mctx, 963 mctx,
934 ancestor, 964 ancestor,
935 branchmerge, 965 branchmerge,
937 matcher, 967 matcher,
938 acceptremote, 968 acceptremote,
939 followcopies, 969 followcopies,
940 forcefulldiff=True, 970 forcefulldiff=True,
941 ) 971 )
942 _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce) 972 _checkunknownfiles(
973 repo, wctx, mctx, force, mresult1.actions, mergeforce
974 )
943 975
944 # Track the shortest set of warning on the theory that bid 976 # Track the shortest set of warning on the theory that bid
945 # merge will correctly incorporate more information 977 # merge will correctly incorporate more information
946 if diverge is None or len(diverge1) < len(diverge): 978 if diverge is None or len(mresult1.diverge) < len(diverge):
947 diverge = diverge1 979 diverge = mresult1.diverge
948 if renamedelete is None or len(renamedelete) < len(renamedelete1): 980 if renamedelete is None or len(renamedelete) < len(
949 renamedelete = renamedelete1 981 mresult1.renamedelete
950 982 ):
951 for f, a in sorted(pycompat.iteritems(actions)): 983 renamedelete = mresult1.renamedelete
984
985 for f, a in sorted(pycompat.iteritems(mresult1.actions)):
952 m, args, msg = a 986 m, args, msg = a
953 if m == mergestatemod.ACTION_GET_OTHER_AND_STORE: 987 if m == mergestatemod.ACTION_GET_OTHER_AND_STORE:
954 m = mergestatemod.ACTION_GET 988 m = mergestatemod.ACTION_GET
955 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m)) 989 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m))
956 if f in fbids: 990 if f in fbids:
998 _(b' %s: ambiguous merge - picked %s action\n') % (f, m) 1032 _(b' %s: ambiguous merge - picked %s action\n') % (f, m)
999 ) 1033 )
1000 actions[f] = l[0] 1034 actions[f] = l[0]
1001 continue 1035 continue
1002 repo.ui.note(_(b'end of auction\n\n')) 1036 repo.ui.note(_(b'end of auction\n\n'))
1037 mresult = mergeresult(actions, diverge, renamedelete)
1003 1038
1004 if wctx.rev() is None: 1039 if wctx.rev() is None:
1005 fractions = _forgetremoved(wctx, mctx, branchmerge) 1040 fractions = _forgetremoved(wctx, mctx, branchmerge)
1006 actions.update(fractions) 1041 mresult.actions.update(fractions)
1007 1042
1008 prunedactions = sparse.filterupdatesactions( 1043 prunedactions = sparse.filterupdatesactions(
1009 repo, wctx, mctx, branchmerge, actions 1044 repo, wctx, mctx, branchmerge, mresult.actions
1010 ) 1045 )
1011 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions) 1046 _resolvetrivial(repo, wctx, mctx, ancestors[0], mresult.actions)
1012 1047
1013 return prunedactions, diverge, renamedelete 1048 mresult.setactions(prunedactions)
1049 return mresult
1014 1050
1015 1051
1016 def _getcwd(): 1052 def _getcwd():
1017 try: 1053 try:
1018 return encoding.getcwd() 1054 return encoding.getcwd()
1732 followcopies = False 1768 followcopies = False
1733 if not branchmerge and not wc.dirty(missing=True): 1769 if not branchmerge and not wc.dirty(missing=True):
1734 followcopies = False 1770 followcopies = False
1735 1771
1736 ### calculate phase 1772 ### calculate phase
1737 actionbyfile, diverge, renamedelete = calculateupdates( 1773 mresult = calculateupdates(
1738 repo, 1774 repo,
1739 wc, 1775 wc,
1740 p2, 1776 p2,
1741 pas, 1777 pas,
1742 branchmerge, 1778 branchmerge,
1744 mergeancestor, 1780 mergeancestor,
1745 followcopies, 1781 followcopies,
1746 matcher=matcher, 1782 matcher=matcher,
1747 mergeforce=mergeforce, 1783 mergeforce=mergeforce,
1748 ) 1784 )
1785
1786 actionbyfile = mresult.actions
1749 1787
1750 if updatecheck == UPDATECHECK_NO_CONFLICT: 1788 if updatecheck == UPDATECHECK_NO_CONFLICT:
1751 for f, (m, args, msg) in pycompat.iteritems(actionbyfile): 1789 for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
1752 if m not in ( 1790 if m not in (
1753 mergestatemod.ACTION_GET, 1791 mergestatemod.ACTION_GET,
1838 _checkcollision(repo, p2.manifest(), None) 1876 _checkcollision(repo, p2.manifest(), None)
1839 else: 1877 else:
1840 _checkcollision(repo, wc.manifest(), actions) 1878 _checkcollision(repo, wc.manifest(), actions)
1841 1879
1842 # divergent renames 1880 # divergent renames
1843 for f, fl in sorted(pycompat.iteritems(diverge)): 1881 for f, fl in sorted(pycompat.iteritems(mresult.diverge)):
1844 repo.ui.warn( 1882 repo.ui.warn(
1845 _( 1883 _(
1846 b"note: possible conflict - %s was renamed " 1884 b"note: possible conflict - %s was renamed "
1847 b"multiple times to:\n" 1885 b"multiple times to:\n"
1848 ) 1886 )
1850 ) 1888 )
1851 for nf in sorted(fl): 1889 for nf in sorted(fl):
1852 repo.ui.warn(b" %s\n" % nf) 1890 repo.ui.warn(b" %s\n" % nf)
1853 1891
1854 # rename and delete 1892 # rename and delete
1855 for f, fl in sorted(pycompat.iteritems(renamedelete)): 1893 for f, fl in sorted(pycompat.iteritems(mresult.renamedelete)):
1856 repo.ui.warn( 1894 repo.ui.warn(
1857 _( 1895 _(
1858 b"note: possible conflict - %s was deleted " 1896 b"note: possible conflict - %s was deleted "
1859 b"and renamed to:\n" 1897 b"and renamed to:\n"
1860 ) 1898 )