Show More
@@ -5986,10 +5986,6 def resolve(ui, repo, *pats, **opts): | |||
|
5986 | 5986 | b'resolve.resolved', |
|
5987 | 5987 | b'R', |
|
5988 | 5988 | ), |
|
5989 | mergestatemod.MERGE_RECORD_DRIVER_RESOLVED: ( | |
|
5990 | b'resolve.driverresolved', | |
|
5991 | b'D', | |
|
5992 | ), | |
|
5993 | 5989 | } |
|
5994 | 5990 | |
|
5995 | 5991 | for f in ms: |
@@ -6014,21 +6010,9 def resolve(ui, repo, *pats, **opts): | |||
|
6014 | 6010 | ) |
|
6015 | 6011 | |
|
6016 | 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 | 6013 | m = scmutil.match(wctx, pats, opts) |
|
6029 | 6014 | ret = 0 |
|
6030 | 6015 | didwork = False |
|
6031 | runconclude = False | |
|
6032 | 6016 | |
|
6033 | 6017 | tocomplete = [] |
|
6034 | 6018 | hasconflictmarkers = [] |
@@ -6043,26 +6027,6 def resolve(ui, repo, *pats, **opts): | |||
|
6043 | 6027 | |
|
6044 | 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 | 6030 | # path conflicts must be resolved manually |
|
6067 | 6031 | if ms[f] in ( |
|
6068 | 6032 | mergestatemod.MERGE_RECORD_UNRESOLVED_PATH, |
@@ -6184,32 +6148,11 def resolve(ui, repo, *pats, **opts): | |||
|
6184 | 6148 | ui.warn(_(b"arguments do not match paths that need resolving\n")) |
|
6185 | 6149 | if hint: |
|
6186 | 6150 | ui.warn(hint) |
|
6187 | elif ms.mergedriver and ms.mdstate() != b's': | |
|
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 | |
|
6151 | ||
|
6201 | 6152 | unresolvedf = list(ms.unresolved()) |
|
6202 | driverresolvedf = list(ms.driverresolved()) | |
|
6203 | if not unresolvedf and not driverresolvedf: | |
|
6153 | if not unresolvedf: | |
|
6204 | 6154 | ui.status(_(b'(no more unresolved files)\n')) |
|
6205 | 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 | 6157 | return ret |
|
6215 | 6158 |
@@ -635,9 +635,6 coreconfigitem( | |||
|
635 | 635 | coreconfigitem( |
|
636 | 636 | b'experimental', b'httppostargs', default=False, |
|
637 | 637 | ) |
|
638 | coreconfigitem( | |
|
639 | b'experimental', b'mergedriver', default=None, | |
|
640 | ) | |
|
641 | 638 | coreconfigitem(b'experimental', b'nointerrupt', default=False) |
|
642 | 639 | coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True) |
|
643 | 640 |
@@ -37,30 +37,18 Currently known records: | |||
|
37 | 37 | | * O: the node of the "other" part of the merge (hexified version) |
|
38 | 38 | | * F: a file to be merged entry |
|
39 | 39 | | * C: a change/delete or delete/change conflict |
|
40 | | * D: a file that the external merge driver will merge internally | |
|
41 | | (experimental) | |
|
42 | 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 | 41 | | * f: a (filename, dictionary) tuple of optional values for a given file |
|
46 | 42 | | * X: unsupported mandatory record type (used in tests) |
|
47 | 43 | | * x: unsupported advisory record type (used in tests) |
|
48 | 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 | 46 | Merge record states (indexed by filename): |
|
58 | 47 | |
|
59 | 48 | | * u: unresolved conflict |
|
60 | 49 | | * r: resolved conflict |
|
61 | 50 | | * pu: unresolved path conflict (file conflicts with directory) |
|
62 | 51 | | * pr: resolved path conflict |
|
63 | | * d: driver-resolved conflict | |
|
64 | 52 | |
|
65 | 53 | The resolve command transitions between 'u' and 'r' for conflicts and |
|
66 | 54 | 'pu' and 'pr' for path conflicts. |
@@ -355,20 +355,6 def _checkcollision(repo, wmf, mresult): | |||
|
355 | 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 | 358 | def _filesindirs(repo, manifest, dirs): |
|
373 | 359 | """ |
|
374 | 360 | Generator that yields pairs of all the files in the manifest that are found |
@@ -1605,27 +1591,6 def applyupdates( | |||
|
1605 | 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 | 1595 | try: |
|
1631 | 1596 | # premerge |
@@ -1655,18 +1620,6 def applyupdates( | |||
|
1655 | 1620 | |
|
1656 | 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 | 1623 | msupdated, msmerged, msremoved = ms.counts() |
|
1671 | 1624 | updated += msupdated |
|
1672 | 1625 | merged += msmerged |
@@ -1674,9 +1627,6 def applyupdates( | |||
|
1674 | 1627 | |
|
1675 | 1628 | extraactions = ms.actions() |
|
1676 | 1629 | if extraactions: |
|
1677 | mfiles = { | |
|
1678 | a[0] for a in mresult.getactions((mergestatemod.ACTION_MERGE,)) | |
|
1679 | } | |
|
1680 | 1630 | for k, acts in pycompat.iteritems(extraactions): |
|
1681 | 1631 | for a in acts: |
|
1682 | 1632 | mresult.addfile(a[0], k, *a[1:]) |
@@ -1684,27 +1634,6 def applyupdates( | |||
|
1684 | 1634 | # no filedata until mergestate is updated to provide it |
|
1685 | 1635 | for a in acts: |
|
1686 | 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 | 1638 | progress.complete() |
|
1710 | 1639 | assert len(getfiledata) == ( |
@@ -48,8 +48,6 RECORD_LOCAL = b'L' | |||
|
48 | 48 | RECORD_OTHER = b'O' |
|
49 | 49 | # record merge labels |
|
50 | 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 | 53 | # record extra information about files, with one entry containing info about one |
@@ -65,7 +63,6 RECORD_FILE_VALUES = b'f' | |||
|
65 | 63 | ##### |
|
66 | 64 | RECORD_MERGED = b'F' |
|
67 | 65 | RECORD_CHANGEDELETE_CONFLICT = b'C' |
|
68 | RECORD_MERGE_DRIVER_MERGE = b'D' | |
|
69 | 66 | # the path was dir on one side of merge and file on another |
|
70 | 67 | RECORD_PATH_CONFLICT = b'P' |
|
71 | 68 | |
@@ -77,7 +74,6 MERGE_RECORD_UNRESOLVED = b'u' | |||
|
77 | 74 | MERGE_RECORD_RESOLVED = b'r' |
|
78 | 75 | MERGE_RECORD_UNRESOLVED_PATH = b'pu' |
|
79 | 76 | MERGE_RECORD_RESOLVED_PATH = b'pr' |
|
80 | MERGE_RECORD_DRIVER_RESOLVED = b'd' | |
|
81 | 77 | # represents that the file was automatically merged in favor |
|
82 | 78 | # of other version. This info is used on commit. |
|
83 | 79 | # This is now deprecated and commit related information is now |
@@ -91,18 +87,16 MERGE_RECORD_MERGED_OTHER = b'o' | |||
|
91 | 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 | 90 | # legacy records which are no longer used but kept to prevent breaking BC |
|
103 | 91 | ##### |
|
104 | 92 | # This record was release in 5.4 and usage was removed in 5.5 |
|
105 | 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 | 102 | ACTION_FORGET = b'f' |
@@ -147,26 +141,15 class _mergestate_base(object): | |||
|
147 | 141 | O: the node of the "other" part of the merge (hexified version) |
|
148 | 142 | F: a file to be merged entry |
|
149 | 143 | C: a change/delete or delete/change conflict |
|
150 | D: a file that the external merge driver will merge internally | |
|
151 | (experimental) | |
|
152 | 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 | 145 | f: a (filename, dictionary) tuple of optional values for a given file |
|
156 | 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 | 148 | Merge record states (stored in self._state, indexed by filename): |
|
165 | 149 | u: unresolved conflict |
|
166 | 150 | r: resolved conflict |
|
167 | 151 | pu: unresolved path conflict (file conflicts with directory) |
|
168 | 152 | pr: resolved path conflict |
|
169 | d: driver-resolved conflict | |
|
170 | 153 | |
|
171 | 154 | The resolve command transitions between 'u' and 'r' for conflicts and |
|
172 | 155 | 'pu' and 'pr' for path conflicts. |
@@ -182,8 +165,6 class _mergestate_base(object): | |||
|
182 | 165 | self._local = None |
|
183 | 166 | self._other = None |
|
184 | 167 | self._labels = None |
|
185 | self._readmergedriver = None | |
|
186 | self._mdstate = MERGE_DRIVER_STATE_UNMARKED | |
|
187 | 168 | # contains a mapping of form: |
|
188 | 169 | # {filename : (merge_return_value, action_to_be_performed} |
|
189 | 170 | # these are results of re-running merge process |
@@ -199,32 +180,6 class _mergestate_base(object): | |||
|
199 | 180 | self._local = node |
|
200 | 181 | self._other = other |
|
201 | 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 | 184 | @util.propertycache |
|
230 | 185 | def local(self): |
@@ -330,9 +285,6 class _mergestate_base(object): | |||
|
330 | 285 | self._state[dfile][0] = state |
|
331 | 286 | self._dirty = True |
|
332 | 287 | |
|
333 | def mdstate(self): | |
|
334 | return self._mdstate | |
|
335 | ||
|
336 | 288 | def unresolved(self): |
|
337 | 289 | """Obtain the paths of unresolved files.""" |
|
338 | 290 | |
@@ -343,13 +295,6 class _mergestate_base(object): | |||
|
343 | 295 | ): |
|
344 | 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 | 298 | def extras(self, filename): |
|
354 | 299 | return self._stateextras[filename] |
|
355 | 300 | |
@@ -358,7 +303,10 class _mergestate_base(object): | |||
|
358 | 303 | Returns whether the merge was completed and the return value of merge |
|
359 | 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 | 310 | return True, 0 |
|
363 | 311 | stateentry = self._state[dfile] |
|
364 | 312 | state, localkey, lfile, afile, anode, ofile, onode, flags = stateentry |
@@ -490,24 +438,6 class _mergestate_base(object): | |||
|
490 | 438 | actions[action].append((f, None, b"merge result")) |
|
491 | 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 | 442 | class mergestate(_mergestate_base): |
|
513 | 443 | |
@@ -535,7 +465,6 class mergestate(_mergestate_base): | |||
|
535 | 465 | This function process "record" entry produced by the de-serialization |
|
536 | 466 | of on disk file. |
|
537 | 467 | """ |
|
538 | self._mdstate = MERGE_DRIVER_STATE_SUCCESS | |
|
539 | 468 | unsupported = set() |
|
540 | 469 | records = self._readrecords() |
|
541 | 470 | for rtype, record in records: |
@@ -543,24 +472,13 class mergestate(_mergestate_base): | |||
|
543 | 472 | self._local = bin(record) |
|
544 | 473 | elif rtype == RECORD_OTHER: |
|
545 | 474 | self._other = bin(record) |
|
546 |
elif rtype == |
|
|
547 | bits = record.split(b'\0', 1) | |
|
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 | |
|
475 | elif rtype == LEGACY_MERGE_DRIVER_STATE: | |
|
476 | pass | |
|
559 | 477 | elif rtype in ( |
|
560 | 478 | RECORD_MERGED, |
|
561 | 479 | RECORD_CHANGEDELETE_CONFLICT, |
|
562 | 480 | RECORD_PATH_CONFLICT, |
|
563 |
|
|
|
481 | LEGACY_MERGE_DRIVER_MERGE, | |
|
564 | 482 | LEGACY_RECORD_RESOLVED_OTHER, |
|
565 | 483 | ): |
|
566 | 484 | bits = record.split(b'\0') |
@@ -710,25 +628,13 class mergestate(_mergestate_base): | |||
|
710 | 628 | records = [] |
|
711 | 629 | records.append((RECORD_LOCAL, hex(self._local))) |
|
712 | 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 | 631 | # Write out state items. In all cases, the value of the state map entry |
|
721 | 632 | # is written as the contents of the record. The record type depends on |
|
722 | 633 | # the type of state that is stored, and capital-letter records are used |
|
723 | 634 | # to prevent older versions of Mercurial that do not support the feature |
|
724 | 635 | # from loading them. |
|
725 | 636 | for filename, v in pycompat.iteritems(self._state): |
|
726 | if v[0] == MERGE_RECORD_DRIVER_RESOLVED: | |
|
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 ( | |
|
637 | if v[0] in ( | |
|
732 | 638 | MERGE_RECORD_UNRESOLVED_PATH, |
|
733 | 639 | MERGE_RECORD_RESOLVED_PATH, |
|
734 | 640 | ): |
@@ -814,17 +720,6 class memmergestate(_mergestate_base): | |||
|
814 | 720 | def _restore_backup(self, fctx, localkey, flags): |
|
815 | 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 | 724 | def recordupdates(repo, actions, branchmerge, getfiledata): |
|
830 | 725 | """record merge actions to the dirstate""" |
@@ -17,8 +17,3 def checkunresolved(ms): | |||
|
17 | 17 | raise error.Abort( |
|
18 | 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 cleanup | |||
|
87 | 87 | $ cd .. |
|
88 | 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 | 90 |
|
|
149 | 91 | |
|
150 | 92 |
$ |
General Comments 0
You need to be logged in to leave comments.
Login now