Mercurial > public > mercurial-scm > hg
comparison mercurial/merge.py @ 27027:a01ecbcfaf84
mergestate: handle additional record types specially
This works around a bug in older Mercurial versions' handling of the v2 merge
state.
We also add a bunch of tests that make sure that
(1) we correctly abort when the merge state has an unsupported record type
(2) aborting the merge, rebase or histedit continues to work and clears out the
merge state.
author | Siddharth Agarwal <sid0@fb.com> |
---|---|
date | Wed, 18 Nov 2015 15:46:45 -0800 |
parents | 35102876d648 |
children | 8be0af32e513 |
comparison
equal
deleted
inserted
replaced
27026:c93b44b79359 | 27027:a01ecbcfaf84 |
---|---|
60 F: a file to be merged entry | 60 F: a file to be merged entry |
61 D: a file that the external merge driver will merge internally | 61 D: a file that the external merge driver will merge internally |
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 |
68 to resolve or commit | 70 to resolve or commit |
69 m: driver-resolved files marked -- only needs to be run before commit | 71 m: driver-resolved files marked -- only needs to be run before commit |
229 [type][length][content] | 231 [type][length][content] |
230 | 232 |
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: |
237 f = self._repo.vfs(self.statepathv2) | 246 f = self._repo.vfs(self.statepathv2) |
238 data = f.read() | 247 data = f.read() |
243 off += 1 | 252 off += 1 |
244 length = _unpack('>I', data[off:(off + 4)])[0] | 253 length = _unpack('>I', data[off:(off + 4)])[0] |
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: |
251 if err.errno != errno.ENOENT: | 262 if err.errno != errno.ENOENT: |
252 raise | 263 raise |
324 if rtype == 'F': | 335 if rtype == 'F': |
325 f.write('%s\n' % _droponode(data)) | 336 f.write('%s\n' % _droponode(data)) |
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() |
336 | 353 |
337 def add(self, fcl, fco, fca, fd): | 354 def add(self, fcl, fco, fca, fd): |