##// END OF EJS Templates
mergedriver: delete it...
Martin von Zweigbergk -
r46091:32ce4cba default
parent child Browse files
Show More
@@ -5986,10 +5986,6 b' def resolve(ui, repo, *pats, **opts):'
5986 b'resolve.resolved',
5986 b'resolve.resolved',
5987 b'R',
5987 b'R',
5988 ),
5988 ),
5989 mergestatemod.MERGE_RECORD_DRIVER_RESOLVED: (
5990 b'resolve.driverresolved',
5991 b'D',
5992 ),
5993 }
5989 }
5994
5990
5995 for f in ms:
5991 for f in ms:
@@ -6014,21 +6010,9 b' def resolve(ui, repo, *pats, **opts):'
6014 )
6010 )
6015
6011
6016 wctx = repo[None]
6012 wctx = repo[None]
6017
6018 if (
6019 ms.mergedriver
6020 and ms.mdstate() == mergestatemod.MERGE_DRIVER_STATE_UNMARKED
6021 ):
6022 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6023 ms.commit()
6024 # allow mark and unmark to go through
6025 if not mark and not unmark and not proceed:
6026 return 1
6027
6028 m = scmutil.match(wctx, pats, opts)
6013 m = scmutil.match(wctx, pats, opts)
6029 ret = 0
6014 ret = 0
6030 didwork = False
6015 didwork = False
6031 runconclude = False
6032
6016
6033 tocomplete = []
6017 tocomplete = []
6034 hasconflictmarkers = []
6018 hasconflictmarkers = []
@@ -6043,26 +6027,6 b' def resolve(ui, repo, *pats, **opts):'
6043
6027
6044 didwork = True
6028 didwork = True
6045
6029
6046 # don't let driver-resolved files be marked, and run the conclude
6047 # step if asked to resolve
6048 if ms[f] == mergestatemod.MERGE_RECORD_DRIVER_RESOLVED:
6049 exact = m.exact(f)
6050 if mark:
6051 if exact:
6052 ui.warn(
6053 _(b'not marking %s as it is driver-resolved\n')
6054 % uipathfn(f)
6055 )
6056 elif unmark:
6057 if exact:
6058 ui.warn(
6059 _(b'not unmarking %s as it is driver-resolved\n')
6060 % uipathfn(f)
6061 )
6062 else:
6063 runconclude = True
6064 continue
6065
6066 # path conflicts must be resolved manually
6030 # path conflicts must be resolved manually
6067 if ms[f] in (
6031 if ms[f] in (
6068 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6032 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
@@ -6184,32 +6148,11 b' def resolve(ui, repo, *pats, **opts):'
6184 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6148 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6185 if hint:
6149 if hint:
6186 ui.warn(hint)
6150 ui.warn(hint)
6187 elif ms.mergedriver and ms.mdstate() != b's':
6151
6188 # run conclude step when either a driver-resolved file is requested
6189 # or there are no driver-resolved files
6190 # we can't use 'ret' to determine whether any files are unresolved
6191 # because we might not have tried to resolve some
6192 if (runconclude or not list(ms.driverresolved())) and not list(
6193 ms.unresolved()
6194 ):
6195 proceed = mergemod.driverconclude(repo, ms, wctx)
6196 ms.commit()
6197 if not proceed:
6198 return 1
6199
6200 # Nudge users into finishing an unfinished operation
6201 unresolvedf = list(ms.unresolved())
6152 unresolvedf = list(ms.unresolved())
6202 driverresolvedf = list(ms.driverresolved())
6153 if not unresolvedf:
6203 if not unresolvedf and not driverresolvedf:
6204 ui.status(_(b'(no more unresolved files)\n'))
6154 ui.status(_(b'(no more unresolved files)\n'))
6205 cmdutil.checkafterresolved(repo)
6155 cmdutil.checkafterresolved(repo)
6206 elif not unresolvedf:
6207 ui.status(
6208 _(
6209 b'(no more unresolved files -- '
6210 b'run "hg resolve --all" to conclude)\n'
6211 )
6212 )
6213
6156
6214 return ret
6157 return ret
6215
6158
@@ -635,9 +635,6 b' coreconfigitem('
635 coreconfigitem(
635 coreconfigitem(
636 b'experimental', b'httppostargs', default=False,
636 b'experimental', b'httppostargs', default=False,
637 )
637 )
638 coreconfigitem(
639 b'experimental', b'mergedriver', default=None,
640 )
641 coreconfigitem(b'experimental', b'nointerrupt', default=False)
638 coreconfigitem(b'experimental', b'nointerrupt', default=False)
642 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
639 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
643
640
@@ -37,30 +37,18 b' Currently known records:'
37 | * O: the node of the "other" part of the merge (hexified version)
37 | * O: the node of the "other" part of the merge (hexified version)
38 | * F: a file to be merged entry
38 | * F: a file to be merged entry
39 | * C: a change/delete or delete/change conflict
39 | * C: a change/delete or delete/change conflict
40 | * D: a file that the external merge driver will merge internally
41 | (experimental)
42 | * P: a path conflict (file vs directory)
40 | * P: a path conflict (file vs directory)
43 | * m: the external merge driver defined for this merge plus its run state
44 | (experimental)
45 | * f: a (filename, dictionary) tuple of optional values for a given file
41 | * f: a (filename, dictionary) tuple of optional values for a given file
46 | * X: unsupported mandatory record type (used in tests)
42 | * X: unsupported mandatory record type (used in tests)
47 | * x: unsupported advisory record type (used in tests)
43 | * x: unsupported advisory record type (used in tests)
48 | * l: the labels for the parts of the merge.
44 | * l: the labels for the parts of the merge.
49
45
50 Merge driver run states (experimental):
51
52 | * u: driver-resolved files unmarked -- needs to be run next time we're
53 | about to resolve or commit
54 | * m: driver-resolved files marked -- only needs to be run before commit
55 | * s: success/skipped -- does not need to be run any more
56
57 Merge record states (indexed by filename):
46 Merge record states (indexed by filename):
58
47
59 | * u: unresolved conflict
48 | * u: unresolved conflict
60 | * r: resolved conflict
49 | * r: resolved conflict
61 | * pu: unresolved path conflict (file conflicts with directory)
50 | * pu: unresolved path conflict (file conflicts with directory)
62 | * pr: resolved path conflict
51 | * pr: resolved path conflict
63 | * d: driver-resolved conflict
64
52
65 The resolve command transitions between 'u' and 'r' for conflicts and
53 The resolve command transitions between 'u' and 'r' for conflicts and
66 'pu' and 'pr' for path conflicts.
54 'pu' and 'pr' for path conflicts.
@@ -355,20 +355,6 b' def _checkcollision(repo, wmf, mresult):'
355 lastfull = f
355 lastfull = f
356
356
357
357
358 def driverpreprocess(repo, ms, wctx, labels=None):
359 """run the preprocess step of the merge driver, if any
360
361 This is currently not implemented -- it's an extension point."""
362 return True
363
364
365 def driverconclude(repo, ms, wctx, labels=None):
366 """run the conclude step of the merge driver, if any
367
368 This is currently not implemented -- it's an extension point."""
369 return True
370
371
372 def _filesindirs(repo, manifest, dirs):
358 def _filesindirs(repo, manifest, dirs):
373 """
359 """
374 Generator that yields pairs of all the files in the manifest that are found
360 Generator that yields pairs of all the files in the manifest that are found
@@ -1605,27 +1591,6 b' def applyupdates('
1605 mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL,
1591 mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL,
1606 )
1592 )
1607 )
1593 )
1608 # the ordering is important here -- ms.mergedriver will raise if the merge
1609 # driver has changed, and we want to be able to bypass it when overwrite is
1610 # True
1611 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1612
1613 if usemergedriver:
1614 ms.commit()
1615 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1616 # the driver might leave some files unresolved
1617 unresolvedf = set(ms.unresolved())
1618 if not proceed:
1619 # XXX setting unresolved to at least 1 is a hack to make sure we
1620 # error out
1621 return updateresult(
1622 updated, merged, removed, max(len(unresolvedf), 1)
1623 )
1624 newactions = []
1625 for f, args, msg in mergeactions:
1626 if f in unresolvedf:
1627 newactions.append((f, args, msg))
1628 mergeactions = newactions
1629
1594
1630 try:
1595 try:
1631 # premerge
1596 # premerge
@@ -1655,18 +1620,6 b' def applyupdates('
1655
1620
1656 unresolved = ms.unresolvedcount()
1621 unresolved = ms.unresolvedcount()
1657
1622
1658 if (
1659 usemergedriver
1660 and not unresolved
1661 and ms.mdstate() != mergestatemod.MERGE_DRIVER_STATE_SUCCESS
1662 ):
1663 if not driverconclude(repo, ms, wctx, labels=labels):
1664 # XXX setting unresolved to at least 1 is a hack to make sure we
1665 # error out
1666 unresolved = max(unresolved, 1)
1667
1668 ms.commit()
1669
1670 msupdated, msmerged, msremoved = ms.counts()
1623 msupdated, msmerged, msremoved = ms.counts()
1671 updated += msupdated
1624 updated += msupdated
1672 merged += msmerged
1625 merged += msmerged
@@ -1674,9 +1627,6 b' def applyupdates('
1674
1627
1675 extraactions = ms.actions()
1628 extraactions = ms.actions()
1676 if extraactions:
1629 if extraactions:
1677 mfiles = {
1678 a[0] for a in mresult.getactions((mergestatemod.ACTION_MERGE,))
1679 }
1680 for k, acts in pycompat.iteritems(extraactions):
1630 for k, acts in pycompat.iteritems(extraactions):
1681 for a in acts:
1631 for a in acts:
1682 mresult.addfile(a[0], k, *a[1:])
1632 mresult.addfile(a[0], k, *a[1:])
@@ -1684,27 +1634,6 b' def applyupdates('
1684 # no filedata until mergestate is updated to provide it
1634 # no filedata until mergestate is updated to provide it
1685 for a in acts:
1635 for a in acts:
1686 getfiledata[a[0]] = None
1636 getfiledata[a[0]] = None
1687 # Remove these files from actions[ACTION_MERGE] as well. This is
1688 # important because in recordupdates, files in actions[ACTION_MERGE]
1689 # are processed after files in other actions, and the merge driver
1690 # might add files to those actions via extraactions above. This can
1691 # lead to a file being recorded twice, with poor results. This is
1692 # especially problematic for actions[ACTION_REMOVE] (currently only
1693 # possible with the merge driver in the initial merge process;
1694 # interrupted merges don't go through this flow).
1695 #
1696 # The real fix here is to have indexes by both file and action so
1697 # that when the action for a file is changed it is automatically
1698 # reflected in the other action lists. But that involves a more
1699 # complex data structure, so this will do for now.
1700 #
1701 # We don't need to do the same operation for 'dc' and 'cd' because
1702 # those lists aren't consulted again.
1703 mfiles.difference_update(a[0] for a in acts)
1704
1705 for a in list(mresult.getactions((mergestatemod.ACTION_MERGE,))):
1706 if a[0] not in mfiles:
1707 mresult.removefile(a[0])
1708
1637
1709 progress.complete()
1638 progress.complete()
1710 assert len(getfiledata) == (
1639 assert len(getfiledata) == (
@@ -48,8 +48,6 b" RECORD_LOCAL = b'L'"
48 RECORD_OTHER = b'O'
48 RECORD_OTHER = b'O'
49 # record merge labels
49 # record merge labels
50 RECORD_LABELS = b'l'
50 RECORD_LABELS = b'l'
51 # store info about merge driver used and it's state
52 RECORD_MERGE_DRIVER_STATE = b'm'
53
51
54 #####
52 #####
55 # record extra information about files, with one entry containing info about one
53 # record extra information about files, with one entry containing info about one
@@ -65,7 +63,6 b" RECORD_FILE_VALUES = b'f'"
65 #####
63 #####
66 RECORD_MERGED = b'F'
64 RECORD_MERGED = b'F'
67 RECORD_CHANGEDELETE_CONFLICT = b'C'
65 RECORD_CHANGEDELETE_CONFLICT = b'C'
68 RECORD_MERGE_DRIVER_MERGE = b'D'
69 # the path was dir on one side of merge and file on another
66 # the path was dir on one side of merge and file on another
70 RECORD_PATH_CONFLICT = b'P'
67 RECORD_PATH_CONFLICT = b'P'
71
68
@@ -77,7 +74,6 b" MERGE_RECORD_UNRESOLVED = b'u'"
77 MERGE_RECORD_RESOLVED = b'r'
74 MERGE_RECORD_RESOLVED = b'r'
78 MERGE_RECORD_UNRESOLVED_PATH = b'pu'
75 MERGE_RECORD_UNRESOLVED_PATH = b'pu'
79 MERGE_RECORD_RESOLVED_PATH = b'pr'
76 MERGE_RECORD_RESOLVED_PATH = b'pr'
80 MERGE_RECORD_DRIVER_RESOLVED = b'd'
81 # represents that the file was automatically merged in favor
77 # represents that the file was automatically merged in favor
82 # of other version. This info is used on commit.
78 # of other version. This info is used on commit.
83 # This is now deprecated and commit related information is now
79 # This is now deprecated and commit related information is now
@@ -91,18 +87,16 b" MERGE_RECORD_MERGED_OTHER = b'o'"
91 RECORD_OVERRIDE = b't'
87 RECORD_OVERRIDE = b't'
92
88
93 #####
89 #####
94 # possible states which a merge driver can have. These are stored inside a
95 # RECORD_MERGE_DRIVER_STATE entry
96 #####
97 MERGE_DRIVER_STATE_UNMARKED = b'u'
98 MERGE_DRIVER_STATE_MARKED = b'm'
99 MERGE_DRIVER_STATE_SUCCESS = b's'
100
101 #####
102 # legacy records which are no longer used but kept to prevent breaking BC
90 # legacy records which are no longer used but kept to prevent breaking BC
103 #####
91 #####
104 # This record was release in 5.4 and usage was removed in 5.5
92 # This record was release in 5.4 and usage was removed in 5.5
105 LEGACY_RECORD_RESOLVED_OTHER = b'R'
93 LEGACY_RECORD_RESOLVED_OTHER = b'R'
94 # This record was release in 3.7 and usage was removed in 5.6
95 LEGACY_RECORD_DRIVER_RESOLVED = b'd'
96 # This record was release in 3.7 and usage was removed in 5.6
97 LEGACY_MERGE_DRIVER_STATE = b'm'
98 # This record was release in 3.7 and usage was removed in 5.6
99 LEGACY_MERGE_DRIVER_MERGE = b'D'
106
100
107
101
108 ACTION_FORGET = b'f'
102 ACTION_FORGET = b'f'
@@ -147,26 +141,15 b' class _mergestate_base(object):'
147 O: the node of the "other" part of the merge (hexified version)
141 O: the node of the "other" part of the merge (hexified version)
148 F: a file to be merged entry
142 F: a file to be merged entry
149 C: a change/delete or delete/change conflict
143 C: a change/delete or delete/change conflict
150 D: a file that the external merge driver will merge internally
151 (experimental)
152 P: a path conflict (file vs directory)
144 P: a path conflict (file vs directory)
153 m: the external merge driver defined for this merge plus its run state
154 (experimental)
155 f: a (filename, dictionary) tuple of optional values for a given file
145 f: a (filename, dictionary) tuple of optional values for a given file
156 l: the labels for the parts of the merge.
146 l: the labels for the parts of the merge.
157
147
158 Merge driver run states (experimental):
159 u: driver-resolved files unmarked -- needs to be run next time we're about
160 to resolve or commit
161 m: driver-resolved files marked -- only needs to be run before commit
162 s: success/skipped -- does not need to be run any more
163
164 Merge record states (stored in self._state, indexed by filename):
148 Merge record states (stored in self._state, indexed by filename):
165 u: unresolved conflict
149 u: unresolved conflict
166 r: resolved conflict
150 r: resolved conflict
167 pu: unresolved path conflict (file conflicts with directory)
151 pu: unresolved path conflict (file conflicts with directory)
168 pr: resolved path conflict
152 pr: resolved path conflict
169 d: driver-resolved conflict
170
153
171 The resolve command transitions between 'u' and 'r' for conflicts and
154 The resolve command transitions between 'u' and 'r' for conflicts and
172 'pu' and 'pr' for path conflicts.
155 'pu' and 'pr' for path conflicts.
@@ -182,8 +165,6 b' class _mergestate_base(object):'
182 self._local = None
165 self._local = None
183 self._other = None
166 self._other = None
184 self._labels = None
167 self._labels = None
185 self._readmergedriver = None
186 self._mdstate = MERGE_DRIVER_STATE_UNMARKED
187 # contains a mapping of form:
168 # contains a mapping of form:
188 # {filename : (merge_return_value, action_to_be_performed}
169 # {filename : (merge_return_value, action_to_be_performed}
189 # these are results of re-running merge process
170 # these are results of re-running merge process
@@ -199,32 +180,6 b' class _mergestate_base(object):'
199 self._local = node
180 self._local = node
200 self._other = other
181 self._other = other
201 self._labels = labels
182 self._labels = labels
202 if self.mergedriver:
203 self._mdstate = MERGE_DRIVER_STATE_SUCCESS
204
205 @util.propertycache
206 def mergedriver(self):
207 # protect against the following:
208 # - A configures a malicious merge driver in their hgrc, then
209 # pauses the merge
210 # - A edits their hgrc to remove references to the merge driver
211 # - A gives a copy of their entire repo, including .hg, to B
212 # - B inspects .hgrc and finds it to be clean
213 # - B then continues the merge and the malicious merge driver
214 # gets invoked
215 configmergedriver = self._repo.ui.config(
216 b'experimental', b'mergedriver'
217 )
218 if (
219 self._readmergedriver is not None
220 and self._readmergedriver != configmergedriver
221 ):
222 raise error.ConfigError(
223 _(b"merge driver changed since merge started"),
224 hint=_(b"revert merge driver change or abort merge"),
225 )
226
227 return configmergedriver
228
183
229 @util.propertycache
184 @util.propertycache
230 def local(self):
185 def local(self):
@@ -330,9 +285,6 b' class _mergestate_base(object):'
330 self._state[dfile][0] = state
285 self._state[dfile][0] = state
331 self._dirty = True
286 self._dirty = True
332
287
333 def mdstate(self):
334 return self._mdstate
335
336 def unresolved(self):
288 def unresolved(self):
337 """Obtain the paths of unresolved files."""
289 """Obtain the paths of unresolved files."""
338
290
@@ -343,13 +295,6 b' class _mergestate_base(object):'
343 ):
295 ):
344 yield f
296 yield f
345
297
346 def driverresolved(self):
347 """Obtain the paths of driver-resolved files."""
348
349 for f, entry in self._state.items():
350 if entry[0] == MERGE_RECORD_DRIVER_RESOLVED:
351 yield f
352
353 def extras(self, filename):
298 def extras(self, filename):
354 return self._stateextras[filename]
299 return self._stateextras[filename]
355
300
@@ -358,7 +303,10 b' class _mergestate_base(object):'
358 Returns whether the merge was completed and the return value of merge
303 Returns whether the merge was completed and the return value of merge
359 obtained from filemerge._filemerge().
304 obtained from filemerge._filemerge().
360 """
305 """
361 if self[dfile] in (MERGE_RECORD_RESOLVED, MERGE_RECORD_DRIVER_RESOLVED):
306 if self[dfile] in (
307 MERGE_RECORD_RESOLVED,
308 LEGACY_RECORD_DRIVER_RESOLVED,
309 ):
362 return True, 0
310 return True, 0
363 stateentry = self._state[dfile]
311 stateentry = self._state[dfile]
364 state, localkey, lfile, afile, anode, ofile, onode, flags = stateentry
312 state, localkey, lfile, afile, anode, ofile, onode, flags = stateentry
@@ -490,24 +438,6 b' class _mergestate_base(object):'
490 actions[action].append((f, None, b"merge result"))
438 actions[action].append((f, None, b"merge result"))
491 return actions
439 return actions
492
440
493 def queueremove(self, f):
494 """queues a file to be removed from the dirstate
495
496 Meant for use by custom merge drivers."""
497 self._results[f] = 0, ACTION_REMOVE
498
499 def queueadd(self, f):
500 """queues a file to be added to the dirstate
501
502 Meant for use by custom merge drivers."""
503 self._results[f] = 0, ACTION_ADD
504
505 def queueget(self, f):
506 """queues a file to be marked modified in the dirstate
507
508 Meant for use by custom merge drivers."""
509 self._results[f] = 0, ACTION_GET
510
511
441
512 class mergestate(_mergestate_base):
442 class mergestate(_mergestate_base):
513
443
@@ -535,7 +465,6 b' class mergestate(_mergestate_base):'
535 This function process "record" entry produced by the de-serialization
465 This function process "record" entry produced by the de-serialization
536 of on disk file.
466 of on disk file.
537 """
467 """
538 self._mdstate = MERGE_DRIVER_STATE_SUCCESS
539 unsupported = set()
468 unsupported = set()
540 records = self._readrecords()
469 records = self._readrecords()
541 for rtype, record in records:
470 for rtype, record in records:
@@ -543,24 +472,13 b' class mergestate(_mergestate_base):'
543 self._local = bin(record)
472 self._local = bin(record)
544 elif rtype == RECORD_OTHER:
473 elif rtype == RECORD_OTHER:
545 self._other = bin(record)
474 self._other = bin(record)
546 elif rtype == RECORD_MERGE_DRIVER_STATE:
475 elif rtype == LEGACY_MERGE_DRIVER_STATE:
547 bits = record.split(b'\0', 1)
476 pass
548 mdstate = bits[1]
549 if len(mdstate) != 1 or mdstate not in (
550 MERGE_DRIVER_STATE_UNMARKED,
551 MERGE_DRIVER_STATE_MARKED,
552 MERGE_DRIVER_STATE_SUCCESS,
553 ):
554 # the merge driver should be idempotent, so just rerun it
555 mdstate = MERGE_DRIVER_STATE_UNMARKED
556
557 self._readmergedriver = bits[0]
558 self._mdstate = mdstate
559 elif rtype in (
477 elif rtype in (
560 RECORD_MERGED,
478 RECORD_MERGED,
561 RECORD_CHANGEDELETE_CONFLICT,
479 RECORD_CHANGEDELETE_CONFLICT,
562 RECORD_PATH_CONFLICT,
480 RECORD_PATH_CONFLICT,
563 RECORD_MERGE_DRIVER_MERGE,
481 LEGACY_MERGE_DRIVER_MERGE,
564 LEGACY_RECORD_RESOLVED_OTHER,
482 LEGACY_RECORD_RESOLVED_OTHER,
565 ):
483 ):
566 bits = record.split(b'\0')
484 bits = record.split(b'\0')
@@ -710,25 +628,13 b' class mergestate(_mergestate_base):'
710 records = []
628 records = []
711 records.append((RECORD_LOCAL, hex(self._local)))
629 records.append((RECORD_LOCAL, hex(self._local)))
712 records.append((RECORD_OTHER, hex(self._other)))
630 records.append((RECORD_OTHER, hex(self._other)))
713 if self.mergedriver:
714 records.append(
715 (
716 RECORD_MERGE_DRIVER_STATE,
717 b'\0'.join([self.mergedriver, self._mdstate]),
718 )
719 )
720 # Write out state items. In all cases, the value of the state map entry
631 # Write out state items. In all cases, the value of the state map entry
721 # is written as the contents of the record. The record type depends on
632 # is written as the contents of the record. The record type depends on
722 # the type of state that is stored, and capital-letter records are used
633 # the type of state that is stored, and capital-letter records are used
723 # to prevent older versions of Mercurial that do not support the feature
634 # to prevent older versions of Mercurial that do not support the feature
724 # from loading them.
635 # from loading them.
725 for filename, v in pycompat.iteritems(self._state):
636 for filename, v in pycompat.iteritems(self._state):
726 if v[0] == MERGE_RECORD_DRIVER_RESOLVED:
637 if v[0] in (
727 # Driver-resolved merge. These are stored in 'D' records.
728 records.append(
729 (RECORD_MERGE_DRIVER_MERGE, b'\0'.join([filename] + v))
730 )
731 elif v[0] in (
732 MERGE_RECORD_UNRESOLVED_PATH,
638 MERGE_RECORD_UNRESOLVED_PATH,
733 MERGE_RECORD_RESOLVED_PATH,
639 MERGE_RECORD_RESOLVED_PATH,
734 ):
640 ):
@@ -814,17 +720,6 b' class memmergestate(_mergestate_base):'
814 def _restore_backup(self, fctx, localkey, flags):
720 def _restore_backup(self, fctx, localkey, flags):
815 fctx.write(self._backups[localkey], flags)
721 fctx.write(self._backups[localkey], flags)
816
722
817 @util.propertycache
818 def mergedriver(self):
819 configmergedriver = self._repo.ui.config(
820 b'experimental', b'mergedriver'
821 )
822 if configmergedriver:
823 raise error.InMemoryMergeConflictsError(
824 b"in-memory merge does not support mergedriver"
825 )
826 return None
827
828
723
829 def recordupdates(repo, actions, branchmerge, getfiledata):
724 def recordupdates(repo, actions, branchmerge, getfiledata):
830 """record merge actions to the dirstate"""
725 """record merge actions to the dirstate"""
@@ -17,8 +17,3 b' def checkunresolved(ms):'
17 raise error.Abort(
17 raise error.Abort(
18 _(b"unresolved merge conflicts (see 'hg help resolve')")
18 _(b"unresolved merge conflicts (see 'hg help resolve')")
19 )
19 )
20 if ms.mdstate() != b's' or list(ms.driverresolved()):
21 raise error.Abort(
22 _(b'driver-resolved merge conflicts'),
23 hint=_(b'run "hg resolve --all" to resolve'),
24 )
@@ -87,64 +87,6 b' cleanup'
87 $ cd ..
87 $ cd ..
88 $ rmdir nested
88 $ rmdir nested
89
89
90 don't allow marking or unmarking driver-resolved files
91
92 $ cat > $TESTTMP/markdriver.py << EOF
93 > '''mark and unmark files as driver-resolved'''
94 > from mercurial import (
95 > mergestate,
96 > pycompat,
97 > registrar,
98 > scmutil,
99 > )
100 > cmdtable = {}
101 > command = registrar.command(cmdtable)
102 > @command(b'markdriver',
103 > [(b'u', b'unmark', None, b'')],
104 > b'FILE...')
105 > def markdriver(ui, repo, *pats, **opts):
106 > wlock = repo.wlock()
107 > opts = pycompat.byteskwargs(opts)
108 > try:
109 > ms = mergestate.mergestate.read(repo)
110 > m = scmutil.match(repo[None], pats, opts)
111 > for f in ms:
112 > if not m(f):
113 > continue
114 > if not opts[b'unmark']:
115 > ms.mark(f, b'd')
116 > else:
117 > ms.mark(f, b'u')
118 > ms.commit()
119 > finally:
120 > wlock.release()
121 > EOF
122 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver file1
123 $ hg resolve --list
124 D file1
125 U file2
126 $ hg resolve --mark file1
127 not marking file1 as it is driver-resolved
128 this should not print out file1
129 $ hg resolve --mark --all
130 (no more unresolved files -- run "hg resolve --all" to conclude)
131 $ hg resolve --mark 'glob:file*'
132 (no more unresolved files -- run "hg resolve --all" to conclude)
133 $ hg resolve --list
134 D file1
135 R file2
136 $ hg resolve --unmark file1
137 not unmarking file1 as it is driver-resolved
138 (no more unresolved files -- run "hg resolve --all" to conclude)
139 $ hg resolve --unmark --all
140 $ hg resolve --list
141 D file1
142 U file2
143 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver --unmark file1
144 $ hg resolve --list
145 U file1
146 U file2
147
148 resolve the failure
90 resolve the failure
149
91
150 $ echo resolved > file1
92 $ echo resolved > file1
General Comments 0
You need to be logged in to leave comments. Login now