mercurial/merge.py
changeset 44687 1b8fd4af3318
parent 44452 9d2b2df2c2ba
child 44856 b7808443ed6a
equal deleted inserted replaced
44686:bca57ad9e630 44687:1b8fd4af3318
    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)
  1811             ACTION_MERGE,
  1838             ACTION_MERGE,
  1812             ACTION_EXEC,
  1839             ACTION_EXEC,
  1813             ACTION_KEEP,
  1840             ACTION_KEEP,
  1814             ACTION_PATH_CONFLICT,
  1841             ACTION_PATH_CONFLICT,
  1815             ACTION_PATH_CONFLICT_RESOLVE,
  1842             ACTION_PATH_CONFLICT_RESOLVE,
       
  1843             ACTION_GET_OTHER_AND_STORE,
  1816         )
  1844         )
  1817     }
  1845     }
  1818 
  1846 
  1819 
  1847 
  1820 def applyupdates(
  1848 def applyupdates(
  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             ):