Show More
@@ -71,6 +71,23 b" MERGE_RECORD_UNRESOLVED_PATH = b'pu'" | |||||
71 | MERGE_RECORD_RESOLVED_PATH = b'pr' |
|
71 | MERGE_RECORD_RESOLVED_PATH = b'pr' | |
72 | MERGE_RECORD_DRIVER_RESOLVED = b'd' |
|
72 | MERGE_RECORD_DRIVER_RESOLVED = b'd' | |
73 |
|
73 | |||
|
74 | ACTION_FORGET = b'f' | |||
|
75 | ACTION_REMOVE = b'r' | |||
|
76 | ACTION_ADD = b'a' | |||
|
77 | ACTION_GET = b'g' | |||
|
78 | ACTION_PATH_CONFLICT = b'p' | |||
|
79 | ACTION_PATH_CONFLICT_RESOLVE = b'pr' | |||
|
80 | ACTION_ADD_MODIFIED = b'am' | |||
|
81 | ACTION_CREATED = b'c' | |||
|
82 | ACTION_DELETED_CHANGED = b'dc' | |||
|
83 | ACTION_CHANGED_DELETED = b'cd' | |||
|
84 | ACTION_MERGE = b'm' | |||
|
85 | ACTION_LOCAL_DIR_RENAME_GET = b'dg' | |||
|
86 | ACTION_DIR_RENAME_MOVE_LOCAL = b'dm' | |||
|
87 | ACTION_KEEP = b'k' | |||
|
88 | ACTION_EXEC = b'e' | |||
|
89 | ACTION_CREATED_MERGE = b'cm' | |||
|
90 | ||||
74 | class mergestate(object): |
|
91 | class mergestate(object): | |
75 | '''track 3-way merge state of individual files |
|
92 | '''track 3-way merge state of individual files | |
76 |
|
93 | |||
@@ -588,18 +605,18 b' class mergestate(object):' | |||||
588 | if fcd.isabsent(): |
|
605 | if fcd.isabsent(): | |
589 | # dc: local picked. Need to drop if present, which may |
|
606 | # dc: local picked. Need to drop if present, which may | |
590 | # happen on re-resolves. |
|
607 | # happen on re-resolves. | |
591 |
action = |
|
608 | action = ACTION_FORGET | |
592 | else: |
|
609 | else: | |
593 | # cd: remote picked (or otherwise deleted) |
|
610 | # cd: remote picked (or otherwise deleted) | |
594 |
action = |
|
611 | action = ACTION_REMOVE | |
595 | else: |
|
612 | else: | |
596 | if fcd.isabsent(): # dc: remote picked |
|
613 | if fcd.isabsent(): # dc: remote picked | |
597 |
action = |
|
614 | action = ACTION_GET | |
598 | elif fco.isabsent(): # cd: local picked |
|
615 | elif fco.isabsent(): # cd: local picked | |
599 | if dfile in self.localctx: |
|
616 | if dfile in self.localctx: | |
600 |
action = |
|
617 | action = ACTION_ADD_MODIFIED | |
601 | else: |
|
618 | else: | |
602 |
action = |
|
619 | action = ACTION_ADD | |
603 | # else: regular merges (no action necessary) |
|
620 | # else: regular merges (no action necessary) | |
604 | self._results[dfile] = r, action |
|
621 | self._results[dfile] = r, action | |
605 |
|
622 | |||
@@ -631,7 +648,7 b' class mergestate(object):' | |||||
631 | if r is None: |
|
648 | if r is None: | |
632 | updated += 1 |
|
649 | updated += 1 | |
633 | elif r == 0: |
|
650 | elif r == 0: | |
634 |
if action == |
|
651 | if action == ACTION_REMOVE: | |
635 | removed += 1 |
|
652 | removed += 1 | |
636 | else: |
|
653 | else: | |
637 | merged += 1 |
|
654 | merged += 1 | |
@@ -643,7 +660,13 b' class mergestate(object):' | |||||
643 |
|
660 | |||
644 | def actions(self): |
|
661 | def actions(self): | |
645 | """return lists of actions to perform on the dirstate""" |
|
662 | """return lists of actions to perform on the dirstate""" | |
646 | actions = {'r': [], 'f': [], 'a': [], 'am': [], 'g': []} |
|
663 | actions = { | |
|
664 | ACTION_REMOVE: [], | |||
|
665 | ACTION_FORGET: [], | |||
|
666 | ACTION_ADD: [], | |||
|
667 | ACTION_ADD_MODIFIED: [], | |||
|
668 | ACTION_GET: [], | |||
|
669 | } | |||
647 | for f, (r, action) in self._results.iteritems(): |
|
670 | for f, (r, action) in self._results.iteritems(): | |
648 | if action is not None: |
|
671 | if action is not None: | |
649 | actions[action].append((f, None, "merge result")) |
|
672 | actions[action].append((f, None, "merge result")) | |
@@ -658,19 +681,19 b' class mergestate(object):' | |||||
658 | """queues a file to be removed from the dirstate |
|
681 | """queues a file to be removed from the dirstate | |
659 |
|
682 | |||
660 | Meant for use by custom merge drivers.""" |
|
683 | Meant for use by custom merge drivers.""" | |
661 |
self._results[f] = 0, |
|
684 | self._results[f] = 0, ACTION_REMOVE | |
662 |
|
685 | |||
663 | def queueadd(self, f): |
|
686 | def queueadd(self, f): | |
664 | """queues a file to be added to the dirstate |
|
687 | """queues a file to be added to the dirstate | |
665 |
|
688 | |||
666 | Meant for use by custom merge drivers.""" |
|
689 | Meant for use by custom merge drivers.""" | |
667 |
self._results[f] = 0, |
|
690 | self._results[f] = 0, ACTION_ADD | |
668 |
|
691 | |||
669 | def queueget(self, f): |
|
692 | def queueget(self, f): | |
670 | """queues a file to be marked modified in the dirstate |
|
693 | """queues a file to be marked modified in the dirstate | |
671 |
|
694 | |||
672 | Meant for use by custom merge drivers.""" |
|
695 | Meant for use by custom merge drivers.""" | |
673 |
self._results[f] = 0, |
|
696 | self._results[f] = 0, ACTION_GET | |
674 |
|
697 | |||
675 | def _getcheckunknownconfig(repo, section, name): |
|
698 | def _getcheckunknownconfig(repo, section, name): | |
676 | config = repo.ui.config(section, name) |
|
699 | config = repo.ui.config(section, name) | |
@@ -772,14 +795,14 b' def _checkunknownfiles(repo, wctx, mctx,' | |||||
772 |
|
795 | |||
773 | checkunknowndirs = _unknowndirschecker() |
|
796 | checkunknowndirs = _unknowndirschecker() | |
774 | for f, (m, args, msg) in actions.iteritems(): |
|
797 | for f, (m, args, msg) in actions.iteritems(): | |
775 | if m in ('c', 'dc'): |
|
798 | if m in (ACTION_CREATED, ACTION_DELETED_CHANGED): | |
776 | if _checkunknownfile(repo, wctx, mctx, f): |
|
799 | if _checkunknownfile(repo, wctx, mctx, f): | |
777 | fileconflicts.add(f) |
|
800 | fileconflicts.add(f) | |
778 | elif pathconfig and f not in wctx: |
|
801 | elif pathconfig and f not in wctx: | |
779 | path = checkunknowndirs(repo, wctx, f) |
|
802 | path = checkunknowndirs(repo, wctx, f) | |
780 | if path is not None: |
|
803 | if path is not None: | |
781 | pathconflicts.add(path) |
|
804 | pathconflicts.add(path) | |
782 | elif m == 'dg': |
|
805 | elif m == ACTION_LOCAL_DIR_RENAME_GET: | |
783 | if _checkunknownfile(repo, wctx, mctx, f, args[0]): |
|
806 | if _checkunknownfile(repo, wctx, mctx, f, args[0]): | |
784 | fileconflicts.add(f) |
|
807 | fileconflicts.add(f) | |
785 |
|
808 | |||
@@ -791,7 +814,7 b' def _checkunknownfiles(repo, wctx, mctx,' | |||||
791 | collectconflicts(unknownconflicts, unknownconfig) |
|
814 | collectconflicts(unknownconflicts, unknownconfig) | |
792 | else: |
|
815 | else: | |
793 | for f, (m, args, msg) in actions.iteritems(): |
|
816 | for f, (m, args, msg) in actions.iteritems(): | |
794 |
if m == |
|
817 | if m == ACTION_CREATED_MERGE: | |
795 | fl2, anc = args |
|
818 | fl2, anc = args | |
796 | different = _checkunknownfile(repo, wctx, mctx, f) |
|
819 | different = _checkunknownfile(repo, wctx, mctx, f) | |
797 | if repo.dirstate._ignore(f): |
|
820 | if repo.dirstate._ignore(f): | |
@@ -812,16 +835,16 b' def _checkunknownfiles(repo, wctx, mctx,' | |||||
812 | # don't like an abort happening in the middle of |
|
835 | # don't like an abort happening in the middle of | |
813 | # merge.update. |
|
836 | # merge.update. | |
814 | if not different: |
|
837 | if not different: | |
815 |
actions[f] = ( |
|
838 | actions[f] = (ACTION_GET, (fl2, False), 'remote created') | |
816 | elif mergeforce or config == 'abort': |
|
839 | elif mergeforce or config == 'abort': | |
817 |
actions[f] = ( |
|
840 | actions[f] = (ACTION_MERGE, (f, f, None, False, anc), | |
818 |
|
|
841 | 'remote differs from untracked local') | |
819 | elif config == 'abort': |
|
842 | elif config == 'abort': | |
820 | abortconflicts.add(f) |
|
843 | abortconflicts.add(f) | |
821 | else: |
|
844 | else: | |
822 | if config == 'warn': |
|
845 | if config == 'warn': | |
823 | warnconflicts.add(f) |
|
846 | warnconflicts.add(f) | |
824 |
actions[f] = ( |
|
847 | actions[f] = (ACTION_GET, (fl2, True), 'remote created') | |
825 |
|
848 | |||
826 | for f in sorted(abortconflicts): |
|
849 | for f in sorted(abortconflicts): | |
827 | warn = repo.ui.warn |
|
850 | warn = repo.ui.warn | |
@@ -843,11 +866,11 b' def _checkunknownfiles(repo, wctx, mctx,' | |||||
843 | repo.ui.warn(_("%s: replacing untracked files in directory\n") % f) |
|
866 | repo.ui.warn(_("%s: replacing untracked files in directory\n") % f) | |
844 |
|
867 | |||
845 | for f, (m, args, msg) in actions.iteritems(): |
|
868 | for f, (m, args, msg) in actions.iteritems(): | |
846 |
if m == |
|
869 | if m == ACTION_CREATED: | |
847 | backup = (f in fileconflicts or f in pathconflicts or |
|
870 | backup = (f in fileconflicts or f in pathconflicts or | |
848 | any(p in pathconflicts for p in util.finddirs(f))) |
|
871 | any(p in pathconflicts for p in util.finddirs(f))) | |
849 | flags, = args |
|
872 | flags, = args | |
850 |
actions[f] = ( |
|
873 | actions[f] = (ACTION_GET, (flags, backup), msg) | |
851 |
|
874 | |||
852 | def _forgetremoved(wctx, mctx, branchmerge): |
|
875 | def _forgetremoved(wctx, mctx, branchmerge): | |
853 | """ |
|
876 | """ | |
@@ -865,9 +888,9 b' def _forgetremoved(wctx, mctx, branchmer' | |||||
865 | """ |
|
888 | """ | |
866 |
|
889 | |||
867 | actions = {} |
|
890 | actions = {} | |
868 | m = 'f' |
|
891 | m = ACTION_FORGET | |
869 | if branchmerge: |
|
892 | if branchmerge: | |
870 |
m = |
|
893 | m = ACTION_REMOVE | |
871 | for f in wctx.deleted(): |
|
894 | for f in wctx.deleted(): | |
872 | if f not in mctx: |
|
895 | if f not in mctx: | |
873 | actions[f] = m, None, "forget deleted" |
|
896 | actions[f] = m, None, "forget deleted" | |
@@ -875,7 +898,7 b' def _forgetremoved(wctx, mctx, branchmer' | |||||
875 | if not branchmerge: |
|
898 | if not branchmerge: | |
876 | for f in wctx.removed(): |
|
899 | for f in wctx.removed(): | |
877 | if f not in mctx: |
|
900 | if f not in mctx: | |
878 |
actions[f] = |
|
901 | actions[f] = ACTION_FORGET, None, "forget removed" | |
879 |
|
902 | |||
880 | return actions |
|
903 | return actions | |
881 |
|
904 | |||
@@ -884,19 +907,20 b' def _checkcollision(repo, wmf, actions):' | |||||
884 | pmmf = set(wmf) |
|
907 | pmmf = set(wmf) | |
885 |
|
908 | |||
886 | if actions: |
|
909 | if actions: | |
887 |
# |
|
910 | # KEEP and EXEC are no-op | |
888 | for m in 'a', 'am', 'f', 'g', 'cd', 'dc': |
|
911 | for m in (ACTION_ADD, ACTION_ADD_MODIFIED, ACTION_FORGET, ACTION_GET, | |
|
912 | ACTION_CHANGED_DELETED, ACTION_DELETED_CHANGED): | |||
889 | for f, args, msg in actions[m]: |
|
913 | for f, args, msg in actions[m]: | |
890 | pmmf.add(f) |
|
914 | pmmf.add(f) | |
891 |
for f, args, msg in actions[ |
|
915 | for f, args, msg in actions[ACTION_REMOVE]: | |
892 | pmmf.discard(f) |
|
916 | pmmf.discard(f) | |
893 |
for f, args, msg in actions[ |
|
917 | for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]: | |
894 | f2, flags = args |
|
918 | f2, flags = args | |
895 | pmmf.discard(f2) |
|
919 | pmmf.discard(f2) | |
896 | pmmf.add(f) |
|
920 | pmmf.add(f) | |
897 |
for f, args, msg in actions[ |
|
921 | for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]: | |
898 | pmmf.add(f) |
|
922 | pmmf.add(f) | |
899 |
for f, args, msg in actions[ |
|
923 | for f, args, msg in actions[ACTION_MERGE]: | |
900 | f1, f2, fa, move, anc = args |
|
924 | f1, f2, fa, move, anc = args | |
901 | if move: |
|
925 | if move: | |
902 | pmmf.discard(f1) |
|
926 | pmmf.discard(f1) | |
@@ -972,7 +996,8 b' def checkpathconflicts(repo, wctx, mctx,' | |||||
972 | deletedfiles = set() |
|
996 | deletedfiles = set() | |
973 |
|
997 | |||
974 | for f, (m, args, msg) in actions.items(): |
|
998 | for f, (m, args, msg) in actions.items(): | |
975 | if m in ('c', 'dc', 'm', 'cm'): |
|
999 | if m in (ACTION_CREATED, ACTION_DELETED_CHANGED, ACTION_MERGE, | |
|
1000 | ACTION_CREATED_MERGE): | |||
976 | # This action may create a new local file. |
|
1001 | # This action may create a new local file. | |
977 | createdfiledirs.update(util.finddirs(f)) |
|
1002 | createdfiledirs.update(util.finddirs(f)) | |
978 | if mf.hasdir(f): |
|
1003 | if mf.hasdir(f): | |
@@ -981,13 +1006,13 b' def checkpathconflicts(repo, wctx, mctx,' | |||||
981 | # will be checked once we know what all the deleted files are. |
|
1006 | # will be checked once we know what all the deleted files are. | |
982 | remoteconflicts.add(f) |
|
1007 | remoteconflicts.add(f) | |
983 | # Track the names of all deleted files. |
|
1008 | # Track the names of all deleted files. | |
984 |
if m == |
|
1009 | if m == ACTION_REMOVE: | |
985 | deletedfiles.add(f) |
|
1010 | deletedfiles.add(f) | |
986 |
if m == |
|
1011 | if m == ACTION_MERGE: | |
987 | f1, f2, fa, move, anc = args |
|
1012 | f1, f2, fa, move, anc = args | |
988 | if move: |
|
1013 | if move: | |
989 | deletedfiles.add(f1) |
|
1014 | deletedfiles.add(f1) | |
990 | if m == 'dm': |
|
1015 | if m == ACTION_DIR_RENAME_MOVE_LOCAL: | |
991 | f2, flags = args |
|
1016 | f2, flags = args | |
992 | deletedfiles.add(f2) |
|
1017 | deletedfiles.add(f2) | |
993 |
|
1018 | |||
@@ -1003,7 +1028,10 b' def checkpathconflicts(repo, wctx, mctx,' | |||||
1003 | # A file is in a directory which aliases a local file. |
|
1028 | # A file is in a directory which aliases a local file. | |
1004 | # We will need to rename the local file. |
|
1029 | # We will need to rename the local file. | |
1005 | localconflicts.add(p) |
|
1030 | localconflicts.add(p) | |
1006 |
if p in actions and actions[p][0] in ( |
|
1031 | if p in actions and actions[p][0] in (ACTION_CREATED, | |
|
1032 | ACTION_DELETED_CHANGED, | |||
|
1033 | ACTION_MERGE, | |||
|
1034 | ACTION_CREATED_MERGE): | |||
1007 | # The file is in a directory which aliases a remote file. |
|
1035 | # The file is in a directory which aliases a remote file. | |
1008 | # This is an internal inconsistency within the remote |
|
1036 | # This is an internal inconsistency within the remote | |
1009 | # manifest. |
|
1037 | # manifest. | |
@@ -1014,8 +1042,10 b' def checkpathconflicts(repo, wctx, mctx,' | |||||
1014 | if p not in deletedfiles: |
|
1042 | if p not in deletedfiles: | |
1015 | ctxname = bytes(wctx).rstrip('+') |
|
1043 | ctxname = bytes(wctx).rstrip('+') | |
1016 | pnew = util.safename(p, ctxname, wctx, set(actions.keys())) |
|
1044 | pnew = util.safename(p, ctxname, wctx, set(actions.keys())) | |
1017 | actions[pnew] = ('pr', (p,), "local path conflict") |
|
1045 | actions[pnew] = (ACTION_PATH_CONFLICT_RESOLVE, (p,), | |
1018 | actions[p] = ('p', (pnew, 'l'), "path conflict") |
|
1046 | 'local path conflict') | |
|
1047 | actions[p] = (ACTION_PATH_CONFLICT, (pnew, 'l'), | |||
|
1048 | 'path conflict') | |||
1019 |
|
1049 | |||
1020 | if remoteconflicts: |
|
1050 | if remoteconflicts: | |
1021 | # Check if all files in the conflicting directories have been removed. |
|
1051 | # Check if all files in the conflicting directories have been removed. | |
@@ -1024,14 +1054,16 b' def checkpathconflicts(repo, wctx, mctx,' | |||||
1024 | if f not in deletedfiles: |
|
1054 | if f not in deletedfiles: | |
1025 | m, args, msg = actions[p] |
|
1055 | m, args, msg = actions[p] | |
1026 | pnew = util.safename(p, ctxname, wctx, set(actions.keys())) |
|
1056 | pnew = util.safename(p, ctxname, wctx, set(actions.keys())) | |
1027 | if m in ('dc', 'm'): |
|
1057 | if m in (ACTION_DELETED_CHANGED, ACTION_MERGE): | |
1028 | # Action was merge, just update target. |
|
1058 | # Action was merge, just update target. | |
1029 | actions[pnew] = (m, args, msg) |
|
1059 | actions[pnew] = (m, args, msg) | |
1030 | else: |
|
1060 | else: | |
1031 | # Action was create, change to renamed get action. |
|
1061 | # Action was create, change to renamed get action. | |
1032 | fl = args[0] |
|
1062 | fl = args[0] | |
1033 |
actions[pnew] = ( |
|
1063 | actions[pnew] = (ACTION_LOCAL_DIR_RENAME_GET, (p, fl), | |
1034 | actions[p] = ('p', (pnew, 'r'), "path conflict") |
|
1064 | 'remote path conflict') | |
|
1065 | actions[p] = (ACTION_PATH_CONFLICT, (pnew, ACTION_REMOVE), | |||
|
1066 | 'path conflict') | |||
1035 | remoteconflicts.remove(p) |
|
1067 | remoteconflicts.remove(p) | |
1036 | break |
|
1068 | break | |
1037 |
|
1069 | |||
@@ -1109,77 +1141,80 b' def manifestmerge(repo, wctx, p2, pa, br' | |||||
1109 | if f not in ma: |
|
1141 | if f not in ma: | |
1110 | fa = copy.get(f, None) |
|
1142 | fa = copy.get(f, None) | |
1111 | if fa is not None: |
|
1143 | if fa is not None: | |
1112 |
actions[f] = ( |
|
1144 | actions[f] = (ACTION_MERGE, (f, f, fa, False, pa.node()), | |
1113 |
|
|
1145 | 'both renamed from %s' % fa) | |
1114 | else: |
|
1146 | else: | |
1115 |
actions[f] = ( |
|
1147 | actions[f] = (ACTION_MERGE, (f, f, None, False, pa.node()), | |
1116 |
|
|
1148 | 'both created') | |
1117 | else: |
|
1149 | else: | |
1118 | a = ma[f] |
|
1150 | a = ma[f] | |
1119 | fla = ma.flags(f) |
|
1151 | fla = ma.flags(f) | |
1120 | nol = 'l' not in fl1 + fl2 + fla |
|
1152 | nol = 'l' not in fl1 + fl2 + fla | |
1121 | if n2 == a and fl2 == fla: |
|
1153 | if n2 == a and fl2 == fla: | |
1122 |
actions[f] = ( |
|
1154 | actions[f] = (ACTION_KEEP, (), 'remote unchanged') | |
1123 | elif n1 == a and fl1 == fla: # local unchanged - use remote |
|
1155 | elif n1 == a and fl1 == fla: # local unchanged - use remote | |
1124 | if n1 == n2: # optimization: keep local content |
|
1156 | if n1 == n2: # optimization: keep local content | |
1125 |
actions[f] = ( |
|
1157 | actions[f] = (ACTION_EXEC, (fl2,), 'update permissions') | |
1126 | else: |
|
1158 | else: | |
1127 |
actions[f] = ( |
|
1159 | actions[f] = (ACTION_GET, (fl2, False), | |
|
1160 | 'remote is newer') | |||
1128 | elif nol and n2 == a: # remote only changed 'x' |
|
1161 | elif nol and n2 == a: # remote only changed 'x' | |
1129 |
actions[f] = ( |
|
1162 | actions[f] = (ACTION_EXEC, (fl2,), 'update permissions') | |
1130 | elif nol and n1 == a: # local only changed 'x' |
|
1163 | elif nol and n1 == a: # local only changed 'x' | |
1131 |
actions[f] = ( |
|
1164 | actions[f] = (ACTION_GET, (fl1, False), 'remote is newer') | |
1132 | else: # both changed something |
|
1165 | else: # both changed something | |
1133 |
actions[f] = ( |
|
1166 | actions[f] = (ACTION_MERGE, (f, f, f, False, pa.node()), | |
1134 |
|
|
1167 | 'versions differ') | |
1135 | elif n1: # file exists only on local side |
|
1168 | elif n1: # file exists only on local side | |
1136 | if f in copied: |
|
1169 | if f in copied: | |
1137 | pass # we'll deal with it on m2 side |
|
1170 | pass # we'll deal with it on m2 side | |
1138 | elif f in movewithdir: # directory rename, move local |
|
1171 | elif f in movewithdir: # directory rename, move local | |
1139 | f2 = movewithdir[f] |
|
1172 | f2 = movewithdir[f] | |
1140 | if f2 in m2: |
|
1173 | if f2 in m2: | |
1141 |
actions[f2] = ( |
|
1174 | actions[f2] = (ACTION_MERGE, (f, f2, None, True, pa.node()), | |
1142 |
|
|
1175 | 'remote directory rename, both created') | |
1143 | else: |
|
1176 | else: | |
1144 |
actions[f2] = ( |
|
1177 | actions[f2] = (ACTION_DIR_RENAME_MOVE_LOCAL, (f, fl1), | |
1145 |
|
|
1178 | 'remote directory rename - move from %s' % f) | |
1146 | elif f in copy: |
|
1179 | elif f in copy: | |
1147 | f2 = copy[f] |
|
1180 | f2 = copy[f] | |
1148 |
actions[f] = ( |
|
1181 | actions[f] = (ACTION_MERGE, (f, f2, f2, False, pa.node()), | |
1149 |
|
|
1182 | 'local copied/moved from %s' % f2) | |
1150 | elif f in ma: # clean, a different, no remote |
|
1183 | elif f in ma: # clean, a different, no remote | |
1151 | if n1 != ma[f]: |
|
1184 | if n1 != ma[f]: | |
1152 | if acceptremote: |
|
1185 | if acceptremote: | |
1153 |
actions[f] = ( |
|
1186 | actions[f] = (ACTION_REMOVE, None, 'remote delete') | |
1154 | else: |
|
1187 | else: | |
1155 | actions[f] = ('cd', (f, None, f, False, pa.node()), |
|
1188 | actions[f] = (ACTION_CHANGED_DELETED, | |
1156 |
|
|
1189 | (f, None, f, False, pa.node()), | |
|
1190 | 'prompt changed/deleted') | |||
1157 | elif n1 == addednodeid: |
|
1191 | elif n1 == addednodeid: | |
1158 | # This extra 'a' is added by working copy manifest to mark |
|
1192 | # This extra 'a' is added by working copy manifest to mark | |
1159 | # the file as locally added. We should forget it instead of |
|
1193 | # the file as locally added. We should forget it instead of | |
1160 | # deleting it. |
|
1194 | # deleting it. | |
1161 |
actions[f] = ( |
|
1195 | actions[f] = (ACTION_FORGET, None, 'remote deleted') | |
1162 | else: |
|
1196 | else: | |
1163 |
actions[f] = ( |
|
1197 | actions[f] = (ACTION_REMOVE, None, 'other deleted') | |
1164 | elif n2: # file exists only on remote side |
|
1198 | elif n2: # file exists only on remote side | |
1165 | if f in copied: |
|
1199 | if f in copied: | |
1166 | pass # we'll deal with it on m1 side |
|
1200 | pass # we'll deal with it on m1 side | |
1167 | elif f in movewithdir: |
|
1201 | elif f in movewithdir: | |
1168 | f2 = movewithdir[f] |
|
1202 | f2 = movewithdir[f] | |
1169 | if f2 in m1: |
|
1203 | if f2 in m1: | |
1170 |
actions[f2] = ( |
|
1204 | actions[f2] = (ACTION_MERGE, | |
1171 |
|
|
1205 | (f2, f, None, False, pa.node()), | |
|
1206 | 'local directory rename, both created') | |||
1172 | else: |
|
1207 | else: | |
1173 |
actions[f2] = ( |
|
1208 | actions[f2] = (ACTION_LOCAL_DIR_RENAME_GET, (f, fl2), | |
1174 |
|
|
1209 | 'local directory rename - get from %s' % f) | |
1175 | elif f in copy: |
|
1210 | elif f in copy: | |
1176 | f2 = copy[f] |
|
1211 | f2 = copy[f] | |
1177 | if f2 in m2: |
|
1212 | if f2 in m2: | |
1178 |
actions[f] = ( |
|
1213 | actions[f] = (ACTION_MERGE, (f2, f, f2, False, pa.node()), | |
1179 |
|
|
1214 | 'remote copied from %s' % f2) | |
1180 | else: |
|
1215 | else: | |
1181 |
actions[f] = ( |
|
1216 | actions[f] = (ACTION_MERGE, (f2, f, f2, True, pa.node()), | |
1182 |
|
|
1217 | 'remote moved from %s' % f2) | |
1183 | elif f not in ma: |
|
1218 | elif f not in ma: | |
1184 | # local unknown, remote created: the logic is described by the |
|
1219 | # local unknown, remote created: the logic is described by the | |
1185 | # following table: |
|
1220 | # following table: | |
@@ -1193,12 +1228,12 b' def manifestmerge(repo, wctx, p2, pa, br' | |||||
1193 | # Checking whether the files are different is expensive, so we |
|
1228 | # Checking whether the files are different is expensive, so we | |
1194 | # don't do that when we can avoid it. |
|
1229 | # don't do that when we can avoid it. | |
1195 | if not force: |
|
1230 | if not force: | |
1196 |
actions[f] = ( |
|
1231 | actions[f] = (ACTION_CREATED, (fl2,), 'remote created') | |
1197 | elif not branchmerge: |
|
1232 | elif not branchmerge: | |
1198 |
actions[f] = ( |
|
1233 | actions[f] = (ACTION_CREATED, (fl2,), 'remote created') | |
1199 | else: |
|
1234 | else: | |
1200 |
actions[f] = ( |
|
1235 | actions[f] = (ACTION_CREATED_MERGE, (fl2, pa.node()), | |
1201 |
|
|
1236 | 'remote created, get or merge') | |
1202 | elif n2 != ma[f]: |
|
1237 | elif n2 != ma[f]: | |
1203 | df = None |
|
1238 | df = None | |
1204 | for d in dirmove: |
|
1239 | for d in dirmove: | |
@@ -1207,13 +1242,15 b' def manifestmerge(repo, wctx, p2, pa, br' | |||||
1207 | df = dirmove[d] + f[len(d):] |
|
1242 | df = dirmove[d] + f[len(d):] | |
1208 | break |
|
1243 | break | |
1209 | if df is not None and df in m1: |
|
1244 | if df is not None and df in m1: | |
1210 |
actions[df] = ( |
|
1245 | actions[df] = (ACTION_MERGE, (df, f, f, False, pa.node()), | |
1211 |
|
|
1246 | 'local directory rename - respect move ' | |
|
1247 | 'from %s' % f) | |||
1212 | elif acceptremote: |
|
1248 | elif acceptremote: | |
1213 |
actions[f] = ( |
|
1249 | actions[f] = (ACTION_CREATED, (fl2,), 'remote recreating') | |
1214 | else: |
|
1250 | else: | |
1215 | actions[f] = ('dc', (None, f, f, False, pa.node()), |
|
1251 | actions[f] = (ACTION_DELETED_CHANGED, | |
1216 |
|
|
1252 | (None, f, f, False, pa.node()), | |
|
1253 | 'prompt deleted/changed') | |||
1217 |
|
1254 | |||
1218 | if repo.ui.configbool('experimental', 'merge.checkpathconflicts'): |
|
1255 | if repo.ui.configbool('experimental', 'merge.checkpathconflicts'): | |
1219 | # If we are merging, look for path conflicts. |
|
1256 | # If we are merging, look for path conflicts. | |
@@ -1227,10 +1264,12 b' def _resolvetrivial(repo, wctx, mctx, an' | |||||
1227 | # We force a copy of actions.items() because we're going to mutate |
|
1264 | # We force a copy of actions.items() because we're going to mutate | |
1228 | # actions as we resolve trivial conflicts. |
|
1265 | # actions as we resolve trivial conflicts. | |
1229 | for f, (m, args, msg) in list(actions.items()): |
|
1266 | for f, (m, args, msg) in list(actions.items()): | |
1230 | if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]): |
|
1267 | if (m == ACTION_CHANGED_DELETED and f in ancestor | |
|
1268 | and not wctx[f].cmp(ancestor[f])): | |||
1231 | # local did change but ended up with same content |
|
1269 | # local did change but ended up with same content | |
1232 |
actions[f] = |
|
1270 | actions[f] = ACTION_REMOVE, None, 'prompt same' | |
1233 | elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]): |
|
1271 | elif (m == ACTION_DELETED_CHANGED and f in ancestor | |
|
1272 | and not mctx[f].cmp(ancestor[f])): | |||
1234 | # remote did change but ended up with same content |
|
1273 | # remote did change but ended up with same content | |
1235 | del actions[f] # don't get = keep local deleted |
|
1274 | del actions[f] # don't get = keep local deleted | |
1236 |
|
1275 | |||
@@ -1294,18 +1333,18 b' def calculateupdates(repo, wctx, mctx, a' | |||||
1294 | if all(a == l[0] for a in l[1:]): # len(bids) is > 1 |
|
1333 | if all(a == l[0] for a in l[1:]): # len(bids) is > 1 | |
1295 | repo.ui.note(_(" %s: consensus for %s\n") % (f, m)) |
|
1334 | repo.ui.note(_(" %s: consensus for %s\n") % (f, m)) | |
1296 | actions[f] = l[0] |
|
1335 | actions[f] = l[0] | |
1297 |
if m == |
|
1336 | if m == ACTION_DIR_RENAME_MOVE_LOCAL: | |
1298 | dms.append(f) |
|
1337 | dms.append(f) | |
1299 | continue |
|
1338 | continue | |
1300 | # If keep is an option, just do it. |
|
1339 | # If keep is an option, just do it. | |
1301 |
if |
|
1340 | if ACTION_KEEP in bids: | |
1302 | repo.ui.note(_(" %s: picking 'keep' action\n") % f) |
|
1341 | repo.ui.note(_(" %s: picking 'keep' action\n") % f) | |
1303 |
actions[f] = bids[ |
|
1342 | actions[f] = bids[ACTION_KEEP][0] | |
1304 | continue |
|
1343 | continue | |
1305 | # If there are gets and they all agree [how could they not?], do it. |
|
1344 | # If there are gets and they all agree [how could they not?], do it. | |
1306 |
if |
|
1345 | if ACTION_GET in bids: | |
1307 |
ga0 = bids[ |
|
1346 | ga0 = bids[ACTION_GET][0] | |
1308 |
if all(a == ga0 for a in bids[ |
|
1347 | if all(a == ga0 for a in bids[ACTION_GET][1:]): | |
1309 | repo.ui.note(_(" %s: picking 'get' action\n") % f) |
|
1348 | repo.ui.note(_(" %s: picking 'get' action\n") % f) | |
1310 | actions[f] = ga0 |
|
1349 | actions[f] = ga0 | |
1311 | continue |
|
1350 | continue | |
@@ -1320,14 +1359,14 b' def calculateupdates(repo, wctx, mctx, a' | |||||
1320 | repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') % |
|
1359 | repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') % | |
1321 | (f, m)) |
|
1360 | (f, m)) | |
1322 | actions[f] = l[0] |
|
1361 | actions[f] = l[0] | |
1323 | if m == 'dm': |
|
1362 | if m == ACTION_DIR_RENAME_MOVE_LOCAL: | |
1324 | dms.append(f) |
|
1363 | dms.append(f) | |
1325 | continue |
|
1364 | continue | |
1326 | # Work around 'dm' that can cause multiple actions for the same file |
|
1365 | # Work around 'dm' that can cause multiple actions for the same file | |
1327 | for f in dms: |
|
1366 | for f in dms: | |
1328 | dm, (f0, flags), msg = actions[f] |
|
1367 | dm, (f0, flags), msg = actions[f] | |
1329 |
assert dm == |
|
1368 | assert dm == ACTION_DIR_RENAME_MOVE_LOCAL, dm | |
1330 |
if f0 in actions and actions[f0][0] == |
|
1369 | if f0 in actions and actions[f0][0] == ACTION_REMOVE: | |
1331 | # We have one bid for removing a file and another for moving it. |
|
1370 | # We have one bid for removing a file and another for moving it. | |
1332 | # These two could be merged as first move and then delete ... |
|
1371 | # These two could be merged as first move and then delete ... | |
1333 | # but instead drop moving and just delete. |
|
1372 | # but instead drop moving and just delete. | |
@@ -1432,7 +1471,8 b' def _prefetchfiles(repo, ctx, actions):' | |||||
1432 | # Skipping 'a', 'am', 'f', 'r', 'dm', 'e', 'k', 'p' and 'pr', because they |
|
1471 | # Skipping 'a', 'am', 'f', 'r', 'dm', 'e', 'k', 'p' and 'pr', because they | |
1433 | # don't touch the context to be merged in. 'cd' is skipped, because |
|
1472 | # don't touch the context to be merged in. 'cd' is skipped, because | |
1434 | # changed/deleted never resolves to something from the remote side. |
|
1473 | # changed/deleted never resolves to something from the remote side. | |
1435 | oplist = [actions[a] for a in 'g dc dg m'.split()] |
|
1474 | oplist = [actions[a] for a in (ACTION_GET, ACTION_DELETED_CHANGED, | |
|
1475 | ACTION_LOCAL_DIR_RENAME_GET, ACTION_MERGE)] | |||
1436 | prefetch = scmutil.fileprefetchhooks |
|
1476 | prefetch = scmutil.fileprefetchhooks | |
1437 | prefetch(repo, ctx, [f for sublist in oplist for f, args, msg in sublist]) |
|
1477 | prefetch(repo, ctx, [f for sublist in oplist for f, args, msg in sublist]) | |
1438 |
|
1478 | |||
@@ -1479,9 +1519,9 b' def applyupdates(repo, actions, wctx, mc' | |||||
1479 | l.sort() |
|
1519 | l.sort() | |
1480 |
|
1520 | |||
1481 | # 'cd' and 'dc' actions are treated like other merge conflicts |
|
1521 | # 'cd' and 'dc' actions are treated like other merge conflicts | |
1482 |
mergeactions = sorted(actions[ |
|
1522 | mergeactions = sorted(actions[ACTION_CHANGED_DELETED]) | |
1483 |
mergeactions.extend(sorted(actions[ |
|
1523 | mergeactions.extend(sorted(actions[ACTION_DELETED_CHANGED])) | |
1484 |
mergeactions.extend(actions[ |
|
1524 | mergeactions.extend(actions[ACTION_MERGE]) | |
1485 | for f, args, msg in mergeactions: |
|
1525 | for f, args, msg in mergeactions: | |
1486 | f1, f2, fa, move, anc = args |
|
1526 | f1, f2, fa, move, anc = args | |
1487 | if f == '.hgsubstate': # merged internally |
|
1527 | if f == '.hgsubstate': # merged internally | |
@@ -1516,14 +1556,15 b' def applyupdates(repo, actions, wctx, mc' | |||||
1516 | wctx[f].audit() |
|
1556 | wctx[f].audit() | |
1517 | wctx[f].remove() |
|
1557 | wctx[f].remove() | |
1518 |
|
1558 | |||
1519 |
numupdates = sum(len(l) for m, l in actions.items() |
|
1559 | numupdates = sum(len(l) for m, l in actions.items() | |
|
1560 | if m != ACTION_KEEP) | |||
1520 | z = 0 |
|
1561 | z = 0 | |
1521 |
|
1562 | |||
1522 |
if [a for a in actions[ |
|
1563 | if [a for a in actions[ACTION_REMOVE] if a[0] == '.hgsubstate']: | |
1523 | subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels) |
|
1564 | subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels) | |
1524 |
|
1565 | |||
1525 | # record path conflicts |
|
1566 | # record path conflicts | |
1526 |
for f, args, msg in actions[ |
|
1567 | for f, args, msg in actions[ACTION_PATH_CONFLICT]: | |
1527 | f1, fo = args |
|
1568 | f1, fo = args | |
1528 | s = repo.ui.status |
|
1569 | s = repo.ui.status | |
1529 | s(_("%s: path conflict - a file or link has the same name as a " |
|
1570 | s(_("%s: path conflict - a file or link has the same name as a " | |
@@ -1543,14 +1584,14 b' def applyupdates(repo, actions, wctx, mc' | |||||
1543 |
|
1584 | |||
1544 | # remove in parallel (must come before resolving path conflicts and getting) |
|
1585 | # remove in parallel (must come before resolving path conflicts and getting) | |
1545 | prog = worker.worker(repo.ui, cost, batchremove, (repo, wctx), |
|
1586 | prog = worker.worker(repo.ui, cost, batchremove, (repo, wctx), | |
1546 |
actions[ |
|
1587 | actions[ACTION_REMOVE]) | |
1547 | for i, item in prog: |
|
1588 | for i, item in prog: | |
1548 | z += i |
|
1589 | z += i | |
1549 | progress(_updating, z, item=item, total=numupdates, unit=_files) |
|
1590 | progress(_updating, z, item=item, total=numupdates, unit=_files) | |
1550 |
removed = len(actions[ |
|
1591 | removed = len(actions[ACTION_REMOVE]) | |
1551 |
|
1592 | |||
1552 | # resolve path conflicts (must come before getting) |
|
1593 | # resolve path conflicts (must come before getting) | |
1553 |
for f, args, msg in actions[ |
|
1594 | for f, args, msg in actions[ACTION_PATH_CONFLICT_RESOLVE]: | |
1554 | repo.ui.debug(" %s: %s -> pr\n" % (f, msg)) |
|
1595 | repo.ui.debug(" %s: %s -> pr\n" % (f, msg)) | |
1555 | f0, = args |
|
1596 | f0, = args | |
1556 | if wctx[f0].lexists(): |
|
1597 | if wctx[f0].lexists(): | |
@@ -1563,40 +1604,40 b' def applyupdates(repo, actions, wctx, mc' | |||||
1563 |
|
1604 | |||
1564 | # get in parallel |
|
1605 | # get in parallel | |
1565 | prog = worker.worker(repo.ui, cost, batchget, (repo, mctx, wctx), |
|
1606 | prog = worker.worker(repo.ui, cost, batchget, (repo, mctx, wctx), | |
1566 |
actions[ |
|
1607 | actions[ACTION_GET]) | |
1567 | for i, item in prog: |
|
1608 | for i, item in prog: | |
1568 | z += i |
|
1609 | z += i | |
1569 | progress(_updating, z, item=item, total=numupdates, unit=_files) |
|
1610 | progress(_updating, z, item=item, total=numupdates, unit=_files) | |
1570 |
updated = len(actions[ |
|
1611 | updated = len(actions[ACTION_GET]) | |
1571 |
|
1612 | |||
1572 |
if [a for a in actions[ |
|
1613 | if [a for a in actions[ACTION_GET] if a[0] == '.hgsubstate']: | |
1573 | subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels) |
|
1614 | subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels) | |
1574 |
|
1615 | |||
1575 | # forget (manifest only, just log it) (must come first) |
|
1616 | # forget (manifest only, just log it) (must come first) | |
1576 |
for f, args, msg in actions[ |
|
1617 | for f, args, msg in actions[ACTION_FORGET]: | |
1577 | repo.ui.debug(" %s: %s -> f\n" % (f, msg)) |
|
1618 | repo.ui.debug(" %s: %s -> f\n" % (f, msg)) | |
1578 | z += 1 |
|
1619 | z += 1 | |
1579 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
1620 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
1580 |
|
1621 | |||
1581 | # re-add (manifest only, just log it) |
|
1622 | # re-add (manifest only, just log it) | |
1582 |
for f, args, msg in actions[ |
|
1623 | for f, args, msg in actions[ACTION_ADD]: | |
1583 | repo.ui.debug(" %s: %s -> a\n" % (f, msg)) |
|
1624 | repo.ui.debug(" %s: %s -> a\n" % (f, msg)) | |
1584 | z += 1 |
|
1625 | z += 1 | |
1585 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
1626 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
1586 |
|
1627 | |||
1587 | # re-add/mark as modified (manifest only, just log it) |
|
1628 | # re-add/mark as modified (manifest only, just log it) | |
1588 |
for f, args, msg in actions[ |
|
1629 | for f, args, msg in actions[ACTION_ADD_MODIFIED]: | |
1589 | repo.ui.debug(" %s: %s -> am\n" % (f, msg)) |
|
1630 | repo.ui.debug(" %s: %s -> am\n" % (f, msg)) | |
1590 | z += 1 |
|
1631 | z += 1 | |
1591 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
1632 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
1592 |
|
1633 | |||
1593 | # keep (noop, just log it) |
|
1634 | # keep (noop, just log it) | |
1594 |
for f, args, msg in actions[ |
|
1635 | for f, args, msg in actions[ACTION_KEEP]: | |
1595 | repo.ui.debug(" %s: %s -> k\n" % (f, msg)) |
|
1636 | repo.ui.debug(" %s: %s -> k\n" % (f, msg)) | |
1596 | # no progress |
|
1637 | # no progress | |
1597 |
|
1638 | |||
1598 | # directory rename, move local |
|
1639 | # directory rename, move local | |
1599 |
for f, args, msg in actions[ |
|
1640 | for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]: | |
1600 | repo.ui.debug(" %s: %s -> dm\n" % (f, msg)) |
|
1641 | repo.ui.debug(" %s: %s -> dm\n" % (f, msg)) | |
1601 | z += 1 |
|
1642 | z += 1 | |
1602 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
1643 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
@@ -1608,7 +1649,7 b' def applyupdates(repo, actions, wctx, mc' | |||||
1608 | updated += 1 |
|
1649 | updated += 1 | |
1609 |
|
1650 | |||
1610 | # local directory rename, get |
|
1651 | # local directory rename, get | |
1611 |
for f, args, msg in actions[ |
|
1652 | for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]: | |
1612 | repo.ui.debug(" %s: %s -> dg\n" % (f, msg)) |
|
1653 | repo.ui.debug(" %s: %s -> dg\n" % (f, msg)) | |
1613 | z += 1 |
|
1654 | z += 1 | |
1614 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
1655 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
@@ -1618,7 +1659,7 b' def applyupdates(repo, actions, wctx, mc' | |||||
1618 | updated += 1 |
|
1659 | updated += 1 | |
1619 |
|
1660 | |||
1620 | # exec |
|
1661 | # exec | |
1621 |
for f, args, msg in actions[ |
|
1662 | for f, args, msg in actions[ACTION_EXEC]: | |
1622 | repo.ui.debug(" %s: %s -> e\n" % (f, msg)) |
|
1663 | repo.ui.debug(" %s: %s -> e\n" % (f, msg)) | |
1623 | z += 1 |
|
1664 | z += 1 | |
1624 | progress(_updating, z, item=f, total=numupdates, unit=_files) |
|
1665 | progress(_updating, z, item=f, total=numupdates, unit=_files) | |
@@ -1696,17 +1737,17 b' def applyupdates(repo, actions, wctx, mc' | |||||
1696 |
|
1737 | |||
1697 | extraactions = ms.actions() |
|
1738 | extraactions = ms.actions() | |
1698 | if extraactions: |
|
1739 | if extraactions: | |
1699 |
mfiles = set(a[0] for a in actions[ |
|
1740 | mfiles = set(a[0] for a in actions[ACTION_MERGE]) | |
1700 | for k, acts in extraactions.iteritems(): |
|
1741 | for k, acts in extraactions.iteritems(): | |
1701 | actions[k].extend(acts) |
|
1742 | actions[k].extend(acts) | |
1702 |
# Remove these files from actions[ |
|
1743 | # Remove these files from actions[ACTION_MERGE] as well. This is | |
1703 |
# because in recordupdates, files in actions[ |
|
1744 | # important because in recordupdates, files in actions[ACTION_MERGE] | |
1704 |
# after files in other actions, and the merge driver |
|
1745 | # are processed after files in other actions, and the merge driver | |
1705 |
# files to those actions via extraactions above. This can |
|
1746 | # might add files to those actions via extraactions above. This can | |
1706 |
# file being recorded twice, with poor results. This is |
|
1747 | # lead to a file being recorded twice, with poor results. This is | |
1707 |
# problematic for actions[ |
|
1748 | # especially problematic for actions[ACTION_REMOVE] (currently only | |
1708 |
# merge driver in the initial merge process; |
|
1749 | # possible with the merge driver in the initial merge process; | |
1709 | # don't go through this flow). |
|
1750 | # interrupted merges don't go through this flow). | |
1710 | # |
|
1751 | # | |
1711 | # The real fix here is to have indexes by both file and action so |
|
1752 | # The real fix here is to have indexes by both file and action so | |
1712 | # that when the action for a file is changed it is automatically |
|
1753 | # that when the action for a file is changed it is automatically | |
@@ -1717,7 +1758,8 b' def applyupdates(repo, actions, wctx, mc' | |||||
1717 | # those lists aren't consulted again. |
|
1758 | # those lists aren't consulted again. | |
1718 | mfiles.difference_update(a[0] for a in acts) |
|
1759 | mfiles.difference_update(a[0] for a in acts) | |
1719 |
|
1760 | |||
1720 |
actions[ |
|
1761 | actions[ACTION_MERGE] = [a for a in actions[ACTION_MERGE] | |
|
1762 | if a[0] in mfiles] | |||
1721 |
|
1763 | |||
1722 | progress(_updating, None, total=numupdates, unit=_files) |
|
1764 | progress(_updating, None, total=numupdates, unit=_files) | |
1723 | return updateresult(updated, merged, removed, unresolved) |
|
1765 | return updateresult(updated, merged, removed, unresolved) | |
@@ -1725,18 +1767,18 b' def applyupdates(repo, actions, wctx, mc' | |||||
1725 | def recordupdates(repo, actions, branchmerge): |
|
1767 | def recordupdates(repo, actions, branchmerge): | |
1726 | "record merge actions to the dirstate" |
|
1768 | "record merge actions to the dirstate" | |
1727 | # remove (must come first) |
|
1769 | # remove (must come first) | |
1728 |
for f, args, msg in actions.get( |
|
1770 | for f, args, msg in actions.get(ACTION_REMOVE, []): | |
1729 | if branchmerge: |
|
1771 | if branchmerge: | |
1730 | repo.dirstate.remove(f) |
|
1772 | repo.dirstate.remove(f) | |
1731 | else: |
|
1773 | else: | |
1732 | repo.dirstate.drop(f) |
|
1774 | repo.dirstate.drop(f) | |
1733 |
|
1775 | |||
1734 | # forget (must come first) |
|
1776 | # forget (must come first) | |
1735 |
for f, args, msg in actions.get( |
|
1777 | for f, args, msg in actions.get(ACTION_FORGET, []): | |
1736 | repo.dirstate.drop(f) |
|
1778 | repo.dirstate.drop(f) | |
1737 |
|
1779 | |||
1738 | # resolve path conflicts |
|
1780 | # resolve path conflicts | |
1739 |
for f, args, msg in actions.get( |
|
1781 | for f, args, msg in actions.get(ACTION_PATH_CONFLICT_RESOLVE, []): | |
1740 | f0, = args |
|
1782 | f0, = args | |
1741 | origf0 = repo.dirstate.copied(f0) or f0 |
|
1783 | origf0 = repo.dirstate.copied(f0) or f0 | |
1742 | repo.dirstate.add(f) |
|
1784 | repo.dirstate.add(f) | |
@@ -1747,33 +1789,33 b' def recordupdates(repo, actions, branchm' | |||||
1747 | repo.dirstate.drop(f0) |
|
1789 | repo.dirstate.drop(f0) | |
1748 |
|
1790 | |||
1749 | # re-add |
|
1791 | # re-add | |
1750 |
for f, args, msg in actions.get( |
|
1792 | for f, args, msg in actions.get(ACTION_ADD, []): | |
1751 | repo.dirstate.add(f) |
|
1793 | repo.dirstate.add(f) | |
1752 |
|
1794 | |||
1753 | # re-add/mark as modified |
|
1795 | # re-add/mark as modified | |
1754 |
for f, args, msg in actions.get( |
|
1796 | for f, args, msg in actions.get(ACTION_ADD_MODIFIED, []): | |
1755 | if branchmerge: |
|
1797 | if branchmerge: | |
1756 | repo.dirstate.normallookup(f) |
|
1798 | repo.dirstate.normallookup(f) | |
1757 | else: |
|
1799 | else: | |
1758 | repo.dirstate.add(f) |
|
1800 | repo.dirstate.add(f) | |
1759 |
|
1801 | |||
1760 | # exec change |
|
1802 | # exec change | |
1761 |
for f, args, msg in actions.get( |
|
1803 | for f, args, msg in actions.get(ACTION_EXEC, []): | |
1762 | repo.dirstate.normallookup(f) |
|
1804 | repo.dirstate.normallookup(f) | |
1763 |
|
1805 | |||
1764 | # keep |
|
1806 | # keep | |
1765 |
for f, args, msg in actions.get( |
|
1807 | for f, args, msg in actions.get(ACTION_KEEP, []): | |
1766 | pass |
|
1808 | pass | |
1767 |
|
1809 | |||
1768 | # get |
|
1810 | # get | |
1769 |
for f, args, msg in actions.get( |
|
1811 | for f, args, msg in actions.get(ACTION_GET, []): | |
1770 | if branchmerge: |
|
1812 | if branchmerge: | |
1771 | repo.dirstate.otherparent(f) |
|
1813 | repo.dirstate.otherparent(f) | |
1772 | else: |
|
1814 | else: | |
1773 | repo.dirstate.normal(f) |
|
1815 | repo.dirstate.normal(f) | |
1774 |
|
1816 | |||
1775 | # merge |
|
1817 | # merge | |
1776 |
for f, args, msg in actions.get( |
|
1818 | for f, args, msg in actions.get(ACTION_MERGE, []): | |
1777 | f1, f2, fa, move, anc = args |
|
1819 | f1, f2, fa, move, anc = args | |
1778 | if branchmerge: |
|
1820 | if branchmerge: | |
1779 | # We've done a branch merge, mark this file as merged |
|
1821 | # We've done a branch merge, mark this file as merged | |
@@ -1798,7 +1840,7 b' def recordupdates(repo, actions, branchm' | |||||
1798 | repo.dirstate.drop(f1) |
|
1840 | repo.dirstate.drop(f1) | |
1799 |
|
1841 | |||
1800 | # directory rename, move local |
|
1842 | # directory rename, move local | |
1801 |
for f, args, msg in actions.get( |
|
1843 | for f, args, msg in actions.get(ACTION_DIR_RENAME_MOVE_LOCAL, []): | |
1802 | f0, flag = args |
|
1844 | f0, flag = args | |
1803 | if branchmerge: |
|
1845 | if branchmerge: | |
1804 | repo.dirstate.add(f) |
|
1846 | repo.dirstate.add(f) | |
@@ -1809,7 +1851,7 b' def recordupdates(repo, actions, branchm' | |||||
1809 | repo.dirstate.drop(f0) |
|
1851 | repo.dirstate.drop(f0) | |
1810 |
|
1852 | |||
1811 | # directory rename, get |
|
1853 | # directory rename, get | |
1812 |
for f, args, msg in actions.get( |
|
1854 | for f, args, msg in actions.get(ACTION_LOCAL_DIR_RENAME_GET, []): | |
1813 | f0, flag = args |
|
1855 | f0, flag = args | |
1814 | if branchmerge: |
|
1856 | if branchmerge: | |
1815 | repo.dirstate.add(f) |
|
1857 | repo.dirstate.add(f) | |
@@ -1982,7 +2024,8 b' def update(repo, node, branchmerge, forc' | |||||
1982 |
|
2024 | |||
1983 | if updatecheck == 'noconflict': |
|
2025 | if updatecheck == 'noconflict': | |
1984 | for f, (m, args, msg) in actionbyfile.iteritems(): |
|
2026 | for f, (m, args, msg) in actionbyfile.iteritems(): | |
1985 | if m not in ('g', 'k', 'e', 'r', 'pr'): |
|
2027 | if m not in (ACTION_GET, ACTION_KEEP, ACTION_EXEC, | |
|
2028 | ACTION_REMOVE, ACTION_PATH_CONFLICT_RESOLVE): | |||
1986 | msg = _("conflicting changes") |
|
2029 | msg = _("conflicting changes") | |
1987 | hint = _("commit or update --clean to discard changes") |
|
2030 | hint = _("commit or update --clean to discard changes") | |
1988 | raise error.Abort(msg, hint=hint) |
|
2031 | raise error.Abort(msg, hint=hint) | |
@@ -1995,30 +2038,45 b' def update(repo, node, branchmerge, forc' | |||||
1995 | m, args, msg = actionbyfile[f] |
|
2038 | m, args, msg = actionbyfile[f] | |
1996 | prompts = filemerge.partextras(labels) |
|
2039 | prompts = filemerge.partextras(labels) | |
1997 | prompts['f'] = f |
|
2040 | prompts['f'] = f | |
1998 |
if m == |
|
2041 | if m == ACTION_CHANGED_DELETED: | |
1999 | if repo.ui.promptchoice( |
|
2042 | if repo.ui.promptchoice( | |
2000 | _("local%(l)s changed %(f)s which other%(o)s deleted\n" |
|
2043 | _("local%(l)s changed %(f)s which other%(o)s deleted\n" | |
2001 | "use (c)hanged version or (d)elete?" |
|
2044 | "use (c)hanged version or (d)elete?" | |
2002 | "$$ &Changed $$ &Delete") % prompts, 0): |
|
2045 | "$$ &Changed $$ &Delete") % prompts, 0): | |
2003 |
actionbyfile[f] = ( |
|
2046 | actionbyfile[f] = (ACTION_REMOVE, None, 'prompt delete') | |
2004 | elif f in p1: |
|
2047 | elif f in p1: | |
2005 |
actionbyfile[f] = ( |
|
2048 | actionbyfile[f] = (ACTION_ADD_MODIFIED, None, 'prompt keep') | |
2006 | else: |
|
2049 | else: | |
2007 |
actionbyfile[f] = ( |
|
2050 | actionbyfile[f] = (ACTION_ADD, None, 'prompt keep') | |
2008 |
elif m == |
|
2051 | elif m == ACTION_DELETED_CHANGED: | |
2009 | f1, f2, fa, move, anc = args |
|
2052 | f1, f2, fa, move, anc = args | |
2010 | flags = p2[f2].flags() |
|
2053 | flags = p2[f2].flags() | |
2011 | if repo.ui.promptchoice( |
|
2054 | if repo.ui.promptchoice( | |
2012 | _("other%(o)s changed %(f)s which local%(l)s deleted\n" |
|
2055 | _("other%(o)s changed %(f)s which local%(l)s deleted\n" | |
2013 | "use (c)hanged version or leave (d)eleted?" |
|
2056 | "use (c)hanged version or leave (d)eleted?" | |
2014 | "$$ &Changed $$ &Deleted") % prompts, 0) == 0: |
|
2057 | "$$ &Changed $$ &Deleted") % prompts, 0) == 0: | |
2015 |
actionbyfile[f] = ( |
|
2058 | actionbyfile[f] = (ACTION_GET, (flags, False), | |
|
2059 | 'prompt recreating') | |||
2016 | else: |
|
2060 | else: | |
2017 | del actionbyfile[f] |
|
2061 | del actionbyfile[f] | |
2018 |
|
2062 | |||
2019 | # Convert to dictionary-of-lists format |
|
2063 | # Convert to dictionary-of-lists format | |
2020 | actions = dict((m, []) |
|
2064 | actions = dict((m, []) | |
2021 |
for m in |
|
2065 | for m in ( | |
|
2066 | ACTION_ADD, | |||
|
2067 | ACTION_ADD_MODIFIED, | |||
|
2068 | ACTION_FORGET, | |||
|
2069 | ACTION_GET, | |||
|
2070 | ACTION_CHANGED_DELETED, | |||
|
2071 | ACTION_DELETED_CHANGED, | |||
|
2072 | ACTION_REMOVE, | |||
|
2073 | ACTION_DIR_RENAME_MOVE_LOCAL, | |||
|
2074 | ACTION_LOCAL_DIR_RENAME_GET, | |||
|
2075 | ACTION_MERGE, | |||
|
2076 | ACTION_EXEC, | |||
|
2077 | ACTION_KEEP, | |||
|
2078 | ACTION_PATH_CONFLICT, | |||
|
2079 | ACTION_PATH_CONFLICT_RESOLVE)) | |||
2022 | for f, (m, args, msg) in actionbyfile.iteritems(): |
|
2080 | for f, (m, args, msg) in actionbyfile.iteritems(): | |
2023 | if m not in actions: |
|
2081 | if m not in actions: | |
2024 | actions[m] = [] |
|
2082 | actions[m] = [] | |
@@ -2081,7 +2139,7 b' def update(repo, node, branchmerge, forc' | |||||
2081 | if (fsmonitorwarning |
|
2139 | if (fsmonitorwarning | |
2082 | and not fsmonitorenabled |
|
2140 | and not fsmonitorenabled | |
2083 | and p1.node() == nullid |
|
2141 | and p1.node() == nullid | |
2084 |
and len(actions[ |
|
2142 | and len(actions[ACTION_GET]) >= fsmonitorthreshold | |
2085 | and pycompat.sysplatform.startswith(('linux', 'darwin'))): |
|
2143 | and pycompat.sysplatform.startswith(('linux', 'darwin'))): | |
2086 | repo.ui.warn( |
|
2144 | repo.ui.warn( | |
2087 | _('(warning: large working directory being used without ' |
|
2145 | _('(warning: large working directory being used without ' |
General Comments 0
You need to be logged in to leave comments.
Login now