comparison mercurial/merge.py @ 34545:1913162854f2

merge: add pathconflict merge state Path conflicts that occur during merges are represented by 'pu' (unresolved) and 'pr' (resolved) records in the merge state. These are stored on disk in 'P' records. Differential Revision: https://phab.mercurial-scm.org/D774
author Mark Thomas <mbthomas@fb.com>
date Mon, 02 Oct 2017 14:05:30 -0700
parents bed1d2eaa108
children 81aebcc73beb
comparison
equal deleted inserted replaced
34544:34c8080d12ac 34545:1913162854f2
64 O: the node of the "other" part of the merge (hexified version) 64 O: the node of the "other" part of the merge (hexified version)
65 F: a file to be merged entry 65 F: a file to be merged entry
66 C: a change/delete or delete/change conflict 66 C: a change/delete or delete/change conflict
67 D: a file that the external merge driver will merge internally 67 D: a file that the external merge driver will merge internally
68 (experimental) 68 (experimental)
69 P: a path conflict (file vs directory)
69 m: the external merge driver defined for this merge plus its run state 70 m: the external merge driver defined for this merge plus its run state
70 (experimental) 71 (experimental)
71 f: a (filename, dictionary) tuple of optional values for a given file 72 f: a (filename, dictionary) tuple of optional values for a given file
72 X: unsupported mandatory record type (used in tests) 73 X: unsupported mandatory record type (used in tests)
73 x: unsupported advisory record type (used in tests) 74 x: unsupported advisory record type (used in tests)
77 u: driver-resolved files unmarked -- needs to be run next time we're about 78 u: driver-resolved files unmarked -- needs to be run next time we're about
78 to resolve or commit 79 to resolve or commit
79 m: driver-resolved files marked -- only needs to be run before commit 80 m: driver-resolved files marked -- only needs to be run before commit
80 s: success/skipped -- does not need to be run any more 81 s: success/skipped -- does not need to be run any more
81 82
83 Merge record states (stored in self._state, indexed by filename):
84 u: unresolved conflict
85 r: resolved conflict
86 pu: unresolved path conflict (file conflicts with directory)
87 pr: resolved path conflict
88 d: driver-resolved conflict
89
90 The resolve command transitions between 'u' and 'r' for conflicts and
91 'pu' and 'pr' for path conflicts.
82 ''' 92 '''
83 statepathv1 = 'merge/state' 93 statepathv1 = 'merge/state'
84 statepathv2 = 'merge/state2' 94 statepathv2 = 'merge/state2'
85 95
86 @staticmethod 96 @staticmethod
156 # the merge driver should be idempotent, so just rerun it 166 # the merge driver should be idempotent, so just rerun it
157 mdstate = 'u' 167 mdstate = 'u'
158 168
159 self._readmergedriver = bits[0] 169 self._readmergedriver = bits[0]
160 self._mdstate = mdstate 170 self._mdstate = mdstate
161 elif rtype in 'FDC': 171 elif rtype in 'FDCP':
162 bits = record.split('\0') 172 bits = record.split('\0')
163 self._state[bits[0]] = bits[1:] 173 self._state[bits[0]] = bits[1:]
164 elif rtype == 'f': 174 elif rtype == 'f':
165 filename, rawextras = record.split('\0', 1) 175 filename, rawextras = record.split('\0', 1)
166 extraparts = rawextras.split('\0') 176 extraparts = rawextras.split('\0')
352 records.append(('m', '\0'.join([ 362 records.append(('m', '\0'.join([
353 self.mergedriver, self._mdstate]))) 363 self.mergedriver, self._mdstate])))
354 for d, v in self._state.iteritems(): 364 for d, v in self._state.iteritems():
355 if v[0] == 'd': 365 if v[0] == 'd':
356 records.append(('D', '\0'.join([d] + v))) 366 records.append(('D', '\0'.join([d] + v)))
367 elif v[0] in ('pu', 'pr'):
368 records.append(('P', '\0'.join([d] + v)))
357 # v[1] == local ('cd'), v[6] == other ('dc') -- not supported by 369 # v[1] == local ('cd'), v[6] == other ('dc') -- not supported by
358 # older versions of Mercurial 370 # older versions of Mercurial
359 elif v[1] == nullhex or v[6] == nullhex: 371 elif v[1] == nullhex or v[6] == nullhex:
360 records.append(('C', '\0'.join([d] + v))) 372 records.append(('C', '\0'.join([d] + v)))
361 else: 373 else:
420 fco.path(), hex(fco.filenode()), 432 fco.path(), hex(fco.filenode()),
421 fcl.flags()] 433 fcl.flags()]
422 self._stateextras[fd] = {'ancestorlinknode': hex(fca.node())} 434 self._stateextras[fd] = {'ancestorlinknode': hex(fca.node())}
423 self._dirty = True 435 self._dirty = True
424 436
437 def addpath(self, path, frename, forigin):
438 """add a new conflicting path to the merge state
439 path: the path that conflicts
440 frename: the filename the conflicting file was renamed to
441 forigin: origin of the file ('l' or 'r' for local/remote)
442 """
443 self._state[path] = ['pu', frename, forigin]
444 self._dirty = True
445
425 def __contains__(self, dfile): 446 def __contains__(self, dfile):
426 return dfile in self._state 447 return dfile in self._state
427 448
428 def __getitem__(self, dfile): 449 def __getitem__(self, dfile):
429 return self._state[dfile][0] 450 return self._state[dfile][0]
443 464
444 def unresolved(self): 465 def unresolved(self):
445 """Obtain the paths of unresolved files.""" 466 """Obtain the paths of unresolved files."""
446 467
447 for f, entry in self._state.iteritems(): 468 for f, entry in self._state.iteritems():
448 if entry[0] == 'u': 469 if entry[0] in ('u', 'pu'):
449 yield f 470 yield f
450 471
451 def driverresolved(self): 472 def driverresolved(self):
452 """Obtain the paths of driver-resolved files.""" 473 """Obtain the paths of driver-resolved files."""
453 474