62 RECORD_FILE_VALUES = b'f' |
62 RECORD_FILE_VALUES = b'f' |
63 RECORD_LABELS = b'l' |
63 RECORD_LABELS = b'l' |
64 RECORD_OVERRIDE = b't' |
64 RECORD_OVERRIDE = b't' |
65 RECORD_UNSUPPORTED_MANDATORY = b'X' |
65 RECORD_UNSUPPORTED_MANDATORY = b'X' |
66 RECORD_UNSUPPORTED_ADVISORY = b'x' |
66 RECORD_UNSUPPORTED_ADVISORY = b'x' |
|
67 RECORD_RESOLVED_OTHER = b'R' |
67 |
68 |
68 MERGE_DRIVER_STATE_UNMARKED = b'u' |
69 MERGE_DRIVER_STATE_UNMARKED = b'u' |
69 MERGE_DRIVER_STATE_MARKED = b'm' |
70 MERGE_DRIVER_STATE_MARKED = b'm' |
70 MERGE_DRIVER_STATE_SUCCESS = b's' |
71 MERGE_DRIVER_STATE_SUCCESS = b's' |
71 |
72 |
72 MERGE_RECORD_UNRESOLVED = b'u' |
73 MERGE_RECORD_UNRESOLVED = b'u' |
73 MERGE_RECORD_RESOLVED = b'r' |
74 MERGE_RECORD_RESOLVED = b'r' |
74 MERGE_RECORD_UNRESOLVED_PATH = b'pu' |
75 MERGE_RECORD_UNRESOLVED_PATH = b'pu' |
75 MERGE_RECORD_RESOLVED_PATH = b'pr' |
76 MERGE_RECORD_RESOLVED_PATH = b'pr' |
76 MERGE_RECORD_DRIVER_RESOLVED = b'd' |
77 MERGE_RECORD_DRIVER_RESOLVED = b'd' |
|
78 # represents that the file was automatically merged in favor |
|
79 # of other version. This info is used on commit. |
|
80 MERGE_RECORD_MERGED_OTHER = b'o' |
77 |
81 |
78 ACTION_FORGET = b'f' |
82 ACTION_FORGET = b'f' |
79 ACTION_REMOVE = b'r' |
83 ACTION_REMOVE = b'r' |
80 ACTION_ADD = b'a' |
84 ACTION_ADD = b'a' |
81 ACTION_GET = b'g' |
85 ACTION_GET = b'g' |
89 ACTION_LOCAL_DIR_RENAME_GET = b'dg' |
93 ACTION_LOCAL_DIR_RENAME_GET = b'dg' |
90 ACTION_DIR_RENAME_MOVE_LOCAL = b'dm' |
94 ACTION_DIR_RENAME_MOVE_LOCAL = b'dm' |
91 ACTION_KEEP = b'k' |
95 ACTION_KEEP = b'k' |
92 ACTION_EXEC = b'e' |
96 ACTION_EXEC = b'e' |
93 ACTION_CREATED_MERGE = b'cm' |
97 ACTION_CREATED_MERGE = b'cm' |
|
98 # GET the other/remote side and store this info in mergestate |
|
99 ACTION_GET_OTHER_AND_STORE = b'gs' |
94 |
100 |
95 |
101 |
96 class mergestate(object): |
102 class mergestate(object): |
97 '''track 3-way merge state of individual files |
103 '''track 3-way merge state of individual files |
98 |
104 |
225 elif rtype in ( |
231 elif rtype in ( |
226 RECORD_MERGED, |
232 RECORD_MERGED, |
227 RECORD_CHANGEDELETE_CONFLICT, |
233 RECORD_CHANGEDELETE_CONFLICT, |
228 RECORD_PATH_CONFLICT, |
234 RECORD_PATH_CONFLICT, |
229 RECORD_MERGE_DRIVER_MERGE, |
235 RECORD_MERGE_DRIVER_MERGE, |
|
236 RECORD_RESOLVED_OTHER, |
230 ): |
237 ): |
231 bits = record.split(b'\0') |
238 bits = record.split(b'\0') |
232 self._state[bits[0]] = bits[1:] |
239 self._state[bits[0]] = bits[1:] |
233 elif rtype == RECORD_FILE_VALUES: |
240 elif rtype == RECORD_FILE_VALUES: |
234 filename, rawextras = record.split(b'\0', 1) |
241 filename, rawextras = record.split(b'\0', 1) |
451 # Path conflicts. These are stored in 'P' records. The current |
458 # Path conflicts. These are stored in 'P' records. The current |
452 # resolution state ('pu' or 'pr') is stored within the record. |
459 # resolution state ('pu' or 'pr') is stored within the record. |
453 records.append( |
460 records.append( |
454 (RECORD_PATH_CONFLICT, b'\0'.join([filename] + v)) |
461 (RECORD_PATH_CONFLICT, b'\0'.join([filename] + v)) |
455 ) |
462 ) |
|
463 elif v[0] == MERGE_RECORD_MERGED_OTHER: |
|
464 records.append( |
|
465 (RECORD_RESOLVED_OTHER, b'\0'.join([filename] + v)) |
|
466 ) |
456 elif v[1] == nullhex or v[6] == nullhex: |
467 elif v[1] == nullhex or v[6] == nullhex: |
457 # Change/Delete or Delete/Change conflicts. These are stored in |
468 # Change/Delete or Delete/Change conflicts. These are stored in |
458 # 'C' records. v[1] is the local file, and is nullhex when the |
469 # 'C' records. v[1] is the local file, and is nullhex when the |
459 # file is deleted locally ('dc'). v[6] is the remote file, and |
470 # file is deleted locally ('dc'). v[6] is the remote file, and |
460 # is nullhex when the file is deleted remotely ('cd'). |
471 # is nullhex when the file is deleted remotely ('cd'). |
549 forigin: origin of the file ('l' or 'r' for local/remote) |
560 forigin: origin of the file ('l' or 'r' for local/remote) |
550 """ |
561 """ |
551 self._state[path] = [MERGE_RECORD_UNRESOLVED_PATH, frename, forigin] |
562 self._state[path] = [MERGE_RECORD_UNRESOLVED_PATH, frename, forigin] |
552 self._dirty = True |
563 self._dirty = True |
553 |
564 |
|
565 def addmergedother(self, path): |
|
566 self._state[path] = [MERGE_RECORD_MERGED_OTHER, nullhex, nullhex] |
|
567 self._dirty = True |
|
568 |
554 def __contains__(self, dfile): |
569 def __contains__(self, dfile): |
555 return dfile in self._state |
570 return dfile in self._state |
556 |
571 |
557 def __getitem__(self, dfile): |
572 def __getitem__(self, dfile): |
558 return self._state[dfile][0] |
573 return self._state[dfile][0] |
591 return self._stateextras.setdefault(filename, {}) |
606 return self._stateextras.setdefault(filename, {}) |
592 |
607 |
593 def _resolve(self, preresolve, dfile, wctx): |
608 def _resolve(self, preresolve, dfile, wctx): |
594 """rerun merge process for file path `dfile`""" |
609 """rerun merge process for file path `dfile`""" |
595 if self[dfile] in (MERGE_RECORD_RESOLVED, MERGE_RECORD_DRIVER_RESOLVED): |
610 if self[dfile] in (MERGE_RECORD_RESOLVED, MERGE_RECORD_DRIVER_RESOLVED): |
|
611 return True, 0 |
|
612 if self._state[dfile][0] == MERGE_RECORD_MERGED_OTHER: |
596 return True, 0 |
613 return True, 0 |
597 stateentry = self._state[dfile] |
614 stateentry = self._state[dfile] |
598 state, localkey, lfile, afile, anode, ofile, onode, flags = stateentry |
615 state, localkey, lfile, afile, anode, ofile, onode, flags = stateentry |
599 octx = self._repo[self._other] |
616 octx = self._repo[self._other] |
600 extras = self.extras(dfile) |
617 extras = self.extras(dfile) |
1207 |
1224 |
1208 Raise an exception if the merge cannot be completed because the repo is |
1225 Raise an exception if the merge cannot be completed because the repo is |
1209 narrowed. |
1226 narrowed. |
1210 """ |
1227 """ |
1211 nooptypes = {b'k'} # TODO: handle with nonconflicttypes |
1228 nooptypes = {b'k'} # TODO: handle with nonconflicttypes |
1212 nonconflicttypes = set(b'a am c cm f g r e'.split()) |
1229 nonconflicttypes = set(b'a am c cm f g gs r e'.split()) |
1213 # We mutate the items in the dict during iteration, so iterate |
1230 # We mutate the items in the dict during iteration, so iterate |
1214 # over a copy. |
1231 # over a copy. |
1215 for f, action in list(actions.items()): |
1232 for f, action in list(actions.items()): |
1216 if narrowmatch(f): |
1233 if narrowmatch(f): |
1217 pass |
1234 pass |
1346 (fl2,), |
1363 (fl2,), |
1347 b'update permissions', |
1364 b'update permissions', |
1348 ) |
1365 ) |
1349 else: |
1366 else: |
1350 actions[f] = ( |
1367 actions[f] = ( |
1351 ACTION_GET, |
1368 ACTION_GET_OTHER_AND_STORE |
|
1369 if branchmerge |
|
1370 else ACTION_GET, |
1352 (fl2, False), |
1371 (fl2, False), |
1353 b'remote is newer', |
1372 b'remote is newer', |
1354 ) |
1373 ) |
1355 elif nol and n2 == a: # remote only changed 'x' |
1374 elif nol and n2 == a: # remote only changed 'x' |
1356 actions[f] = (ACTION_EXEC, (fl2,), b'update permissions') |
1375 actions[f] = (ACTION_EXEC, (fl2,), b'update permissions') |
1357 elif nol and n1 == a: # local only changed 'x' |
1376 elif nol and n1 == a: # local only changed 'x' |
1358 actions[f] = (ACTION_GET, (fl1, False), b'remote is newer') |
1377 actions[f] = ( |
|
1378 ACTION_GET_OTHER_AND_STORE |
|
1379 if branchmerge |
|
1380 else ACTION_GET, |
|
1381 (fl1, False), |
|
1382 b'remote is newer', |
|
1383 ) |
1359 else: # both changed something |
1384 else: # both changed something |
1360 actions[f] = ( |
1385 actions[f] = ( |
1361 ACTION_MERGE, |
1386 ACTION_MERGE, |
1362 (f, f, f, False, pa.node()), |
1387 (f, f, f, False, pa.node()), |
1363 b'versions differ', |
1388 b'versions differ', |
1586 if renamedelete is None or len(renamedelete) < len(renamedelete1): |
1611 if renamedelete is None or len(renamedelete) < len(renamedelete1): |
1587 renamedelete = renamedelete1 |
1612 renamedelete = renamedelete1 |
1588 |
1613 |
1589 for f, a in sorted(pycompat.iteritems(actions)): |
1614 for f, a in sorted(pycompat.iteritems(actions)): |
1590 m, args, msg = a |
1615 m, args, msg = a |
|
1616 if m == ACTION_GET_OTHER_AND_STORE: |
|
1617 m = ACTION_GET |
1591 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m)) |
1618 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m)) |
1592 if f in fbids: |
1619 if f in fbids: |
1593 d = fbids[f] |
1620 d = fbids[f] |
1594 if m in d: |
1621 if m in d: |
1595 d[m].append(a) |
1622 d[m].append(a) |
1833 |
1861 |
1834 _prefetchfiles(repo, mctx, actions) |
1862 _prefetchfiles(repo, mctx, actions) |
1835 |
1863 |
1836 updated, merged, removed = 0, 0, 0 |
1864 updated, merged, removed = 0, 0, 0 |
1837 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node(), labels) |
1865 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node(), labels) |
|
1866 |
|
1867 # add ACTION_GET_OTHER_AND_STORE to mergestate |
|
1868 for e in actions[ACTION_GET_OTHER_AND_STORE]: |
|
1869 ms.addmergedother(e[0]) |
|
1870 |
1838 moves = [] |
1871 moves = [] |
1839 for m, l in actions.items(): |
1872 for m, l in actions.items(): |
1840 l.sort() |
1873 l.sort() |
1841 |
1874 |
1842 # 'cd' and 'dc' actions are treated like other merge conflicts |
1875 # 'cd' and 'dc' actions are treated like other merge conflicts |
2413 ACTION_GET, |
2446 ACTION_GET, |
2414 ACTION_KEEP, |
2447 ACTION_KEEP, |
2415 ACTION_EXEC, |
2448 ACTION_EXEC, |
2416 ACTION_REMOVE, |
2449 ACTION_REMOVE, |
2417 ACTION_PATH_CONFLICT_RESOLVE, |
2450 ACTION_PATH_CONFLICT_RESOLVE, |
|
2451 ACTION_GET_OTHER_AND_STORE, |
2418 ): |
2452 ): |
2419 msg = _(b"conflicting changes") |
2453 msg = _(b"conflicting changes") |
2420 hint = _(b"commit or update --clean to discard changes") |
2454 hint = _(b"commit or update --clean to discard changes") |
2421 raise error.Abort(msg, hint=hint) |
2455 raise error.Abort(msg, hint=hint) |
2422 |
2456 |
2475 for f, (m, args, msg) in pycompat.iteritems(actionbyfile): |
2509 for f, (m, args, msg) in pycompat.iteritems(actionbyfile): |
2476 if m not in actions: |
2510 if m not in actions: |
2477 actions[m] = [] |
2511 actions[m] = [] |
2478 actions[m].append((f, args, msg)) |
2512 actions[m].append((f, args, msg)) |
2479 |
2513 |
|
2514 # ACTION_GET_OTHER_AND_STORE is a ACTION_GET + store in mergestate |
|
2515 for e in actions[ACTION_GET_OTHER_AND_STORE]: |
|
2516 actions[ACTION_GET].append(e) |
|
2517 |
2480 if not util.fscasesensitive(repo.path): |
2518 if not util.fscasesensitive(repo.path): |
2481 # check collision between files only in p2 for clean update |
2519 # check collision between files only in p2 for clean update |
2482 if not branchmerge and ( |
2520 if not branchmerge and ( |
2483 force or not wc.dirty(missing=True, branch=False) |
2521 force or not wc.dirty(missing=True, branch=False) |
2484 ): |
2522 ): |