215 abortconflicts.add(f) |
215 abortconflicts.add(f) |
216 else: |
216 else: |
217 if config == b'warn': |
217 if config == b'warn': |
218 warnconflicts.add(f) |
218 warnconflicts.add(f) |
219 mresult.addfile( |
219 mresult.addfile( |
220 f, mergestatemod.ACTION_GET, (fl2, True), b'remote created', |
220 f, |
|
221 mergestatemod.ACTION_GET, |
|
222 (fl2, True), |
|
223 b'remote created', |
221 ) |
224 ) |
222 |
225 |
223 for f in sorted(abortconflicts): |
226 for f in sorted(abortconflicts): |
224 warn = repo.ui.warn |
227 warn = repo.ui.warn |
225 if f in pathconflicts: |
228 if f in pathconflicts: |
542 _(b'conflict in file \'%s\' is outside narrow clone') % f |
548 _(b'conflict in file \'%s\' is outside narrow clone') % f |
543 ) |
549 ) |
544 |
550 |
545 |
551 |
546 class mergeresult(object): |
552 class mergeresult(object): |
547 '''An object representing result of merging manifests. |
553 """An object representing result of merging manifests. |
548 |
554 |
549 It has information about what actions need to be performed on dirstate |
555 It has information about what actions need to be performed on dirstate |
550 mapping of divergent renames and other such cases.''' |
556 mapping of divergent renames and other such cases.""" |
551 |
557 |
552 def __init__(self): |
558 def __init__(self): |
553 """ |
559 """ |
554 filemapping: dict of filename as keys and action related info as values |
560 filemapping: dict of filename as keys and action related info as values |
555 diverge: mapping of source name -> list of dest name for |
561 diverge: mapping of source name -> list of dest name for |
570 def updatevalues(self, diverge, renamedelete): |
576 def updatevalues(self, diverge, renamedelete): |
571 self._diverge = diverge |
577 self._diverge = diverge |
572 self._renamedelete = renamedelete |
578 self._renamedelete = renamedelete |
573 |
579 |
574 def addfile(self, filename, action, data, message): |
580 def addfile(self, filename, action, data, message): |
575 """ adds a new file to the mergeresult object |
581 """adds a new file to the mergeresult object |
576 |
582 |
577 filename: file which we are adding |
583 filename: file which we are adding |
578 action: one of mergestatemod.ACTION_* |
584 action: one of mergestatemod.ACTION_* |
579 data: a tuple of information like fctx and ctx related to this merge |
585 data: a tuple of information like fctx and ctx related to this merge |
580 message: a message about the merge |
586 message: a message about the merge |
587 |
593 |
588 self._filemapping[filename] = (action, data, message) |
594 self._filemapping[filename] = (action, data, message) |
589 self._actionmapping[action][filename] = (data, message) |
595 self._actionmapping[action][filename] = (data, message) |
590 |
596 |
591 def getfile(self, filename, default_return=None): |
597 def getfile(self, filename, default_return=None): |
592 """ returns (action, args, msg) about this file |
598 """returns (action, args, msg) about this file |
593 |
599 |
594 returns default_return if the file is not present """ |
600 returns default_return if the file is not present""" |
595 if filename in self._filemapping: |
601 if filename in self._filemapping: |
596 return self._filemapping[filename] |
602 return self._filemapping[filename] |
597 return default_return |
603 return default_return |
598 |
604 |
599 def files(self, actions=None): |
605 def files(self, actions=None): |
600 """ returns files on which provided action needs to perfromed |
606 """returns files on which provided action needs to perfromed |
601 |
607 |
602 If actions is None, all files are returned |
608 If actions is None, all files are returned |
603 """ |
609 """ |
604 # TODO: think whether we should return renamedelete and |
610 # TODO: think whether we should return renamedelete and |
605 # diverge filenames also |
611 # diverge filenames also |
611 for a in actions: |
617 for a in actions: |
612 for f in self._actionmapping[a]: |
618 for f in self._actionmapping[a]: |
613 yield f |
619 yield f |
614 |
620 |
615 def removefile(self, filename): |
621 def removefile(self, filename): |
616 """ removes a file from the mergeresult object as the file might |
622 """removes a file from the mergeresult object as the file might |
617 not merging anymore """ |
623 not merging anymore""" |
618 action, data, message = self._filemapping[filename] |
624 action, data, message = self._filemapping[filename] |
619 del self._filemapping[filename] |
625 del self._filemapping[filename] |
620 del self._actionmapping[action][filename] |
626 del self._actionmapping[action][filename] |
621 |
627 |
622 def getactions(self, actions, sort=False): |
628 def getactions(self, actions, sort=False): |
623 """ get list of files which are marked with these actions |
629 """get list of files which are marked with these actions |
624 if sort is true, files for each action is sorted and then added |
630 if sort is true, files for each action is sorted and then added |
625 |
631 |
626 Returns a list of tuple of form (filename, data, message) |
632 Returns a list of tuple of form (filename, data, message) |
627 """ |
633 """ |
628 for a in actions: |
634 for a in actions: |
635 self._actionmapping[a] |
641 self._actionmapping[a] |
636 ): |
642 ): |
637 yield f, args, msg |
643 yield f, args, msg |
638 |
644 |
639 def len(self, actions=None): |
645 def len(self, actions=None): |
640 """ returns number of files which needs actions |
646 """returns number of files which needs actions |
641 |
647 |
642 if actions is passed, total of number of files in that action |
648 if actions is passed, total of number of files in that action |
643 only is returned """ |
649 only is returned""" |
644 |
650 |
645 if actions is None: |
651 if actions is None: |
646 return len(self._filemapping) |
652 return len(self._filemapping) |
647 |
653 |
648 return sum(len(self._actionmapping[a]) for a in actions) |
654 return sum(len(self._actionmapping[a]) for a in actions) |
654 else: |
660 else: |
655 for key, val in pycompat.iteritems(self._filemapping): |
661 for key, val in pycompat.iteritems(self._filemapping): |
656 yield key, val |
662 yield key, val |
657 |
663 |
658 def addcommitinfo(self, filename, key, value): |
664 def addcommitinfo(self, filename, key, value): |
659 """ adds key-value information about filename which will be required |
665 """adds key-value information about filename which will be required |
660 while committing this merge """ |
666 while committing this merge""" |
661 self._commitinfo[filename][key] = value |
667 self._commitinfo[filename][key] = value |
662 |
668 |
663 @property |
669 @property |
664 def diverge(self): |
670 def diverge(self): |
665 return self._diverge |
671 return self._diverge |
672 def commitinfo(self): |
678 def commitinfo(self): |
673 return self._commitinfo |
679 return self._commitinfo |
674 |
680 |
675 @property |
681 @property |
676 def actionsdict(self): |
682 def actionsdict(self): |
677 """ returns a dictionary of actions to be perfomed with action as key |
683 """returns a dictionary of actions to be perfomed with action as key |
678 and a list of files and related arguments as values """ |
684 and a list of files and related arguments as values""" |
679 res = collections.defaultdict(list) |
685 res = collections.defaultdict(list) |
680 for a, d in pycompat.iteritems(self._actionmapping): |
686 for a, d in pycompat.iteritems(self._actionmapping): |
681 for f, (args, msg) in pycompat.iteritems(d): |
687 for f, (args, msg) in pycompat.iteritems(d): |
682 res[a].append((f, args, msg)) |
688 res[a].append((f, args, msg)) |
683 return res |
689 return res |
687 self._actionmapping = collections.defaultdict(dict) |
693 self._actionmapping = collections.defaultdict(dict) |
688 for f, (act, data, msg) in pycompat.iteritems(self._filemapping): |
694 for f, (act, data, msg) in pycompat.iteritems(self._filemapping): |
689 self._actionmapping[act][f] = data, msg |
695 self._actionmapping[act][f] = data, msg |
690 |
696 |
691 def hasconflicts(self): |
697 def hasconflicts(self): |
692 """ tells whether this merge resulted in some actions which can |
698 """tells whether this merge resulted in some actions which can |
693 result in conflicts or not """ |
699 result in conflicts or not""" |
694 for a in self._actionmapping.keys(): |
700 for a in self._actionmapping.keys(): |
695 if ( |
701 if ( |
696 a |
702 a |
697 not in ( |
703 not in ( |
698 mergestatemod.ACTION_GET, |
704 mergestatemod.ACTION_GET, |
837 a = ma[f] |
843 a = ma[f] |
838 fla = ma.flags(f) |
844 fla = ma.flags(f) |
839 nol = b'l' not in fl1 + fl2 + fla |
845 nol = b'l' not in fl1 + fl2 + fla |
840 if n2 == a and fl2 == fla: |
846 if n2 == a and fl2 == fla: |
841 mresult.addfile( |
847 mresult.addfile( |
842 f, mergestatemod.ACTION_KEEP, (), b'remote unchanged', |
848 f, |
|
849 mergestatemod.ACTION_KEEP, |
|
850 (), |
|
851 b'remote unchanged', |
843 ) |
852 ) |
844 elif n1 == a and fl1 == fla: # local unchanged - use remote |
853 elif n1 == a and fl1 == fla: # local unchanged - use remote |
845 if n1 == n2: # optimization: keep local content |
854 if n1 == n2: # optimization: keep local content |
846 mresult.addfile( |
855 mresult.addfile( |
847 f, |
856 f, |
934 ) |
943 ) |
935 elif n1 == addednodeid: |
944 elif n1 == addednodeid: |
936 # This file was locally added. We should forget it instead of |
945 # This file was locally added. We should forget it instead of |
937 # deleting it. |
946 # deleting it. |
938 mresult.addfile( |
947 mresult.addfile( |
939 f, mergestatemod.ACTION_FORGET, None, b'remote deleted', |
948 f, |
|
949 mergestatemod.ACTION_FORGET, |
|
950 None, |
|
951 b'remote deleted', |
940 ) |
952 ) |
941 else: |
953 else: |
942 mresult.addfile( |
954 mresult.addfile( |
943 f, mergestatemod.ACTION_REMOVE, None, b'other deleted', |
955 f, |
|
956 mergestatemod.ACTION_REMOVE, |
|
957 None, |
|
958 b'other deleted', |
944 ) |
959 ) |
945 if branchmerge: |
960 if branchmerge: |
946 # the file must be absent after merging, |
961 # the file must be absent after merging, |
947 # howeber the user might make |
962 # howeber the user might make |
948 # the file reappear using revert and if they does, |
963 # the file reappear using revert and if they does, |
1084 return mresult |
1099 return mresult |
1085 |
1100 |
1086 |
1101 |
1087 def _resolvetrivial(repo, wctx, mctx, ancestor, mresult): |
1102 def _resolvetrivial(repo, wctx, mctx, ancestor, mresult): |
1088 """Resolves false conflicts where the nodeid changed but the content |
1103 """Resolves false conflicts where the nodeid changed but the content |
1089 remained the same.""" |
1104 remained the same.""" |
1090 # We force a copy of actions.items() because we're going to mutate |
1105 # We force a copy of actions.items() because we're going to mutate |
1091 # actions as we resolve trivial conflicts. |
1106 # actions as we resolve trivial conflicts. |
1092 for f in list(mresult.files((mergestatemod.ACTION_CHANGED_DELETED,))): |
1107 for f in list(mresult.files((mergestatemod.ACTION_CHANGED_DELETED,))): |
1093 if f in ancestor and not wctx[f].cmp(ancestor[f]): |
1108 if f in ancestor and not wctx[f].cmp(ancestor[f]): |
1094 # local did change but ended up with same content |
1109 # local did change but ended up with same content |
1421 ) |
1436 ) |
1422 |
1437 |
1423 prefetch = scmutil.prefetchfiles |
1438 prefetch = scmutil.prefetchfiles |
1424 matchfiles = scmutil.matchfiles |
1439 matchfiles = scmutil.matchfiles |
1425 prefetch( |
1440 prefetch( |
1426 repo, [(ctx.rev(), matchfiles(repo, files),)], |
1441 repo, |
|
1442 [ |
|
1443 ( |
|
1444 ctx.rev(), |
|
1445 matchfiles(repo, files), |
|
1446 ) |
|
1447 ], |
1427 ) |
1448 ) |
1428 |
1449 |
1429 |
1450 |
1430 @attr.s(frozen=True) |
1451 @attr.s(frozen=True) |
1431 class updateresult(object): |
1452 class updateresult(object): |
1442 or self.unresolvedcount |
1463 or self.unresolvedcount |
1443 ) |
1464 ) |
1444 |
1465 |
1445 |
1466 |
1446 def applyupdates( |
1467 def applyupdates( |
1447 repo, mresult, wctx, mctx, overwrite, wantfiledata, labels=None, |
1468 repo, |
|
1469 mresult, |
|
1470 wctx, |
|
1471 mctx, |
|
1472 overwrite, |
|
1473 wantfiledata, |
|
1474 labels=None, |
1448 ): |
1475 ): |
1449 """apply the merge action list to the working directory |
1476 """apply the merge action list to the working directory |
1450 |
1477 |
1451 mresult is a mergeresult object representing result of the merge |
1478 mresult is a mergeresult object representing result of the merge |
1452 wctx is the working copy context |
1479 wctx is the working copy context |
1732 from . import dirstate |
1759 from . import dirstate |
1733 |
1760 |
1734 if dirstate.rustmod is not None: |
1761 if dirstate.rustmod is not None: |
1735 # When using rust status, fsmonitor becomes necessary at higher sizes |
1762 # When using rust status, fsmonitor becomes necessary at higher sizes |
1736 fsmonitorthreshold = repo.ui.configint( |
1763 fsmonitorthreshold = repo.ui.configint( |
1737 b'fsmonitor', b'warn_update_file_count_rust', |
1764 b'fsmonitor', |
|
1765 b'warn_update_file_count_rust', |
1738 ) |
1766 ) |
1739 |
1767 |
1740 try: |
1768 try: |
1741 # avoid cycle: extensions -> cmdutil -> merge |
1769 # avoid cycle: extensions -> cmdutil -> merge |
1742 from . import extensions |
1770 from . import extensions |
1999 ) |
2027 ) |
2000 % prompts, |
2028 % prompts, |
2001 0, |
2029 0, |
2002 ): |
2030 ): |
2003 mresult.addfile( |
2031 mresult.addfile( |
2004 f, mergestatemod.ACTION_REMOVE, None, b'prompt delete', |
2032 f, |
|
2033 mergestatemod.ACTION_REMOVE, |
|
2034 None, |
|
2035 b'prompt delete', |
2005 ) |
2036 ) |
2006 elif f in p1: |
2037 elif f in p1: |
2007 mresult.addfile( |
2038 mresult.addfile( |
2008 f, |
2039 f, |
2009 mergestatemod.ACTION_ADD_MODIFIED, |
2040 mergestatemod.ACTION_ADD_MODIFIED, |
2010 None, |
2041 None, |
2011 b'prompt keep', |
2042 b'prompt keep', |
2012 ) |
2043 ) |
2013 else: |
2044 else: |
2014 mresult.addfile( |
2045 mresult.addfile( |
2015 f, mergestatemod.ACTION_ADD, None, b'prompt keep', |
2046 f, |
|
2047 mergestatemod.ACTION_ADD, |
|
2048 None, |
|
2049 b'prompt keep', |
2016 ) |
2050 ) |
2017 elif m == mergestatemod.ACTION_DELETED_CHANGED: |
2051 elif m == mergestatemod.ACTION_DELETED_CHANGED: |
2018 f1, f2, fa, move, anc = args |
2052 f1, f2, fa, move, anc = args |
2019 flags = p2[f2].flags() |
2053 flags = p2[f2].flags() |
2020 if ( |
2054 if ( |
2087 repo, mresult.len((mergestatemod.ACTION_GET,)), p1.node() |
2121 repo, mresult.len((mergestatemod.ACTION_GET,)), p1.node() |
2088 ) |
2122 ) |
2089 |
2123 |
2090 wantfiledata = updatedirstate and not branchmerge |
2124 wantfiledata = updatedirstate and not branchmerge |
2091 stats, getfiledata = applyupdates( |
2125 stats, getfiledata = applyupdates( |
2092 repo, mresult, wc, p2, overwrite, wantfiledata, labels=labels, |
2126 repo, |
|
2127 mresult, |
|
2128 wc, |
|
2129 p2, |
|
2130 overwrite, |
|
2131 wantfiledata, |
|
2132 labels=labels, |
2093 ) |
2133 ) |
2094 |
2134 |
2095 if updatedirstate: |
2135 if updatedirstate: |
2096 with repo.dirstate.parentchange(): |
2136 with repo.dirstate.parentchange(): |
2097 repo.setparents(fp1, fp2) |
2137 repo.setparents(fp1, fp2) |