Show More
@@ -0,0 +1,25 | |||||
|
1 | # Extension to write out fake unsupported records into the merge state | |||
|
2 | # | |||
|
3 | # | |||
|
4 | ||||
|
5 | from __future__ import absolute_import | |||
|
6 | ||||
|
7 | from mercurial import ( | |||
|
8 | cmdutil, | |||
|
9 | merge, | |||
|
10 | ) | |||
|
11 | ||||
|
12 | cmdtable = {} | |||
|
13 | command = cmdutil.command(cmdtable) | |||
|
14 | ||||
|
15 | @command('fakemergerecord', | |||
|
16 | [('X', 'mandatory', None, 'add a fake mandatory record'), | |||
|
17 | ('x', 'advisory', None, 'add a fake advisory record')], '') | |||
|
18 | def fakemergerecord(ui, repo, *pats, **opts): | |||
|
19 | ms = merge.mergestate.read(repo) | |||
|
20 | records = ms._makerecords() | |||
|
21 | if opts.get('mandatory'): | |||
|
22 | records.append(('X', 'mandatory record')) | |||
|
23 | if opts.get('advisory'): | |||
|
24 | records.append(('x', 'advisory record')) | |||
|
25 | ms._writerecords(records) |
@@ -62,6 +62,8 class mergestate(object): | |||||
62 | (experimental) |
|
62 | (experimental) | |
63 | m: the external merge driver defined for this merge plus its run state |
|
63 | m: the external merge driver defined for this merge plus its run state | |
64 | (experimental) |
|
64 | (experimental) | |
|
65 | X: unsupported mandatory record type (used in tests) | |||
|
66 | x: unsupported advisory record type (used in tests) | |||
65 |
|
67 | |||
66 | Merge driver run states (experimental): |
|
68 | Merge driver run states (experimental): | |
67 | u: driver-resolved files unmarked -- needs to be run next time we're about |
|
69 | u: driver-resolved files unmarked -- needs to be run next time we're about | |
@@ -231,6 +233,13 class mergestate(object): | |||||
231 | `type` is a single character, `length` is a 4 byte integer, and |
|
233 | `type` is a single character, `length` is a 4 byte integer, and | |
232 | `content` is an arbitrary byte sequence of length `length`. |
|
234 | `content` is an arbitrary byte sequence of length `length`. | |
233 |
|
235 | |||
|
236 | Mercurial versions prior to 3.7 have a bug where if there are | |||
|
237 | unsupported mandatory merge records, attempting to clear out the merge | |||
|
238 | state with hg update --clean or similar aborts. The 't' record type | |||
|
239 | works around that by writing out what those versions treat as an | |||
|
240 | advisory record, but later versions interpret as special: the first | |||
|
241 | character is the 'real' record type and everything onwards is the data. | |||
|
242 | ||||
234 | Returns list of records [(TYPE, data), ...].""" |
|
243 | Returns list of records [(TYPE, data), ...].""" | |
235 | records = [] |
|
244 | records = [] | |
236 | try: |
|
245 | try: | |
@@ -245,6 +254,8 class mergestate(object): | |||||
245 | off += 4 |
|
254 | off += 4 | |
246 | record = data[off:(off + length)] |
|
255 | record = data[off:(off + length)] | |
247 | off += length |
|
256 | off += length | |
|
257 | if rtype == 't': | |||
|
258 | rtype, record = record[0], record[1:] | |||
248 | records.append((rtype, record)) |
|
259 | records.append((rtype, record)) | |
249 | f.close() |
|
260 | f.close() | |
250 | except IOError as err: |
|
261 | except IOError as err: | |
@@ -326,10 +337,16 class mergestate(object): | |||||
326 | f.close() |
|
337 | f.close() | |
327 |
|
338 | |||
328 | def _writerecordsv2(self, records): |
|
339 | def _writerecordsv2(self, records): | |
329 |
"""Write current state on disk in a version 2 file |
|
340 | """Write current state on disk in a version 2 file | |
|
341 | ||||
|
342 | See the docstring for _readrecordsv2 for why we use 't'.""" | |||
|
343 | # these are the records that all version 2 clients can read | |||
|
344 | whitelist = 'LOF' | |||
330 | f = self._repo.vfs(self.statepathv2, 'w') |
|
345 | f = self._repo.vfs(self.statepathv2, 'w') | |
331 | for key, data in records: |
|
346 | for key, data in records: | |
332 | assert len(key) == 1 |
|
347 | assert len(key) == 1 | |
|
348 | if key not in whitelist: | |||
|
349 | key, data = 't', '%s%s' % (key, data) | |||
333 | format = '>sI%is' % len(data) |
|
350 | format = '>sI%is' % len(data) | |
334 | f.write(_pack(format, key, len(data), data)) |
|
351 | f.write(_pack(format, key, len(data), data)) | |
335 | f.close() |
|
352 | f.close() |
@@ -75,10 +75,45 edit the history | |||||
75 | warning: conflicts while merging e! (edit, then use 'hg resolve --mark') |
|
75 | warning: conflicts while merging e! (edit, then use 'hg resolve --mark') | |
76 | Fix up the change and run hg histedit --continue |
|
76 | Fix up the change and run hg histedit --continue | |
77 |
|
77 | |||
|
78 | insert unsupported advisory merge record | |||
|
79 | $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x | |||
|
80 | $ hg debugmergestate | |||
|
81 | * version 2 records | |||
|
82 | local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758 | |||
|
83 | other: e860deea161a2f77de56603b340ebbb4536308ae | |||
|
84 | unrecognized entry: x advisory record | |||
|
85 | file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f) | |||
|
86 | local path: e (flags "") | |||
|
87 | ancestor path: e (node 0000000000000000000000000000000000000000) | |||
|
88 | other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f) | |||
|
89 | $ hg resolve -l | |||
|
90 | U e | |||
78 |
|
91 | |||
79 | abort the edit |
|
92 | insert unsupported mandatory merge record | |
|
93 | $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X | |||
|
94 | $ hg debugmergestate | |||
|
95 | * version 2 records | |||
|
96 | local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758 | |||
|
97 | other: e860deea161a2f77de56603b340ebbb4536308ae | |||
|
98 | file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f) | |||
|
99 | local path: e (flags "") | |||
|
100 | ancestor path: e (node 0000000000000000000000000000000000000000) | |||
|
101 | other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f) | |||
|
102 | unrecognized entry: X mandatory record | |||
|
103 | $ hg resolve -l | |||
|
104 | abort: unsupported merge state records: X | |||
|
105 | (see https://mercurial-scm.org/wiki/MergeStateRecords for more information) | |||
|
106 | [255] | |||
|
107 | $ hg resolve -ma | |||
|
108 | abort: unsupported merge state records: X | |||
|
109 | (see https://mercurial-scm.org/wiki/MergeStateRecords for more information) | |||
|
110 | [255] | |||
|
111 | ||||
|
112 | abort the edit (should clear out merge state) | |||
80 | $ hg histedit --abort 2>&1 | fixbundle |
|
113 | $ hg histedit --abort 2>&1 | fixbundle | |
81 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
114 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
115 | $ hg debugmergestate | |||
|
116 | no merge state found | |||
82 |
|
117 | |||
83 | log after abort |
|
118 | log after abort | |
84 | $ hg resolve -l |
|
119 | $ hg resolve -l |
@@ -68,11 +68,49 Conflicting rebase: | |||||
68 | unresolved conflicts (see hg resolve, then hg rebase --continue) |
|
68 | unresolved conflicts (see hg resolve, then hg rebase --continue) | |
69 | [1] |
|
69 | [1] | |
70 |
|
70 | |||
71 | Abort: |
|
71 | Insert unsupported advisory merge record: | |
|
72 | ||||
|
73 | $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x | |||
|
74 | $ hg debugmergestate | |||
|
75 | * version 2 records | |||
|
76 | local: 3e046f2ecedb793b97ed32108086edd1a162f8bc | |||
|
77 | other: 46f0b057b5c061d276b91491c22151f78698abd2 | |||
|
78 | unrecognized entry: x advisory record | |||
|
79 | file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1) | |||
|
80 | local path: common (flags "") | |||
|
81 | ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6) | |||
|
82 | other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5) | |||
|
83 | $ hg resolve -l | |||
|
84 | U common | |||
|
85 | ||||
|
86 | Insert unsupported mandatory merge record: | |||
|
87 | ||||
|
88 | $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X | |||
|
89 | $ hg debugmergestate | |||
|
90 | * version 2 records | |||
|
91 | local: 3e046f2ecedb793b97ed32108086edd1a162f8bc | |||
|
92 | other: 46f0b057b5c061d276b91491c22151f78698abd2 | |||
|
93 | file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1) | |||
|
94 | local path: common (flags "") | |||
|
95 | ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6) | |||
|
96 | other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5) | |||
|
97 | unrecognized entry: X mandatory record | |||
|
98 | $ hg resolve -l | |||
|
99 | abort: unsupported merge state records: X | |||
|
100 | (see https://mercurial-scm.org/wiki/MergeStateRecords for more information) | |||
|
101 | [255] | |||
|
102 | $ hg resolve -ma | |||
|
103 | abort: unsupported merge state records: X | |||
|
104 | (see https://mercurial-scm.org/wiki/MergeStateRecords for more information) | |||
|
105 | [255] | |||
|
106 | ||||
|
107 | Abort (should clear out unsupported merge state): | |||
72 |
|
108 | |||
73 | $ hg rebase --abort |
|
109 | $ hg rebase --abort | |
74 | saved backup bundle to $TESTTMP/a/.hg/strip-backup/3e046f2ecedb-6beef7d5-backup.hg (glob) |
|
110 | saved backup bundle to $TESTTMP/a/.hg/strip-backup/3e046f2ecedb-6beef7d5-backup.hg (glob) | |
75 | rebase aborted |
|
111 | rebase aborted | |
|
112 | $ hg debugmergestate | |||
|
113 | no merge state found | |||
76 |
|
114 | |||
77 | $ hg tglog |
|
115 | $ hg tglog | |
78 | @ 4:draft 'L2' |
|
116 | @ 4:draft 'L2' |
@@ -249,9 +249,69 resolve <file> should do nothing if 'fil | |||||
249 | $ cat file1 |
|
249 | $ cat file1 | |
250 | resolved |
|
250 | resolved | |
251 |
|
251 | |||
|
252 | insert unsupported advisory merge record | |||
|
253 | ||||
|
254 | $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x | |||
|
255 | $ hg debugmergestate | |||
|
256 | * version 2 records | |||
|
257 | local: 57653b9f834a4493f7240b0681efcb9ae7cab745 | |||
|
258 | other: dc77451844e37f03f5c559e3b8529b2b48d381d1 | |||
|
259 | unrecognized entry: x advisory record | |||
|
260 | file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390) | |||
|
261 | local path: file1 (flags "") | |||
|
262 | ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd) | |||
|
263 | other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d) | |||
|
264 | file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523) | |||
|
265 | local path: file2 (flags "") | |||
|
266 | ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd) | |||
|
267 | other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d) | |||
|
268 | $ hg resolve -l | |||
|
269 | R file1 | |||
|
270 | U file2 | |||
|
271 | ||||
|
272 | insert unsupported mandatory merge record | |||
|
273 | ||||
|
274 | $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X | |||
|
275 | $ hg debugmergestate | |||
|
276 | * version 2 records | |||
|
277 | local: 57653b9f834a4493f7240b0681efcb9ae7cab745 | |||
|
278 | other: dc77451844e37f03f5c559e3b8529b2b48d381d1 | |||
|
279 | file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390) | |||
|
280 | local path: file1 (flags "") | |||
|
281 | ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd) | |||
|
282 | other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d) | |||
|
283 | file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523) | |||
|
284 | local path: file2 (flags "") | |||
|
285 | ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd) | |||
|
286 | other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d) | |||
|
287 | unrecognized entry: X mandatory record | |||
|
288 | $ hg resolve -l | |||
|
289 | abort: unsupported merge state records: X | |||
|
290 | (see https://mercurial-scm.org/wiki/MergeStateRecords for more information) | |||
|
291 | [255] | |||
|
292 | $ hg resolve -ma | |||
|
293 | abort: unsupported merge state records: X | |||
|
294 | (see https://mercurial-scm.org/wiki/MergeStateRecords for more information) | |||
|
295 | [255] | |||
|
296 | $ hg summary | |||
|
297 | parent: 2:57653b9f834a | |||
|
298 | append baz to files | |||
|
299 | parent: 1:dc77451844e3 | |||
|
300 | append bar to files | |||
|
301 | branch: default | |||
|
302 | warning: merge state has unsupported record types: X | |||
|
303 | commit: 2 modified, 2 unknown (merge) | |||
|
304 | update: 2 new changesets (update) | |||
|
305 | phases: 5 draft | |||
|
306 | ||||
|
307 | update --clean shouldn't abort on unsupported records | |||
|
308 | ||||
|
309 | $ hg up -qC 1 | |||
|
310 | $ hg debugmergestate | |||
|
311 | no merge state found | |||
|
312 | ||||
252 | test crashed merge with empty mergestate |
|
313 | test crashed merge with empty mergestate | |
253 |
|
314 | |||
254 | $ hg up -qC 1 |
|
|||
255 | $ mkdir .hg/merge |
|
315 | $ mkdir .hg/merge | |
256 | $ touch .hg/merge/state |
|
316 | $ touch .hg/merge/state | |
257 |
|
317 |
General Comments 0
You need to be logged in to leave comments.
Login now