mercurial/merge.py
changeset 44856 b7808443ed6a
parent 44687 1b8fd4af3318
child 44939 818b4f19ef23
equal deleted inserted replaced
44855:1d2d353e5c4a 44856:b7808443ed6a
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
     8 from __future__ import absolute_import
     9 
     9 
    10 import errno
    10 import errno
    11 import shutil
       
    12 import stat
    11 import stat
    13 import struct
    12 import struct
    14 
    13 
    15 from .i18n import _
    14 from .i18n import _
    16 from .node import (
    15 from .node import (
    17     addednodeid,
    16     addednodeid,
    18     bin,
       
    19     hex,
       
    20     modifiednodeid,
    17     modifiednodeid,
    21     nullhex,
       
    22     nullid,
    18     nullid,
    23     nullrev,
    19     nullrev,
    24 )
    20 )
    25 from .pycompat import delattr
       
    26 from .thirdparty import attr
    21 from .thirdparty import attr
    27 from . import (
    22 from . import (
    28     copies,
    23     copies,
    29     encoding,
    24     encoding,
    30     error,
    25     error,
    31     filemerge,
    26     filemerge,
    32     match as matchmod,
    27     match as matchmod,
       
    28     mergestate as mergestatemod,
    33     obsutil,
    29     obsutil,
    34     pathutil,
    30     pathutil,
    35     pycompat,
    31     pycompat,
    36     scmutil,
    32     scmutil,
    37     subrepoutil,
    33     subrepoutil,
    38     util,
    34     util,
    39     worker,
    35     worker,
    40 )
    36 )
    41 from .utils import hashutil
       
    42 
    37 
    43 _pack = struct.pack
    38 _pack = struct.pack
    44 _unpack = struct.unpack
    39 _unpack = struct.unpack
    45 
       
    46 
       
    47 def _droponode(data):
       
    48     # used for compatibility for v1
       
    49     bits = data.split(b'\0')
       
    50     bits = bits[:-2] + bits[-1:]
       
    51     return b'\0'.join(bits)
       
    52 
       
    53 
       
    54 # Merge state record types. See ``mergestate`` docs for more.
       
    55 RECORD_LOCAL = b'L'
       
    56 RECORD_OTHER = b'O'
       
    57 RECORD_MERGED = b'F'
       
    58 RECORD_CHANGEDELETE_CONFLICT = b'C'
       
    59 RECORD_MERGE_DRIVER_MERGE = b'D'
       
    60 RECORD_PATH_CONFLICT = b'P'
       
    61 RECORD_MERGE_DRIVER_STATE = b'm'
       
    62 RECORD_FILE_VALUES = b'f'
       
    63 RECORD_LABELS = b'l'
       
    64 RECORD_OVERRIDE = b't'
       
    65 RECORD_UNSUPPORTED_MANDATORY = b'X'
       
    66 RECORD_UNSUPPORTED_ADVISORY = b'x'
       
    67 RECORD_RESOLVED_OTHER = b'R'
       
    68 
       
    69 MERGE_DRIVER_STATE_UNMARKED = b'u'
       
    70 MERGE_DRIVER_STATE_MARKED = b'm'
       
    71 MERGE_DRIVER_STATE_SUCCESS = b's'
       
    72 
       
    73 MERGE_RECORD_UNRESOLVED = b'u'
       
    74 MERGE_RECORD_RESOLVED = b'r'
       
    75 MERGE_RECORD_UNRESOLVED_PATH = b'pu'
       
    76 MERGE_RECORD_RESOLVED_PATH = b'pr'
       
    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'
       
    81 
       
    82 ACTION_FORGET = b'f'
       
    83 ACTION_REMOVE = b'r'
       
    84 ACTION_ADD = b'a'
       
    85 ACTION_GET = b'g'
       
    86 ACTION_PATH_CONFLICT = b'p'
       
    87 ACTION_PATH_CONFLICT_RESOLVE = b'pr'
       
    88 ACTION_ADD_MODIFIED = b'am'
       
    89 ACTION_CREATED = b'c'
       
    90 ACTION_DELETED_CHANGED = b'dc'
       
    91 ACTION_CHANGED_DELETED = b'cd'
       
    92 ACTION_MERGE = b'm'
       
    93 ACTION_LOCAL_DIR_RENAME_GET = b'dg'
       
    94 ACTION_DIR_RENAME_MOVE_LOCAL = b'dm'
       
    95 ACTION_KEEP = b'k'
       
    96 ACTION_EXEC = b'e'
       
    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'
       
   100 
       
   101 
       
   102 class mergestate(object):
       
   103     '''track 3-way merge state of individual files
       
   104 
       
   105     The merge state is stored on disk when needed. Two files are used: one with
       
   106     an old format (version 1), and one with a new format (version 2). Version 2
       
   107     stores a superset of the data in version 1, including new kinds of records
       
   108     in the future. For more about the new format, see the documentation for
       
   109     `_readrecordsv2`.
       
   110 
       
   111     Each record can contain arbitrary content, and has an associated type. This
       
   112     `type` should be a letter. If `type` is uppercase, the record is mandatory:
       
   113     versions of Mercurial that don't support it should abort. If `type` is
       
   114     lowercase, the record can be safely ignored.
       
   115 
       
   116     Currently known records:
       
   117 
       
   118     L: the node of the "local" part of the merge (hexified version)
       
   119     O: the node of the "other" part of the merge (hexified version)
       
   120     F: a file to be merged entry
       
   121     C: a change/delete or delete/change conflict
       
   122     D: a file that the external merge driver will merge internally
       
   123        (experimental)
       
   124     P: a path conflict (file vs directory)
       
   125     m: the external merge driver defined for this merge plus its run state
       
   126        (experimental)
       
   127     f: a (filename, dictionary) tuple of optional values for a given file
       
   128     X: unsupported mandatory record type (used in tests)
       
   129     x: unsupported advisory record type (used in tests)
       
   130     l: the labels for the parts of the merge.
       
   131 
       
   132     Merge driver run states (experimental):
       
   133     u: driver-resolved files unmarked -- needs to be run next time we're about
       
   134        to resolve or commit
       
   135     m: driver-resolved files marked -- only needs to be run before commit
       
   136     s: success/skipped -- does not need to be run any more
       
   137 
       
   138     Merge record states (stored in self._state, indexed by filename):
       
   139     u: unresolved conflict
       
   140     r: resolved conflict
       
   141     pu: unresolved path conflict (file conflicts with directory)
       
   142     pr: resolved path conflict
       
   143     d: driver-resolved conflict
       
   144 
       
   145     The resolve command transitions between 'u' and 'r' for conflicts and
       
   146     'pu' and 'pr' for path conflicts.
       
   147     '''
       
   148 
       
   149     statepathv1 = b'merge/state'
       
   150     statepathv2 = b'merge/state2'
       
   151 
       
   152     @staticmethod
       
   153     def clean(repo, node=None, other=None, labels=None):
       
   154         """Initialize a brand new merge state, removing any existing state on
       
   155         disk."""
       
   156         ms = mergestate(repo)
       
   157         ms.reset(node, other, labels)
       
   158         return ms
       
   159 
       
   160     @staticmethod
       
   161     def read(repo):
       
   162         """Initialize the merge state, reading it from disk."""
       
   163         ms = mergestate(repo)
       
   164         ms._read()
       
   165         return ms
       
   166 
       
   167     def __init__(self, repo):
       
   168         """Initialize the merge state.
       
   169 
       
   170         Do not use this directly! Instead call read() or clean()."""
       
   171         self._repo = repo
       
   172         self._dirty = False
       
   173         self._labels = None
       
   174 
       
   175     def reset(self, node=None, other=None, labels=None):
       
   176         self._state = {}
       
   177         self._stateextras = {}
       
   178         self._local = None
       
   179         self._other = None
       
   180         self._labels = labels
       
   181         for var in ('localctx', 'otherctx'):
       
   182             if var in vars(self):
       
   183                 delattr(self, var)
       
   184         if node:
       
   185             self._local = node
       
   186             self._other = other
       
   187         self._readmergedriver = None
       
   188         if self.mergedriver:
       
   189             self._mdstate = MERGE_DRIVER_STATE_SUCCESS
       
   190         else:
       
   191             self._mdstate = MERGE_DRIVER_STATE_UNMARKED
       
   192         shutil.rmtree(self._repo.vfs.join(b'merge'), True)
       
   193         self._results = {}
       
   194         self._dirty = False
       
   195 
       
   196     def _read(self):
       
   197         """Analyse each record content to restore a serialized state from disk
       
   198 
       
   199         This function process "record" entry produced by the de-serialization
       
   200         of on disk file.
       
   201         """
       
   202         self._state = {}
       
   203         self._stateextras = {}
       
   204         self._local = None
       
   205         self._other = None
       
   206         for var in ('localctx', 'otherctx'):
       
   207             if var in vars(self):
       
   208                 delattr(self, var)
       
   209         self._readmergedriver = None
       
   210         self._mdstate = MERGE_DRIVER_STATE_SUCCESS
       
   211         unsupported = set()
       
   212         records = self._readrecords()
       
   213         for rtype, record in records:
       
   214             if rtype == RECORD_LOCAL:
       
   215                 self._local = bin(record)
       
   216             elif rtype == RECORD_OTHER:
       
   217                 self._other = bin(record)
       
   218             elif rtype == RECORD_MERGE_DRIVER_STATE:
       
   219                 bits = record.split(b'\0', 1)
       
   220                 mdstate = bits[1]
       
   221                 if len(mdstate) != 1 or mdstate not in (
       
   222                     MERGE_DRIVER_STATE_UNMARKED,
       
   223                     MERGE_DRIVER_STATE_MARKED,
       
   224                     MERGE_DRIVER_STATE_SUCCESS,
       
   225                 ):
       
   226                     # the merge driver should be idempotent, so just rerun it
       
   227                     mdstate = MERGE_DRIVER_STATE_UNMARKED
       
   228 
       
   229                 self._readmergedriver = bits[0]
       
   230                 self._mdstate = mdstate
       
   231             elif rtype in (
       
   232                 RECORD_MERGED,
       
   233                 RECORD_CHANGEDELETE_CONFLICT,
       
   234                 RECORD_PATH_CONFLICT,
       
   235                 RECORD_MERGE_DRIVER_MERGE,
       
   236                 RECORD_RESOLVED_OTHER,
       
   237             ):
       
   238                 bits = record.split(b'\0')
       
   239                 self._state[bits[0]] = bits[1:]
       
   240             elif rtype == RECORD_FILE_VALUES:
       
   241                 filename, rawextras = record.split(b'\0', 1)
       
   242                 extraparts = rawextras.split(b'\0')
       
   243                 extras = {}
       
   244                 i = 0
       
   245                 while i < len(extraparts):
       
   246                     extras[extraparts[i]] = extraparts[i + 1]
       
   247                     i += 2
       
   248 
       
   249                 self._stateextras[filename] = extras
       
   250             elif rtype == RECORD_LABELS:
       
   251                 labels = record.split(b'\0', 2)
       
   252                 self._labels = [l for l in labels if len(l) > 0]
       
   253             elif not rtype.islower():
       
   254                 unsupported.add(rtype)
       
   255         self._results = {}
       
   256         self._dirty = False
       
   257 
       
   258         if unsupported:
       
   259             raise error.UnsupportedMergeRecords(unsupported)
       
   260 
       
   261     def _readrecords(self):
       
   262         """Read merge state from disk and return a list of record (TYPE, data)
       
   263 
       
   264         We read data from both v1 and v2 files and decide which one to use.
       
   265 
       
   266         V1 has been used by version prior to 2.9.1 and contains less data than
       
   267         v2. We read both versions and check if no data in v2 contradicts
       
   268         v1. If there is not contradiction we can safely assume that both v1
       
   269         and v2 were written at the same time and use the extract data in v2. If
       
   270         there is contradiction we ignore v2 content as we assume an old version
       
   271         of Mercurial has overwritten the mergestate file and left an old v2
       
   272         file around.
       
   273 
       
   274         returns list of record [(TYPE, data), ...]"""
       
   275         v1records = self._readrecordsv1()
       
   276         v2records = self._readrecordsv2()
       
   277         if self._v1v2match(v1records, v2records):
       
   278             return v2records
       
   279         else:
       
   280             # v1 file is newer than v2 file, use it
       
   281             # we have to infer the "other" changeset of the merge
       
   282             # we cannot do better than that with v1 of the format
       
   283             mctx = self._repo[None].parents()[-1]
       
   284             v1records.append((RECORD_OTHER, mctx.hex()))
       
   285             # add place holder "other" file node information
       
   286             # nobody is using it yet so we do no need to fetch the data
       
   287             # if mctx was wrong `mctx[bits[-2]]` may fails.
       
   288             for idx, r in enumerate(v1records):
       
   289                 if r[0] == RECORD_MERGED:
       
   290                     bits = r[1].split(b'\0')
       
   291                     bits.insert(-2, b'')
       
   292                     v1records[idx] = (r[0], b'\0'.join(bits))
       
   293             return v1records
       
   294 
       
   295     def _v1v2match(self, v1records, v2records):
       
   296         oldv2 = set()  # old format version of v2 record
       
   297         for rec in v2records:
       
   298             if rec[0] == RECORD_LOCAL:
       
   299                 oldv2.add(rec)
       
   300             elif rec[0] == RECORD_MERGED:
       
   301                 # drop the onode data (not contained in v1)
       
   302                 oldv2.add((RECORD_MERGED, _droponode(rec[1])))
       
   303         for rec in v1records:
       
   304             if rec not in oldv2:
       
   305                 return False
       
   306         else:
       
   307             return True
       
   308 
       
   309     def _readrecordsv1(self):
       
   310         """read on disk merge state for version 1 file
       
   311 
       
   312         returns list of record [(TYPE, data), ...]
       
   313 
       
   314         Note: the "F" data from this file are one entry short
       
   315               (no "other file node" entry)
       
   316         """
       
   317         records = []
       
   318         try:
       
   319             f = self._repo.vfs(self.statepathv1)
       
   320             for i, l in enumerate(f):
       
   321                 if i == 0:
       
   322                     records.append((RECORD_LOCAL, l[:-1]))
       
   323                 else:
       
   324                     records.append((RECORD_MERGED, l[:-1]))
       
   325             f.close()
       
   326         except IOError as err:
       
   327             if err.errno != errno.ENOENT:
       
   328                 raise
       
   329         return records
       
   330 
       
   331     def _readrecordsv2(self):
       
   332         """read on disk merge state for version 2 file
       
   333 
       
   334         This format is a list of arbitrary records of the form:
       
   335 
       
   336           [type][length][content]
       
   337 
       
   338         `type` is a single character, `length` is a 4 byte integer, and
       
   339         `content` is an arbitrary byte sequence of length `length`.
       
   340 
       
   341         Mercurial versions prior to 3.7 have a bug where if there are
       
   342         unsupported mandatory merge records, attempting to clear out the merge
       
   343         state with hg update --clean or similar aborts. The 't' record type
       
   344         works around that by writing out what those versions treat as an
       
   345         advisory record, but later versions interpret as special: the first
       
   346         character is the 'real' record type and everything onwards is the data.
       
   347 
       
   348         Returns list of records [(TYPE, data), ...]."""
       
   349         records = []
       
   350         try:
       
   351             f = self._repo.vfs(self.statepathv2)
       
   352             data = f.read()
       
   353             off = 0
       
   354             end = len(data)
       
   355             while off < end:
       
   356                 rtype = data[off : off + 1]
       
   357                 off += 1
       
   358                 length = _unpack(b'>I', data[off : (off + 4)])[0]
       
   359                 off += 4
       
   360                 record = data[off : (off + length)]
       
   361                 off += length
       
   362                 if rtype == RECORD_OVERRIDE:
       
   363                     rtype, record = record[0:1], record[1:]
       
   364                 records.append((rtype, record))
       
   365             f.close()
       
   366         except IOError as err:
       
   367             if err.errno != errno.ENOENT:
       
   368                 raise
       
   369         return records
       
   370 
       
   371     @util.propertycache
       
   372     def mergedriver(self):
       
   373         # protect against the following:
       
   374         # - A configures a malicious merge driver in their hgrc, then
       
   375         #   pauses the merge
       
   376         # - A edits their hgrc to remove references to the merge driver
       
   377         # - A gives a copy of their entire repo, including .hg, to B
       
   378         # - B inspects .hgrc and finds it to be clean
       
   379         # - B then continues the merge and the malicious merge driver
       
   380         #  gets invoked
       
   381         configmergedriver = self._repo.ui.config(
       
   382             b'experimental', b'mergedriver'
       
   383         )
       
   384         if (
       
   385             self._readmergedriver is not None
       
   386             and self._readmergedriver != configmergedriver
       
   387         ):
       
   388             raise error.ConfigError(
       
   389                 _(b"merge driver changed since merge started"),
       
   390                 hint=_(b"revert merge driver change or abort merge"),
       
   391             )
       
   392 
       
   393         return configmergedriver
       
   394 
       
   395     @util.propertycache
       
   396     def local(self):
       
   397         if self._local is None:
       
   398             msg = b"local accessed but self._local isn't set"
       
   399             raise error.ProgrammingError(msg)
       
   400         return self._local
       
   401 
       
   402     @util.propertycache
       
   403     def localctx(self):
       
   404         return self._repo[self.local]
       
   405 
       
   406     @util.propertycache
       
   407     def other(self):
       
   408         if self._other is None:
       
   409             msg = b"other accessed but self._other isn't set"
       
   410             raise error.ProgrammingError(msg)
       
   411         return self._other
       
   412 
       
   413     @util.propertycache
       
   414     def otherctx(self):
       
   415         return self._repo[self.other]
       
   416 
       
   417     def active(self):
       
   418         """Whether mergestate is active.
       
   419 
       
   420         Returns True if there appears to be mergestate. This is a rough proxy
       
   421         for "is a merge in progress."
       
   422         """
       
   423         return bool(self._local) or bool(self._state)
       
   424 
       
   425     def commit(self):
       
   426         """Write current state on disk (if necessary)"""
       
   427         if self._dirty:
       
   428             records = self._makerecords()
       
   429             self._writerecords(records)
       
   430             self._dirty = False
       
   431 
       
   432     def _makerecords(self):
       
   433         records = []
       
   434         records.append((RECORD_LOCAL, hex(self._local)))
       
   435         records.append((RECORD_OTHER, hex(self._other)))
       
   436         if self.mergedriver:
       
   437             records.append(
       
   438                 (
       
   439                     RECORD_MERGE_DRIVER_STATE,
       
   440                     b'\0'.join([self.mergedriver, self._mdstate]),
       
   441                 )
       
   442             )
       
   443         # Write out state items. In all cases, the value of the state map entry
       
   444         # is written as the contents of the record. The record type depends on
       
   445         # the type of state that is stored, and capital-letter records are used
       
   446         # to prevent older versions of Mercurial that do not support the feature
       
   447         # from loading them.
       
   448         for filename, v in pycompat.iteritems(self._state):
       
   449             if v[0] == MERGE_RECORD_DRIVER_RESOLVED:
       
   450                 # Driver-resolved merge. These are stored in 'D' records.
       
   451                 records.append(
       
   452                     (RECORD_MERGE_DRIVER_MERGE, b'\0'.join([filename] + v))
       
   453                 )
       
   454             elif v[0] in (
       
   455                 MERGE_RECORD_UNRESOLVED_PATH,
       
   456                 MERGE_RECORD_RESOLVED_PATH,
       
   457             ):
       
   458                 # Path conflicts. These are stored in 'P' records.  The current
       
   459                 # resolution state ('pu' or 'pr') is stored within the record.
       
   460                 records.append(
       
   461                     (RECORD_PATH_CONFLICT, b'\0'.join([filename] + v))
       
   462                 )
       
   463             elif v[0] == MERGE_RECORD_MERGED_OTHER:
       
   464                 records.append(
       
   465                     (RECORD_RESOLVED_OTHER, b'\0'.join([filename] + v))
       
   466                 )
       
   467             elif v[1] == nullhex or v[6] == nullhex:
       
   468                 # Change/Delete or Delete/Change conflicts. These are stored in
       
   469                 # 'C' records. v[1] is the local file, and is nullhex when the
       
   470                 # file is deleted locally ('dc'). v[6] is the remote file, and
       
   471                 # is nullhex when the file is deleted remotely ('cd').
       
   472                 records.append(
       
   473                     (RECORD_CHANGEDELETE_CONFLICT, b'\0'.join([filename] + v))
       
   474                 )
       
   475             else:
       
   476                 # Normal files.  These are stored in 'F' records.
       
   477                 records.append((RECORD_MERGED, b'\0'.join([filename] + v)))
       
   478         for filename, extras in sorted(pycompat.iteritems(self._stateextras)):
       
   479             rawextras = b'\0'.join(
       
   480                 b'%s\0%s' % (k, v) for k, v in pycompat.iteritems(extras)
       
   481             )
       
   482             records.append(
       
   483                 (RECORD_FILE_VALUES, b'%s\0%s' % (filename, rawextras))
       
   484             )
       
   485         if self._labels is not None:
       
   486             labels = b'\0'.join(self._labels)
       
   487             records.append((RECORD_LABELS, labels))
       
   488         return records
       
   489 
       
   490     def _writerecords(self, records):
       
   491         """Write current state on disk (both v1 and v2)"""
       
   492         self._writerecordsv1(records)
       
   493         self._writerecordsv2(records)
       
   494 
       
   495     def _writerecordsv1(self, records):
       
   496         """Write current state on disk in a version 1 file"""
       
   497         f = self._repo.vfs(self.statepathv1, b'wb')
       
   498         irecords = iter(records)
       
   499         lrecords = next(irecords)
       
   500         assert lrecords[0] == RECORD_LOCAL
       
   501         f.write(hex(self._local) + b'\n')
       
   502         for rtype, data in irecords:
       
   503             if rtype == RECORD_MERGED:
       
   504                 f.write(b'%s\n' % _droponode(data))
       
   505         f.close()
       
   506 
       
   507     def _writerecordsv2(self, records):
       
   508         """Write current state on disk in a version 2 file
       
   509 
       
   510         See the docstring for _readrecordsv2 for why we use 't'."""
       
   511         # these are the records that all version 2 clients can read
       
   512         allowlist = (RECORD_LOCAL, RECORD_OTHER, RECORD_MERGED)
       
   513         f = self._repo.vfs(self.statepathv2, b'wb')
       
   514         for key, data in records:
       
   515             assert len(key) == 1
       
   516             if key not in allowlist:
       
   517                 key, data = RECORD_OVERRIDE, b'%s%s' % (key, data)
       
   518             format = b'>sI%is' % len(data)
       
   519             f.write(_pack(format, key, len(data), data))
       
   520         f.close()
       
   521 
       
   522     @staticmethod
       
   523     def getlocalkey(path):
       
   524         """hash the path of a local file context for storage in the .hg/merge
       
   525         directory."""
       
   526 
       
   527         return hex(hashutil.sha1(path).digest())
       
   528 
       
   529     def add(self, fcl, fco, fca, fd):
       
   530         """add a new (potentially?) conflicting file the merge state
       
   531         fcl: file context for local,
       
   532         fco: file context for remote,
       
   533         fca: file context for ancestors,
       
   534         fd:  file path of the resulting merge.
       
   535 
       
   536         note: also write the local version to the `.hg/merge` directory.
       
   537         """
       
   538         if fcl.isabsent():
       
   539             localkey = nullhex
       
   540         else:
       
   541             localkey = mergestate.getlocalkey(fcl.path())
       
   542             self._repo.vfs.write(b'merge/' + localkey, fcl.data())
       
   543         self._state[fd] = [
       
   544             MERGE_RECORD_UNRESOLVED,
       
   545             localkey,
       
   546             fcl.path(),
       
   547             fca.path(),
       
   548             hex(fca.filenode()),
       
   549             fco.path(),
       
   550             hex(fco.filenode()),
       
   551             fcl.flags(),
       
   552         ]
       
   553         self._stateextras[fd] = {b'ancestorlinknode': hex(fca.node())}
       
   554         self._dirty = True
       
   555 
       
   556     def addpath(self, path, frename, forigin):
       
   557         """add a new conflicting path to the merge state
       
   558         path:    the path that conflicts
       
   559         frename: the filename the conflicting file was renamed to
       
   560         forigin: origin of the file ('l' or 'r' for local/remote)
       
   561         """
       
   562         self._state[path] = [MERGE_RECORD_UNRESOLVED_PATH, frename, forigin]
       
   563         self._dirty = True
       
   564 
       
   565     def addmergedother(self, path):
       
   566         self._state[path] = [MERGE_RECORD_MERGED_OTHER, nullhex, nullhex]
       
   567         self._dirty = True
       
   568 
       
   569     def __contains__(self, dfile):
       
   570         return dfile in self._state
       
   571 
       
   572     def __getitem__(self, dfile):
       
   573         return self._state[dfile][0]
       
   574 
       
   575     def __iter__(self):
       
   576         return iter(sorted(self._state))
       
   577 
       
   578     def files(self):
       
   579         return self._state.keys()
       
   580 
       
   581     def mark(self, dfile, state):
       
   582         self._state[dfile][0] = state
       
   583         self._dirty = True
       
   584 
       
   585     def mdstate(self):
       
   586         return self._mdstate
       
   587 
       
   588     def unresolved(self):
       
   589         """Obtain the paths of unresolved files."""
       
   590 
       
   591         for f, entry in pycompat.iteritems(self._state):
       
   592             if entry[0] in (
       
   593                 MERGE_RECORD_UNRESOLVED,
       
   594                 MERGE_RECORD_UNRESOLVED_PATH,
       
   595             ):
       
   596                 yield f
       
   597 
       
   598     def driverresolved(self):
       
   599         """Obtain the paths of driver-resolved files."""
       
   600 
       
   601         for f, entry in self._state.items():
       
   602             if entry[0] == MERGE_RECORD_DRIVER_RESOLVED:
       
   603                 yield f
       
   604 
       
   605     def extras(self, filename):
       
   606         return self._stateextras.setdefault(filename, {})
       
   607 
       
   608     def _resolve(self, preresolve, dfile, wctx):
       
   609         """rerun merge process for file path `dfile`"""
       
   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:
       
   613             return True, 0
       
   614         stateentry = self._state[dfile]
       
   615         state, localkey, lfile, afile, anode, ofile, onode, flags = stateentry
       
   616         octx = self._repo[self._other]
       
   617         extras = self.extras(dfile)
       
   618         anccommitnode = extras.get(b'ancestorlinknode')
       
   619         if anccommitnode:
       
   620             actx = self._repo[anccommitnode]
       
   621         else:
       
   622             actx = None
       
   623         fcd = self._filectxorabsent(localkey, wctx, dfile)
       
   624         fco = self._filectxorabsent(onode, octx, ofile)
       
   625         # TODO: move this to filectxorabsent
       
   626         fca = self._repo.filectx(afile, fileid=anode, changectx=actx)
       
   627         # "premerge" x flags
       
   628         flo = fco.flags()
       
   629         fla = fca.flags()
       
   630         if b'x' in flags + flo + fla and b'l' not in flags + flo + fla:
       
   631             if fca.node() == nullid and flags != flo:
       
   632                 if preresolve:
       
   633                     self._repo.ui.warn(
       
   634                         _(
       
   635                             b'warning: cannot merge flags for %s '
       
   636                             b'without common ancestor - keeping local flags\n'
       
   637                         )
       
   638                         % afile
       
   639                     )
       
   640             elif flags == fla:
       
   641                 flags = flo
       
   642         if preresolve:
       
   643             # restore local
       
   644             if localkey != nullhex:
       
   645                 f = self._repo.vfs(b'merge/' + localkey)
       
   646                 wctx[dfile].write(f.read(), flags)
       
   647                 f.close()
       
   648             else:
       
   649                 wctx[dfile].remove(ignoremissing=True)
       
   650             complete, r, deleted = filemerge.premerge(
       
   651                 self._repo,
       
   652                 wctx,
       
   653                 self._local,
       
   654                 lfile,
       
   655                 fcd,
       
   656                 fco,
       
   657                 fca,
       
   658                 labels=self._labels,
       
   659             )
       
   660         else:
       
   661             complete, r, deleted = filemerge.filemerge(
       
   662                 self._repo,
       
   663                 wctx,
       
   664                 self._local,
       
   665                 lfile,
       
   666                 fcd,
       
   667                 fco,
       
   668                 fca,
       
   669                 labels=self._labels,
       
   670             )
       
   671         if r is None:
       
   672             # no real conflict
       
   673             del self._state[dfile]
       
   674             self._stateextras.pop(dfile, None)
       
   675             self._dirty = True
       
   676         elif not r:
       
   677             self.mark(dfile, MERGE_RECORD_RESOLVED)
       
   678 
       
   679         if complete:
       
   680             action = None
       
   681             if deleted:
       
   682                 if fcd.isabsent():
       
   683                     # dc: local picked. Need to drop if present, which may
       
   684                     # happen on re-resolves.
       
   685                     action = ACTION_FORGET
       
   686                 else:
       
   687                     # cd: remote picked (or otherwise deleted)
       
   688                     action = ACTION_REMOVE
       
   689             else:
       
   690                 if fcd.isabsent():  # dc: remote picked
       
   691                     action = ACTION_GET
       
   692                 elif fco.isabsent():  # cd: local picked
       
   693                     if dfile in self.localctx:
       
   694                         action = ACTION_ADD_MODIFIED
       
   695                     else:
       
   696                         action = ACTION_ADD
       
   697                 # else: regular merges (no action necessary)
       
   698             self._results[dfile] = r, action
       
   699 
       
   700         return complete, r
       
   701 
       
   702     def _filectxorabsent(self, hexnode, ctx, f):
       
   703         if hexnode == nullhex:
       
   704             return filemerge.absentfilectx(ctx, f)
       
   705         else:
       
   706             return ctx[f]
       
   707 
       
   708     def preresolve(self, dfile, wctx):
       
   709         """run premerge process for dfile
       
   710 
       
   711         Returns whether the merge is complete, and the exit code."""
       
   712         return self._resolve(True, dfile, wctx)
       
   713 
       
   714     def resolve(self, dfile, wctx):
       
   715         """run merge process (assuming premerge was run) for dfile
       
   716 
       
   717         Returns the exit code of the merge."""
       
   718         return self._resolve(False, dfile, wctx)[1]
       
   719 
       
   720     def counts(self):
       
   721         """return counts for updated, merged and removed files in this
       
   722         session"""
       
   723         updated, merged, removed = 0, 0, 0
       
   724         for r, action in pycompat.itervalues(self._results):
       
   725             if r is None:
       
   726                 updated += 1
       
   727             elif r == 0:
       
   728                 if action == ACTION_REMOVE:
       
   729                     removed += 1
       
   730                 else:
       
   731                     merged += 1
       
   732         return updated, merged, removed
       
   733 
       
   734     def unresolvedcount(self):
       
   735         """get unresolved count for this merge (persistent)"""
       
   736         return len(list(self.unresolved()))
       
   737 
       
   738     def actions(self):
       
   739         """return lists of actions to perform on the dirstate"""
       
   740         actions = {
       
   741             ACTION_REMOVE: [],
       
   742             ACTION_FORGET: [],
       
   743             ACTION_ADD: [],
       
   744             ACTION_ADD_MODIFIED: [],
       
   745             ACTION_GET: [],
       
   746         }
       
   747         for f, (r, action) in pycompat.iteritems(self._results):
       
   748             if action is not None:
       
   749                 actions[action].append((f, None, b"merge result"))
       
   750         return actions
       
   751 
       
   752     def recordactions(self):
       
   753         """record remove/add/get actions in the dirstate"""
       
   754         branchmerge = self._repo.dirstate.p2() != nullid
       
   755         recordupdates(self._repo, self.actions(), branchmerge, None)
       
   756 
       
   757     def queueremove(self, f):
       
   758         """queues a file to be removed from the dirstate
       
   759 
       
   760         Meant for use by custom merge drivers."""
       
   761         self._results[f] = 0, ACTION_REMOVE
       
   762 
       
   763     def queueadd(self, f):
       
   764         """queues a file to be added to the dirstate
       
   765 
       
   766         Meant for use by custom merge drivers."""
       
   767         self._results[f] = 0, ACTION_ADD
       
   768 
       
   769     def queueget(self, f):
       
   770         """queues a file to be marked modified in the dirstate
       
   771 
       
   772         Meant for use by custom merge drivers."""
       
   773         self._results[f] = 0, ACTION_GET
       
   774 
    40 
   775 
    41 
   776 def _getcheckunknownconfig(repo, section, name):
    42 def _getcheckunknownconfig(repo, section, name):
   777     config = repo.ui.config(section, name)
    43     config = repo.ui.config(section, name)
   778     valid = [b'abort', b'ignore', b'warn']
    44     valid = [b'abort', b'ignore', b'warn']
   883             elif config == b'warn':
   149             elif config == b'warn':
   884                 warnconflicts.update(conflicts)
   150                 warnconflicts.update(conflicts)
   885 
   151 
   886         checkunknowndirs = _unknowndirschecker()
   152         checkunknowndirs = _unknowndirschecker()
   887         for f, (m, args, msg) in pycompat.iteritems(actions):
   153         for f, (m, args, msg) in pycompat.iteritems(actions):
   888             if m in (ACTION_CREATED, ACTION_DELETED_CHANGED):
   154             if m in (
       
   155                 mergestatemod.ACTION_CREATED,
       
   156                 mergestatemod.ACTION_DELETED_CHANGED,
       
   157             ):
   889                 if _checkunknownfile(repo, wctx, mctx, f):
   158                 if _checkunknownfile(repo, wctx, mctx, f):
   890                     fileconflicts.add(f)
   159                     fileconflicts.add(f)
   891                 elif pathconfig and f not in wctx:
   160                 elif pathconfig and f not in wctx:
   892                     path = checkunknowndirs(repo, wctx, f)
   161                     path = checkunknowndirs(repo, wctx, f)
   893                     if path is not None:
   162                     if path is not None:
   894                         pathconflicts.add(path)
   163                         pathconflicts.add(path)
   895             elif m == ACTION_LOCAL_DIR_RENAME_GET:
   164             elif m == mergestatemod.ACTION_LOCAL_DIR_RENAME_GET:
   896                 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
   165                 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
   897                     fileconflicts.add(f)
   166                     fileconflicts.add(f)
   898 
   167 
   899         allconflicts = fileconflicts | pathconflicts
   168         allconflicts = fileconflicts | pathconflicts
   900         ignoredconflicts = {c for c in allconflicts if repo.dirstate._ignore(c)}
   169         ignoredconflicts = {c for c in allconflicts if repo.dirstate._ignore(c)}
   901         unknownconflicts = allconflicts - ignoredconflicts
   170         unknownconflicts = allconflicts - ignoredconflicts
   902         collectconflicts(ignoredconflicts, ignoredconfig)
   171         collectconflicts(ignoredconflicts, ignoredconfig)
   903         collectconflicts(unknownconflicts, unknownconfig)
   172         collectconflicts(unknownconflicts, unknownconfig)
   904     else:
   173     else:
   905         for f, (m, args, msg) in pycompat.iteritems(actions):
   174         for f, (m, args, msg) in pycompat.iteritems(actions):
   906             if m == ACTION_CREATED_MERGE:
   175             if m == mergestatemod.ACTION_CREATED_MERGE:
   907                 fl2, anc = args
   176                 fl2, anc = args
   908                 different = _checkunknownfile(repo, wctx, mctx, f)
   177                 different = _checkunknownfile(repo, wctx, mctx, f)
   909                 if repo.dirstate._ignore(f):
   178                 if repo.dirstate._ignore(f):
   910                     config = ignoredconfig
   179                     config = ignoredconfig
   911                 else:
   180                 else:
   922                 # (1) this is probably the wrong behavior here -- we should
   191                 # (1) this is probably the wrong behavior here -- we should
   923                 #     probably abort, but some actions like rebases currently
   192                 #     probably abort, but some actions like rebases currently
   924                 #     don't like an abort happening in the middle of
   193                 #     don't like an abort happening in the middle of
   925                 #     merge.update.
   194                 #     merge.update.
   926                 if not different:
   195                 if not different:
   927                     actions[f] = (ACTION_GET, (fl2, False), b'remote created')
   196                     actions[f] = (
       
   197                         mergestatemod.ACTION_GET,
       
   198                         (fl2, False),
       
   199                         b'remote created',
       
   200                     )
   928                 elif mergeforce or config == b'abort':
   201                 elif mergeforce or config == b'abort':
   929                     actions[f] = (
   202                     actions[f] = (
   930                         ACTION_MERGE,
   203                         mergestatemod.ACTION_MERGE,
   931                         (f, f, None, False, anc),
   204                         (f, f, None, False, anc),
   932                         b'remote differs from untracked local',
   205                         b'remote differs from untracked local',
   933                     )
   206                     )
   934                 elif config == b'abort':
   207                 elif config == b'abort':
   935                     abortconflicts.add(f)
   208                     abortconflicts.add(f)
   936                 else:
   209                 else:
   937                     if config == b'warn':
   210                     if config == b'warn':
   938                         warnconflicts.add(f)
   211                         warnconflicts.add(f)
   939                     actions[f] = (ACTION_GET, (fl2, True), b'remote created')
   212                     actions[f] = (
       
   213                         mergestatemod.ACTION_GET,
       
   214                         (fl2, True),
       
   215                         b'remote created',
       
   216                     )
   940 
   217 
   941     for f in sorted(abortconflicts):
   218     for f in sorted(abortconflicts):
   942         warn = repo.ui.warn
   219         warn = repo.ui.warn
   943         if f in pathconflicts:
   220         if f in pathconflicts:
   944             if repo.wvfs.isfileorlink(f):
   221             if repo.wvfs.isfileorlink(f):
   960             repo.ui.warn(_(b"%s: replacing untracked file\n") % f)
   237             repo.ui.warn(_(b"%s: replacing untracked file\n") % f)
   961         else:
   238         else:
   962             repo.ui.warn(_(b"%s: replacing untracked files in directory\n") % f)
   239             repo.ui.warn(_(b"%s: replacing untracked files in directory\n") % f)
   963 
   240 
   964     for f, (m, args, msg) in pycompat.iteritems(actions):
   241     for f, (m, args, msg) in pycompat.iteritems(actions):
   965         if m == ACTION_CREATED:
   242         if m == mergestatemod.ACTION_CREATED:
   966             backup = (
   243             backup = (
   967                 f in fileconflicts
   244                 f in fileconflicts
   968                 or f in pathconflicts
   245                 or f in pathconflicts
   969                 or any(p in pathconflicts for p in pathutil.finddirs(f))
   246                 or any(p in pathconflicts for p in pathutil.finddirs(f))
   970             )
   247             )
   971             (flags,) = args
   248             (flags,) = args
   972             actions[f] = (ACTION_GET, (flags, backup), msg)
   249             actions[f] = (mergestatemod.ACTION_GET, (flags, backup), msg)
   973 
   250 
   974 
   251 
   975 def _forgetremoved(wctx, mctx, branchmerge):
   252 def _forgetremoved(wctx, mctx, branchmerge):
   976     """
   253     """
   977     Forget removed files
   254     Forget removed files
   986     that is not present in the working directory, we need to mark it
   263     that is not present in the working directory, we need to mark it
   987     as removed.
   264     as removed.
   988     """
   265     """
   989 
   266 
   990     actions = {}
   267     actions = {}
   991     m = ACTION_FORGET
   268     m = mergestatemod.ACTION_FORGET
   992     if branchmerge:
   269     if branchmerge:
   993         m = ACTION_REMOVE
   270         m = mergestatemod.ACTION_REMOVE
   994     for f in wctx.deleted():
   271     for f in wctx.deleted():
   995         if f not in mctx:
   272         if f not in mctx:
   996             actions[f] = m, None, b"forget deleted"
   273             actions[f] = m, None, b"forget deleted"
   997 
   274 
   998     if not branchmerge:
   275     if not branchmerge:
   999         for f in wctx.removed():
   276         for f in wctx.removed():
  1000             if f not in mctx:
   277             if f not in mctx:
  1001                 actions[f] = ACTION_FORGET, None, b"forget removed"
   278                 actions[f] = (
       
   279                     mergestatemod.ACTION_FORGET,
       
   280                     None,
       
   281                     b"forget removed",
       
   282                 )
  1002 
   283 
  1003     return actions
   284     return actions
  1004 
   285 
  1005 
   286 
  1006 def _checkcollision(repo, wmf, actions):
   287 def _checkcollision(repo, wmf, actions):
  1024         pmmf = set(wmf)
   305         pmmf = set(wmf)
  1025 
   306 
  1026     if actions:
   307     if actions:
  1027         # KEEP and EXEC are no-op
   308         # KEEP and EXEC are no-op
  1028         for m in (
   309         for m in (
  1029             ACTION_ADD,
   310             mergestatemod.ACTION_ADD,
  1030             ACTION_ADD_MODIFIED,
   311             mergestatemod.ACTION_ADD_MODIFIED,
  1031             ACTION_FORGET,
   312             mergestatemod.ACTION_FORGET,
  1032             ACTION_GET,
   313             mergestatemod.ACTION_GET,
  1033             ACTION_CHANGED_DELETED,
   314             mergestatemod.ACTION_CHANGED_DELETED,
  1034             ACTION_DELETED_CHANGED,
   315             mergestatemod.ACTION_DELETED_CHANGED,
  1035         ):
   316         ):
  1036             for f, args, msg in actions[m]:
   317             for f, args, msg in actions[m]:
  1037                 pmmf.add(f)
   318                 pmmf.add(f)
  1038         for f, args, msg in actions[ACTION_REMOVE]:
   319         for f, args, msg in actions[mergestatemod.ACTION_REMOVE]:
  1039             pmmf.discard(f)
   320             pmmf.discard(f)
  1040         for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]:
   321         for f, args, msg in actions[mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL]:
  1041             f2, flags = args
   322             f2, flags = args
  1042             pmmf.discard(f2)
   323             pmmf.discard(f2)
  1043             pmmf.add(f)
   324             pmmf.add(f)
  1044         for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]:
   325         for f, args, msg in actions[mergestatemod.ACTION_LOCAL_DIR_RENAME_GET]:
  1045             pmmf.add(f)
   326             pmmf.add(f)
  1046         for f, args, msg in actions[ACTION_MERGE]:
   327         for f, args, msg in actions[mergestatemod.ACTION_MERGE]:
  1047             f1, f2, fa, move, anc = args
   328             f1, f2, fa, move, anc = args
  1048             if move:
   329             if move:
  1049                 pmmf.discard(f1)
   330                 pmmf.discard(f1)
  1050             pmmf.add(f)
   331             pmmf.add(f)
  1051 
   332 
  1126     # The set of files deleted by all the actions.
   407     # The set of files deleted by all the actions.
  1127     deletedfiles = set()
   408     deletedfiles = set()
  1128 
   409 
  1129     for f, (m, args, msg) in actions.items():
   410     for f, (m, args, msg) in actions.items():
  1130         if m in (
   411         if m in (
  1131             ACTION_CREATED,
   412             mergestatemod.ACTION_CREATED,
  1132             ACTION_DELETED_CHANGED,
   413             mergestatemod.ACTION_DELETED_CHANGED,
  1133             ACTION_MERGE,
   414             mergestatemod.ACTION_MERGE,
  1134             ACTION_CREATED_MERGE,
   415             mergestatemod.ACTION_CREATED_MERGE,
  1135         ):
   416         ):
  1136             # This action may create a new local file.
   417             # This action may create a new local file.
  1137             createdfiledirs.update(pathutil.finddirs(f))
   418             createdfiledirs.update(pathutil.finddirs(f))
  1138             if mf.hasdir(f):
   419             if mf.hasdir(f):
  1139                 # The file aliases a local directory.  This might be ok if all
   420                 # The file aliases a local directory.  This might be ok if all
  1140                 # the files in the local directory are being deleted.  This
   421                 # the files in the local directory are being deleted.  This
  1141                 # will be checked once we know what all the deleted files are.
   422                 # will be checked once we know what all the deleted files are.
  1142                 remoteconflicts.add(f)
   423                 remoteconflicts.add(f)
  1143         # Track the names of all deleted files.
   424         # Track the names of all deleted files.
  1144         if m == ACTION_REMOVE:
   425         if m == mergestatemod.ACTION_REMOVE:
  1145             deletedfiles.add(f)
   426             deletedfiles.add(f)
  1146         if m == ACTION_MERGE:
   427         if m == mergestatemod.ACTION_MERGE:
  1147             f1, f2, fa, move, anc = args
   428             f1, f2, fa, move, anc = args
  1148             if move:
   429             if move:
  1149                 deletedfiles.add(f1)
   430                 deletedfiles.add(f1)
  1150         if m == ACTION_DIR_RENAME_MOVE_LOCAL:
   431         if m == mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL:
  1151             f2, flags = args
   432             f2, flags = args
  1152             deletedfiles.add(f2)
   433             deletedfiles.add(f2)
  1153 
   434 
  1154     # Check all directories that contain created files for path conflicts.
   435     # Check all directories that contain created files for path conflicts.
  1155     for p in createdfiledirs:
   436     for p in createdfiledirs:
  1162             else:
   443             else:
  1163                 # A file is in a directory which aliases a local file.
   444                 # A file is in a directory which aliases a local file.
  1164                 # We will need to rename the local file.
   445                 # We will need to rename the local file.
  1165                 localconflicts.add(p)
   446                 localconflicts.add(p)
  1166         if p in actions and actions[p][0] in (
   447         if p in actions and actions[p][0] in (
  1167             ACTION_CREATED,
   448             mergestatemod.ACTION_CREATED,
  1168             ACTION_DELETED_CHANGED,
   449             mergestatemod.ACTION_DELETED_CHANGED,
  1169             ACTION_MERGE,
   450             mergestatemod.ACTION_MERGE,
  1170             ACTION_CREATED_MERGE,
   451             mergestatemod.ACTION_CREATED_MERGE,
  1171         ):
   452         ):
  1172             # The file is in a directory which aliases a remote file.
   453             # The file is in a directory which aliases a remote file.
  1173             # This is an internal inconsistency within the remote
   454             # This is an internal inconsistency within the remote
  1174             # manifest.
   455             # manifest.
  1175             invalidconflicts.add(p)
   456             invalidconflicts.add(p)
  1178     for p in localconflicts:
   459     for p in localconflicts:
  1179         if p not in deletedfiles:
   460         if p not in deletedfiles:
  1180             ctxname = bytes(wctx).rstrip(b'+')
   461             ctxname = bytes(wctx).rstrip(b'+')
  1181             pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
   462             pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
  1182             actions[pnew] = (
   463             actions[pnew] = (
  1183                 ACTION_PATH_CONFLICT_RESOLVE,
   464                 mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
  1184                 (p,),
   465                 (p,),
  1185                 b'local path conflict',
   466                 b'local path conflict',
  1186             )
   467             )
  1187             actions[p] = (ACTION_PATH_CONFLICT, (pnew, b'l'), b'path conflict')
   468             actions[p] = (
       
   469                 mergestatemod.ACTION_PATH_CONFLICT,
       
   470                 (pnew, b'l'),
       
   471                 b'path conflict',
       
   472             )
  1188 
   473 
  1189     if remoteconflicts:
   474     if remoteconflicts:
  1190         # Check if all files in the conflicting directories have been removed.
   475         # Check if all files in the conflicting directories have been removed.
  1191         ctxname = bytes(mctx).rstrip(b'+')
   476         ctxname = bytes(mctx).rstrip(b'+')
  1192         for f, p in _filesindirs(repo, mf, remoteconflicts):
   477         for f, p in _filesindirs(repo, mf, remoteconflicts):
  1193             if f not in deletedfiles:
   478             if f not in deletedfiles:
  1194                 m, args, msg = actions[p]
   479                 m, args, msg = actions[p]
  1195                 pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
   480                 pnew = util.safename(p, ctxname, wctx, set(actions.keys()))
  1196                 if m in (ACTION_DELETED_CHANGED, ACTION_MERGE):
   481                 if m in (
       
   482                     mergestatemod.ACTION_DELETED_CHANGED,
       
   483                     mergestatemod.ACTION_MERGE,
       
   484                 ):
  1197                     # Action was merge, just update target.
   485                     # Action was merge, just update target.
  1198                     actions[pnew] = (m, args, msg)
   486                     actions[pnew] = (m, args, msg)
  1199                 else:
   487                 else:
  1200                     # Action was create, change to renamed get action.
   488                     # Action was create, change to renamed get action.
  1201                     fl = args[0]
   489                     fl = args[0]
  1202                     actions[pnew] = (
   490                     actions[pnew] = (
  1203                         ACTION_LOCAL_DIR_RENAME_GET,
   491                         mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,
  1204                         (p, fl),
   492                         (p, fl),
  1205                         b'remote path conflict',
   493                         b'remote path conflict',
  1206                     )
   494                     )
  1207                 actions[p] = (
   495                 actions[p] = (
  1208                     ACTION_PATH_CONFLICT,
   496                     mergestatemod.ACTION_PATH_CONFLICT,
  1209                     (pnew, ACTION_REMOVE),
   497                     (pnew, mergestatemod.ACTION_REMOVE),
  1210                     b'path conflict',
   498                     b'path conflict',
  1211                 )
   499                 )
  1212                 remoteconflicts.remove(p)
   500                 remoteconflicts.remove(p)
  1213                 break
   501                 break
  1214 
   502 
  1338                 fa = branch_copies1.copy.get(
   626                 fa = branch_copies1.copy.get(
  1339                     f, None
   627                     f, None
  1340                 ) or branch_copies2.copy.get(f, None)
   628                 ) or branch_copies2.copy.get(f, None)
  1341                 if fa is not None:
   629                 if fa is not None:
  1342                     actions[f] = (
   630                     actions[f] = (
  1343                         ACTION_MERGE,
   631                         mergestatemod.ACTION_MERGE,
  1344                         (f, f, fa, False, pa.node()),
   632                         (f, f, fa, False, pa.node()),
  1345                         b'both renamed from %s' % fa,
   633                         b'both renamed from %s' % fa,
  1346                     )
   634                     )
  1347                 else:
   635                 else:
  1348                     actions[f] = (
   636                     actions[f] = (
  1349                         ACTION_MERGE,
   637                         mergestatemod.ACTION_MERGE,
  1350                         (f, f, None, False, pa.node()),
   638                         (f, f, None, False, pa.node()),
  1351                         b'both created',
   639                         b'both created',
  1352                     )
   640                     )
  1353             else:
   641             else:
  1354                 a = ma[f]
   642                 a = ma[f]
  1355                 fla = ma.flags(f)
   643                 fla = ma.flags(f)
  1356                 nol = b'l' not in fl1 + fl2 + fla
   644                 nol = b'l' not in fl1 + fl2 + fla
  1357                 if n2 == a and fl2 == fla:
   645                 if n2 == a and fl2 == fla:
  1358                     actions[f] = (ACTION_KEEP, (), b'remote unchanged')
   646                     actions[f] = (
       
   647                         mergestatemod.ACTION_KEEP,
       
   648                         (),
       
   649                         b'remote unchanged',
       
   650                     )
  1359                 elif n1 == a and fl1 == fla:  # local unchanged - use remote
   651                 elif n1 == a and fl1 == fla:  # local unchanged - use remote
  1360                     if n1 == n2:  # optimization: keep local content
   652                     if n1 == n2:  # optimization: keep local content
  1361                         actions[f] = (
   653                         actions[f] = (
  1362                             ACTION_EXEC,
   654                             mergestatemod.ACTION_EXEC,
  1363                             (fl2,),
   655                             (fl2,),
  1364                             b'update permissions',
   656                             b'update permissions',
  1365                         )
   657                         )
  1366                     else:
   658                     else:
  1367                         actions[f] = (
   659                         actions[f] = (
  1368                             ACTION_GET_OTHER_AND_STORE
   660                             mergestatemod.ACTION_GET_OTHER_AND_STORE
  1369                             if branchmerge
   661                             if branchmerge
  1370                             else ACTION_GET,
   662                             else mergestatemod.ACTION_GET,
  1371                             (fl2, False),
   663                             (fl2, False),
  1372                             b'remote is newer',
   664                             b'remote is newer',
  1373                         )
   665                         )
  1374                 elif nol and n2 == a:  # remote only changed 'x'
   666                 elif nol and n2 == a:  # remote only changed 'x'
  1375                     actions[f] = (ACTION_EXEC, (fl2,), b'update permissions')
   667                     actions[f] = (
       
   668                         mergestatemod.ACTION_EXEC,
       
   669                         (fl2,),
       
   670                         b'update permissions',
       
   671                     )
  1376                 elif nol and n1 == a:  # local only changed 'x'
   672                 elif nol and n1 == a:  # local only changed 'x'
  1377                     actions[f] = (
   673                     actions[f] = (
  1378                         ACTION_GET_OTHER_AND_STORE
   674                         mergestatemod.ACTION_GET_OTHER_AND_STORE
  1379                         if branchmerge
   675                         if branchmerge
  1380                         else ACTION_GET,
   676                         else mergestatemod.ACTION_GET,
  1381                         (fl1, False),
   677                         (fl1, False),
  1382                         b'remote is newer',
   678                         b'remote is newer',
  1383                     )
   679                     )
  1384                 else:  # both changed something
   680                 else:  # both changed something
  1385                     actions[f] = (
   681                     actions[f] = (
  1386                         ACTION_MERGE,
   682                         mergestatemod.ACTION_MERGE,
  1387                         (f, f, f, False, pa.node()),
   683                         (f, f, f, False, pa.node()),
  1388                         b'versions differ',
   684                         b'versions differ',
  1389                     )
   685                     )
  1390         elif n1:  # file exists only on local side
   686         elif n1:  # file exists only on local side
  1391             if f in copied2:
   687             if f in copied2:
  1394                 f in branch_copies1.movewithdir
   690                 f in branch_copies1.movewithdir
  1395             ):  # directory rename, move local
   691             ):  # directory rename, move local
  1396                 f2 = branch_copies1.movewithdir[f]
   692                 f2 = branch_copies1.movewithdir[f]
  1397                 if f2 in m2:
   693                 if f2 in m2:
  1398                     actions[f2] = (
   694                     actions[f2] = (
  1399                         ACTION_MERGE,
   695                         mergestatemod.ACTION_MERGE,
  1400                         (f, f2, None, True, pa.node()),
   696                         (f, f2, None, True, pa.node()),
  1401                         b'remote directory rename, both created',
   697                         b'remote directory rename, both created',
  1402                     )
   698                     )
  1403                 else:
   699                 else:
  1404                     actions[f2] = (
   700                     actions[f2] = (
  1405                         ACTION_DIR_RENAME_MOVE_LOCAL,
   701                         mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL,
  1406                         (f, fl1),
   702                         (f, fl1),
  1407                         b'remote directory rename - move from %s' % f,
   703                         b'remote directory rename - move from %s' % f,
  1408                     )
   704                     )
  1409             elif f in branch_copies1.copy:
   705             elif f in branch_copies1.copy:
  1410                 f2 = branch_copies1.copy[f]
   706                 f2 = branch_copies1.copy[f]
  1411                 actions[f] = (
   707                 actions[f] = (
  1412                     ACTION_MERGE,
   708                     mergestatemod.ACTION_MERGE,
  1413                     (f, f2, f2, False, pa.node()),
   709                     (f, f2, f2, False, pa.node()),
  1414                     b'local copied/moved from %s' % f2,
   710                     b'local copied/moved from %s' % f2,
  1415                 )
   711                 )
  1416             elif f in ma:  # clean, a different, no remote
   712             elif f in ma:  # clean, a different, no remote
  1417                 if n1 != ma[f]:
   713                 if n1 != ma[f]:
  1418                     if acceptremote:
   714                     if acceptremote:
  1419                         actions[f] = (ACTION_REMOVE, None, b'remote delete')
   715                         actions[f] = (
       
   716                             mergestatemod.ACTION_REMOVE,
       
   717                             None,
       
   718                             b'remote delete',
       
   719                         )
  1420                     else:
   720                     else:
  1421                         actions[f] = (
   721                         actions[f] = (
  1422                             ACTION_CHANGED_DELETED,
   722                             mergestatemod.ACTION_CHANGED_DELETED,
  1423                             (f, None, f, False, pa.node()),
   723                             (f, None, f, False, pa.node()),
  1424                             b'prompt changed/deleted',
   724                             b'prompt changed/deleted',
  1425                         )
   725                         )
  1426                 elif n1 == addednodeid:
   726                 elif n1 == addednodeid:
  1427                     # This extra 'a' is added by working copy manifest to mark
   727                     # This extra 'a' is added by working copy manifest to mark
  1428                     # the file as locally added. We should forget it instead of
   728                     # the file as locally added. We should forget it instead of
  1429                     # deleting it.
   729                     # deleting it.
  1430                     actions[f] = (ACTION_FORGET, None, b'remote deleted')
   730                     actions[f] = (
       
   731                         mergestatemod.ACTION_FORGET,
       
   732                         None,
       
   733                         b'remote deleted',
       
   734                     )
  1431                 else:
   735                 else:
  1432                     actions[f] = (ACTION_REMOVE, None, b'other deleted')
   736                     actions[f] = (
       
   737                         mergestatemod.ACTION_REMOVE,
       
   738                         None,
       
   739                         b'other deleted',
       
   740                     )
  1433         elif n2:  # file exists only on remote side
   741         elif n2:  # file exists only on remote side
  1434             if f in copied1:
   742             if f in copied1:
  1435                 pass  # we'll deal with it on m1 side
   743                 pass  # we'll deal with it on m1 side
  1436             elif f in branch_copies2.movewithdir:
   744             elif f in branch_copies2.movewithdir:
  1437                 f2 = branch_copies2.movewithdir[f]
   745                 f2 = branch_copies2.movewithdir[f]
  1438                 if f2 in m1:
   746                 if f2 in m1:
  1439                     actions[f2] = (
   747                     actions[f2] = (
  1440                         ACTION_MERGE,
   748                         mergestatemod.ACTION_MERGE,
  1441                         (f2, f, None, False, pa.node()),
   749                         (f2, f, None, False, pa.node()),
  1442                         b'local directory rename, both created',
   750                         b'local directory rename, both created',
  1443                     )
   751                     )
  1444                 else:
   752                 else:
  1445                     actions[f2] = (
   753                     actions[f2] = (
  1446                         ACTION_LOCAL_DIR_RENAME_GET,
   754                         mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,
  1447                         (f, fl2),
   755                         (f, fl2),
  1448                         b'local directory rename - get from %s' % f,
   756                         b'local directory rename - get from %s' % f,
  1449                     )
   757                     )
  1450             elif f in branch_copies2.copy:
   758             elif f in branch_copies2.copy:
  1451                 f2 = branch_copies2.copy[f]
   759                 f2 = branch_copies2.copy[f]
  1452                 if f2 in m2:
   760                 if f2 in m2:
  1453                     actions[f] = (
   761                     actions[f] = (
  1454                         ACTION_MERGE,
   762                         mergestatemod.ACTION_MERGE,
  1455                         (f2, f, f2, False, pa.node()),
   763                         (f2, f, f2, False, pa.node()),
  1456                         b'remote copied from %s' % f2,
   764                         b'remote copied from %s' % f2,
  1457                     )
   765                     )
  1458                 else:
   766                 else:
  1459                     actions[f] = (
   767                     actions[f] = (
  1460                         ACTION_MERGE,
   768                         mergestatemod.ACTION_MERGE,
  1461                         (f2, f, f2, True, pa.node()),
   769                         (f2, f, f2, True, pa.node()),
  1462                         b'remote moved from %s' % f2,
   770                         b'remote moved from %s' % f2,
  1463                     )
   771                     )
  1464             elif f not in ma:
   772             elif f not in ma:
  1465                 # local unknown, remote created: the logic is described by the
   773                 # local unknown, remote created: the logic is described by the
  1472                 #   y         y           y      |   merge
   780                 #   y         y           y      |   merge
  1473                 #
   781                 #
  1474                 # Checking whether the files are different is expensive, so we
   782                 # Checking whether the files are different is expensive, so we
  1475                 # don't do that when we can avoid it.
   783                 # don't do that when we can avoid it.
  1476                 if not force:
   784                 if not force:
  1477                     actions[f] = (ACTION_CREATED, (fl2,), b'remote created')
   785                     actions[f] = (
       
   786                         mergestatemod.ACTION_CREATED,
       
   787                         (fl2,),
       
   788                         b'remote created',
       
   789                     )
  1478                 elif not branchmerge:
   790                 elif not branchmerge:
  1479                     actions[f] = (ACTION_CREATED, (fl2,), b'remote created')
   791                     actions[f] = (
       
   792                         mergestatemod.ACTION_CREATED,
       
   793                         (fl2,),
       
   794                         b'remote created',
       
   795                     )
  1480                 else:
   796                 else:
  1481                     actions[f] = (
   797                     actions[f] = (
  1482                         ACTION_CREATED_MERGE,
   798                         mergestatemod.ACTION_CREATED_MERGE,
  1483                         (fl2, pa.node()),
   799                         (fl2, pa.node()),
  1484                         b'remote created, get or merge',
   800                         b'remote created, get or merge',
  1485                     )
   801                     )
  1486             elif n2 != ma[f]:
   802             elif n2 != ma[f]:
  1487                 df = None
   803                 df = None
  1490                         # new file added in a directory that was moved
   806                         # new file added in a directory that was moved
  1491                         df = branch_copies1.dirmove[d] + f[len(d) :]
   807                         df = branch_copies1.dirmove[d] + f[len(d) :]
  1492                         break
   808                         break
  1493                 if df is not None and df in m1:
   809                 if df is not None and df in m1:
  1494                     actions[df] = (
   810                     actions[df] = (
  1495                         ACTION_MERGE,
   811                         mergestatemod.ACTION_MERGE,
  1496                         (df, f, f, False, pa.node()),
   812                         (df, f, f, False, pa.node()),
  1497                         b'local directory rename - respect move '
   813                         b'local directory rename - respect move '
  1498                         b'from %s' % f,
   814                         b'from %s' % f,
  1499                     )
   815                     )
  1500                 elif acceptremote:
   816                 elif acceptremote:
  1501                     actions[f] = (ACTION_CREATED, (fl2,), b'remote recreating')
   817                     actions[f] = (
       
   818                         mergestatemod.ACTION_CREATED,
       
   819                         (fl2,),
       
   820                         b'remote recreating',
       
   821                     )
  1502                 else:
   822                 else:
  1503                     actions[f] = (
   823                     actions[f] = (
  1504                         ACTION_DELETED_CHANGED,
   824                         mergestatemod.ACTION_DELETED_CHANGED,
  1505                         (None, f, f, False, pa.node()),
   825                         (None, f, f, False, pa.node()),
  1506                         b'prompt deleted/changed',
   826                         b'prompt deleted/changed',
  1507                     )
   827                     )
  1508 
   828 
  1509     if repo.ui.configbool(b'experimental', b'merge.checkpathconflicts'):
   829     if repo.ui.configbool(b'experimental', b'merge.checkpathconflicts'):
  1526        remained the same."""
   846        remained the same."""
  1527     # We force a copy of actions.items() because we're going to mutate
   847     # We force a copy of actions.items() because we're going to mutate
  1528     # actions as we resolve trivial conflicts.
   848     # actions as we resolve trivial conflicts.
  1529     for f, (m, args, msg) in list(actions.items()):
   849     for f, (m, args, msg) in list(actions.items()):
  1530         if (
   850         if (
  1531             m == ACTION_CHANGED_DELETED
   851             m == mergestatemod.ACTION_CHANGED_DELETED
  1532             and f in ancestor
   852             and f in ancestor
  1533             and not wctx[f].cmp(ancestor[f])
   853             and not wctx[f].cmp(ancestor[f])
  1534         ):
   854         ):
  1535             # local did change but ended up with same content
   855             # local did change but ended up with same content
  1536             actions[f] = ACTION_REMOVE, None, b'prompt same'
   856             actions[f] = mergestatemod.ACTION_REMOVE, None, b'prompt same'
  1537         elif (
   857         elif (
  1538             m == ACTION_DELETED_CHANGED
   858             m == mergestatemod.ACTION_DELETED_CHANGED
  1539             and f in ancestor
   859             and f in ancestor
  1540             and not mctx[f].cmp(ancestor[f])
   860             and not mctx[f].cmp(ancestor[f])
  1541         ):
   861         ):
  1542             # remote did change but ended up with same content
   862             # remote did change but ended up with same content
  1543             del actions[f]  # don't get = keep local deleted
   863             del actions[f]  # don't get = keep local deleted
  1611             if renamedelete is None or len(renamedelete) < len(renamedelete1):
   931             if renamedelete is None or len(renamedelete) < len(renamedelete1):
  1612                 renamedelete = renamedelete1
   932                 renamedelete = renamedelete1
  1613 
   933 
  1614             for f, a in sorted(pycompat.iteritems(actions)):
   934             for f, a in sorted(pycompat.iteritems(actions)):
  1615                 m, args, msg = a
   935                 m, args, msg = a
  1616                 if m == ACTION_GET_OTHER_AND_STORE:
   936                 if m == mergestatemod.ACTION_GET_OTHER_AND_STORE:
  1617                     m = ACTION_GET
   937                     m = mergestatemod.ACTION_GET
  1618                 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m))
   938                 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m))
  1619                 if f in fbids:
   939                 if f in fbids:
  1620                     d = fbids[f]
   940                     d = fbids[f]
  1621                     if m in d:
   941                     if m in d:
  1622                         d[m].append(a)
   942                         d[m].append(a)
  1636                 if all(a == l[0] for a in l[1:]):  # len(bids) is > 1
   956                 if all(a == l[0] for a in l[1:]):  # len(bids) is > 1
  1637                     repo.ui.note(_(b" %s: consensus for %s\n") % (f, m))
   957                     repo.ui.note(_(b" %s: consensus for %s\n") % (f, m))
  1638                     actions[f] = l[0]
   958                     actions[f] = l[0]
  1639                     continue
   959                     continue
  1640             # If keep is an option, just do it.
   960             # If keep is an option, just do it.
  1641             if ACTION_KEEP in bids:
   961             if mergestatemod.ACTION_KEEP in bids:
  1642                 repo.ui.note(_(b" %s: picking 'keep' action\n") % f)
   962                 repo.ui.note(_(b" %s: picking 'keep' action\n") % f)
  1643                 actions[f] = bids[ACTION_KEEP][0]
   963                 actions[f] = bids[mergestatemod.ACTION_KEEP][0]
  1644                 continue
   964                 continue
  1645             # If there are gets and they all agree [how could they not?], do it.
   965             # If there are gets and they all agree [how could they not?], do it.
  1646             if ACTION_GET in bids:
   966             if mergestatemod.ACTION_GET in bids:
  1647                 ga0 = bids[ACTION_GET][0]
   967                 ga0 = bids[mergestatemod.ACTION_GET][0]
  1648                 if all(a == ga0 for a in bids[ACTION_GET][1:]):
   968                 if all(a == ga0 for a in bids[mergestatemod.ACTION_GET][1:]):
  1649                     repo.ui.note(_(b" %s: picking 'get' action\n") % f)
   969                     repo.ui.note(_(b" %s: picking 'get' action\n") % f)
  1650                     actions[f] = ga0
   970                     actions[f] = ga0
  1651                     continue
   971                     continue
  1652             # TODO: Consider other simple actions such as mode changes
   972             # TODO: Consider other simple actions such as mode changes
  1653             # Handle inefficient democrazy.
   973             # Handle inefficient democrazy.
  1788     # don't touch the context to be merged in.  'cd' is skipped, because
  1108     # don't touch the context to be merged in.  'cd' is skipped, because
  1789     # changed/deleted never resolves to something from the remote side.
  1109     # changed/deleted never resolves to something from the remote side.
  1790     oplist = [
  1110     oplist = [
  1791         actions[a]
  1111         actions[a]
  1792         for a in (
  1112         for a in (
  1793             ACTION_GET,
  1113             mergestatemod.ACTION_GET,
  1794             ACTION_DELETED_CHANGED,
  1114             mergestatemod.ACTION_DELETED_CHANGED,
  1795             ACTION_LOCAL_DIR_RENAME_GET,
  1115             mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,
  1796             ACTION_MERGE,
  1116             mergestatemod.ACTION_MERGE,
  1797         )
  1117         )
  1798     ]
  1118     ]
  1799     prefetch = scmutil.prefetchfiles
  1119     prefetch = scmutil.prefetchfiles
  1800     matchfiles = scmutil.matchfiles
  1120     matchfiles = scmutil.matchfiles
  1801     prefetch(
  1121     prefetch(
  1824 def emptyactions():
  1144 def emptyactions():
  1825     """create an actions dict, to be populated and passed to applyupdates()"""
  1145     """create an actions dict, to be populated and passed to applyupdates()"""
  1826     return {
  1146     return {
  1827         m: []
  1147         m: []
  1828         for m in (
  1148         for m in (
  1829             ACTION_ADD,
  1149             mergestatemod.ACTION_ADD,
  1830             ACTION_ADD_MODIFIED,
  1150             mergestatemod.ACTION_ADD_MODIFIED,
  1831             ACTION_FORGET,
  1151             mergestatemod.ACTION_FORGET,
  1832             ACTION_GET,
  1152             mergestatemod.ACTION_GET,
  1833             ACTION_CHANGED_DELETED,
  1153             mergestatemod.ACTION_CHANGED_DELETED,
  1834             ACTION_DELETED_CHANGED,
  1154             mergestatemod.ACTION_DELETED_CHANGED,
  1835             ACTION_REMOVE,
  1155             mergestatemod.ACTION_REMOVE,
  1836             ACTION_DIR_RENAME_MOVE_LOCAL,
  1156             mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL,
  1837             ACTION_LOCAL_DIR_RENAME_GET,
  1157             mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,
  1838             ACTION_MERGE,
  1158             mergestatemod.ACTION_MERGE,
  1839             ACTION_EXEC,
  1159             mergestatemod.ACTION_EXEC,
  1840             ACTION_KEEP,
  1160             mergestatemod.ACTION_KEEP,
  1841             ACTION_PATH_CONFLICT,
  1161             mergestatemod.ACTION_PATH_CONFLICT,
  1842             ACTION_PATH_CONFLICT_RESOLVE,
  1162             mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
  1843             ACTION_GET_OTHER_AND_STORE,
  1163             mergestatemod.ACTION_GET_OTHER_AND_STORE,
  1844         )
  1164         )
  1845     }
  1165     }
  1846 
  1166 
  1847 
  1167 
  1848 def applyupdates(
  1168 def applyupdates(
  1860     """
  1180     """
  1861 
  1181 
  1862     _prefetchfiles(repo, mctx, actions)
  1182     _prefetchfiles(repo, mctx, actions)
  1863 
  1183 
  1864     updated, merged, removed = 0, 0, 0
  1184     updated, merged, removed = 0, 0, 0
  1865     ms = mergestate.clean(repo, wctx.p1().node(), mctx.node(), labels)
  1185     ms = mergestatemod.mergestate.clean(
       
  1186         repo, wctx.p1().node(), mctx.node(), labels
       
  1187     )
  1866 
  1188 
  1867     # add ACTION_GET_OTHER_AND_STORE to mergestate
  1189     # add ACTION_GET_OTHER_AND_STORE to mergestate
  1868     for e in actions[ACTION_GET_OTHER_AND_STORE]:
  1190     for e in actions[mergestatemod.ACTION_GET_OTHER_AND_STORE]:
  1869         ms.addmergedother(e[0])
  1191         ms.addmergedother(e[0])
  1870 
  1192 
  1871     moves = []
  1193     moves = []
  1872     for m, l in actions.items():
  1194     for m, l in actions.items():
  1873         l.sort()
  1195         l.sort()
  1874 
  1196 
  1875     # 'cd' and 'dc' actions are treated like other merge conflicts
  1197     # 'cd' and 'dc' actions are treated like other merge conflicts
  1876     mergeactions = sorted(actions[ACTION_CHANGED_DELETED])
  1198     mergeactions = sorted(actions[mergestatemod.ACTION_CHANGED_DELETED])
  1877     mergeactions.extend(sorted(actions[ACTION_DELETED_CHANGED]))
  1199     mergeactions.extend(sorted(actions[mergestatemod.ACTION_DELETED_CHANGED]))
  1878     mergeactions.extend(actions[ACTION_MERGE])
  1200     mergeactions.extend(actions[mergestatemod.ACTION_MERGE])
  1879     for f, args, msg in mergeactions:
  1201     for f, args, msg in mergeactions:
  1880         f1, f2, fa, move, anc = args
  1202         f1, f2, fa, move, anc = args
  1881         if f == b'.hgsubstate':  # merged internally
  1203         if f == b'.hgsubstate':  # merged internally
  1882             continue
  1204             continue
  1883         if f1 is None:
  1205         if f1 is None:
  1904         if wctx[f].lexists():
  1226         if wctx[f].lexists():
  1905             repo.ui.debug(b"removing %s\n" % f)
  1227             repo.ui.debug(b"removing %s\n" % f)
  1906             wctx[f].audit()
  1228             wctx[f].audit()
  1907             wctx[f].remove()
  1229             wctx[f].remove()
  1908 
  1230 
  1909     numupdates = sum(len(l) for m, l in actions.items() if m != ACTION_KEEP)
  1231     numupdates = sum(
       
  1232         len(l) for m, l in actions.items() if m != mergestatemod.ACTION_KEEP
       
  1233     )
  1910     progress = repo.ui.makeprogress(
  1234     progress = repo.ui.makeprogress(
  1911         _(b'updating'), unit=_(b'files'), total=numupdates
  1235         _(b'updating'), unit=_(b'files'), total=numupdates
  1912     )
  1236     )
  1913 
  1237 
  1914     if [a for a in actions[ACTION_REMOVE] if a[0] == b'.hgsubstate']:
  1238     if [
       
  1239         a
       
  1240         for a in actions[mergestatemod.ACTION_REMOVE]
       
  1241         if a[0] == b'.hgsubstate'
       
  1242     ]:
  1915         subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
  1243         subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
  1916 
  1244 
  1917     # record path conflicts
  1245     # record path conflicts
  1918     for f, args, msg in actions[ACTION_PATH_CONFLICT]:
  1246     for f, args, msg in actions[mergestatemod.ACTION_PATH_CONFLICT]:
  1919         f1, fo = args
  1247         f1, fo = args
  1920         s = repo.ui.status
  1248         s = repo.ui.status
  1921         s(
  1249         s(
  1922             _(
  1250             _(
  1923                 b"%s: path conflict - a file or link has the same name as a "
  1251                 b"%s: path conflict - a file or link has the same name as a "
  1937     # per-item cost at 0 in that case.
  1265     # per-item cost at 0 in that case.
  1938     cost = 0 if wctx.isinmemory() else 0.001
  1266     cost = 0 if wctx.isinmemory() else 0.001
  1939 
  1267 
  1940     # remove in parallel (must come before resolving path conflicts and getting)
  1268     # remove in parallel (must come before resolving path conflicts and getting)
  1941     prog = worker.worker(
  1269     prog = worker.worker(
  1942         repo.ui, cost, batchremove, (repo, wctx), actions[ACTION_REMOVE]
  1270         repo.ui,
       
  1271         cost,
       
  1272         batchremove,
       
  1273         (repo, wctx),
       
  1274         actions[mergestatemod.ACTION_REMOVE],
  1943     )
  1275     )
  1944     for i, item in prog:
  1276     for i, item in prog:
  1945         progress.increment(step=i, item=item)
  1277         progress.increment(step=i, item=item)
  1946     removed = len(actions[ACTION_REMOVE])
  1278     removed = len(actions[mergestatemod.ACTION_REMOVE])
  1947 
  1279 
  1948     # resolve path conflicts (must come before getting)
  1280     # resolve path conflicts (must come before getting)
  1949     for f, args, msg in actions[ACTION_PATH_CONFLICT_RESOLVE]:
  1281     for f, args, msg in actions[mergestatemod.ACTION_PATH_CONFLICT_RESOLVE]:
  1950         repo.ui.debug(b" %s: %s -> pr\n" % (f, msg))
  1282         repo.ui.debug(b" %s: %s -> pr\n" % (f, msg))
  1951         (f0,) = args
  1283         (f0,) = args
  1952         if wctx[f0].lexists():
  1284         if wctx[f0].lexists():
  1953             repo.ui.note(_(b"moving %s to %s\n") % (f0, f))
  1285             repo.ui.note(_(b"moving %s to %s\n") % (f0, f))
  1954             wctx[f].audit()
  1286             wctx[f].audit()
  1963     prog = worker.worker(
  1295     prog = worker.worker(
  1964         repo.ui,
  1296         repo.ui,
  1965         cost,
  1297         cost,
  1966         batchget,
  1298         batchget,
  1967         (repo, mctx, wctx, wantfiledata),
  1299         (repo, mctx, wctx, wantfiledata),
  1968         actions[ACTION_GET],
  1300         actions[mergestatemod.ACTION_GET],
  1969         threadsafe=threadsafe,
  1301         threadsafe=threadsafe,
  1970         hasretval=True,
  1302         hasretval=True,
  1971     )
  1303     )
  1972     getfiledata = {}
  1304     getfiledata = {}
  1973     for final, res in prog:
  1305     for final, res in prog:
  1974         if final:
  1306         if final:
  1975             getfiledata = res
  1307             getfiledata = res
  1976         else:
  1308         else:
  1977             i, item = res
  1309             i, item = res
  1978             progress.increment(step=i, item=item)
  1310             progress.increment(step=i, item=item)
  1979     updated = len(actions[ACTION_GET])
  1311     updated = len(actions[mergestatemod.ACTION_GET])
  1980 
  1312 
  1981     if [a for a in actions[ACTION_GET] if a[0] == b'.hgsubstate']:
  1313     if [a for a in actions[mergestatemod.ACTION_GET] if a[0] == b'.hgsubstate']:
  1982         subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
  1314         subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
  1983 
  1315 
  1984     # forget (manifest only, just log it) (must come first)
  1316     # forget (manifest only, just log it) (must come first)
  1985     for f, args, msg in actions[ACTION_FORGET]:
  1317     for f, args, msg in actions[mergestatemod.ACTION_FORGET]:
  1986         repo.ui.debug(b" %s: %s -> f\n" % (f, msg))
  1318         repo.ui.debug(b" %s: %s -> f\n" % (f, msg))
  1987         progress.increment(item=f)
  1319         progress.increment(item=f)
  1988 
  1320 
  1989     # re-add (manifest only, just log it)
  1321     # re-add (manifest only, just log it)
  1990     for f, args, msg in actions[ACTION_ADD]:
  1322     for f, args, msg in actions[mergestatemod.ACTION_ADD]:
  1991         repo.ui.debug(b" %s: %s -> a\n" % (f, msg))
  1323         repo.ui.debug(b" %s: %s -> a\n" % (f, msg))
  1992         progress.increment(item=f)
  1324         progress.increment(item=f)
  1993 
  1325 
  1994     # re-add/mark as modified (manifest only, just log it)
  1326     # re-add/mark as modified (manifest only, just log it)
  1995     for f, args, msg in actions[ACTION_ADD_MODIFIED]:
  1327     for f, args, msg in actions[mergestatemod.ACTION_ADD_MODIFIED]:
  1996         repo.ui.debug(b" %s: %s -> am\n" % (f, msg))
  1328         repo.ui.debug(b" %s: %s -> am\n" % (f, msg))
  1997         progress.increment(item=f)
  1329         progress.increment(item=f)
  1998 
  1330 
  1999     # keep (noop, just log it)
  1331     # keep (noop, just log it)
  2000     for f, args, msg in actions[ACTION_KEEP]:
  1332     for f, args, msg in actions[mergestatemod.ACTION_KEEP]:
  2001         repo.ui.debug(b" %s: %s -> k\n" % (f, msg))
  1333         repo.ui.debug(b" %s: %s -> k\n" % (f, msg))
  2002         # no progress
  1334         # no progress
  2003 
  1335 
  2004     # directory rename, move local
  1336     # directory rename, move local
  2005     for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]:
  1337     for f, args, msg in actions[mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL]:
  2006         repo.ui.debug(b" %s: %s -> dm\n" % (f, msg))
  1338         repo.ui.debug(b" %s: %s -> dm\n" % (f, msg))
  2007         progress.increment(item=f)
  1339         progress.increment(item=f)
  2008         f0, flags = args
  1340         f0, flags = args
  2009         repo.ui.note(_(b"moving %s to %s\n") % (f0, f))
  1341         repo.ui.note(_(b"moving %s to %s\n") % (f0, f))
  2010         wctx[f].audit()
  1342         wctx[f].audit()
  2011         wctx[f].write(wctx.filectx(f0).data(), flags)
  1343         wctx[f].write(wctx.filectx(f0).data(), flags)
  2012         wctx[f0].remove()
  1344         wctx[f0].remove()
  2013         updated += 1
  1345         updated += 1
  2014 
  1346 
  2015     # local directory rename, get
  1347     # local directory rename, get
  2016     for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]:
  1348     for f, args, msg in actions[mergestatemod.ACTION_LOCAL_DIR_RENAME_GET]:
  2017         repo.ui.debug(b" %s: %s -> dg\n" % (f, msg))
  1349         repo.ui.debug(b" %s: %s -> dg\n" % (f, msg))
  2018         progress.increment(item=f)
  1350         progress.increment(item=f)
  2019         f0, flags = args
  1351         f0, flags = args
  2020         repo.ui.note(_(b"getting %s to %s\n") % (f0, f))
  1352         repo.ui.note(_(b"getting %s to %s\n") % (f0, f))
  2021         wctx[f].write(mctx.filectx(f0).data(), flags)
  1353         wctx[f].write(mctx.filectx(f0).data(), flags)
  2022         updated += 1
  1354         updated += 1
  2023 
  1355 
  2024     # exec
  1356     # exec
  2025     for f, args, msg in actions[ACTION_EXEC]:
  1357     for f, args, msg in actions[mergestatemod.ACTION_EXEC]:
  2026         repo.ui.debug(b" %s: %s -> e\n" % (f, msg))
  1358         repo.ui.debug(b" %s: %s -> e\n" % (f, msg))
  2027         progress.increment(item=f)
  1359         progress.increment(item=f)
  2028         (flags,) = args
  1360         (flags,) = args
  2029         wctx[f].audit()
  1361         wctx[f].audit()
  2030         wctx[f].setflags(b'l' in flags, b'x' in flags)
  1362         wctx[f].setflags(b'l' in flags, b'x' in flags)
  2085     unresolved = ms.unresolvedcount()
  1417     unresolved = ms.unresolvedcount()
  2086 
  1418 
  2087     if (
  1419     if (
  2088         usemergedriver
  1420         usemergedriver
  2089         and not unresolved
  1421         and not unresolved
  2090         and ms.mdstate() != MERGE_DRIVER_STATE_SUCCESS
  1422         and ms.mdstate() != mergestatemod.MERGE_DRIVER_STATE_SUCCESS
  2091     ):
  1423     ):
  2092         if not driverconclude(repo, ms, wctx, labels=labels):
  1424         if not driverconclude(repo, ms, wctx, labels=labels):
  2093             # XXX setting unresolved to at least 1 is a hack to make sure we
  1425             # XXX setting unresolved to at least 1 is a hack to make sure we
  2094             # error out
  1426             # error out
  2095             unresolved = max(unresolved, 1)
  1427             unresolved = max(unresolved, 1)
  2101     merged += msmerged
  1433     merged += msmerged
  2102     removed += msremoved
  1434     removed += msremoved
  2103 
  1435 
  2104     extraactions = ms.actions()
  1436     extraactions = ms.actions()
  2105     if extraactions:
  1437     if extraactions:
  2106         mfiles = {a[0] for a in actions[ACTION_MERGE]}
  1438         mfiles = {a[0] for a in actions[mergestatemod.ACTION_MERGE]}
  2107         for k, acts in pycompat.iteritems(extraactions):
  1439         for k, acts in pycompat.iteritems(extraactions):
  2108             actions[k].extend(acts)
  1440             actions[k].extend(acts)
  2109             if k == ACTION_GET and wantfiledata:
  1441             if k == mergestatemod.ACTION_GET and wantfiledata:
  2110                 # no filedata until mergestate is updated to provide it
  1442                 # no filedata until mergestate is updated to provide it
  2111                 for a in acts:
  1443                 for a in acts:
  2112                     getfiledata[a[0]] = None
  1444                     getfiledata[a[0]] = None
  2113             # Remove these files from actions[ACTION_MERGE] as well. This is
  1445             # Remove these files from actions[ACTION_MERGE] as well. This is
  2114             # important because in recordupdates, files in actions[ACTION_MERGE]
  1446             # important because in recordupdates, files in actions[ACTION_MERGE]
  2126             #
  1458             #
  2127             # We don't need to do the same operation for 'dc' and 'cd' because
  1459             # We don't need to do the same operation for 'dc' and 'cd' because
  2128             # those lists aren't consulted again.
  1460             # those lists aren't consulted again.
  2129             mfiles.difference_update(a[0] for a in acts)
  1461             mfiles.difference_update(a[0] for a in acts)
  2130 
  1462 
  2131         actions[ACTION_MERGE] = [
  1463         actions[mergestatemod.ACTION_MERGE] = [
  2132             a for a in actions[ACTION_MERGE] if a[0] in mfiles
  1464             a for a in actions[mergestatemod.ACTION_MERGE] if a[0] in mfiles
  2133         ]
  1465         ]
  2134 
  1466 
  2135     progress.complete()
  1467     progress.complete()
  2136     assert len(getfiledata) == (len(actions[ACTION_GET]) if wantfiledata else 0)
  1468     assert len(getfiledata) == (
       
  1469         len(actions[mergestatemod.ACTION_GET]) if wantfiledata else 0
       
  1470     )
  2137     return updateresult(updated, merged, removed, unresolved), getfiledata
  1471     return updateresult(updated, merged, removed, unresolved), getfiledata
  2138 
       
  2139 
       
  2140 def recordupdates(repo, actions, branchmerge, getfiledata):
       
  2141     """record merge actions to the dirstate"""
       
  2142     # remove (must come first)
       
  2143     for f, args, msg in actions.get(ACTION_REMOVE, []):
       
  2144         if branchmerge:
       
  2145             repo.dirstate.remove(f)
       
  2146         else:
       
  2147             repo.dirstate.drop(f)
       
  2148 
       
  2149     # forget (must come first)
       
  2150     for f, args, msg in actions.get(ACTION_FORGET, []):
       
  2151         repo.dirstate.drop(f)
       
  2152 
       
  2153     # resolve path conflicts
       
  2154     for f, args, msg in actions.get(ACTION_PATH_CONFLICT_RESOLVE, []):
       
  2155         (f0,) = args
       
  2156         origf0 = repo.dirstate.copied(f0) or f0
       
  2157         repo.dirstate.add(f)
       
  2158         repo.dirstate.copy(origf0, f)
       
  2159         if f0 == origf0:
       
  2160             repo.dirstate.remove(f0)
       
  2161         else:
       
  2162             repo.dirstate.drop(f0)
       
  2163 
       
  2164     # re-add
       
  2165     for f, args, msg in actions.get(ACTION_ADD, []):
       
  2166         repo.dirstate.add(f)
       
  2167 
       
  2168     # re-add/mark as modified
       
  2169     for f, args, msg in actions.get(ACTION_ADD_MODIFIED, []):
       
  2170         if branchmerge:
       
  2171             repo.dirstate.normallookup(f)
       
  2172         else:
       
  2173             repo.dirstate.add(f)
       
  2174 
       
  2175     # exec change
       
  2176     for f, args, msg in actions.get(ACTION_EXEC, []):
       
  2177         repo.dirstate.normallookup(f)
       
  2178 
       
  2179     # keep
       
  2180     for f, args, msg in actions.get(ACTION_KEEP, []):
       
  2181         pass
       
  2182 
       
  2183     # get
       
  2184     for f, args, msg in actions.get(ACTION_GET, []):
       
  2185         if branchmerge:
       
  2186             repo.dirstate.otherparent(f)
       
  2187         else:
       
  2188             parentfiledata = getfiledata[f] if getfiledata else None
       
  2189             repo.dirstate.normal(f, parentfiledata=parentfiledata)
       
  2190 
       
  2191     # merge
       
  2192     for f, args, msg in actions.get(ACTION_MERGE, []):
       
  2193         f1, f2, fa, move, anc = args
       
  2194         if branchmerge:
       
  2195             # We've done a branch merge, mark this file as merged
       
  2196             # so that we properly record the merger later
       
  2197             repo.dirstate.merge(f)
       
  2198             if f1 != f2:  # copy/rename
       
  2199                 if move:
       
  2200                     repo.dirstate.remove(f1)
       
  2201                 if f1 != f:
       
  2202                     repo.dirstate.copy(f1, f)
       
  2203                 else:
       
  2204                     repo.dirstate.copy(f2, f)
       
  2205         else:
       
  2206             # We've update-merged a locally modified file, so
       
  2207             # we set the dirstate to emulate a normal checkout
       
  2208             # of that file some time in the past. Thus our
       
  2209             # merge will appear as a normal local file
       
  2210             # modification.
       
  2211             if f2 == f:  # file not locally copied/moved
       
  2212                 repo.dirstate.normallookup(f)
       
  2213             if move:
       
  2214                 repo.dirstate.drop(f1)
       
  2215 
       
  2216     # directory rename, move local
       
  2217     for f, args, msg in actions.get(ACTION_DIR_RENAME_MOVE_LOCAL, []):
       
  2218         f0, flag = args
       
  2219         if branchmerge:
       
  2220             repo.dirstate.add(f)
       
  2221             repo.dirstate.remove(f0)
       
  2222             repo.dirstate.copy(f0, f)
       
  2223         else:
       
  2224             repo.dirstate.normal(f)
       
  2225             repo.dirstate.drop(f0)
       
  2226 
       
  2227     # directory rename, get
       
  2228     for f, args, msg in actions.get(ACTION_LOCAL_DIR_RENAME_GET, []):
       
  2229         f0, flag = args
       
  2230         if branchmerge:
       
  2231             repo.dirstate.add(f)
       
  2232             repo.dirstate.copy(f0, f)
       
  2233         else:
       
  2234             repo.dirstate.normal(f)
       
  2235 
  1472 
  2236 
  1473 
  2237 UPDATECHECK_ABORT = b'abort'  # handled at higher layers
  1474 UPDATECHECK_ABORT = b'abort'  # handled at higher layers
  2238 UPDATECHECK_NONE = b'none'
  1475 UPDATECHECK_NONE = b'none'
  2239 UPDATECHECK_LINEAR = b'linear'
  1476 UPDATECHECK_LINEAR = b'linear'
  2354         overwrite = force and not branchmerge
  1591         overwrite = force and not branchmerge
  2355         ### check phase
  1592         ### check phase
  2356         if not overwrite:
  1593         if not overwrite:
  2357             if len(pl) > 1:
  1594             if len(pl) > 1:
  2358                 raise error.Abort(_(b"outstanding uncommitted merge"))
  1595                 raise error.Abort(_(b"outstanding uncommitted merge"))
  2359             ms = mergestate.read(repo)
  1596             ms = mergestatemod.mergestate.read(repo)
  2360             if list(ms.unresolved()):
  1597             if list(ms.unresolved()):
  2361                 raise error.Abort(
  1598                 raise error.Abort(
  2362                     _(b"outstanding merge conflicts"),
  1599                     _(b"outstanding merge conflicts"),
  2363                     hint=_(b"use 'hg resolve' to resolve"),
  1600                     hint=_(b"use 'hg resolve' to resolve"),
  2364                 )
  1601                 )
  2441         )
  1678         )
  2442 
  1679 
  2443         if updatecheck == UPDATECHECK_NO_CONFLICT:
  1680         if updatecheck == UPDATECHECK_NO_CONFLICT:
  2444             for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
  1681             for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
  2445                 if m not in (
  1682                 if m not in (
  2446                     ACTION_GET,
  1683                     mergestatemod.ACTION_GET,
  2447                     ACTION_KEEP,
  1684                     mergestatemod.ACTION_KEEP,
  2448                     ACTION_EXEC,
  1685                     mergestatemod.ACTION_EXEC,
  2449                     ACTION_REMOVE,
  1686                     mergestatemod.ACTION_REMOVE,
  2450                     ACTION_PATH_CONFLICT_RESOLVE,
  1687                     mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
  2451                     ACTION_GET_OTHER_AND_STORE,
  1688                     mergestatemod.ACTION_GET_OTHER_AND_STORE,
  2452                 ):
  1689                 ):
  2453                     msg = _(b"conflicting changes")
  1690                     msg = _(b"conflicting changes")
  2454                     hint = _(b"commit or update --clean to discard changes")
  1691                     hint = _(b"commit or update --clean to discard changes")
  2455                     raise error.Abort(msg, hint=hint)
  1692                     raise error.Abort(msg, hint=hint)
  2456 
  1693 
  2460         if b'.hgsubstate' in actionbyfile:
  1697         if b'.hgsubstate' in actionbyfile:
  2461             f = b'.hgsubstate'
  1698             f = b'.hgsubstate'
  2462             m, args, msg = actionbyfile[f]
  1699             m, args, msg = actionbyfile[f]
  2463             prompts = filemerge.partextras(labels)
  1700             prompts = filemerge.partextras(labels)
  2464             prompts[b'f'] = f
  1701             prompts[b'f'] = f
  2465             if m == ACTION_CHANGED_DELETED:
  1702             if m == mergestatemod.ACTION_CHANGED_DELETED:
  2466                 if repo.ui.promptchoice(
  1703                 if repo.ui.promptchoice(
  2467                     _(
  1704                     _(
  2468                         b"local%(l)s changed %(f)s which other%(o)s deleted\n"
  1705                         b"local%(l)s changed %(f)s which other%(o)s deleted\n"
  2469                         b"use (c)hanged version or (d)elete?"
  1706                         b"use (c)hanged version or (d)elete?"
  2470                         b"$$ &Changed $$ &Delete"
  1707                         b"$$ &Changed $$ &Delete"
  2471                     )
  1708                     )
  2472                     % prompts,
  1709                     % prompts,
  2473                     0,
  1710                     0,
  2474                 ):
  1711                 ):
  2475                     actionbyfile[f] = (ACTION_REMOVE, None, b'prompt delete')
  1712                     actionbyfile[f] = (
       
  1713                         mergestatemod.ACTION_REMOVE,
       
  1714                         None,
       
  1715                         b'prompt delete',
       
  1716                     )
  2476                 elif f in p1:
  1717                 elif f in p1:
  2477                     actionbyfile[f] = (
  1718                     actionbyfile[f] = (
  2478                         ACTION_ADD_MODIFIED,
  1719                         mergestatemod.ACTION_ADD_MODIFIED,
  2479                         None,
  1720                         None,
  2480                         b'prompt keep',
  1721                         b'prompt keep',
  2481                     )
  1722                     )
  2482                 else:
  1723                 else:
  2483                     actionbyfile[f] = (ACTION_ADD, None, b'prompt keep')
  1724                     actionbyfile[f] = (
  2484             elif m == ACTION_DELETED_CHANGED:
  1725                         mergestatemod.ACTION_ADD,
       
  1726                         None,
       
  1727                         b'prompt keep',
       
  1728                     )
       
  1729             elif m == mergestatemod.ACTION_DELETED_CHANGED:
  2485                 f1, f2, fa, move, anc = args
  1730                 f1, f2, fa, move, anc = args
  2486                 flags = p2[f2].flags()
  1731                 flags = p2[f2].flags()
  2487                 if (
  1732                 if (
  2488                     repo.ui.promptchoice(
  1733                     repo.ui.promptchoice(
  2489                         _(
  1734                         _(
  2495                         0,
  1740                         0,
  2496                     )
  1741                     )
  2497                     == 0
  1742                     == 0
  2498                 ):
  1743                 ):
  2499                     actionbyfile[f] = (
  1744                     actionbyfile[f] = (
  2500                         ACTION_GET,
  1745                         mergestatemod.ACTION_GET,
  2501                         (flags, False),
  1746                         (flags, False),
  2502                         b'prompt recreating',
  1747                         b'prompt recreating',
  2503                     )
  1748                     )
  2504                 else:
  1749                 else:
  2505                     del actionbyfile[f]
  1750                     del actionbyfile[f]
  2509         for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
  1754         for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
  2510             if m not in actions:
  1755             if m not in actions:
  2511                 actions[m] = []
  1756                 actions[m] = []
  2512             actions[m].append((f, args, msg))
  1757             actions[m].append((f, args, msg))
  2513 
  1758 
  2514         # ACTION_GET_OTHER_AND_STORE is a ACTION_GET + store in mergestate
  1759         # ACTION_GET_OTHER_AND_STORE is a mergestatemod.ACTION_GET + store in mergestate
  2515         for e in actions[ACTION_GET_OTHER_AND_STORE]:
  1760         for e in actions[mergestatemod.ACTION_GET_OTHER_AND_STORE]:
  2516             actions[ACTION_GET].append(e)
  1761             actions[mergestatemod.ACTION_GET].append(e)
  2517 
  1762 
  2518         if not util.fscasesensitive(repo.path):
  1763         if not util.fscasesensitive(repo.path):
  2519             # check collision between files only in p2 for clean update
  1764             # check collision between files only in p2 for clean update
  2520             if not branchmerge and (
  1765             if not branchmerge and (
  2521                 force or not wc.dirty(missing=True, branch=False)
  1766                 force or not wc.dirty(missing=True, branch=False)
  2588 
  1833 
  2589         if (
  1834         if (
  2590             fsmonitorwarning
  1835             fsmonitorwarning
  2591             and not fsmonitorenabled
  1836             and not fsmonitorenabled
  2592             and p1.node() == nullid
  1837             and p1.node() == nullid
  2593             and len(actions[ACTION_GET]) >= fsmonitorthreshold
  1838             and len(actions[mergestatemod.ACTION_GET]) >= fsmonitorthreshold
  2594             and pycompat.sysplatform.startswith((b'linux', b'darwin'))
  1839             and pycompat.sysplatform.startswith((b'linux', b'darwin'))
  2595         ):
  1840         ):
  2596             repo.ui.warn(
  1841             repo.ui.warn(
  2597                 _(
  1842                 _(
  2598                     b'(warning: large working directory being used without '
  1843                     b'(warning: large working directory being used without '
  2607         )
  1852         )
  2608 
  1853 
  2609         if updatedirstate:
  1854         if updatedirstate:
  2610             with repo.dirstate.parentchange():
  1855             with repo.dirstate.parentchange():
  2611                 repo.setparents(fp1, fp2)
  1856                 repo.setparents(fp1, fp2)
  2612                 recordupdates(repo, actions, branchmerge, getfiledata)
  1857                 mergestatemod.recordupdates(
       
  1858                     repo, actions, branchmerge, getfiledata
       
  1859                 )
  2613                 # update completed, clear state
  1860                 # update completed, clear state
  2614                 util.unlink(repo.vfs.join(b'updatestate'))
  1861                 util.unlink(repo.vfs.join(b'updatestate'))
  2615 
  1862 
  2616                 if not branchmerge:
  1863                 if not branchmerge:
  2617                     repo.dirstate.setbranch(p2.branch())
  1864                     repo.dirstate.setbranch(p2.branch())