##// END OF EJS Templates
merge: add file ancestor linknode to mergestate...
Durham Goode -
r28011:8abd9f78 default
parent child Browse files
Show More
@@ -1,1608 +1,1615 b''
1 1 # merge.py - directory-level update/merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import errno
11 11 import os
12 12 import shutil
13 13 import struct
14 14
15 15 from .i18n import _
16 16 from .node import (
17 17 bin,
18 18 hex,
19 19 nullhex,
20 20 nullid,
21 21 nullrev,
22 22 )
23 23 from . import (
24 24 copies,
25 25 destutil,
26 26 error,
27 27 filemerge,
28 28 obsolete,
29 29 scmutil,
30 30 subrepo,
31 31 util,
32 32 worker,
33 33 )
34 34
35 35 _pack = struct.pack
36 36 _unpack = struct.unpack
37 37
38 38 def _droponode(data):
39 39 # used for compatibility for v1
40 40 bits = data.split('\0')
41 41 bits = bits[:-2] + bits[-1:]
42 42 return '\0'.join(bits)
43 43
44 44 class mergestate(object):
45 45 '''track 3-way merge state of individual files
46 46
47 47 The merge state is stored on disk when needed. Two files are used: one with
48 48 an old format (version 1), and one with a new format (version 2). Version 2
49 49 stores a superset of the data in version 1, including new kinds of records
50 50 in the future. For more about the new format, see the documentation for
51 51 `_readrecordsv2`.
52 52
53 53 Each record can contain arbitrary content, and has an associated type. This
54 54 `type` should be a letter. If `type` is uppercase, the record is mandatory:
55 55 versions of Mercurial that don't support it should abort. If `type` is
56 56 lowercase, the record can be safely ignored.
57 57
58 58 Currently known records:
59 59
60 60 L: the node of the "local" part of the merge (hexified version)
61 61 O: the node of the "other" part of the merge (hexified version)
62 62 F: a file to be merged entry
63 63 C: a change/delete or delete/change conflict
64 64 D: a file that the external merge driver will merge internally
65 65 (experimental)
66 66 m: the external merge driver defined for this merge plus its run state
67 67 (experimental)
68 68 f: a (filename, dictonary) tuple of optional values for a given file
69 69 X: unsupported mandatory record type (used in tests)
70 70 x: unsupported advisory record type (used in tests)
71 71
72 72 Merge driver run states (experimental):
73 73 u: driver-resolved files unmarked -- needs to be run next time we're about
74 74 to resolve or commit
75 75 m: driver-resolved files marked -- only needs to be run before commit
76 76 s: success/skipped -- does not need to be run any more
77 77
78 78 '''
79 79 statepathv1 = 'merge/state'
80 80 statepathv2 = 'merge/state2'
81 81
82 82 @staticmethod
83 83 def clean(repo, node=None, other=None):
84 84 """Initialize a brand new merge state, removing any existing state on
85 85 disk."""
86 86 ms = mergestate(repo)
87 87 ms.reset(node, other)
88 88 return ms
89 89
90 90 @staticmethod
91 91 def read(repo):
92 92 """Initialize the merge state, reading it from disk."""
93 93 ms = mergestate(repo)
94 94 ms._read()
95 95 return ms
96 96
97 97 def __init__(self, repo):
98 98 """Initialize the merge state.
99 99
100 100 Do not use this directly! Instead call read() or clean()."""
101 101 self._repo = repo
102 102 self._dirty = False
103 103
104 104 def reset(self, node=None, other=None):
105 105 self._state = {}
106 106 self._stateextras = {}
107 107 self._local = None
108 108 self._other = None
109 109 for var in ('localctx', 'otherctx'):
110 110 if var in vars(self):
111 111 delattr(self, var)
112 112 if node:
113 113 self._local = node
114 114 self._other = other
115 115 self._readmergedriver = None
116 116 if self.mergedriver:
117 117 self._mdstate = 's'
118 118 else:
119 119 self._mdstate = 'u'
120 120 shutil.rmtree(self._repo.join('merge'), True)
121 121 self._results = {}
122 122 self._dirty = False
123 123
124 124 def _read(self):
125 125 """Analyse each record content to restore a serialized state from disk
126 126
127 127 This function process "record" entry produced by the de-serialization
128 128 of on disk file.
129 129 """
130 130 self._state = {}
131 131 self._stateextras = {}
132 132 self._local = None
133 133 self._other = None
134 134 for var in ('localctx', 'otherctx'):
135 135 if var in vars(self):
136 136 delattr(self, var)
137 137 self._readmergedriver = None
138 138 self._mdstate = 's'
139 139 unsupported = set()
140 140 records = self._readrecords()
141 141 for rtype, record in records:
142 142 if rtype == 'L':
143 143 self._local = bin(record)
144 144 elif rtype == 'O':
145 145 self._other = bin(record)
146 146 elif rtype == 'm':
147 147 bits = record.split('\0', 1)
148 148 mdstate = bits[1]
149 149 if len(mdstate) != 1 or mdstate not in 'ums':
150 150 # the merge driver should be idempotent, so just rerun it
151 151 mdstate = 'u'
152 152
153 153 self._readmergedriver = bits[0]
154 154 self._mdstate = mdstate
155 155 elif rtype in 'FDC':
156 156 bits = record.split('\0')
157 157 self._state[bits[0]] = bits[1:]
158 158 elif rtype == 'f':
159 159 filename, rawextras = record.split('\0', 1)
160 160 extraparts = rawextras.split('\0')
161 161 extras = {}
162 162 i = 0
163 163 while i < len(extraparts):
164 164 extras[extraparts[i]] = extraparts[i + 1]
165 165 i += 2
166 166
167 167 self._stateextras[filename] = extras
168 168 elif not rtype.islower():
169 169 unsupported.add(rtype)
170 170 self._results = {}
171 171 self._dirty = False
172 172
173 173 if unsupported:
174 174 raise error.UnsupportedMergeRecords(unsupported)
175 175
176 176 def _readrecords(self):
177 177 """Read merge state from disk and return a list of record (TYPE, data)
178 178
179 179 We read data from both v1 and v2 files and decide which one to use.
180 180
181 181 V1 has been used by version prior to 2.9.1 and contains less data than
182 182 v2. We read both versions and check if no data in v2 contradicts
183 183 v1. If there is not contradiction we can safely assume that both v1
184 184 and v2 were written at the same time and use the extract data in v2. If
185 185 there is contradiction we ignore v2 content as we assume an old version
186 186 of Mercurial has overwritten the mergestate file and left an old v2
187 187 file around.
188 188
189 189 returns list of record [(TYPE, data), ...]"""
190 190 v1records = self._readrecordsv1()
191 191 v2records = self._readrecordsv2()
192 192 if self._v1v2match(v1records, v2records):
193 193 return v2records
194 194 else:
195 195 # v1 file is newer than v2 file, use it
196 196 # we have to infer the "other" changeset of the merge
197 197 # we cannot do better than that with v1 of the format
198 198 mctx = self._repo[None].parents()[-1]
199 199 v1records.append(('O', mctx.hex()))
200 200 # add place holder "other" file node information
201 201 # nobody is using it yet so we do no need to fetch the data
202 202 # if mctx was wrong `mctx[bits[-2]]` may fails.
203 203 for idx, r in enumerate(v1records):
204 204 if r[0] == 'F':
205 205 bits = r[1].split('\0')
206 206 bits.insert(-2, '')
207 207 v1records[idx] = (r[0], '\0'.join(bits))
208 208 return v1records
209 209
210 210 def _v1v2match(self, v1records, v2records):
211 211 oldv2 = set() # old format version of v2 record
212 212 for rec in v2records:
213 213 if rec[0] == 'L':
214 214 oldv2.add(rec)
215 215 elif rec[0] == 'F':
216 216 # drop the onode data (not contained in v1)
217 217 oldv2.add(('F', _droponode(rec[1])))
218 218 for rec in v1records:
219 219 if rec not in oldv2:
220 220 return False
221 221 else:
222 222 return True
223 223
224 224 def _readrecordsv1(self):
225 225 """read on disk merge state for version 1 file
226 226
227 227 returns list of record [(TYPE, data), ...]
228 228
229 229 Note: the "F" data from this file are one entry short
230 230 (no "other file node" entry)
231 231 """
232 232 records = []
233 233 try:
234 234 f = self._repo.vfs(self.statepathv1)
235 235 for i, l in enumerate(f):
236 236 if i == 0:
237 237 records.append(('L', l[:-1]))
238 238 else:
239 239 records.append(('F', l[:-1]))
240 240 f.close()
241 241 except IOError as err:
242 242 if err.errno != errno.ENOENT:
243 243 raise
244 244 return records
245 245
246 246 def _readrecordsv2(self):
247 247 """read on disk merge state for version 2 file
248 248
249 249 This format is a list of arbitrary records of the form:
250 250
251 251 [type][length][content]
252 252
253 253 `type` is a single character, `length` is a 4 byte integer, and
254 254 `content` is an arbitrary byte sequence of length `length`.
255 255
256 256 Mercurial versions prior to 3.7 have a bug where if there are
257 257 unsupported mandatory merge records, attempting to clear out the merge
258 258 state with hg update --clean or similar aborts. The 't' record type
259 259 works around that by writing out what those versions treat as an
260 260 advisory record, but later versions interpret as special: the first
261 261 character is the 'real' record type and everything onwards is the data.
262 262
263 263 Returns list of records [(TYPE, data), ...]."""
264 264 records = []
265 265 try:
266 266 f = self._repo.vfs(self.statepathv2)
267 267 data = f.read()
268 268 off = 0
269 269 end = len(data)
270 270 while off < end:
271 271 rtype = data[off]
272 272 off += 1
273 273 length = _unpack('>I', data[off:(off + 4)])[0]
274 274 off += 4
275 275 record = data[off:(off + length)]
276 276 off += length
277 277 if rtype == 't':
278 278 rtype, record = record[0], record[1:]
279 279 records.append((rtype, record))
280 280 f.close()
281 281 except IOError as err:
282 282 if err.errno != errno.ENOENT:
283 283 raise
284 284 return records
285 285
286 286 @util.propertycache
287 287 def mergedriver(self):
288 288 # protect against the following:
289 289 # - A configures a malicious merge driver in their hgrc, then
290 290 # pauses the merge
291 291 # - A edits their hgrc to remove references to the merge driver
292 292 # - A gives a copy of their entire repo, including .hg, to B
293 293 # - B inspects .hgrc and finds it to be clean
294 294 # - B then continues the merge and the malicious merge driver
295 295 # gets invoked
296 296 configmergedriver = self._repo.ui.config('experimental', 'mergedriver')
297 297 if (self._readmergedriver is not None
298 298 and self._readmergedriver != configmergedriver):
299 299 raise error.ConfigError(
300 300 _("merge driver changed since merge started"),
301 301 hint=_("revert merge driver change or abort merge"))
302 302
303 303 return configmergedriver
304 304
305 305 @util.propertycache
306 306 def localctx(self):
307 307 if self._local is None:
308 308 raise RuntimeError("localctx accessed but self._local isn't set")
309 309 return self._repo[self._local]
310 310
311 311 @util.propertycache
312 312 def otherctx(self):
313 313 if self._other is None:
314 314 raise RuntimeError("localctx accessed but self._local isn't set")
315 315 return self._repo[self._other]
316 316
317 317 def active(self):
318 318 """Whether mergestate is active.
319 319
320 320 Returns True if there appears to be mergestate. This is a rough proxy
321 321 for "is a merge in progress."
322 322 """
323 323 # Check local variables before looking at filesystem for performance
324 324 # reasons.
325 325 return bool(self._local) or bool(self._state) or \
326 326 self._repo.vfs.exists(self.statepathv1) or \
327 327 self._repo.vfs.exists(self.statepathv2)
328 328
329 329 def commit(self):
330 330 """Write current state on disk (if necessary)"""
331 331 if self._dirty:
332 332 records = self._makerecords()
333 333 self._writerecords(records)
334 334 self._dirty = False
335 335
336 336 def _makerecords(self):
337 337 records = []
338 338 records.append(('L', hex(self._local)))
339 339 records.append(('O', hex(self._other)))
340 340 if self.mergedriver:
341 341 records.append(('m', '\0'.join([
342 342 self.mergedriver, self._mdstate])))
343 343 for d, v in self._state.iteritems():
344 344 if v[0] == 'd':
345 345 records.append(('D', '\0'.join([d] + v)))
346 346 # v[1] == local ('cd'), v[6] == other ('dc') -- not supported by
347 347 # older versions of Mercurial
348 348 elif v[1] == nullhex or v[6] == nullhex:
349 349 records.append(('C', '\0'.join([d] + v)))
350 350 else:
351 351 records.append(('F', '\0'.join([d] + v)))
352 352 for filename, extras in sorted(self._stateextras.iteritems()):
353 353 rawextras = '\0'.join('%s\0%s' % (k, v) for k, v in
354 354 extras.iteritems())
355 355 records.append(('f', '%s\0%s' % (filename, rawextras)))
356 356 return records
357 357
358 358 def _writerecords(self, records):
359 359 """Write current state on disk (both v1 and v2)"""
360 360 self._writerecordsv1(records)
361 361 self._writerecordsv2(records)
362 362
363 363 def _writerecordsv1(self, records):
364 364 """Write current state on disk in a version 1 file"""
365 365 f = self._repo.vfs(self.statepathv1, 'w')
366 366 irecords = iter(records)
367 367 lrecords = irecords.next()
368 368 assert lrecords[0] == 'L'
369 369 f.write(hex(self._local) + '\n')
370 370 for rtype, data in irecords:
371 371 if rtype == 'F':
372 372 f.write('%s\n' % _droponode(data))
373 373 f.close()
374 374
375 375 def _writerecordsv2(self, records):
376 376 """Write current state on disk in a version 2 file
377 377
378 378 See the docstring for _readrecordsv2 for why we use 't'."""
379 379 # these are the records that all version 2 clients can read
380 380 whitelist = 'LOF'
381 381 f = self._repo.vfs(self.statepathv2, 'w')
382 382 for key, data in records:
383 383 assert len(key) == 1
384 384 if key not in whitelist:
385 385 key, data = 't', '%s%s' % (key, data)
386 386 format = '>sI%is' % len(data)
387 387 f.write(_pack(format, key, len(data), data))
388 388 f.close()
389 389
390 390 def add(self, fcl, fco, fca, fd):
391 391 """add a new (potentially?) conflicting file the merge state
392 392 fcl: file context for local,
393 393 fco: file context for remote,
394 394 fca: file context for ancestors,
395 395 fd: file path of the resulting merge.
396 396
397 397 note: also write the local version to the `.hg/merge` directory.
398 398 """
399 399 if fcl.isabsent():
400 400 hash = nullhex
401 401 else:
402 402 hash = util.sha1(fcl.path()).hexdigest()
403 403 self._repo.vfs.write('merge/' + hash, fcl.data())
404 404 self._state[fd] = ['u', hash, fcl.path(),
405 405 fca.path(), hex(fca.filenode()),
406 406 fco.path(), hex(fco.filenode()),
407 407 fcl.flags()]
408 self._stateextras[fd] = { 'ancestorlinknode' : hex(fca.node()) }
408 409 self._dirty = True
409 410
410 411 def __contains__(self, dfile):
411 412 return dfile in self._state
412 413
413 414 def __getitem__(self, dfile):
414 415 return self._state[dfile][0]
415 416
416 417 def __iter__(self):
417 418 return iter(sorted(self._state))
418 419
419 420 def files(self):
420 421 return self._state.keys()
421 422
422 423 def mark(self, dfile, state):
423 424 self._state[dfile][0] = state
424 425 self._dirty = True
425 426
426 427 def mdstate(self):
427 428 return self._mdstate
428 429
429 430 def unresolved(self):
430 431 """Obtain the paths of unresolved files."""
431 432
432 433 for f, entry in self._state.items():
433 434 if entry[0] == 'u':
434 435 yield f
435 436
436 437 def driverresolved(self):
437 438 """Obtain the paths of driver-resolved files."""
438 439
439 440 for f, entry in self._state.items():
440 441 if entry[0] == 'd':
441 442 yield f
442 443
443 444 def extras(self, filename):
444 445 return self._stateextras.setdefault(filename, {})
445 446
446 447 def _resolve(self, preresolve, dfile, wctx, labels=None):
447 448 """rerun merge process for file path `dfile`"""
448 449 if self[dfile] in 'rd':
449 450 return True, 0
450 451 stateentry = self._state[dfile]
451 452 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
452 453 octx = self._repo[self._other]
454 extras = self.extras(dfile)
455 anccommitnode = extras.get('ancestorlinknode')
456 if anccommitnode:
457 actx = self._repo[anccommitnode]
458 else:
459 actx = None
453 460 fcd = self._filectxorabsent(hash, wctx, dfile)
454 461 fco = self._filectxorabsent(onode, octx, ofile)
455 462 # TODO: move this to filectxorabsent
456 fca = self._repo.filectx(afile, fileid=anode)
463 fca = self._repo.filectx(afile, fileid=anode, changeid=actx)
457 464 # "premerge" x flags
458 465 flo = fco.flags()
459 466 fla = fca.flags()
460 467 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
461 468 if fca.node() == nullid:
462 469 if preresolve:
463 470 self._repo.ui.warn(
464 471 _('warning: cannot merge flags for %s\n') % afile)
465 472 elif flags == fla:
466 473 flags = flo
467 474 if preresolve:
468 475 # restore local
469 476 if hash != nullhex:
470 477 f = self._repo.vfs('merge/' + hash)
471 478 self._repo.wwrite(dfile, f.read(), flags)
472 479 f.close()
473 480 else:
474 481 self._repo.wvfs.unlinkpath(dfile, ignoremissing=True)
475 482 complete, r, deleted = filemerge.premerge(self._repo, self._local,
476 483 lfile, fcd, fco, fca,
477 484 labels=labels)
478 485 else:
479 486 complete, r, deleted = filemerge.filemerge(self._repo, self._local,
480 487 lfile, fcd, fco, fca,
481 488 labels=labels)
482 489 if r is None:
483 490 # no real conflict
484 491 del self._state[dfile]
485 492 self._stateextras.pop(dfile, None)
486 493 self._dirty = True
487 494 elif not r:
488 495 self.mark(dfile, 'r')
489 496
490 497 if complete:
491 498 action = None
492 499 if deleted:
493 500 if fcd.isabsent():
494 501 # dc: local picked. Need to drop if present, which may
495 502 # happen on re-resolves.
496 503 action = 'f'
497 504 else:
498 505 # cd: remote picked (or otherwise deleted)
499 506 action = 'r'
500 507 else:
501 508 if fcd.isabsent(): # dc: remote picked
502 509 action = 'g'
503 510 elif fco.isabsent(): # cd: local picked
504 511 if dfile in self.localctx:
505 512 action = 'am'
506 513 else:
507 514 action = 'a'
508 515 # else: regular merges (no action necessary)
509 516 self._results[dfile] = r, action
510 517
511 518 return complete, r
512 519
513 520 def _filectxorabsent(self, hexnode, ctx, f):
514 521 if hexnode == nullhex:
515 522 return filemerge.absentfilectx(ctx, f)
516 523 else:
517 524 return ctx[f]
518 525
519 526 def preresolve(self, dfile, wctx, labels=None):
520 527 """run premerge process for dfile
521 528
522 529 Returns whether the merge is complete, and the exit code."""
523 530 return self._resolve(True, dfile, wctx, labels=labels)
524 531
525 532 def resolve(self, dfile, wctx, labels=None):
526 533 """run merge process (assuming premerge was run) for dfile
527 534
528 535 Returns the exit code of the merge."""
529 536 return self._resolve(False, dfile, wctx, labels=labels)[1]
530 537
531 538 def counts(self):
532 539 """return counts for updated, merged and removed files in this
533 540 session"""
534 541 updated, merged, removed = 0, 0, 0
535 542 for r, action in self._results.itervalues():
536 543 if r is None:
537 544 updated += 1
538 545 elif r == 0:
539 546 if action == 'r':
540 547 removed += 1
541 548 else:
542 549 merged += 1
543 550 return updated, merged, removed
544 551
545 552 def unresolvedcount(self):
546 553 """get unresolved count for this merge (persistent)"""
547 554 return len([True for f, entry in self._state.iteritems()
548 555 if entry[0] == 'u'])
549 556
550 557 def actions(self):
551 558 """return lists of actions to perform on the dirstate"""
552 559 actions = {'r': [], 'f': [], 'a': [], 'am': [], 'g': []}
553 560 for f, (r, action) in self._results.iteritems():
554 561 if action is not None:
555 562 actions[action].append((f, None, "merge result"))
556 563 return actions
557 564
558 565 def recordactions(self):
559 566 """record remove/add/get actions in the dirstate"""
560 567 branchmerge = self._repo.dirstate.p2() != nullid
561 568 recordupdates(self._repo, self.actions(), branchmerge)
562 569
563 570 def queueremove(self, f):
564 571 """queues a file to be removed from the dirstate
565 572
566 573 Meant for use by custom merge drivers."""
567 574 self._results[f] = 0, 'r'
568 575
569 576 def queueadd(self, f):
570 577 """queues a file to be added to the dirstate
571 578
572 579 Meant for use by custom merge drivers."""
573 580 self._results[f] = 0, 'a'
574 581
575 582 def queueget(self, f):
576 583 """queues a file to be marked modified in the dirstate
577 584
578 585 Meant for use by custom merge drivers."""
579 586 self._results[f] = 0, 'g'
580 587
581 588 def _getcheckunknownconfig(repo, section, name):
582 589 config = repo.ui.config(section, name, default='abort')
583 590 valid = ['abort', 'ignore', 'warn']
584 591 if config not in valid:
585 592 validstr = ', '.join(["'" + v + "'" for v in valid])
586 593 raise error.ConfigError(_("%s.%s not valid "
587 594 "('%s' is none of %s)")
588 595 % (section, name, config, validstr))
589 596 return config
590 597
591 598 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
592 599 if f2 is None:
593 600 f2 = f
594 601 return (repo.wvfs.isfileorlink(f)
595 602 and repo.wvfs.audit.check(f)
596 603 and repo.dirstate.normalize(f) not in repo.dirstate
597 604 and mctx[f2].cmp(wctx[f]))
598 605
599 606 def _checkunknownfiles(repo, wctx, mctx, force, actions):
600 607 """
601 608 Considers any actions that care about the presence of conflicting unknown
602 609 files. For some actions, the result is to abort; for others, it is to
603 610 choose a different action.
604 611 """
605 612 conflicts = set()
606 613 if not force:
607 614 abortconflicts = set()
608 615 warnconflicts = set()
609 616 def collectconflicts(conflicts, config):
610 617 if config == 'abort':
611 618 abortconflicts.update(conflicts)
612 619 elif config == 'warn':
613 620 warnconflicts.update(conflicts)
614 621
615 622 unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
616 623 ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
617 624 for f, (m, args, msg) in actions.iteritems():
618 625 if m in ('c', 'dc'):
619 626 if _checkunknownfile(repo, wctx, mctx, f):
620 627 conflicts.add(f)
621 628 elif m == 'dg':
622 629 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
623 630 conflicts.add(f)
624 631
625 632 ignoredconflicts = set([c for c in conflicts
626 633 if repo.dirstate._ignore(c)])
627 634 unknownconflicts = conflicts - ignoredconflicts
628 635 collectconflicts(ignoredconflicts, ignoredconfig)
629 636 collectconflicts(unknownconflicts, unknownconfig)
630 637 for f in sorted(abortconflicts):
631 638 repo.ui.warn(_("%s: untracked file differs\n") % f)
632 639 if abortconflicts:
633 640 raise error.Abort(_("untracked files in working directory "
634 641 "differ from files in requested revision"))
635 642
636 643 for f in sorted(warnconflicts):
637 644 repo.ui.warn(_("%s: replacing untracked file\n") % f)
638 645
639 646 for f, (m, args, msg) in actions.iteritems():
640 647 backup = f in conflicts
641 648 if m == 'c':
642 649 flags, = args
643 650 actions[f] = ('g', (flags, backup), msg)
644 651 elif m == 'cm':
645 652 fl2, anc = args
646 653 different = _checkunknownfile(repo, wctx, mctx, f)
647 654 if different:
648 655 actions[f] = ('m', (f, f, None, False, anc),
649 656 "remote differs from untracked local")
650 657 else:
651 658 actions[f] = ('g', (fl2, backup), "remote created")
652 659
653 660 def _forgetremoved(wctx, mctx, branchmerge):
654 661 """
655 662 Forget removed files
656 663
657 664 If we're jumping between revisions (as opposed to merging), and if
658 665 neither the working directory nor the target rev has the file,
659 666 then we need to remove it from the dirstate, to prevent the
660 667 dirstate from listing the file when it is no longer in the
661 668 manifest.
662 669
663 670 If we're merging, and the other revision has removed a file
664 671 that is not present in the working directory, we need to mark it
665 672 as removed.
666 673 """
667 674
668 675 actions = {}
669 676 m = 'f'
670 677 if branchmerge:
671 678 m = 'r'
672 679 for f in wctx.deleted():
673 680 if f not in mctx:
674 681 actions[f] = m, None, "forget deleted"
675 682
676 683 if not branchmerge:
677 684 for f in wctx.removed():
678 685 if f not in mctx:
679 686 actions[f] = 'f', None, "forget removed"
680 687
681 688 return actions
682 689
683 690 def _checkcollision(repo, wmf, actions):
684 691 # build provisional merged manifest up
685 692 pmmf = set(wmf)
686 693
687 694 if actions:
688 695 # k, dr, e and rd are no-op
689 696 for m in 'a', 'am', 'f', 'g', 'cd', 'dc':
690 697 for f, args, msg in actions[m]:
691 698 pmmf.add(f)
692 699 for f, args, msg in actions['r']:
693 700 pmmf.discard(f)
694 701 for f, args, msg in actions['dm']:
695 702 f2, flags = args
696 703 pmmf.discard(f2)
697 704 pmmf.add(f)
698 705 for f, args, msg in actions['dg']:
699 706 pmmf.add(f)
700 707 for f, args, msg in actions['m']:
701 708 f1, f2, fa, move, anc = args
702 709 if move:
703 710 pmmf.discard(f1)
704 711 pmmf.add(f)
705 712
706 713 # check case-folding collision in provisional merged manifest
707 714 foldmap = {}
708 715 for f in sorted(pmmf):
709 716 fold = util.normcase(f)
710 717 if fold in foldmap:
711 718 raise error.Abort(_("case-folding collision between %s and %s")
712 719 % (f, foldmap[fold]))
713 720 foldmap[fold] = f
714 721
715 722 # check case-folding of directories
716 723 foldprefix = unfoldprefix = lastfull = ''
717 724 for fold, f in sorted(foldmap.items()):
718 725 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
719 726 # the folded prefix matches but actual casing is different
720 727 raise error.Abort(_("case-folding collision between "
721 728 "%s and directory of %s") % (lastfull, f))
722 729 foldprefix = fold + '/'
723 730 unfoldprefix = f + '/'
724 731 lastfull = f
725 732
726 733 def driverpreprocess(repo, ms, wctx, labels=None):
727 734 """run the preprocess step of the merge driver, if any
728 735
729 736 This is currently not implemented -- it's an extension point."""
730 737 return True
731 738
732 739 def driverconclude(repo, ms, wctx, labels=None):
733 740 """run the conclude step of the merge driver, if any
734 741
735 742 This is currently not implemented -- it's an extension point."""
736 743 return True
737 744
738 745 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
739 746 acceptremote, followcopies):
740 747 """
741 748 Merge p1 and p2 with ancestor pa and generate merge action list
742 749
743 750 branchmerge and force are as passed in to update
744 751 matcher = matcher to filter file lists
745 752 acceptremote = accept the incoming changes without prompting
746 753 """
747 754 if matcher is not None and matcher.always():
748 755 matcher = None
749 756
750 757 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
751 758
752 759 # manifests fetched in order are going to be faster, so prime the caches
753 760 [x.manifest() for x in
754 761 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
755 762
756 763 if followcopies:
757 764 ret = copies.mergecopies(repo, wctx, p2, pa)
758 765 copy, movewithdir, diverge, renamedelete = ret
759 766
760 767 repo.ui.note(_("resolving manifests\n"))
761 768 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
762 769 % (bool(branchmerge), bool(force), bool(matcher)))
763 770 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
764 771
765 772 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
766 773 copied = set(copy.values())
767 774 copied.update(movewithdir.values())
768 775
769 776 if '.hgsubstate' in m1:
770 777 # check whether sub state is modified
771 778 for s in sorted(wctx.substate):
772 779 if wctx.sub(s).dirty():
773 780 m1['.hgsubstate'] += '+'
774 781 break
775 782
776 783 # Compare manifests
777 784 if matcher is not None:
778 785 m1 = m1.matches(matcher)
779 786 m2 = m2.matches(matcher)
780 787 diff = m1.diff(m2)
781 788
782 789 actions = {}
783 790 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
784 791 if n1 and n2: # file exists on both local and remote side
785 792 if f not in ma:
786 793 fa = copy.get(f, None)
787 794 if fa is not None:
788 795 actions[f] = ('m', (f, f, fa, False, pa.node()),
789 796 "both renamed from " + fa)
790 797 else:
791 798 actions[f] = ('m', (f, f, None, False, pa.node()),
792 799 "both created")
793 800 else:
794 801 a = ma[f]
795 802 fla = ma.flags(f)
796 803 nol = 'l' not in fl1 + fl2 + fla
797 804 if n2 == a and fl2 == fla:
798 805 actions[f] = ('k' , (), "remote unchanged")
799 806 elif n1 == a and fl1 == fla: # local unchanged - use remote
800 807 if n1 == n2: # optimization: keep local content
801 808 actions[f] = ('e', (fl2,), "update permissions")
802 809 else:
803 810 actions[f] = ('g', (fl2, False), "remote is newer")
804 811 elif nol and n2 == a: # remote only changed 'x'
805 812 actions[f] = ('e', (fl2,), "update permissions")
806 813 elif nol and n1 == a: # local only changed 'x'
807 814 actions[f] = ('g', (fl1, False), "remote is newer")
808 815 else: # both changed something
809 816 actions[f] = ('m', (f, f, f, False, pa.node()),
810 817 "versions differ")
811 818 elif n1: # file exists only on local side
812 819 if f in copied:
813 820 pass # we'll deal with it on m2 side
814 821 elif f in movewithdir: # directory rename, move local
815 822 f2 = movewithdir[f]
816 823 if f2 in m2:
817 824 actions[f2] = ('m', (f, f2, None, True, pa.node()),
818 825 "remote directory rename, both created")
819 826 else:
820 827 actions[f2] = ('dm', (f, fl1),
821 828 "remote directory rename - move from " + f)
822 829 elif f in copy:
823 830 f2 = copy[f]
824 831 actions[f] = ('m', (f, f2, f2, False, pa.node()),
825 832 "local copied/moved from " + f2)
826 833 elif f in ma: # clean, a different, no remote
827 834 if n1 != ma[f]:
828 835 if acceptremote:
829 836 actions[f] = ('r', None, "remote delete")
830 837 else:
831 838 actions[f] = ('cd', (f, None, f, False, pa.node()),
832 839 "prompt changed/deleted")
833 840 elif n1[20:] == 'a':
834 841 # This extra 'a' is added by working copy manifest to mark
835 842 # the file as locally added. We should forget it instead of
836 843 # deleting it.
837 844 actions[f] = ('f', None, "remote deleted")
838 845 else:
839 846 actions[f] = ('r', None, "other deleted")
840 847 elif n2: # file exists only on remote side
841 848 if f in copied:
842 849 pass # we'll deal with it on m1 side
843 850 elif f in movewithdir:
844 851 f2 = movewithdir[f]
845 852 if f2 in m1:
846 853 actions[f2] = ('m', (f2, f, None, False, pa.node()),
847 854 "local directory rename, both created")
848 855 else:
849 856 actions[f2] = ('dg', (f, fl2),
850 857 "local directory rename - get from " + f)
851 858 elif f in copy:
852 859 f2 = copy[f]
853 860 if f2 in m2:
854 861 actions[f] = ('m', (f2, f, f2, False, pa.node()),
855 862 "remote copied from " + f2)
856 863 else:
857 864 actions[f] = ('m', (f2, f, f2, True, pa.node()),
858 865 "remote moved from " + f2)
859 866 elif f not in ma:
860 867 # local unknown, remote created: the logic is described by the
861 868 # following table:
862 869 #
863 870 # force branchmerge different | action
864 871 # n * * | create
865 872 # y n * | create
866 873 # y y n | create
867 874 # y y y | merge
868 875 #
869 876 # Checking whether the files are different is expensive, so we
870 877 # don't do that when we can avoid it.
871 878 if not force:
872 879 actions[f] = ('c', (fl2,), "remote created")
873 880 elif not branchmerge:
874 881 actions[f] = ('c', (fl2,), "remote created")
875 882 else:
876 883 actions[f] = ('cm', (fl2, pa.node()),
877 884 "remote created, get or merge")
878 885 elif n2 != ma[f]:
879 886 if acceptremote:
880 887 actions[f] = ('c', (fl2,), "remote recreating")
881 888 else:
882 889 actions[f] = ('dc', (None, f, f, False, pa.node()),
883 890 "prompt deleted/changed")
884 891
885 892 return actions, diverge, renamedelete
886 893
887 894 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
888 895 """Resolves false conflicts where the nodeid changed but the content
889 896 remained the same."""
890 897
891 898 for f, (m, args, msg) in actions.items():
892 899 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
893 900 # local did change but ended up with same content
894 901 actions[f] = 'r', None, "prompt same"
895 902 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
896 903 # remote did change but ended up with same content
897 904 del actions[f] # don't get = keep local deleted
898 905
899 906 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force,
900 907 acceptremote, followcopies, matcher=None):
901 908 "Calculate the actions needed to merge mctx into wctx using ancestors"
902 909 if len(ancestors) == 1: # default
903 910 actions, diverge, renamedelete = manifestmerge(
904 911 repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
905 912 acceptremote, followcopies)
906 913 _checkunknownfiles(repo, wctx, mctx, force, actions)
907 914
908 915 else: # only when merge.preferancestor=* - the default
909 916 repo.ui.note(
910 917 _("note: merging %s and %s using bids from ancestors %s\n") %
911 918 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
912 919
913 920 # Call for bids
914 921 fbids = {} # mapping filename to bids (action method to list af actions)
915 922 diverge, renamedelete = None, None
916 923 for ancestor in ancestors:
917 924 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
918 925 actions, diverge1, renamedelete1 = manifestmerge(
919 926 repo, wctx, mctx, ancestor, branchmerge, force, matcher,
920 927 acceptremote, followcopies)
921 928 _checkunknownfiles(repo, wctx, mctx, force, actions)
922 929
923 930 # Track the shortest set of warning on the theory that bid
924 931 # merge will correctly incorporate more information
925 932 if diverge is None or len(diverge1) < len(diverge):
926 933 diverge = diverge1
927 934 if renamedelete is None or len(renamedelete) < len(renamedelete1):
928 935 renamedelete = renamedelete1
929 936
930 937 for f, a in sorted(actions.iteritems()):
931 938 m, args, msg = a
932 939 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
933 940 if f in fbids:
934 941 d = fbids[f]
935 942 if m in d:
936 943 d[m].append(a)
937 944 else:
938 945 d[m] = [a]
939 946 else:
940 947 fbids[f] = {m: [a]}
941 948
942 949 # Pick the best bid for each file
943 950 repo.ui.note(_('\nauction for merging merge bids\n'))
944 951 actions = {}
945 952 for f, bids in sorted(fbids.items()):
946 953 # bids is a mapping from action method to list af actions
947 954 # Consensus?
948 955 if len(bids) == 1: # all bids are the same kind of method
949 956 m, l = bids.items()[0]
950 957 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
951 958 repo.ui.note(" %s: consensus for %s\n" % (f, m))
952 959 actions[f] = l[0]
953 960 continue
954 961 # If keep is an option, just do it.
955 962 if 'k' in bids:
956 963 repo.ui.note(" %s: picking 'keep' action\n" % f)
957 964 actions[f] = bids['k'][0]
958 965 continue
959 966 # If there are gets and they all agree [how could they not?], do it.
960 967 if 'g' in bids:
961 968 ga0 = bids['g'][0]
962 969 if all(a == ga0 for a in bids['g'][1:]):
963 970 repo.ui.note(" %s: picking 'get' action\n" % f)
964 971 actions[f] = ga0
965 972 continue
966 973 # TODO: Consider other simple actions such as mode changes
967 974 # Handle inefficient democrazy.
968 975 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
969 976 for m, l in sorted(bids.items()):
970 977 for _f, args, msg in l:
971 978 repo.ui.note(' %s -> %s\n' % (msg, m))
972 979 # Pick random action. TODO: Instead, prompt user when resolving
973 980 m, l = bids.items()[0]
974 981 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
975 982 (f, m))
976 983 actions[f] = l[0]
977 984 continue
978 985 repo.ui.note(_('end of auction\n\n'))
979 986
980 987 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
981 988
982 989 if wctx.rev() is None:
983 990 fractions = _forgetremoved(wctx, mctx, branchmerge)
984 991 actions.update(fractions)
985 992
986 993 return actions, diverge, renamedelete
987 994
988 995 def batchremove(repo, actions):
989 996 """apply removes to the working directory
990 997
991 998 yields tuples for progress updates
992 999 """
993 1000 verbose = repo.ui.verbose
994 1001 unlink = util.unlinkpath
995 1002 wjoin = repo.wjoin
996 1003 audit = repo.wvfs.audit
997 1004 i = 0
998 1005 for f, args, msg in actions:
999 1006 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
1000 1007 if verbose:
1001 1008 repo.ui.note(_("removing %s\n") % f)
1002 1009 audit(f)
1003 1010 try:
1004 1011 unlink(wjoin(f), ignoremissing=True)
1005 1012 except OSError as inst:
1006 1013 repo.ui.warn(_("update failed to remove %s: %s!\n") %
1007 1014 (f, inst.strerror))
1008 1015 if i == 100:
1009 1016 yield i, f
1010 1017 i = 0
1011 1018 i += 1
1012 1019 if i > 0:
1013 1020 yield i, f
1014 1021
1015 1022 def batchget(repo, mctx, actions):
1016 1023 """apply gets to the working directory
1017 1024
1018 1025 mctx is the context to get from
1019 1026
1020 1027 yields tuples for progress updates
1021 1028 """
1022 1029 verbose = repo.ui.verbose
1023 1030 fctx = mctx.filectx
1024 1031 wwrite = repo.wwrite
1025 1032 ui = repo.ui
1026 1033 i = 0
1027 1034 for f, (flags, backup), msg in actions:
1028 1035 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
1029 1036 if verbose:
1030 1037 repo.ui.note(_("getting %s\n") % f)
1031 1038
1032 1039 if backup:
1033 1040 absf = repo.wjoin(f)
1034 1041 orig = scmutil.origpath(ui, repo, absf)
1035 1042 try:
1036 1043 # TODO Mercurial has always aborted if an untracked directory
1037 1044 # is replaced by a tracked file, or generally with
1038 1045 # file/directory merges. This needs to be sorted out.
1039 1046 if repo.wvfs.isfileorlink(f):
1040 1047 util.rename(absf, orig)
1041 1048 except OSError as e:
1042 1049 if e.errno != errno.ENOENT:
1043 1050 raise
1044 1051
1045 1052 wwrite(f, fctx(f).data(), flags)
1046 1053 if i == 100:
1047 1054 yield i, f
1048 1055 i = 0
1049 1056 i += 1
1050 1057 if i > 0:
1051 1058 yield i, f
1052 1059
1053 1060 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
1054 1061 """apply the merge action list to the working directory
1055 1062
1056 1063 wctx is the working copy context
1057 1064 mctx is the context to be merged into the working copy
1058 1065
1059 1066 Return a tuple of counts (updated, merged, removed, unresolved) that
1060 1067 describes how many files were affected by the update.
1061 1068 """
1062 1069
1063 1070 updated, merged, removed = 0, 0, 0
1064 1071 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node())
1065 1072 moves = []
1066 1073 for m, l in actions.items():
1067 1074 l.sort()
1068 1075
1069 1076 # 'cd' and 'dc' actions are treated like other merge conflicts
1070 1077 mergeactions = sorted(actions['cd'])
1071 1078 mergeactions.extend(sorted(actions['dc']))
1072 1079 mergeactions.extend(actions['m'])
1073 1080 for f, args, msg in mergeactions:
1074 1081 f1, f2, fa, move, anc = args
1075 1082 if f == '.hgsubstate': # merged internally
1076 1083 continue
1077 1084 if f1 is None:
1078 1085 fcl = filemerge.absentfilectx(wctx, fa)
1079 1086 else:
1080 1087 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
1081 1088 fcl = wctx[f1]
1082 1089 if f2 is None:
1083 1090 fco = filemerge.absentfilectx(mctx, fa)
1084 1091 else:
1085 1092 fco = mctx[f2]
1086 1093 actx = repo[anc]
1087 1094 if fa in actx:
1088 1095 fca = actx[fa]
1089 1096 else:
1090 1097 # TODO: move to absentfilectx
1091 1098 fca = repo.filectx(f1, fileid=nullrev)
1092 1099 ms.add(fcl, fco, fca, f)
1093 1100 if f1 != f and move:
1094 1101 moves.append(f1)
1095 1102
1096 1103 audit = repo.wvfs.audit
1097 1104 _updating = _('updating')
1098 1105 _files = _('files')
1099 1106 progress = repo.ui.progress
1100 1107
1101 1108 # remove renamed files after safely stored
1102 1109 for f in moves:
1103 1110 if os.path.lexists(repo.wjoin(f)):
1104 1111 repo.ui.debug("removing %s\n" % f)
1105 1112 audit(f)
1106 1113 util.unlinkpath(repo.wjoin(f))
1107 1114
1108 1115 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
1109 1116
1110 1117 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
1111 1118 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1112 1119
1113 1120 # remove in parallel (must come first)
1114 1121 z = 0
1115 1122 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
1116 1123 for i, item in prog:
1117 1124 z += i
1118 1125 progress(_updating, z, item=item, total=numupdates, unit=_files)
1119 1126 removed = len(actions['r'])
1120 1127
1121 1128 # get in parallel
1122 1129 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
1123 1130 for i, item in prog:
1124 1131 z += i
1125 1132 progress(_updating, z, item=item, total=numupdates, unit=_files)
1126 1133 updated = len(actions['g'])
1127 1134
1128 1135 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
1129 1136 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1130 1137
1131 1138 # forget (manifest only, just log it) (must come first)
1132 1139 for f, args, msg in actions['f']:
1133 1140 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
1134 1141 z += 1
1135 1142 progress(_updating, z, item=f, total=numupdates, unit=_files)
1136 1143
1137 1144 # re-add (manifest only, just log it)
1138 1145 for f, args, msg in actions['a']:
1139 1146 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1140 1147 z += 1
1141 1148 progress(_updating, z, item=f, total=numupdates, unit=_files)
1142 1149
1143 1150 # re-add/mark as modified (manifest only, just log it)
1144 1151 for f, args, msg in actions['am']:
1145 1152 repo.ui.debug(" %s: %s -> am\n" % (f, msg))
1146 1153 z += 1
1147 1154 progress(_updating, z, item=f, total=numupdates, unit=_files)
1148 1155
1149 1156 # keep (noop, just log it)
1150 1157 for f, args, msg in actions['k']:
1151 1158 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1152 1159 # no progress
1153 1160
1154 1161 # directory rename, move local
1155 1162 for f, args, msg in actions['dm']:
1156 1163 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
1157 1164 z += 1
1158 1165 progress(_updating, z, item=f, total=numupdates, unit=_files)
1159 1166 f0, flags = args
1160 1167 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1161 1168 audit(f)
1162 1169 repo.wwrite(f, wctx.filectx(f0).data(), flags)
1163 1170 util.unlinkpath(repo.wjoin(f0))
1164 1171 updated += 1
1165 1172
1166 1173 # local directory rename, get
1167 1174 for f, args, msg in actions['dg']:
1168 1175 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
1169 1176 z += 1
1170 1177 progress(_updating, z, item=f, total=numupdates, unit=_files)
1171 1178 f0, flags = args
1172 1179 repo.ui.note(_("getting %s to %s\n") % (f0, f))
1173 1180 repo.wwrite(f, mctx.filectx(f0).data(), flags)
1174 1181 updated += 1
1175 1182
1176 1183 # exec
1177 1184 for f, args, msg in actions['e']:
1178 1185 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
1179 1186 z += 1
1180 1187 progress(_updating, z, item=f, total=numupdates, unit=_files)
1181 1188 flags, = args
1182 1189 audit(f)
1183 1190 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
1184 1191 updated += 1
1185 1192
1186 1193 # the ordering is important here -- ms.mergedriver will raise if the merge
1187 1194 # driver has changed, and we want to be able to bypass it when overwrite is
1188 1195 # True
1189 1196 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1190 1197
1191 1198 if usemergedriver:
1192 1199 ms.commit()
1193 1200 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1194 1201 # the driver might leave some files unresolved
1195 1202 unresolvedf = set(ms.unresolved())
1196 1203 if not proceed:
1197 1204 # XXX setting unresolved to at least 1 is a hack to make sure we
1198 1205 # error out
1199 1206 return updated, merged, removed, max(len(unresolvedf), 1)
1200 1207 newactions = []
1201 1208 for f, args, msg in mergeactions:
1202 1209 if f in unresolvedf:
1203 1210 newactions.append((f, args, msg))
1204 1211 mergeactions = newactions
1205 1212
1206 1213 # premerge
1207 1214 tocomplete = []
1208 1215 for f, args, msg in mergeactions:
1209 1216 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
1210 1217 z += 1
1211 1218 progress(_updating, z, item=f, total=numupdates, unit=_files)
1212 1219 if f == '.hgsubstate': # subrepo states need updating
1213 1220 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
1214 1221 overwrite)
1215 1222 continue
1216 1223 audit(f)
1217 1224 complete, r = ms.preresolve(f, wctx, labels=labels)
1218 1225 if not complete:
1219 1226 numupdates += 1
1220 1227 tocomplete.append((f, args, msg))
1221 1228
1222 1229 # merge
1223 1230 for f, args, msg in tocomplete:
1224 1231 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
1225 1232 z += 1
1226 1233 progress(_updating, z, item=f, total=numupdates, unit=_files)
1227 1234 ms.resolve(f, wctx, labels=labels)
1228 1235
1229 1236 ms.commit()
1230 1237
1231 1238 unresolved = ms.unresolvedcount()
1232 1239
1233 1240 if usemergedriver and not unresolved and ms.mdstate() != 's':
1234 1241 if not driverconclude(repo, ms, wctx, labels=labels):
1235 1242 # XXX setting unresolved to at least 1 is a hack to make sure we
1236 1243 # error out
1237 1244 unresolved = max(unresolved, 1)
1238 1245
1239 1246 ms.commit()
1240 1247
1241 1248 msupdated, msmerged, msremoved = ms.counts()
1242 1249 updated += msupdated
1243 1250 merged += msmerged
1244 1251 removed += msremoved
1245 1252
1246 1253 extraactions = ms.actions()
1247 1254 for k, acts in extraactions.iteritems():
1248 1255 actions[k].extend(acts)
1249 1256
1250 1257 progress(_updating, None, total=numupdates, unit=_files)
1251 1258
1252 1259 return updated, merged, removed, unresolved
1253 1260
1254 1261 def recordupdates(repo, actions, branchmerge):
1255 1262 "record merge actions to the dirstate"
1256 1263 # remove (must come first)
1257 1264 for f, args, msg in actions.get('r', []):
1258 1265 if branchmerge:
1259 1266 repo.dirstate.remove(f)
1260 1267 else:
1261 1268 repo.dirstate.drop(f)
1262 1269
1263 1270 # forget (must come first)
1264 1271 for f, args, msg in actions.get('f', []):
1265 1272 repo.dirstate.drop(f)
1266 1273
1267 1274 # re-add
1268 1275 for f, args, msg in actions.get('a', []):
1269 1276 repo.dirstate.add(f)
1270 1277
1271 1278 # re-add/mark as modified
1272 1279 for f, args, msg in actions.get('am', []):
1273 1280 if branchmerge:
1274 1281 repo.dirstate.normallookup(f)
1275 1282 else:
1276 1283 repo.dirstate.add(f)
1277 1284
1278 1285 # exec change
1279 1286 for f, args, msg in actions.get('e', []):
1280 1287 repo.dirstate.normallookup(f)
1281 1288
1282 1289 # keep
1283 1290 for f, args, msg in actions.get('k', []):
1284 1291 pass
1285 1292
1286 1293 # get
1287 1294 for f, args, msg in actions.get('g', []):
1288 1295 if branchmerge:
1289 1296 repo.dirstate.otherparent(f)
1290 1297 else:
1291 1298 repo.dirstate.normal(f)
1292 1299
1293 1300 # merge
1294 1301 for f, args, msg in actions.get('m', []):
1295 1302 f1, f2, fa, move, anc = args
1296 1303 if branchmerge:
1297 1304 # We've done a branch merge, mark this file as merged
1298 1305 # so that we properly record the merger later
1299 1306 repo.dirstate.merge(f)
1300 1307 if f1 != f2: # copy/rename
1301 1308 if move:
1302 1309 repo.dirstate.remove(f1)
1303 1310 if f1 != f:
1304 1311 repo.dirstate.copy(f1, f)
1305 1312 else:
1306 1313 repo.dirstate.copy(f2, f)
1307 1314 else:
1308 1315 # We've update-merged a locally modified file, so
1309 1316 # we set the dirstate to emulate a normal checkout
1310 1317 # of that file some time in the past. Thus our
1311 1318 # merge will appear as a normal local file
1312 1319 # modification.
1313 1320 if f2 == f: # file not locally copied/moved
1314 1321 repo.dirstate.normallookup(f)
1315 1322 if move:
1316 1323 repo.dirstate.drop(f1)
1317 1324
1318 1325 # directory rename, move local
1319 1326 for f, args, msg in actions.get('dm', []):
1320 1327 f0, flag = args
1321 1328 if branchmerge:
1322 1329 repo.dirstate.add(f)
1323 1330 repo.dirstate.remove(f0)
1324 1331 repo.dirstate.copy(f0, f)
1325 1332 else:
1326 1333 repo.dirstate.normal(f)
1327 1334 repo.dirstate.drop(f0)
1328 1335
1329 1336 # directory rename, get
1330 1337 for f, args, msg in actions.get('dg', []):
1331 1338 f0, flag = args
1332 1339 if branchmerge:
1333 1340 repo.dirstate.add(f)
1334 1341 repo.dirstate.copy(f0, f)
1335 1342 else:
1336 1343 repo.dirstate.normal(f)
1337 1344
1338 1345 def update(repo, node, branchmerge, force, ancestor=None,
1339 1346 mergeancestor=False, labels=None, matcher=None):
1340 1347 """
1341 1348 Perform a merge between the working directory and the given node
1342 1349
1343 1350 node = the node to update to, or None if unspecified
1344 1351 branchmerge = whether to merge between branches
1345 1352 force = whether to force branch merging or file overwriting
1346 1353 matcher = a matcher to filter file lists (dirstate not updated)
1347 1354 mergeancestor = whether it is merging with an ancestor. If true,
1348 1355 we should accept the incoming changes for any prompts that occur.
1349 1356 If false, merging with an ancestor (fast-forward) is only allowed
1350 1357 between different named branches. This flag is used by rebase extension
1351 1358 as a temporary fix and should be avoided in general.
1352 1359
1353 1360 The table below shows all the behaviors of the update command
1354 1361 given the -c and -C or no options, whether the working directory
1355 1362 is dirty, whether a revision is specified, and the relationship of
1356 1363 the parent rev to the target rev (linear, on the same named
1357 1364 branch, or on another named branch).
1358 1365
1359 1366 This logic is tested by test-update-branches.t.
1360 1367
1361 1368 -c -C dirty rev | linear same cross
1362 1369 n n n n | ok (1) x
1363 1370 n n n y | ok ok ok
1364 1371 n n y n | merge (2) (2)
1365 1372 n n y y | merge (3) (3)
1366 1373 n y * * | discard discard discard
1367 1374 y n y * | (4) (4) (4)
1368 1375 y n n * | ok ok ok
1369 1376 y y * * | (5) (5) (5)
1370 1377
1371 1378 x = can't happen
1372 1379 * = don't-care
1373 1380 1 = abort: not a linear update (merge or update --check to force update)
1374 1381 2 = abort: uncommitted changes (commit and merge, or update --clean to
1375 1382 discard changes)
1376 1383 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1377 1384 4 = abort: uncommitted changes (checked in commands.py)
1378 1385 5 = incompatible options (checked in commands.py)
1379 1386
1380 1387 Return the same tuple as applyupdates().
1381 1388 """
1382 1389
1383 1390 onode = node
1384 1391 # If we're doing a partial update, we need to skip updating
1385 1392 # the dirstate, so make a note of any partial-ness to the
1386 1393 # update here.
1387 1394 if matcher is None or matcher.always():
1388 1395 partial = False
1389 1396 else:
1390 1397 partial = True
1391 1398 with repo.wlock():
1392 1399 wc = repo[None]
1393 1400 pl = wc.parents()
1394 1401 p1 = pl[0]
1395 1402 pas = [None]
1396 1403 if ancestor is not None:
1397 1404 pas = [repo[ancestor]]
1398 1405
1399 1406 if node is None:
1400 1407 if (repo.ui.configbool('devel', 'all-warnings')
1401 1408 or repo.ui.configbool('devel', 'oldapi')):
1402 1409 repo.ui.develwarn('update with no target')
1403 1410 rev, _mark, _act = destutil.destupdate(repo)
1404 1411 node = repo[rev].node()
1405 1412
1406 1413 overwrite = force and not branchmerge
1407 1414
1408 1415 p2 = repo[node]
1409 1416 if pas[0] is None:
1410 1417 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1411 1418 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1412 1419 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1413 1420 else:
1414 1421 pas = [p1.ancestor(p2, warn=branchmerge)]
1415 1422
1416 1423 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1417 1424
1418 1425 ### check phase
1419 1426 if not overwrite:
1420 1427 if len(pl) > 1:
1421 1428 raise error.Abort(_("outstanding uncommitted merge"))
1422 1429 ms = mergestate.read(repo)
1423 1430 if list(ms.unresolved()):
1424 1431 raise error.Abort(_("outstanding merge conflicts"))
1425 1432 if branchmerge:
1426 1433 if pas == [p2]:
1427 1434 raise error.Abort(_("merging with a working directory ancestor"
1428 1435 " has no effect"))
1429 1436 elif pas == [p1]:
1430 1437 if not mergeancestor and p1.branch() == p2.branch():
1431 1438 raise error.Abort(_("nothing to merge"),
1432 1439 hint=_("use 'hg update' "
1433 1440 "or check 'hg heads'"))
1434 1441 if not force and (wc.files() or wc.deleted()):
1435 1442 raise error.Abort(_("uncommitted changes"),
1436 1443 hint=_("use 'hg status' to list changes"))
1437 1444 for s in sorted(wc.substate):
1438 1445 wc.sub(s).bailifchanged()
1439 1446
1440 1447 elif not overwrite:
1441 1448 if p1 == p2: # no-op update
1442 1449 # call the hooks and exit early
1443 1450 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1444 1451 repo.hook('update', parent1=xp2, parent2='', error=0)
1445 1452 return 0, 0, 0, 0
1446 1453
1447 1454 if pas not in ([p1], [p2]): # nonlinear
1448 1455 dirty = wc.dirty(missing=True)
1449 1456 if dirty or onode is None:
1450 1457 # Branching is a bit strange to ensure we do the minimal
1451 1458 # amount of call to obsolete.background.
1452 1459 foreground = obsolete.foreground(repo, [p1.node()])
1453 1460 # note: the <node> variable contains a random identifier
1454 1461 if repo[node].node() in foreground:
1455 1462 pas = [p1] # allow updating to successors
1456 1463 elif dirty:
1457 1464 msg = _("uncommitted changes")
1458 1465 if onode is None:
1459 1466 hint = _("commit and merge, or update --clean to"
1460 1467 " discard changes")
1461 1468 else:
1462 1469 hint = _("commit or update --clean to discard"
1463 1470 " changes")
1464 1471 raise error.Abort(msg, hint=hint)
1465 1472 else: # node is none
1466 1473 msg = _("not a linear update")
1467 1474 hint = _("merge or update --check to force update")
1468 1475 raise error.Abort(msg, hint=hint)
1469 1476 else:
1470 1477 # Allow jumping branches if clean and specific rev given
1471 1478 pas = [p1]
1472 1479
1473 1480 # deprecated config: merge.followcopies
1474 1481 followcopies = False
1475 1482 if overwrite:
1476 1483 pas = [wc]
1477 1484 elif pas == [p2]: # backwards
1478 1485 pas = [wc.p1()]
1479 1486 elif not branchmerge and not wc.dirty(missing=True):
1480 1487 pass
1481 1488 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1482 1489 followcopies = True
1483 1490
1484 1491 ### calculate phase
1485 1492 actionbyfile, diverge, renamedelete = calculateupdates(
1486 1493 repo, wc, p2, pas, branchmerge, force, mergeancestor,
1487 1494 followcopies, matcher=matcher)
1488 1495
1489 1496 # Prompt and create actions. Most of this is in the resolve phase
1490 1497 # already, but we can't handle .hgsubstate in filemerge or
1491 1498 # subrepo.submerge yet so we have to keep prompting for it.
1492 1499 if '.hgsubstate' in actionbyfile:
1493 1500 f = '.hgsubstate'
1494 1501 m, args, msg = actionbyfile[f]
1495 1502 if m == 'cd':
1496 1503 if repo.ui.promptchoice(
1497 1504 _("local changed %s which remote deleted\n"
1498 1505 "use (c)hanged version or (d)elete?"
1499 1506 "$$ &Changed $$ &Delete") % f, 0):
1500 1507 actionbyfile[f] = ('r', None, "prompt delete")
1501 1508 elif f in p1:
1502 1509 actionbyfile[f] = ('am', None, "prompt keep")
1503 1510 else:
1504 1511 actionbyfile[f] = ('a', None, "prompt keep")
1505 1512 elif m == 'dc':
1506 1513 f1, f2, fa, move, anc = args
1507 1514 flags = p2[f2].flags()
1508 1515 if repo.ui.promptchoice(
1509 1516 _("remote changed %s which local deleted\n"
1510 1517 "use (c)hanged version or leave (d)eleted?"
1511 1518 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1512 1519 actionbyfile[f] = ('g', (flags, False), "prompt recreating")
1513 1520 else:
1514 1521 del actionbyfile[f]
1515 1522
1516 1523 # Convert to dictionary-of-lists format
1517 1524 actions = dict((m, []) for m in 'a am f g cd dc r dm dg m e k'.split())
1518 1525 for f, (m, args, msg) in actionbyfile.iteritems():
1519 1526 if m not in actions:
1520 1527 actions[m] = []
1521 1528 actions[m].append((f, args, msg))
1522 1529
1523 1530 if not util.checkcase(repo.path):
1524 1531 # check collision between files only in p2 for clean update
1525 1532 if (not branchmerge and
1526 1533 (force or not wc.dirty(missing=True, branch=False))):
1527 1534 _checkcollision(repo, p2.manifest(), None)
1528 1535 else:
1529 1536 _checkcollision(repo, wc.manifest(), actions)
1530 1537
1531 1538 # divergent renames
1532 1539 for f, fl in sorted(diverge.iteritems()):
1533 1540 repo.ui.warn(_("note: possible conflict - %s was renamed "
1534 1541 "multiple times to:\n") % f)
1535 1542 for nf in fl:
1536 1543 repo.ui.warn(" %s\n" % nf)
1537 1544
1538 1545 # rename and delete
1539 1546 for f, fl in sorted(renamedelete.iteritems()):
1540 1547 repo.ui.warn(_("note: possible conflict - %s was deleted "
1541 1548 "and renamed to:\n") % f)
1542 1549 for nf in fl:
1543 1550 repo.ui.warn(" %s\n" % nf)
1544 1551
1545 1552 ### apply phase
1546 1553 if not branchmerge: # just jump to the new rev
1547 1554 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1548 1555 if not partial:
1549 1556 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1550 1557 # note that we're in the middle of an update
1551 1558 repo.vfs.write('updatestate', p2.hex())
1552 1559
1553 1560 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1554 1561
1555 1562 if not partial:
1556 1563 repo.dirstate.beginparentchange()
1557 1564 repo.setparents(fp1, fp2)
1558 1565 recordupdates(repo, actions, branchmerge)
1559 1566 # update completed, clear state
1560 1567 util.unlink(repo.join('updatestate'))
1561 1568
1562 1569 if not branchmerge:
1563 1570 repo.dirstate.setbranch(p2.branch())
1564 1571 repo.dirstate.endparentchange()
1565 1572
1566 1573 if not partial:
1567 1574 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1568 1575 return stats
1569 1576
1570 1577 def graft(repo, ctx, pctx, labels, keepparent=False):
1571 1578 """Do a graft-like merge.
1572 1579
1573 1580 This is a merge where the merge ancestor is chosen such that one
1574 1581 or more changesets are grafted onto the current changeset. In
1575 1582 addition to the merge, this fixes up the dirstate to include only
1576 1583 a single parent (if keepparent is False) and tries to duplicate any
1577 1584 renames/copies appropriately.
1578 1585
1579 1586 ctx - changeset to rebase
1580 1587 pctx - merge base, usually ctx.p1()
1581 1588 labels - merge labels eg ['local', 'graft']
1582 1589 keepparent - keep second parent if any
1583 1590
1584 1591 """
1585 1592 # If we're grafting a descendant onto an ancestor, be sure to pass
1586 1593 # mergeancestor=True to update. This does two things: 1) allows the merge if
1587 1594 # the destination is the same as the parent of the ctx (so we can use graft
1588 1595 # to copy commits), and 2) informs update that the incoming changes are
1589 1596 # newer than the destination so it doesn't prompt about "remote changed foo
1590 1597 # which local deleted".
1591 1598 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1592 1599
1593 1600 stats = update(repo, ctx.node(), True, True, pctx.node(),
1594 1601 mergeancestor=mergeancestor, labels=labels)
1595 1602
1596 1603 pother = nullid
1597 1604 parents = ctx.parents()
1598 1605 if keepparent and len(parents) == 2 and pctx in parents:
1599 1606 parents.remove(pctx)
1600 1607 pother = parents[0].node()
1601 1608
1602 1609 repo.dirstate.beginparentchange()
1603 1610 repo.setparents(repo['.'].node(), pother)
1604 1611 repo.dirstate.write(repo.currenttransaction())
1605 1612 # fix up dirstate for copies and renames
1606 1613 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1607 1614 repo.dirstate.endparentchange()
1608 1615 return stats
@@ -1,762 +1,763 b''
1 1 $ hg init basic
2 2 $ cd basic
3 3
4 4 should complain
5 5
6 6 $ hg backout
7 7 abort: please specify a revision to backout
8 8 [255]
9 9 $ hg backout -r 0 0
10 10 abort: please specify just one revision
11 11 [255]
12 12
13 13 basic operation
14 14 (this also tests that editor is invoked if the commit message is not
15 15 specified explicitly)
16 16
17 17 $ echo a > a
18 18 $ hg commit -d '0 0' -A -m a
19 19 adding a
20 20 $ echo b >> a
21 21 $ hg commit -d '1 0' -m b
22 22
23 23 $ hg status --rev tip --rev "tip^1"
24 24 M a
25 25 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true
26 26 reverting a
27 27 Backed out changeset a820f4f40a57
28 28
29 29
30 30 HG: Enter commit message. Lines beginning with 'HG:' are removed.
31 31 HG: Leave message empty to abort commit.
32 32 HG: --
33 33 HG: user: test
34 34 HG: branch 'default'
35 35 HG: changed a
36 36 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
37 37 $ cat a
38 38 a
39 39 $ hg summary
40 40 parent: 2:2929462c3dff tip
41 41 Backed out changeset a820f4f40a57
42 42 branch: default
43 43 commit: (clean)
44 44 update: (current)
45 45 phases: 3 draft
46 46
47 47 commit option
48 48
49 49 $ cd ..
50 50 $ hg init commit
51 51 $ cd commit
52 52
53 53 $ echo tomatoes > a
54 54 $ hg add a
55 55 $ hg commit -d '0 0' -m tomatoes
56 56
57 57 $ echo chair > b
58 58 $ hg add b
59 59 $ hg commit -d '1 0' -m chair
60 60
61 61 $ echo grapes >> a
62 62 $ hg commit -d '2 0' -m grapes
63 63
64 64 $ hg backout -d '4 0' 1 --tool=:fail
65 65 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 66 changeset 3:1c2161e97c0a backs out changeset 1:22cb4f70d813
67 67 $ hg summary
68 68 parent: 3:1c2161e97c0a tip
69 69 Backed out changeset 22cb4f70d813
70 70 branch: default
71 71 commit: (clean)
72 72 update: (current)
73 73 phases: 4 draft
74 74
75 75 $ echo ypples > a
76 76 $ hg commit -d '5 0' -m ypples
77 77
78 78 $ hg backout -d '6 0' 2 --tool=:fail
79 79 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
80 80 use 'hg resolve' to retry unresolved file merges
81 81 [1]
82 82 $ hg summary
83 83 parent: 4:ed99997b793d tip
84 84 ypples
85 85 branch: default
86 86 commit: 1 unresolved (clean)
87 87 update: (current)
88 88 phases: 5 draft
89 89
90 90 file that was removed is recreated
91 91 (this also tests that editor is not invoked if the commit message is
92 92 specified explicitly)
93 93
94 94 $ cd ..
95 95 $ hg init remove
96 96 $ cd remove
97 97
98 98 $ echo content > a
99 99 $ hg commit -d '0 0' -A -m a
100 100 adding a
101 101
102 102 $ hg rm a
103 103 $ hg commit -d '1 0' -m b
104 104
105 105 $ HGEDITOR=cat hg backout -d '2 0' tip --tool=true -m "Backed out changeset 76862dcce372"
106 106 adding a
107 107 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
108 108 $ cat a
109 109 content
110 110 $ hg summary
111 111 parent: 2:de31bdc76c0d tip
112 112 Backed out changeset 76862dcce372
113 113 branch: default
114 114 commit: (clean)
115 115 update: (current)
116 116 phases: 3 draft
117 117
118 118 backout of backout is as if nothing happened
119 119
120 120 $ hg backout -d '3 0' --merge tip --tool=true
121 121 removing a
122 122 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
123 123 $ test -f a
124 124 [1]
125 125 $ hg summary
126 126 parent: 3:7f6d0f120113 tip
127 127 Backed out changeset de31bdc76c0d
128 128 branch: default
129 129 commit: (clean)
130 130 update: (current)
131 131 phases: 4 draft
132 132
133 133 Test that 'hg rollback' restores dirstate just before opening
134 134 transaction: in-memory dirstate changes should be written into
135 135 '.hg/journal.dirstate' as expected.
136 136
137 137 $ echo 'removed soon' > b
138 138 $ hg commit -A -d '4 0' -m 'prepare for subsequent removing'
139 139 adding b
140 140 $ echo 'newly added' > c
141 141 $ hg add c
142 142 $ hg remove b
143 143 $ hg commit -d '5 0' -m 'prepare for subsequent backout'
144 144 $ touch -t 200001010000 c
145 145 $ hg status -A
146 146 C c
147 147 $ hg debugstate --nodates
148 148 n 644 12 set c
149 149 $ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
150 150 adding b
151 151 removing c
152 152 changeset 6:4bfec048029d backs out changeset 5:fac0b729a654
153 153 $ hg rollback -q
154 154 $ hg status -A
155 155 A b
156 156 R c
157 157 $ hg debugstate --nodates
158 158 a 0 -1 unset b
159 159 r 0 0 set c
160 160
161 161 across branch
162 162
163 163 $ cd ..
164 164 $ hg init branch
165 165 $ cd branch
166 166 $ echo a > a
167 167 $ hg ci -Am0
168 168 adding a
169 169 $ echo b > b
170 170 $ hg ci -Am1
171 171 adding b
172 172 $ hg co -C 0
173 173 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
174 174 $ hg summary
175 175 parent: 0:f7b1eb17ad24
176 176 0
177 177 branch: default
178 178 commit: (clean)
179 179 update: 1 new changesets (update)
180 180 phases: 2 draft
181 181
182 182 should fail
183 183
184 184 $ hg backout 1
185 185 abort: cannot backout change that is not an ancestor
186 186 [255]
187 187 $ echo c > c
188 188 $ hg ci -Am2
189 189 adding c
190 190 created new head
191 191 $ hg summary
192 192 parent: 2:db815d6d32e6 tip
193 193 2
194 194 branch: default
195 195 commit: (clean)
196 196 update: 1 new changesets, 2 branch heads (merge)
197 197 phases: 3 draft
198 198
199 199 should fail
200 200
201 201 $ hg backout 1
202 202 abort: cannot backout change that is not an ancestor
203 203 [255]
204 204 $ hg summary
205 205 parent: 2:db815d6d32e6 tip
206 206 2
207 207 branch: default
208 208 commit: (clean)
209 209 update: 1 new changesets, 2 branch heads (merge)
210 210 phases: 3 draft
211 211
212 212 backout with merge
213 213
214 214 $ cd ..
215 215 $ hg init merge
216 216 $ cd merge
217 217
218 218 $ echo line 1 > a
219 219 $ echo line 2 >> a
220 220 $ hg commit -d '0 0' -A -m a
221 221 adding a
222 222 $ hg summary
223 223 parent: 0:59395513a13a tip
224 224 a
225 225 branch: default
226 226 commit: (clean)
227 227 update: (current)
228 228 phases: 1 draft
229 229
230 230 remove line 1
231 231
232 232 $ echo line 2 > a
233 233 $ hg commit -d '1 0' -m b
234 234
235 235 $ echo line 3 >> a
236 236 $ hg commit -d '2 0' -m c
237 237
238 238 $ hg backout --merge -d '3 0' 1 --tool=true
239 239 reverting a
240 240 created new head
241 241 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
242 242 merging with changeset 3:26b8ccb9ad91
243 243 merging a
244 244 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
245 245 (branch merge, don't forget to commit)
246 246 $ hg commit -d '4 0' -m d
247 247 $ hg summary
248 248 parent: 4:c7df5e0b9c09 tip
249 249 d
250 250 branch: default
251 251 commit: (clean)
252 252 update: (current)
253 253 phases: 5 draft
254 254
255 255 check line 1 is back
256 256
257 257 $ cat a
258 258 line 1
259 259 line 2
260 260 line 3
261 261
262 262 Test visibility of in-memory dirstate changes outside transaction to
263 263 external hook process
264 264
265 265 $ cat > $TESTTMP/checkvisibility.sh <<EOF
266 266 > echo "==== \$1:"
267 267 > hg parents --template "{rev}:{node|short}\n"
268 268 > echo "===="
269 269 > EOF
270 270
271 271 "hg backout --merge REV1" at REV2 below implies steps below:
272 272
273 273 (1) update to REV1 (REV2 => REV1)
274 274 (2) revert by REV1^1
275 275 (3) commit backnig out revision (REV3)
276 276 (4) update to REV2 (REV3 => REV2)
277 277 (5) merge with REV3 (REV2 => REV2, REV3)
278 278
279 279 == test visibility to external preupdate hook
280 280
281 281 $ hg update -q -C 2
282 282 $ hg --config extensions.strip= strip 3
283 283 saved backup bundle to * (glob)
284 284
285 285 $ cat >> .hg/hgrc <<EOF
286 286 > [hooks]
287 287 > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
288 288 > EOF
289 289
290 290 ("-m" is needed to avoid writing dirstte changes out at other than
291 291 invocation of the hook to be examined)
292 292
293 293 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
294 294 ==== preupdate:
295 295 2:6ea3f2a197a2
296 296 ====
297 297 reverting a
298 298 created new head
299 299 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
300 300 ==== preupdate:
301 301 3:d92a3f57f067
302 302 ====
303 303 merging with changeset 3:d92a3f57f067
304 304 ==== preupdate:
305 305 2:6ea3f2a197a2
306 306 ====
307 307 merging a
308 308 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
309 309 (branch merge, don't forget to commit)
310 310
311 311 $ cat >> .hg/hgrc <<EOF
312 312 > [hooks]
313 313 > preupdate.visibility =
314 314 > EOF
315 315
316 316 == test visibility to external update hook
317 317
318 318 $ hg update -q -C 2
319 319 $ hg --config extensions.strip= strip 3
320 320 saved backup bundle to * (glob)
321 321
322 322 $ cat >> .hg/hgrc <<EOF
323 323 > [hooks]
324 324 > update.visibility = sh $TESTTMP/checkvisibility.sh update
325 325 > EOF
326 326
327 327 $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
328 328 ==== update:
329 329 1:5a50a024c182
330 330 ====
331 331 reverting a
332 332 created new head
333 333 changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
334 334 ==== update:
335 335 2:6ea3f2a197a2
336 336 ====
337 337 merging with changeset 3:d92a3f57f067
338 338 merging a
339 339 ==== update:
340 340 2:6ea3f2a197a2
341 341 3:d92a3f57f067
342 342 ====
343 343 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
344 344 (branch merge, don't forget to commit)
345 345
346 346 $ cat >> .hg/hgrc <<EOF
347 347 > [hooks]
348 348 > update.visibility =
349 349 > EOF
350 350
351 351 $ cd ..
352 352
353 353 backout should not back out subsequent changesets
354 354
355 355 $ hg init onecs
356 356 $ cd onecs
357 357 $ echo 1 > a
358 358 $ hg commit -d '0 0' -A -m a
359 359 adding a
360 360 $ echo 2 >> a
361 361 $ hg commit -d '1 0' -m b
362 362 $ echo 1 > b
363 363 $ hg commit -d '2 0' -A -m c
364 364 adding b
365 365 $ hg summary
366 366 parent: 2:882396649954 tip
367 367 c
368 368 branch: default
369 369 commit: (clean)
370 370 update: (current)
371 371 phases: 3 draft
372 372
373 373 without --merge
374 374 $ hg backout --no-commit -d '3 0' 1 --tool=true
375 375 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 376 changeset 22bca4c721e5 backed out, don't forget to commit.
377 377 $ hg locate b
378 378 b
379 379 $ hg update -C tip
380 380 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
381 381 $ hg locate b
382 382 b
383 383 $ hg summary
384 384 parent: 2:882396649954 tip
385 385 c
386 386 branch: default
387 387 commit: (clean)
388 388 update: (current)
389 389 phases: 3 draft
390 390
391 391 with --merge
392 392 $ hg backout --merge -d '3 0' 1 --tool=true
393 393 reverting a
394 394 created new head
395 395 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
396 396 merging with changeset 3:3202beb76721
397 397 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
398 398 (branch merge, don't forget to commit)
399 399 $ hg locate b
400 400 b
401 401 $ hg update -C tip
402 402 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
403 403 $ hg locate b
404 404 [1]
405 405
406 406 $ cd ..
407 407 $ hg init m
408 408 $ cd m
409 409 $ echo a > a
410 410 $ hg commit -d '0 0' -A -m a
411 411 adding a
412 412 $ echo b > b
413 413 $ hg commit -d '1 0' -A -m b
414 414 adding b
415 415 $ echo c > c
416 416 $ hg commit -d '2 0' -A -m b
417 417 adding c
418 418 $ hg update 1
419 419 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
420 420 $ echo d > d
421 421 $ hg commit -d '3 0' -A -m c
422 422 adding d
423 423 created new head
424 424 $ hg merge 2
425 425 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 426 (branch merge, don't forget to commit)
427 427 $ hg commit -d '4 0' -A -m d
428 428 $ hg summary
429 429 parent: 4:b2f3bb92043e tip
430 430 d
431 431 branch: default
432 432 commit: (clean)
433 433 update: (current)
434 434 phases: 5 draft
435 435
436 436 backout of merge should fail
437 437
438 438 $ hg backout 4
439 439 abort: cannot backout a merge changeset
440 440 [255]
441 441
442 442 backout of merge with bad parent should fail
443 443
444 444 $ hg backout --parent 0 4
445 445 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
446 446 [255]
447 447
448 448 backout of non-merge with parent should fail
449 449
450 450 $ hg backout --parent 0 3
451 451 abort: cannot use --parent on non-merge changeset
452 452 [255]
453 453
454 454 backout with valid parent should be ok
455 455
456 456 $ hg backout -d '5 0' --parent 2 4 --tool=true
457 457 removing d
458 458 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
459 459 $ hg summary
460 460 parent: 5:10e5328c8435 tip
461 461 Backed out changeset b2f3bb92043e
462 462 branch: default
463 463 commit: (clean)
464 464 update: (current)
465 465 phases: 6 draft
466 466
467 467 $ hg rollback
468 468 repository tip rolled back to revision 4 (undo commit)
469 469 working directory now based on revision 4
470 470 $ hg update -C
471 471 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
472 472 $ hg summary
473 473 parent: 4:b2f3bb92043e tip
474 474 d
475 475 branch: default
476 476 commit: (clean)
477 477 update: (current)
478 478 phases: 5 draft
479 479
480 480 $ hg backout -d '6 0' --parent 3 4 --tool=true
481 481 removing c
482 482 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
483 483 $ hg summary
484 484 parent: 5:033590168430 tip
485 485 Backed out changeset b2f3bb92043e
486 486 branch: default
487 487 commit: (clean)
488 488 update: (current)
489 489 phases: 6 draft
490 490
491 491 $ cd ..
492 492
493 493 named branches
494 494
495 495 $ hg init named_branches
496 496 $ cd named_branches
497 497
498 498 $ echo default > default
499 499 $ hg ci -d '0 0' -Am default
500 500 adding default
501 501 $ hg branch branch1
502 502 marked working directory as branch branch1
503 503 (branches are permanent and global, did you want a bookmark?)
504 504 $ echo branch1 > file1
505 505 $ hg ci -d '1 0' -Am file1
506 506 adding file1
507 507 $ hg branch branch2
508 508 marked working directory as branch branch2
509 509 $ echo branch2 > file2
510 510 $ hg ci -d '2 0' -Am file2
511 511 adding file2
512 512
513 513 without --merge
514 514 $ hg backout --no-commit -r 1 --tool=true
515 515 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
516 516 changeset bf1602f437f3 backed out, don't forget to commit.
517 517 $ hg branch
518 518 branch2
519 519 $ hg status -A
520 520 R file1
521 521 C default
522 522 C file2
523 523 $ hg summary
524 524 parent: 2:45bbcd363bf0 tip
525 525 file2
526 526 branch: branch2
527 527 commit: 1 removed
528 528 update: (current)
529 529 phases: 3 draft
530 530
531 531 with --merge
532 532 (this also tests that editor is invoked if '--edit' is specified
533 533 explicitly regardless of '--message')
534 534
535 535 $ hg update -qC
536 536 $ HGEDITOR=cat hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true --edit
537 537 removing file1
538 538 backout on branch1
539 539
540 540
541 541 HG: Enter commit message. Lines beginning with 'HG:' are removed.
542 542 HG: Leave message empty to abort commit.
543 543 HG: --
544 544 HG: user: test
545 545 HG: branch 'branch2'
546 546 HG: removed file1
547 547 created new head
548 548 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
549 549 merging with changeset 3:d4e8f6db59fb
550 550 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
551 551 (branch merge, don't forget to commit)
552 552 $ hg summary
553 553 parent: 2:45bbcd363bf0
554 554 file2
555 555 parent: 3:d4e8f6db59fb tip
556 556 backout on branch1
557 557 branch: branch2
558 558 commit: 1 removed (merge)
559 559 update: (current)
560 560 phases: 4 draft
561 561 $ hg update -q -C 2
562 562
563 563 on branch2 with branch1 not merged, so file1 should still exist:
564 564
565 565 $ hg id
566 566 45bbcd363bf0 (branch2)
567 567 $ hg st -A
568 568 C default
569 569 C file1
570 570 C file2
571 571 $ hg summary
572 572 parent: 2:45bbcd363bf0
573 573 file2
574 574 branch: branch2
575 575 commit: (clean)
576 576 update: 1 new changesets, 2 branch heads (merge)
577 577 phases: 4 draft
578 578
579 579 on branch2 with branch1 merged, so file1 should be gone:
580 580
581 581 $ hg merge
582 582 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
583 583 (branch merge, don't forget to commit)
584 584 $ hg ci -d '4 0' -m 'merge backout of branch1'
585 585 $ hg id
586 586 22149cdde76d (branch2) tip
587 587 $ hg st -A
588 588 C default
589 589 C file2
590 590 $ hg summary
591 591 parent: 4:22149cdde76d tip
592 592 merge backout of branch1
593 593 branch: branch2
594 594 commit: (clean)
595 595 update: (current)
596 596 phases: 5 draft
597 597
598 598 on branch1, so no file1 and file2:
599 599
600 600 $ hg co -C branch1
601 601 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
602 602 $ hg id
603 603 bf1602f437f3 (branch1)
604 604 $ hg st -A
605 605 C default
606 606 C file1
607 607 $ hg summary
608 608 parent: 1:bf1602f437f3
609 609 file1
610 610 branch: branch1
611 611 commit: (clean)
612 612 update: (current)
613 613 phases: 5 draft
614 614
615 615 $ cd ..
616 616
617 617 backout of empty changeset (issue4190)
618 618
619 619 $ hg init emptycommit
620 620 $ cd emptycommit
621 621
622 622 $ touch file1
623 623 $ hg ci -Aqm file1
624 624 $ hg branch -q branch1
625 625 $ hg ci -qm branch1
626 626 $ hg backout -v 1
627 627 resolving manifests
628 628 nothing changed
629 629 [1]
630 630
631 631 $ cd ..
632 632
633 633
634 634 Test usage of `hg resolve` in case of conflict
635 635 (issue4163)
636 636
637 637 $ hg init issue4163
638 638 $ cd issue4163
639 639 $ touch foo
640 640 $ hg add foo
641 641 $ cat > foo << EOF
642 642 > one
643 643 > two
644 644 > three
645 645 > four
646 646 > five
647 647 > six
648 648 > seven
649 649 > height
650 650 > nine
651 651 > ten
652 652 > EOF
653 653 $ hg ci -m 'initial'
654 654 $ cat > foo << EOF
655 655 > one
656 656 > two
657 657 > THREE
658 658 > four
659 659 > five
660 660 > six
661 661 > seven
662 662 > height
663 663 > nine
664 664 > ten
665 665 > EOF
666 666 $ hg ci -m 'capital three'
667 667 $ cat > foo << EOF
668 668 > one
669 669 > two
670 670 > THREE
671 671 > four
672 672 > five
673 673 > six
674 674 > seven
675 675 > height
676 676 > nine
677 677 > TEN
678 678 > EOF
679 679 $ hg ci -m 'capital ten'
680 680 $ hg backout -r 'desc("capital three")' --tool internal:fail
681 681 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
682 682 use 'hg resolve' to retry unresolved file merges
683 683 [1]
684 684 $ hg status
685 685 $ hg debugmergestate
686 686 * version 2 records
687 687 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
688 688 other: a30dd8addae3ce71b8667868478542bc417439e6
689 file extras: foo (ancestorlinknode = 91360952243723bd5b1138d5f26bd8c8564cb553)
689 690 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
690 691 local path: foo (flags "")
691 692 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
692 693 other path: foo (node f50039b486d6fa1a90ae51778388cad161f425ee)
693 694 $ mv .hg/merge/state2 .hg/merge/state2-moved
694 695 $ hg debugmergestate
695 696 * version 1 records
696 697 local: b71750c4b0fdf719734971e3ef90dbeab5919a2d
697 698 file: foo (record type "F", state "u", hash 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33)
698 699 local path: foo (flags "")
699 700 ancestor path: foo (node f89532f44c247a0e993d63e3a734dd781ab04708)
700 701 other path: foo (node not stored in v1 format)
701 702 $ mv .hg/merge/state2-moved .hg/merge/state2
702 703 $ hg resolve -l # still unresolved
703 704 U foo
704 705 $ hg summary
705 706 parent: 2:b71750c4b0fd tip
706 707 capital ten
707 708 branch: default
708 709 commit: 1 unresolved (clean)
709 710 update: (current)
710 711 phases: 3 draft
711 712 $ hg resolve --all --debug
712 713 picked tool ':merge' for foo (binary False symlink False changedelete False)
713 714 merging foo
714 715 my foo@b71750c4b0fd+ other foo@a30dd8addae3 ancestor foo@913609522437
715 716 premerge successful
716 717 (no more unresolved files)
717 718 continue: hg commit
718 719 $ hg status
719 720 M foo
720 721 ? foo.orig
721 722 $ hg resolve -l
722 723 R foo
723 724 $ hg summary
724 725 parent: 2:b71750c4b0fd tip
725 726 capital ten
726 727 branch: default
727 728 commit: 1 modified, 1 unknown
728 729 update: (current)
729 730 phases: 3 draft
730 731 $ cat foo
731 732 one
732 733 two
733 734 three
734 735 four
735 736 five
736 737 six
737 738 seven
738 739 height
739 740 nine
740 741 TEN
741 742
742 743 --no-commit shouldn't commit
743 744
744 745 $ hg init a
745 746 $ cd a
746 747 $ for i in 1 2 3; do
747 748 > touch $i
748 749 > hg ci -Am $i
749 750 > done
750 751 adding 1
751 752 adding 2
752 753 adding 3
753 754 $ hg backout --no-commit .
754 755 removing 3
755 756 changeset cccc23d9d68f backed out, don't forget to commit.
756 757 $ hg revert -aq
757 758
758 759 --no-commit can't be used with --merge
759 760
760 761 $ hg backout --merge --no-commit 2
761 762 abort: cannot use --merge with --no-commit
762 763 [255]
@@ -1,830 +1,830 b''
1 1 Create a repo with some stuff in it:
2 2
3 3 $ hg init a
4 4 $ cd a
5 5 $ echo a > a
6 6 $ echo a > d
7 7 $ echo a > e
8 8 $ hg ci -qAm0
9 9 $ echo b > a
10 10 $ hg ci -m1 -u bar
11 11 $ hg mv a b
12 12 $ hg ci -m2
13 13 $ hg cp b c
14 14 $ hg ci -m3 -u baz
15 15 $ echo b > d
16 16 $ echo f > e
17 17 $ hg ci -m4
18 18 $ hg up -q 3
19 19 $ echo b > e
20 20 $ hg branch -q stable
21 21 $ hg ci -m5
22 22 $ hg merge -q default --tool internal:local
23 23 $ hg branch -q default
24 24 $ hg ci -m6
25 25 $ hg phase --public 3
26 26 $ hg phase --force --secret 6
27 27
28 28 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
29 29 @ test@6.secret: 6
30 30 |\
31 31 | o test@5.draft: 5
32 32 | |
33 33 o | test@4.draft: 4
34 34 |/
35 35 o baz@3.public: 3
36 36 |
37 37 o test@2.public: 2
38 38 |
39 39 o bar@1.public: 1
40 40 |
41 41 o test@0.public: 0
42 42
43 43
44 44 Need to specify a rev:
45 45
46 46 $ hg graft
47 47 abort: no revisions specified
48 48 [255]
49 49
50 50 Can't graft ancestor:
51 51
52 52 $ hg graft 1 2
53 53 skipping ancestor revision 1:5d205f8b35b6
54 54 skipping ancestor revision 2:5c095ad7e90f
55 55 [255]
56 56
57 57 Specify revisions with -r:
58 58
59 59 $ hg graft -r 1 -r 2
60 60 skipping ancestor revision 1:5d205f8b35b6
61 61 skipping ancestor revision 2:5c095ad7e90f
62 62 [255]
63 63
64 64 $ hg graft -r 1 2
65 65 warning: inconsistent use of --rev might give unexpected revision ordering!
66 66 skipping ancestor revision 2:5c095ad7e90f
67 67 skipping ancestor revision 1:5d205f8b35b6
68 68 [255]
69 69
70 70 Can't graft with dirty wd:
71 71
72 72 $ hg up -q 0
73 73 $ echo foo > a
74 74 $ hg graft 1
75 75 abort: uncommitted changes
76 76 [255]
77 77 $ hg revert a
78 78
79 79 Graft a rename:
80 80 (this also tests that editor is invoked if '--edit' is specified)
81 81
82 82 $ hg status --rev "2^1" --rev 2
83 83 A b
84 84 R a
85 85 $ HGEDITOR=cat hg graft 2 -u foo --edit
86 86 grafting 2:5c095ad7e90f "2"
87 87 merging a and b to b
88 88 2
89 89
90 90
91 91 HG: Enter commit message. Lines beginning with 'HG:' are removed.
92 92 HG: Leave message empty to abort commit.
93 93 HG: --
94 94 HG: user: foo
95 95 HG: branch 'default'
96 96 HG: added b
97 97 HG: removed a
98 98 $ hg export tip --git
99 99 # HG changeset patch
100 100 # User foo
101 101 # Date 0 0
102 102 # Thu Jan 01 00:00:00 1970 +0000
103 103 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
104 104 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
105 105 2
106 106
107 107 diff --git a/a b/b
108 108 rename from a
109 109 rename to b
110 110
111 111 Look for extra:source
112 112
113 113 $ hg log --debug -r tip
114 114 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
115 115 tag: tip
116 116 phase: draft
117 117 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
118 118 parent: -1:0000000000000000000000000000000000000000
119 119 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
120 120 user: foo
121 121 date: Thu Jan 01 00:00:00 1970 +0000
122 122 files+: b
123 123 files-: a
124 124 extra: branch=default
125 125 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
126 126 description:
127 127 2
128 128
129 129
130 130
131 131 Graft out of order, skipping a merge and a duplicate
132 132 (this also tests that editor is not invoked if '--edit' is not specified)
133 133
134 134 $ hg graft 1 5 4 3 'merge()' 2 -n
135 135 skipping ungraftable merge revision 6
136 136 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
137 137 grafting 1:5d205f8b35b6 "1"
138 138 grafting 5:97f8bfe72746 "5"
139 139 grafting 4:9c233e8e184d "4"
140 140 grafting 3:4c60f11aa304 "3"
141 141
142 142 $ HGEDITOR=cat hg graft 1 5 'merge()' 2 --debug
143 143 skipping ungraftable merge revision 6
144 144 scanning for duplicate grafts
145 145 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
146 146 grafting 1:5d205f8b35b6 "1"
147 147 searching for copies back to rev 1
148 148 unmatched files in local:
149 149 b
150 150 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
151 151 src: 'a' -> dst: 'b' *
152 152 checking for directory renames
153 153 resolving manifests
154 154 branchmerge: True, force: True, partial: False
155 155 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
156 156 preserving b for resolve of b
157 157 b: local copied/moved from a -> m (premerge)
158 158 picked tool ':merge' for b (binary False symlink False changedelete False)
159 159 merging b and a to b
160 160 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
161 161 premerge successful
162 162 committing files:
163 163 b
164 164 committing manifest
165 165 committing changelog
166 166 grafting 5:97f8bfe72746 "5"
167 167 searching for copies back to rev 1
168 168 resolving manifests
169 169 branchmerge: True, force: True, partial: False
170 170 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
171 171 e: remote is newer -> g
172 172 getting e
173 173 b: remote unchanged -> k
174 174 committing files:
175 175 e
176 176 committing manifest
177 177 committing changelog
178 178 $ HGEDITOR=cat hg graft 4 3 --log --debug
179 179 scanning for duplicate grafts
180 180 grafting 4:9c233e8e184d "4"
181 181 searching for copies back to rev 1
182 182 resolving manifests
183 183 branchmerge: True, force: True, partial: False
184 184 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
185 185 preserving e for resolve of e
186 186 d: remote is newer -> g
187 187 getting d
188 188 b: remote unchanged -> k
189 189 e: versions differ -> m (premerge)
190 190 picked tool ':merge' for e (binary False symlink False changedelete False)
191 191 merging e
192 my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
192 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
193 193 e: versions differ -> m (merge)
194 194 picked tool ':merge' for e (binary False symlink False changedelete False)
195 my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
195 my e@1905859650ec+ other e@9c233e8e184d ancestor e@4c60f11aa304
196 196 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
197 197 abort: unresolved conflicts, can't continue
198 198 (use hg resolve and hg graft --continue --log)
199 199 [255]
200 200
201 201 Summary should mention graft:
202 202
203 203 $ hg summary |grep graft
204 204 commit: 2 modified, 2 unknown, 1 unresolved (graft in progress)
205 205
206 206 Commit while interrupted should fail:
207 207
208 208 $ hg ci -m 'commit interrupted graft'
209 209 abort: graft in progress
210 210 (use 'hg graft --continue' or 'hg update' to abort)
211 211 [255]
212 212
213 213 Abort the graft and try committing:
214 214
215 215 $ hg up -C .
216 216 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 217 $ echo c >> e
218 218 $ hg ci -mtest
219 219
220 220 $ hg strip . --config extensions.strip=
221 221 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
222 222 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
223 223
224 224 Graft again:
225 225
226 226 $ hg graft 1 5 4 3 'merge()' 2
227 227 skipping ungraftable merge revision 6
228 228 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
229 229 skipping revision 1:5d205f8b35b6 (already grafted to 8:6b9e5368ca4e)
230 230 skipping revision 5:97f8bfe72746 (already grafted to 9:1905859650ec)
231 231 grafting 4:9c233e8e184d "4"
232 232 merging e
233 233 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
234 234 abort: unresolved conflicts, can't continue
235 235 (use hg resolve and hg graft --continue)
236 236 [255]
237 237
238 238 Continue without resolve should fail:
239 239
240 240 $ hg graft -c
241 241 grafting 4:9c233e8e184d "4"
242 242 abort: unresolved merge conflicts (see "hg help resolve")
243 243 [255]
244 244
245 245 Fix up:
246 246
247 247 $ echo b > e
248 248 $ hg resolve -m e
249 249 (no more unresolved files)
250 250 continue: hg graft --continue
251 251
252 252 Continue with a revision should fail:
253 253
254 254 $ hg graft -c 6
255 255 abort: can't specify --continue and revisions
256 256 [255]
257 257
258 258 $ hg graft -c -r 6
259 259 abort: can't specify --continue and revisions
260 260 [255]
261 261
262 262 Continue for real, clobber usernames
263 263
264 264 $ hg graft -c -U
265 265 grafting 4:9c233e8e184d "4"
266 266 grafting 3:4c60f11aa304 "3"
267 267
268 268 Compare with original:
269 269
270 270 $ hg diff -r 6
271 271 $ hg status --rev 0:. -C
272 272 M d
273 273 M e
274 274 A b
275 275 a
276 276 A c
277 277 a
278 278 R a
279 279
280 280 View graph:
281 281
282 282 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
283 283 @ test@11.draft: 3
284 284 |
285 285 o test@10.draft: 4
286 286 |
287 287 o test@9.draft: 5
288 288 |
289 289 o bar@8.draft: 1
290 290 |
291 291 o foo@7.draft: 2
292 292 |
293 293 | o test@6.secret: 6
294 294 | |\
295 295 | | o test@5.draft: 5
296 296 | | |
297 297 | o | test@4.draft: 4
298 298 | |/
299 299 | o baz@3.public: 3
300 300 | |
301 301 | o test@2.public: 2
302 302 | |
303 303 | o bar@1.public: 1
304 304 |/
305 305 o test@0.public: 0
306 306
307 307 Graft again onto another branch should preserve the original source
308 308 $ hg up -q 0
309 309 $ echo 'g'>g
310 310 $ hg add g
311 311 $ hg ci -m 7
312 312 created new head
313 313 $ hg graft 7
314 314 grafting 7:ef0ef43d49e7 "2"
315 315
316 316 $ hg log -r 7 --template '{rev}:{node}\n'
317 317 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
318 318 $ hg log -r 2 --template '{rev}:{node}\n'
319 319 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
320 320
321 321 $ hg log --debug -r tip
322 322 changeset: 13:7a4785234d87ec1aa420ed6b11afe40fa73e12a9
323 323 tag: tip
324 324 phase: draft
325 325 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
326 326 parent: -1:0000000000000000000000000000000000000000
327 327 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
328 328 user: foo
329 329 date: Thu Jan 01 00:00:00 1970 +0000
330 330 files+: b
331 331 files-: a
332 332 extra: branch=default
333 333 extra: intermediate-source=ef0ef43d49e79e81ddafdc7997401ba0041efc82
334 334 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
335 335 description:
336 336 2
337 337
338 338
339 339 Disallow grafting an already grafted cset onto its original branch
340 340 $ hg up -q 6
341 341 $ hg graft 7
342 342 skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
343 343 [255]
344 344
345 345 $ hg extdiff --config extensions.extdiff= --patch -r 2 -r 13
346 346 --- */hg-5c095ad7e90f.patch * +0000 (glob)
347 347 +++ */hg-7a4785234d87.patch * +0000 (glob)
348 348 @@ -1,18 +1,18 @@
349 349 # HG changeset patch
350 350 -# User test
351 351 +# User foo
352 352 # Date 0 0
353 353 # Thu Jan 01 00:00:00 1970 +0000
354 354 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
355 355 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
356 356 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
357 357 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
358 358 2
359 359
360 360 -diff -r 5d205f8b35b6 -r 5c095ad7e90f a
361 361 +diff -r b592ea63bb0c -r 7a4785234d87 a
362 362 --- a/a Thu Jan 01 00:00:00 1970 +0000
363 363 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
364 364 @@ -1,1 +0,0 @@
365 365 --b
366 366 -diff -r 5d205f8b35b6 -r 5c095ad7e90f b
367 367 +-a
368 368 +diff -r b592ea63bb0c -r 7a4785234d87 b
369 369 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
370 370 +++ b/b Thu Jan 01 00:00:00 1970 +0000
371 371 @@ -0,0 +1,1 @@
372 372 -+b
373 373 ++a
374 374 [1]
375 375
376 376 $ hg extdiff --config extensions.extdiff= --patch -r 2 -r 13 -X .
377 377 --- */hg-5c095ad7e90f.patch * +0000 (glob)
378 378 +++ */hg-7a4785234d87.patch * +0000 (glob)
379 379 @@ -1,8 +1,8 @@
380 380 # HG changeset patch
381 381 -# User test
382 382 +# User foo
383 383 # Date 0 0
384 384 # Thu Jan 01 00:00:00 1970 +0000
385 385 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
386 386 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
387 387 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
388 388 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
389 389 2
390 390
391 391 [1]
392 392
393 393 Disallow grafting already grafted csets with the same origin onto each other
394 394 $ hg up -q 13
395 395 $ hg graft 2
396 396 skipping revision 2:5c095ad7e90f (already grafted to 13:7a4785234d87)
397 397 [255]
398 398 $ hg graft 7
399 399 skipping already grafted revision 7:ef0ef43d49e7 (13:7a4785234d87 also has origin 2:5c095ad7e90f)
400 400 [255]
401 401
402 402 $ hg up -q 7
403 403 $ hg graft 2
404 404 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
405 405 [255]
406 406 $ hg graft tip
407 407 skipping already grafted revision 13:7a4785234d87 (7:ef0ef43d49e7 also has origin 2:5c095ad7e90f)
408 408 [255]
409 409
410 410 Graft with --log
411 411
412 412 $ hg up -Cq 1
413 413 $ hg graft 3 --log -u foo
414 414 grafting 3:4c60f11aa304 "3"
415 415 warning: can't find ancestor for 'c' copied from 'b'!
416 416 $ hg log --template '{rev} {parents} {desc}\n' -r tip
417 417 14 1:5d205f8b35b6 3
418 418 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
419 419
420 420 Resolve conflicted graft
421 421 $ hg up -q 0
422 422 $ echo b > a
423 423 $ hg ci -m 8
424 424 created new head
425 425 $ echo c > a
426 426 $ hg ci -m 9
427 427 $ hg graft 1 --tool internal:fail
428 428 grafting 1:5d205f8b35b6 "1"
429 429 abort: unresolved conflicts, can't continue
430 430 (use hg resolve and hg graft --continue)
431 431 [255]
432 432 $ hg resolve --all
433 433 merging a
434 434 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
435 435 [1]
436 436 $ cat a
437 437 <<<<<<< local: aaa4406d4f0a - test: 9
438 438 c
439 439 =======
440 440 b
441 441 >>>>>>> other: 5d205f8b35b6 - bar: 1
442 442 $ echo b > a
443 443 $ hg resolve -m a
444 444 (no more unresolved files)
445 445 continue: hg graft --continue
446 446 $ hg graft -c
447 447 grafting 1:5d205f8b35b6 "1"
448 448 $ hg export tip --git
449 449 # HG changeset patch
450 450 # User bar
451 451 # Date 0 0
452 452 # Thu Jan 01 00:00:00 1970 +0000
453 453 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
454 454 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
455 455 1
456 456
457 457 diff --git a/a b/a
458 458 --- a/a
459 459 +++ b/a
460 460 @@ -1,1 +1,1 @@
461 461 -c
462 462 +b
463 463
464 464 Resolve conflicted graft with rename
465 465 $ echo c > a
466 466 $ hg ci -m 10
467 467 $ hg graft 2 --tool internal:fail
468 468 grafting 2:5c095ad7e90f "2"
469 469 abort: unresolved conflicts, can't continue
470 470 (use hg resolve and hg graft --continue)
471 471 [255]
472 472 $ hg resolve --all
473 473 merging a and b to b
474 474 (no more unresolved files)
475 475 continue: hg graft --continue
476 476 $ hg graft -c
477 477 grafting 2:5c095ad7e90f "2"
478 478 $ hg export tip --git
479 479 # HG changeset patch
480 480 # User test
481 481 # Date 0 0
482 482 # Thu Jan 01 00:00:00 1970 +0000
483 483 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
484 484 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
485 485 2
486 486
487 487 diff --git a/a b/b
488 488 rename from a
489 489 rename to b
490 490
491 491 Test simple origin(), with and without args
492 492 $ hg log -r 'origin()'
493 493 changeset: 1:5d205f8b35b6
494 494 user: bar
495 495 date: Thu Jan 01 00:00:00 1970 +0000
496 496 summary: 1
497 497
498 498 changeset: 2:5c095ad7e90f
499 499 user: test
500 500 date: Thu Jan 01 00:00:00 1970 +0000
501 501 summary: 2
502 502
503 503 changeset: 3:4c60f11aa304
504 504 user: baz
505 505 date: Thu Jan 01 00:00:00 1970 +0000
506 506 summary: 3
507 507
508 508 changeset: 4:9c233e8e184d
509 509 user: test
510 510 date: Thu Jan 01 00:00:00 1970 +0000
511 511 summary: 4
512 512
513 513 changeset: 5:97f8bfe72746
514 514 branch: stable
515 515 parent: 3:4c60f11aa304
516 516 user: test
517 517 date: Thu Jan 01 00:00:00 1970 +0000
518 518 summary: 5
519 519
520 520 $ hg log -r 'origin(7)'
521 521 changeset: 2:5c095ad7e90f
522 522 user: test
523 523 date: Thu Jan 01 00:00:00 1970 +0000
524 524 summary: 2
525 525
526 526 Now transplant a graft to test following through copies
527 527 $ hg up -q 0
528 528 $ hg branch -q dev
529 529 $ hg ci -qm "dev branch"
530 530 $ hg --config extensions.transplant= transplant -q 7
531 531 $ hg log -r 'origin(.)'
532 532 changeset: 2:5c095ad7e90f
533 533 user: test
534 534 date: Thu Jan 01 00:00:00 1970 +0000
535 535 summary: 2
536 536
537 537 Test that the graft and transplant markers in extra are converted, allowing
538 538 origin() to still work. Note that these recheck the immediately preceeding two
539 539 tests.
540 540 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
541 541
542 542 The graft case
543 543 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
544 544 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
545 545 branch=default
546 546 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
547 547 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
548 548 $ hg -R ../converted log -r 'origin(7)'
549 549 changeset: 2:e0213322b2c1
550 550 user: test
551 551 date: Thu Jan 01 00:00:00 1970 +0000
552 552 summary: 2
553 553
554 554 Test that template correctly expands more than one 'extra' (issue4362), and that
555 555 'intermediate-source' is converted.
556 556 $ hg -R ../converted log -r 13 --template "{extras % ' Extra: {extra}\n'}"
557 557 Extra: branch=default
558 558 Extra: convert_revision=7a4785234d87ec1aa420ed6b11afe40fa73e12a9
559 559 Extra: intermediate-source=7ae846e9111fc8f57745634250c7b9ac0a60689b
560 560 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
561 561
562 562 The transplant case
563 563 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
564 564 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
565 565 branch=dev
566 566 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
567 567 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
568 568 `h\x9b (esc)
569 569 $ hg -R ../converted log -r 'origin(tip)'
570 570 changeset: 2:e0213322b2c1
571 571 user: test
572 572 date: Thu Jan 01 00:00:00 1970 +0000
573 573 summary: 2
574 574
575 575
576 576 Test simple destination
577 577 $ hg log -r 'destination()'
578 578 changeset: 7:ef0ef43d49e7
579 579 parent: 0:68795b066622
580 580 user: foo
581 581 date: Thu Jan 01 00:00:00 1970 +0000
582 582 summary: 2
583 583
584 584 changeset: 8:6b9e5368ca4e
585 585 user: bar
586 586 date: Thu Jan 01 00:00:00 1970 +0000
587 587 summary: 1
588 588
589 589 changeset: 9:1905859650ec
590 590 user: test
591 591 date: Thu Jan 01 00:00:00 1970 +0000
592 592 summary: 5
593 593
594 594 changeset: 10:52dc0b4c6907
595 595 user: test
596 596 date: Thu Jan 01 00:00:00 1970 +0000
597 597 summary: 4
598 598
599 599 changeset: 11:882b35362a6b
600 600 user: test
601 601 date: Thu Jan 01 00:00:00 1970 +0000
602 602 summary: 3
603 603
604 604 changeset: 13:7a4785234d87
605 605 user: foo
606 606 date: Thu Jan 01 00:00:00 1970 +0000
607 607 summary: 2
608 608
609 609 changeset: 14:f64defefacee
610 610 parent: 1:5d205f8b35b6
611 611 user: foo
612 612 date: Thu Jan 01 00:00:00 1970 +0000
613 613 summary: 3
614 614
615 615 changeset: 17:f67661df0c48
616 616 user: bar
617 617 date: Thu Jan 01 00:00:00 1970 +0000
618 618 summary: 1
619 619
620 620 changeset: 19:9627f653b421
621 621 user: test
622 622 date: Thu Jan 01 00:00:00 1970 +0000
623 623 summary: 2
624 624
625 625 changeset: 21:7e61b508e709
626 626 branch: dev
627 627 tag: tip
628 628 user: foo
629 629 date: Thu Jan 01 00:00:00 1970 +0000
630 630 summary: 2
631 631
632 632 $ hg log -r 'destination(2)'
633 633 changeset: 7:ef0ef43d49e7
634 634 parent: 0:68795b066622
635 635 user: foo
636 636 date: Thu Jan 01 00:00:00 1970 +0000
637 637 summary: 2
638 638
639 639 changeset: 13:7a4785234d87
640 640 user: foo
641 641 date: Thu Jan 01 00:00:00 1970 +0000
642 642 summary: 2
643 643
644 644 changeset: 19:9627f653b421
645 645 user: test
646 646 date: Thu Jan 01 00:00:00 1970 +0000
647 647 summary: 2
648 648
649 649 changeset: 21:7e61b508e709
650 650 branch: dev
651 651 tag: tip
652 652 user: foo
653 653 date: Thu Jan 01 00:00:00 1970 +0000
654 654 summary: 2
655 655
656 656 Transplants of grafts can find a destination...
657 657 $ hg log -r 'destination(7)'
658 658 changeset: 21:7e61b508e709
659 659 branch: dev
660 660 tag: tip
661 661 user: foo
662 662 date: Thu Jan 01 00:00:00 1970 +0000
663 663 summary: 2
664 664
665 665 ... grafts of grafts unfortunately can't
666 666 $ hg graft -q 13
667 667 warning: can't find ancestor for 'b' copied from 'a'!
668 668 $ hg log -r 'destination(13)'
669 669 All copies of a cset
670 670 $ hg log -r 'origin(13) or destination(origin(13))'
671 671 changeset: 2:5c095ad7e90f
672 672 user: test
673 673 date: Thu Jan 01 00:00:00 1970 +0000
674 674 summary: 2
675 675
676 676 changeset: 7:ef0ef43d49e7
677 677 parent: 0:68795b066622
678 678 user: foo
679 679 date: Thu Jan 01 00:00:00 1970 +0000
680 680 summary: 2
681 681
682 682 changeset: 13:7a4785234d87
683 683 user: foo
684 684 date: Thu Jan 01 00:00:00 1970 +0000
685 685 summary: 2
686 686
687 687 changeset: 19:9627f653b421
688 688 user: test
689 689 date: Thu Jan 01 00:00:00 1970 +0000
690 690 summary: 2
691 691
692 692 changeset: 21:7e61b508e709
693 693 branch: dev
694 694 user: foo
695 695 date: Thu Jan 01 00:00:00 1970 +0000
696 696 summary: 2
697 697
698 698 changeset: 22:d1cb6591fa4b
699 699 branch: dev
700 700 tag: tip
701 701 user: foo
702 702 date: Thu Jan 01 00:00:00 1970 +0000
703 703 summary: 2
704 704
705 705
706 706 graft works on complex revset
707 707
708 708 $ hg graft 'origin(13) or destination(origin(13))'
709 709 skipping ancestor revision 21:7e61b508e709
710 710 skipping ancestor revision 22:d1cb6591fa4b
711 711 skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
712 712 grafting 7:ef0ef43d49e7 "2"
713 713 warning: can't find ancestor for 'b' copied from 'a'!
714 714 grafting 13:7a4785234d87 "2"
715 715 warning: can't find ancestor for 'b' copied from 'a'!
716 716 grafting 19:9627f653b421 "2"
717 717 merging b
718 718 warning: can't find ancestor for 'b' copied from 'a'!
719 719
720 720 graft with --force (still doesn't graft merges)
721 721
722 722 $ hg graft 19 0 6
723 723 skipping ungraftable merge revision 6
724 724 skipping ancestor revision 0:68795b066622
725 725 skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
726 726 [255]
727 727 $ hg graft 19 0 6 --force
728 728 skipping ungraftable merge revision 6
729 729 grafting 19:9627f653b421 "2"
730 730 merging b
731 731 warning: can't find ancestor for 'b' copied from 'a'!
732 732 grafting 0:68795b066622 "0"
733 733
734 734 graft --force after backout
735 735
736 736 $ echo abc > a
737 737 $ hg ci -m 28
738 738 $ hg backout 28
739 739 reverting a
740 740 changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
741 741 $ hg graft 28
742 742 skipping ancestor revision 28:50a516bb8b57
743 743 [255]
744 744 $ hg graft 28 --force
745 745 grafting 28:50a516bb8b57 "28"
746 746 merging a
747 747 $ cat a
748 748 abc
749 749
750 750 graft --continue after --force
751 751
752 752 $ echo def > a
753 753 $ hg ci -m 31
754 754 $ hg graft 28 --force --tool internal:fail
755 755 grafting 28:50a516bb8b57 "28"
756 756 abort: unresolved conflicts, can't continue
757 757 (use hg resolve and hg graft --continue)
758 758 [255]
759 759 $ hg resolve --all
760 760 merging a
761 761 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
762 762 [1]
763 763 $ echo abc > a
764 764 $ hg resolve -m a
765 765 (no more unresolved files)
766 766 continue: hg graft --continue
767 767 $ hg graft -c
768 768 grafting 28:50a516bb8b57 "28"
769 769 $ cat a
770 770 abc
771 771
772 772 Continue testing same origin policy, using revision numbers from test above
773 773 but do some destructive editing of the repo:
774 774
775 775 $ hg up -qC 7
776 776 $ hg tag -l -r 13 tmp
777 777 $ hg --config extensions.strip= strip 2
778 778 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-d323a1e4-backup.hg (glob)
779 779 $ hg graft tmp
780 780 skipping already grafted revision 8:7a4785234d87 (2:ef0ef43d49e7 also has unknown origin 5c095ad7e90f)
781 781 [255]
782 782
783 783 Empty graft
784 784
785 785 $ hg up -qr 26
786 786 $ hg tag -f something
787 787 $ hg graft -qr 27
788 788 $ hg graft -f 27
789 789 grafting 27:ed6c7e54e319 "28"
790 790 note: graft of 27:ed6c7e54e319 created no changes to commit
791 791
792 792 $ cd ..
793 793
794 794 Graft to duplicate a commit
795 795
796 796 $ hg init graftsibling
797 797 $ cd graftsibling
798 798 $ touch a
799 799 $ hg commit -qAm a
800 800 $ touch b
801 801 $ hg commit -qAm b
802 802 $ hg log -G -T '{rev}\n'
803 803 @ 1
804 804 |
805 805 o 0
806 806
807 807 $ hg up -q 0
808 808 $ hg graft -r 1
809 809 grafting 1:0e067c57feba "b" (tip)
810 810 $ hg log -G -T '{rev}\n'
811 811 @ 2
812 812 |
813 813 | o 1
814 814 |/
815 815 o 0
816 816
817 817 Graft to duplicate a commit twice
818 818
819 819 $ hg up -q 0
820 820 $ hg graft -r 2
821 821 grafting 2:044ec77f6389 "b" (tip)
822 822 $ hg log -G -T '{rev}\n'
823 823 @ 3
824 824 |
825 825 | o 2
826 826 |/
827 827 | o 1
828 828 |/
829 829 o 0
830 830
@@ -1,157 +1,159 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > EOF
7 7
8 8 $ initrepo ()
9 9 > {
10 10 > hg init r
11 11 > cd r
12 12 > for x in a b c d e f ; do
13 13 > echo $x > $x
14 14 > hg add $x
15 15 > hg ci -m $x
16 16 > done
17 17 > echo a >> e
18 18 > hg ci -m 'does not commute with e'
19 19 > cd ..
20 20 > }
21 21
22 22 $ initrepo
23 23 $ cd r
24 24
25 25 log before edit
26 26 $ hg log --graph
27 27 @ changeset: 6:bfa474341cc9
28 28 | tag: tip
29 29 | user: test
30 30 | date: Thu Jan 01 00:00:00 1970 +0000
31 31 | summary: does not commute with e
32 32 |
33 33 o changeset: 5:652413bf663e
34 34 | user: test
35 35 | date: Thu Jan 01 00:00:00 1970 +0000
36 36 | summary: f
37 37 |
38 38 o changeset: 4:e860deea161a
39 39 | user: test
40 40 | date: Thu Jan 01 00:00:00 1970 +0000
41 41 | summary: e
42 42 |
43 43 o changeset: 3:055a42cdd887
44 44 | user: test
45 45 | date: Thu Jan 01 00:00:00 1970 +0000
46 46 | summary: d
47 47 |
48 48 o changeset: 2:177f92b77385
49 49 | user: test
50 50 | date: Thu Jan 01 00:00:00 1970 +0000
51 51 | summary: c
52 52 |
53 53 o changeset: 1:d2ae7f538514
54 54 | user: test
55 55 | date: Thu Jan 01 00:00:00 1970 +0000
56 56 | summary: b
57 57 |
58 58 o changeset: 0:cb9a9f314b8b
59 59 user: test
60 60 date: Thu Jan 01 00:00:00 1970 +0000
61 61 summary: a
62 62
63 63
64 64 edit the history
65 65 $ hg histedit 177f92b77385 --commands - 2>&1 <<EOF | fixbundle
66 66 > pick 177f92b77385 c
67 67 > pick 055a42cdd887 d
68 68 > pick bfa474341cc9 does not commute with e
69 69 > pick e860deea161a e
70 70 > pick 652413bf663e f
71 71 > EOF
72 72 merging e
73 73 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
74 74 Fix up the change (pick e860deea161a)
75 75 (hg histedit --continue to resume)
76 76
77 77 insert unsupported advisory merge record
78 78 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
79 79 $ hg debugmergestate
80 80 * version 2 records
81 81 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
82 82 other: e860deea161a2f77de56603b340ebbb4536308ae
83 83 unrecognized entry: x advisory record
84 file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
84 85 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
85 86 local path: e (flags "")
86 87 ancestor path: e (node null)
87 88 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
88 89 $ hg resolve -l
89 90 U e
90 91
91 92 insert unsupported mandatory merge record
92 93 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
93 94 $ hg debugmergestate
94 95 * version 2 records
95 96 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
96 97 other: e860deea161a2f77de56603b340ebbb4536308ae
98 file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
97 99 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
98 100 local path: e (flags "")
99 101 ancestor path: e (node null)
100 102 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
101 103 unrecognized entry: X mandatory record
102 104 $ hg resolve -l
103 105 abort: unsupported merge state records: X
104 106 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
105 107 [255]
106 108 $ hg resolve -ma
107 109 abort: unsupported merge state records: X
108 110 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
109 111 [255]
110 112
111 113 abort the edit (should clear out merge state)
112 114 $ hg histedit --abort 2>&1 | fixbundle
113 115 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
114 116 $ hg debugmergestate
115 117 no merge state found
116 118
117 119 log after abort
118 120 $ hg resolve -l
119 121 $ hg log --graph
120 122 @ changeset: 6:bfa474341cc9
121 123 | tag: tip
122 124 | user: test
123 125 | date: Thu Jan 01 00:00:00 1970 +0000
124 126 | summary: does not commute with e
125 127 |
126 128 o changeset: 5:652413bf663e
127 129 | user: test
128 130 | date: Thu Jan 01 00:00:00 1970 +0000
129 131 | summary: f
130 132 |
131 133 o changeset: 4:e860deea161a
132 134 | user: test
133 135 | date: Thu Jan 01 00:00:00 1970 +0000
134 136 | summary: e
135 137 |
136 138 o changeset: 3:055a42cdd887
137 139 | user: test
138 140 | date: Thu Jan 01 00:00:00 1970 +0000
139 141 | summary: d
140 142 |
141 143 o changeset: 2:177f92b77385
142 144 | user: test
143 145 | date: Thu Jan 01 00:00:00 1970 +0000
144 146 | summary: c
145 147 |
146 148 o changeset: 1:d2ae7f538514
147 149 | user: test
148 150 | date: Thu Jan 01 00:00:00 1970 +0000
149 151 | summary: b
150 152 |
151 153 o changeset: 0:cb9a9f314b8b
152 154 user: test
153 155 date: Thu Jan 01 00:00:00 1970 +0000
154 156 summary: a
155 157
156 158
157 159 $ cd ..
@@ -1,98 +1,98 b''
1 1 https://bz.mercurial-scm.org/672
2 2
3 3 # 0-2-4
4 4 # \ \ \
5 5 # 1-3-5
6 6 #
7 7 # rename in #1, content change in #4.
8 8
9 9 $ hg init
10 10
11 11 $ touch 1
12 12 $ touch 2
13 13 $ hg commit -Am init # 0
14 14 adding 1
15 15 adding 2
16 16
17 17 $ hg rename 1 1a
18 18 $ hg commit -m rename # 1
19 19
20 20 $ hg co -C 0
21 21 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
22 22
23 23 $ echo unrelated >> 2
24 24 $ hg ci -m unrelated1 # 2
25 25 created new head
26 26
27 27 $ hg merge --debug 1
28 28 searching for copies back to rev 1
29 29 unmatched files in other:
30 30 1a
31 31 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
32 32 src: '1' -> dst: '1a'
33 33 checking for directory renames
34 34 resolving manifests
35 35 branchmerge: True, force: False, partial: False
36 36 ancestor: 81f4b099af3d, local: c64f439569a9+, remote: c12dcd37c90a
37 37 1: other deleted -> r
38 38 removing 1
39 39 1a: remote created -> g
40 40 getting 1a
41 41 2: remote unchanged -> k
42 42 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
43 43 (branch merge, don't forget to commit)
44 44
45 45 $ hg ci -m merge1 # 3
46 46
47 47 $ hg co -C 2
48 48 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
49 49
50 50 $ echo hello >> 1
51 51 $ hg ci -m unrelated2 # 4
52 52 created new head
53 53
54 54 $ hg co -C 3
55 55 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
56 56
57 57 $ hg merge -y --debug 4
58 58 searching for copies back to rev 1
59 59 unmatched files in local:
60 60 1a
61 61 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
62 62 src: '1' -> dst: '1a' *
63 63 checking for directory renames
64 64 resolving manifests
65 65 branchmerge: True, force: False, partial: False
66 66 ancestor: c64f439569a9, local: e327dca35ac8+, remote: 746e9549ea96
67 67 preserving 1a for resolve of 1a
68 68 1a: local copied/moved from 1 -> m (premerge)
69 69 picked tool ':merge' for 1a (binary False symlink False changedelete False)
70 70 merging 1a and 1 to 1a
71 my 1a@e327dca35ac8+ other 1@746e9549ea96 ancestor 1@81f4b099af3d
71 my 1a@e327dca35ac8+ other 1@746e9549ea96 ancestor 1@c64f439569a9
72 72 premerge successful
73 73 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
74 74 (branch merge, don't forget to commit)
75 75
76 76 $ hg co -C 4
77 77 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
78 78
79 79 $ hg merge -y --debug 3
80 80 searching for copies back to rev 1
81 81 unmatched files in other:
82 82 1a
83 83 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
84 84 src: '1' -> dst: '1a' *
85 85 checking for directory renames
86 86 resolving manifests
87 87 branchmerge: True, force: False, partial: False
88 88 ancestor: c64f439569a9, local: 746e9549ea96+, remote: e327dca35ac8
89 89 preserving 1 for resolve of 1a
90 90 removing 1
91 91 1a: remote moved from 1 -> m (premerge)
92 92 picked tool ':merge' for 1a (binary False symlink False changedelete False)
93 93 merging 1 and 1a to 1a
94 my 1a@746e9549ea96+ other 1a@e327dca35ac8 ancestor 1@81f4b099af3d
94 my 1a@746e9549ea96+ other 1a@e327dca35ac8 ancestor 1@c64f439569a9
95 95 premerge successful
96 96 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
97 97 (branch merge, don't forget to commit)
98 98
@@ -1,992 +1,1034 b''
1 1 Tests for change/delete conflicts, including:
2 2 b5605d88dc27: Make ui.prompt repeat on "unrecognized response" again
3 3 (issue897)
4 4
5 5 840e2b315c1f: Fix misleading error and prompts during update/merge
6 6 (issue556)
7 7
8 8 Make sure HGMERGE doesn't interfere with the test
9 9 $ unset HGMERGE
10 10
11 11 $ status() {
12 12 > echo "--- status ---"
13 13 > hg st -A file1 file2 file3
14 14 > echo "--- resolve --list ---"
15 15 > hg resolve --list file1 file2 file3
16 16 > echo "--- debugmergestate ---"
17 17 > hg debugmergestate
18 18 > for file in file1 file2 file3; do
19 19 > if [ -f $file ]; then
20 20 > echo "--- $file ---"
21 21 > cat $file
22 22 > else
23 23 > echo "*** $file does not exist"
24 24 > fi
25 25 > done
26 26 > }
27 27
28 28 $ hg init repo
29 29 $ cd repo
30 30
31 31 $ echo 1 > file1
32 32 $ echo 2 > file2
33 33 $ echo 3 > file3
34 34 $ hg ci -Am 'added files'
35 35 adding file1
36 36 adding file2
37 37 adding file3
38 38
39 39 $ hg rm file1
40 40 $ echo changed >> file2
41 41 $ echo changed1 >> file3
42 42 $ hg ci -m 'removed file1, changed file2, changed file3'
43 43
44 44 $ hg co 0
45 45 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 46
47 47 $ echo changed >> file1
48 48 $ hg rm file2
49 49 $ echo changed2 >> file3
50 50 $ hg ci -m 'changed file1, removed file2, changed file3'
51 51 created new head
52 52
53 53
54 54 Non-interactive merge:
55 55
56 56 $ hg merge -y
57 57 local changed file1 which remote deleted
58 58 use (c)hanged version, (d)elete, or leave (u)nresolved? u
59 59 remote changed file2 which local deleted
60 60 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
61 61 merging file3
62 62 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
63 63 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
64 64 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
65 65 [1]
66 66
67 67 $ status
68 68 --- status ---
69 69 M file2
70 70 M file3
71 71 C file1
72 72 --- resolve --list ---
73 73 U file1
74 74 U file2
75 75 U file3
76 76 --- debugmergestate ---
77 77 * version 2 records
78 78 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
79 79 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
80 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
80 81 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
81 82 local path: file1 (flags "")
82 83 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
83 84 other path: file1 (node null)
85 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
84 86 file: file2 (record type "C", state "u", hash null)
85 87 local path: file2 (flags "")
86 88 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
87 89 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
90 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
88 91 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
89 92 local path: file3 (flags "")
90 93 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
91 94 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
92 95 --- file1 ---
93 96 1
94 97 changed
95 98 --- file2 ---
96 99 2
97 100 changed
98 101 --- file3 ---
99 102 3
100 103 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
101 104 changed2
102 105 =======
103 106 changed1
104 107 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
105 108
106 109
107 110 Interactive merge:
108 111
109 112 $ hg co -C
110 113 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
111 114
112 115 $ hg merge --config ui.interactive=true <<EOF
113 116 > c
114 117 > d
115 118 > EOF
116 119 local changed file1 which remote deleted
117 120 use (c)hanged version, (d)elete, or leave (u)nresolved? c
118 121 remote changed file2 which local deleted
119 122 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? d
120 123 merging file3
121 124 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
122 125 0 files updated, 2 files merged, 0 files removed, 1 files unresolved
123 126 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
124 127 [1]
125 128
126 129 $ status
127 130 --- status ---
128 131 file2: * (glob)
129 132 M file3
130 133 C file1
131 134 --- resolve --list ---
132 135 R file1
133 136 R file2
134 137 U file3
135 138 --- debugmergestate ---
136 139 * version 2 records
137 140 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
138 141 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
142 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
139 143 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
140 144 local path: file1 (flags "")
141 145 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
142 146 other path: file1 (node null)
147 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
143 148 file: file2 (record type "C", state "r", hash null)
144 149 local path: file2 (flags "")
145 150 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
146 151 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
152 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
147 153 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
148 154 local path: file3 (flags "")
149 155 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
150 156 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
151 157 --- file1 ---
152 158 1
153 159 changed
154 160 *** file2 does not exist
155 161 --- file3 ---
156 162 3
157 163 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
158 164 changed2
159 165 =======
160 166 changed1
161 167 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
162 168
163 169
164 170 Interactive merge with bad input:
165 171
166 172 $ hg co -C
167 173 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
168 174
169 175 $ hg merge --config ui.interactive=true <<EOF
170 176 > foo
171 177 > bar
172 178 > d
173 179 > baz
174 180 > c
175 181 > EOF
176 182 local changed file1 which remote deleted
177 183 use (c)hanged version, (d)elete, or leave (u)nresolved? foo
178 184 unrecognized response
179 185 local changed file1 which remote deleted
180 186 use (c)hanged version, (d)elete, or leave (u)nresolved? bar
181 187 unrecognized response
182 188 local changed file1 which remote deleted
183 189 use (c)hanged version, (d)elete, or leave (u)nresolved? d
184 190 remote changed file2 which local deleted
185 191 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? baz
186 192 unrecognized response
187 193 remote changed file2 which local deleted
188 194 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? c
189 195 merging file3
190 196 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
191 197 0 files updated, 1 files merged, 1 files removed, 1 files unresolved
192 198 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
193 199 [1]
194 200
195 201 $ status
196 202 --- status ---
197 203 M file2
198 204 M file3
199 205 R file1
200 206 --- resolve --list ---
201 207 R file1
202 208 R file2
203 209 U file3
204 210 --- debugmergestate ---
205 211 * version 2 records
206 212 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
207 213 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
214 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
208 215 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
209 216 local path: file1 (flags "")
210 217 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
211 218 other path: file1 (node null)
219 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
212 220 file: file2 (record type "C", state "r", hash null)
213 221 local path: file2 (flags "")
214 222 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
215 223 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
224 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
216 225 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
217 226 local path: file3 (flags "")
218 227 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
219 228 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
220 229 *** file1 does not exist
221 230 --- file2 ---
222 231 2
223 232 changed
224 233 --- file3 ---
225 234 3
226 235 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
227 236 changed2
228 237 =======
229 238 changed1
230 239 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
231 240
232 241
233 242 Interactive merge with not enough input:
234 243
235 244 $ hg co -C
236 245 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
237 246
238 247 $ hg merge --config ui.interactive=true <<EOF
239 248 > d
240 249 > EOF
241 250 local changed file1 which remote deleted
242 251 use (c)hanged version, (d)elete, or leave (u)nresolved? d
243 252 remote changed file2 which local deleted
244 253 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
245 254 merging file3
246 255 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
247 256 0 files updated, 0 files merged, 1 files removed, 2 files unresolved
248 257 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
249 258 [1]
250 259
251 260 $ status
252 261 --- status ---
253 262 M file2
254 263 M file3
255 264 R file1
256 265 --- resolve --list ---
257 266 R file1
258 267 U file2
259 268 U file3
260 269 --- debugmergestate ---
261 270 * version 2 records
262 271 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
263 272 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
273 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
264 274 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
265 275 local path: file1 (flags "")
266 276 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
267 277 other path: file1 (node null)
278 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
268 279 file: file2 (record type "C", state "u", hash null)
269 280 local path: file2 (flags "")
270 281 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
271 282 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
283 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
272 284 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
273 285 local path: file3 (flags "")
274 286 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
275 287 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
276 288 *** file1 does not exist
277 289 --- file2 ---
278 290 2
279 291 changed
280 292 --- file3 ---
281 293 3
282 294 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
283 295 changed2
284 296 =======
285 297 changed1
286 298 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
287 299
288 300 Choose local versions of files
289 301
290 302 $ hg co -C
291 303 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
292 304
293 305 $ hg merge --tool :local
294 306 0 files updated, 3 files merged, 0 files removed, 0 files unresolved
295 307 (branch merge, don't forget to commit)
296 308 $ status 2>&1 | tee $TESTTMP/local.status
297 309 --- status ---
298 310 file2: * (glob)
299 311 M file3
300 312 C file1
301 313 --- resolve --list ---
302 314 R file1
303 315 R file2
304 316 R file3
305 317 --- debugmergestate ---
306 318 * version 2 records
307 319 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
308 320 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
321 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
309 322 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
310 323 local path: file1 (flags "")
311 324 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
312 325 other path: file1 (node null)
326 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
313 327 file: file2 (record type "C", state "r", hash null)
314 328 local path: file2 (flags "")
315 329 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
316 330 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
331 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
317 332 file: file3 (record type "F", state "r", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
318 333 local path: file3 (flags "")
319 334 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
320 335 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
321 336 --- file1 ---
322 337 1
323 338 changed
324 339 *** file2 does not exist
325 340 --- file3 ---
326 341 3
327 342 changed2
328 343
329 344 Choose other versions of files
330 345
331 346 $ hg co -C
332 347 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
333 348
334 349 $ hg merge --tool :other
335 350 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
336 351 (branch merge, don't forget to commit)
337 352 $ status 2>&1 | tee $TESTTMP/other.status
338 353 --- status ---
339 354 M file2
340 355 M file3
341 356 R file1
342 357 --- resolve --list ---
343 358 R file1
344 359 R file2
345 360 R file3
346 361 --- debugmergestate ---
347 362 * version 2 records
348 363 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
349 364 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
365 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
350 366 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
351 367 local path: file1 (flags "")
352 368 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
353 369 other path: file1 (node null)
370 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
354 371 file: file2 (record type "C", state "r", hash null)
355 372 local path: file2 (flags "")
356 373 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
357 374 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
375 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
358 376 file: file3 (record type "F", state "r", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
359 377 local path: file3 (flags "")
360 378 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
361 379 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
362 380 *** file1 does not exist
363 381 --- file2 ---
364 382 2
365 383 changed
366 384 --- file3 ---
367 385 3
368 386 changed1
369 387
370 388 Fail
371 389
372 390 $ hg co -C
373 391 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
374 392
375 393 $ hg merge --tool :fail
376 394 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
377 395 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
378 396 [1]
379 397 $ status 2>&1 | tee $TESTTMP/fail.status
380 398 --- status ---
381 399 M file2
382 400 M file3
383 401 C file1
384 402 --- resolve --list ---
385 403 U file1
386 404 U file2
387 405 U file3
388 406 --- debugmergestate ---
389 407 * version 2 records
390 408 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
391 409 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
410 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
392 411 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
393 412 local path: file1 (flags "")
394 413 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
395 414 other path: file1 (node null)
415 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
396 416 file: file2 (record type "C", state "u", hash null)
397 417 local path: file2 (flags "")
398 418 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
399 419 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
420 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
400 421 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
401 422 local path: file3 (flags "")
402 423 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
403 424 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
404 425 --- file1 ---
405 426 1
406 427 changed
407 428 --- file2 ---
408 429 2
409 430 changed
410 431 --- file3 ---
411 432 3
412 433 changed2
413 434
414 435 Force prompts with no input (should be similar to :fail)
415 436
416 437 $ hg co -C
417 438 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
418 439
419 440 $ hg merge --config ui.interactive=True --tool :prompt
420 441 local changed file1 which remote deleted
421 442 use (c)hanged version, (d)elete, or leave (u)nresolved?
422 443 remote changed file2 which local deleted
423 444 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
424 445 no tool found to merge file3
425 446 keep (l)ocal, take (o)ther, or leave (u)nresolved?
426 447 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
427 448 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
428 449 [1]
429 450 $ status 2>&1 | tee $TESTTMP/prompt.status
430 451 --- status ---
431 452 M file2
432 453 M file3
433 454 C file1
434 455 --- resolve --list ---
435 456 U file1
436 457 U file2
437 458 U file3
438 459 --- debugmergestate ---
439 460 * version 2 records
440 461 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
441 462 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
463 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
442 464 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
443 465 local path: file1 (flags "")
444 466 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
445 467 other path: file1 (node null)
468 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
446 469 file: file2 (record type "C", state "u", hash null)
447 470 local path: file2 (flags "")
448 471 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
449 472 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
473 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
450 474 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
451 475 local path: file3 (flags "")
452 476 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
453 477 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
454 478 --- file1 ---
455 479 1
456 480 changed
457 481 --- file2 ---
458 482 2
459 483 changed
460 484 --- file3 ---
461 485 3
462 486 changed2
463 487 $ cmp $TESTTMP/fail.status $TESTTMP/prompt.status || diff -U8 $TESTTMP/fail.status $TESTTMP/prompt.status
464 488
465 489
466 490 Force prompts
467 491
468 492 $ hg co -C
469 493 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
470 494
471 495 $ hg merge --tool :prompt
472 496 local changed file1 which remote deleted
473 497 use (c)hanged version, (d)elete, or leave (u)nresolved? u
474 498 remote changed file2 which local deleted
475 499 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
476 500 no tool found to merge file3
477 501 keep (l)ocal, take (o)ther, or leave (u)nresolved? u
478 502 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
479 503 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
480 504 [1]
481 505 $ status
482 506 --- status ---
483 507 M file2
484 508 M file3
485 509 C file1
486 510 --- resolve --list ---
487 511 U file1
488 512 U file2
489 513 U file3
490 514 --- debugmergestate ---
491 515 * version 2 records
492 516 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
493 517 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
518 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
494 519 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
495 520 local path: file1 (flags "")
496 521 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
497 522 other path: file1 (node null)
523 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
498 524 file: file2 (record type "C", state "u", hash null)
499 525 local path: file2 (flags "")
500 526 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
501 527 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
528 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
502 529 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
503 530 local path: file3 (flags "")
504 531 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
505 532 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
506 533 --- file1 ---
507 534 1
508 535 changed
509 536 --- file2 ---
510 537 2
511 538 changed
512 539 --- file3 ---
513 540 3
514 541 changed2
515 542
516 543 Choose to merge all files
517 544
518 545 $ hg co -C
519 546 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
520 547
521 548 $ hg merge --tool :merge3
522 549 local changed file1 which remote deleted
523 550 use (c)hanged version, (d)elete, or leave (u)nresolved? u
524 551 remote changed file2 which local deleted
525 552 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
526 553 merging file3
527 554 warning: conflicts while merging file3! (edit, then use 'hg resolve --mark')
528 555 0 files updated, 0 files merged, 0 files removed, 3 files unresolved
529 556 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
530 557 [1]
531 558 $ status
532 559 --- status ---
533 560 M file2
534 561 M file3
535 562 C file1
536 563 --- resolve --list ---
537 564 U file1
538 565 U file2
539 566 U file3
540 567 --- debugmergestate ---
541 568 * version 2 records
542 569 local: 13910f48cf7bdb2a0ba6e24b4900e4fdd5739dd4
543 570 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
571 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
544 572 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
545 573 local path: file1 (flags "")
546 574 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
547 575 other path: file1 (node null)
576 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
548 577 file: file2 (record type "C", state "u", hash null)
549 578 local path: file2 (flags "")
550 579 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
551 580 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
581 file extras: file3 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
552 582 file: file3 (record type "F", state "u", hash d5b0a58bc47161b1b8a831084b366f757c4f0b11)
553 583 local path: file3 (flags "")
554 584 ancestor path: file3 (node 2661d26c649684b482d10f91960cc3db683c38b4)
555 585 other path: file3 (node a2644c43e210356772c7772a8674544a62e06beb)
556 586 --- file1 ---
557 587 1
558 588 changed
559 589 --- file2 ---
560 590 2
561 591 changed
562 592 --- file3 ---
563 593 3
564 594 <<<<<<< local: 13910f48cf7b - test: changed file1, removed file2, changed file3
565 595 changed2
566 596 ||||||| base
567 597 =======
568 598 changed1
569 599 >>>>>>> other: 10f9a0a634e8 - test: removed file1, changed file2, changed file3
570 600
571 601 Exercise transitions between local, other, fail and prompt, and make sure the
572 602 dirstate stays consistent. (Compare with each other and to the above
573 603 invocations.)
574 604
575 605 $ testtransitions() {
576 606 > # this traversal order covers every transition
577 607 > tools="local other prompt local fail other local prompt other fail prompt fail local"
578 608 > lasttool="merge3"
579 609 > for tool in $tools; do
580 610 > echo "=== :$lasttool -> :$tool ==="
581 611 > ref="$TESTTMP/$tool.status"
582 612 > hg resolve --unmark --all
583 613 > hg resolve --tool ":$tool" --all --config ui.interactive=True
584 614 > status > "$TESTTMP/compare.status" 2>&1
585 615 > echo '--- diff of status ---'
586 616 > if cmp "$TESTTMP/$tool.status" "$TESTTMP/compare.status" || diff -U8 "$TESTTMP/$tool.status" "$TESTTMP/compare.status"; then
587 617 > echo '(status identical)'
588 618 > fi
589 619 > lasttool="$tool"
590 620 > echo
591 621 > done
592 622 > }
593 623
594 624 $ testtransitions
595 625 === :merge3 -> :local ===
596 626 (no more unresolved files)
597 627 --- diff of status ---
598 628 (status identical)
599 629
600 630 === :local -> :other ===
601 631 (no more unresolved files)
602 632 --- diff of status ---
603 633 (status identical)
604 634
605 635 === :other -> :prompt ===
606 636 local changed file1 which remote deleted
607 637 use (c)hanged version, (d)elete, or leave (u)nresolved?
608 638 remote changed file2 which local deleted
609 639 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
610 640 no tool found to merge file3
611 641 keep (l)ocal, take (o)ther, or leave (u)nresolved?
612 642 --- diff of status ---
613 643 (status identical)
614 644
615 645 === :prompt -> :local ===
616 646 (no more unresolved files)
617 647 --- diff of status ---
618 648 (status identical)
619 649
620 650 === :local -> :fail ===
621 651 --- diff of status ---
622 652 (status identical)
623 653
624 654 === :fail -> :other ===
625 655 (no more unresolved files)
626 656 --- diff of status ---
627 657 (status identical)
628 658
629 659 === :other -> :local ===
630 660 (no more unresolved files)
631 661 --- diff of status ---
632 662 (status identical)
633 663
634 664 === :local -> :prompt ===
635 665 local changed file1 which remote deleted
636 666 use (c)hanged version, (d)elete, or leave (u)nresolved?
637 667 remote changed file2 which local deleted
638 668 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
639 669 no tool found to merge file3
640 670 keep (l)ocal, take (o)ther, or leave (u)nresolved?
641 671 --- diff of status ---
642 672 (status identical)
643 673
644 674 === :prompt -> :other ===
645 675 (no more unresolved files)
646 676 --- diff of status ---
647 677 (status identical)
648 678
649 679 === :other -> :fail ===
650 680 --- diff of status ---
651 681 (status identical)
652 682
653 683 === :fail -> :prompt ===
654 684 local changed file1 which remote deleted
655 685 use (c)hanged version, (d)elete, or leave (u)nresolved?
656 686 remote changed file2 which local deleted
657 687 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
658 688 no tool found to merge file3
659 689 keep (l)ocal, take (o)ther, or leave (u)nresolved?
660 690 --- diff of status ---
661 691 (status identical)
662 692
663 693 === :prompt -> :fail ===
664 694 --- diff of status ---
665 695 (status identical)
666 696
667 697 === :fail -> :local ===
668 698 (no more unresolved files)
669 699 --- diff of status ---
670 700 (status identical)
671 701
672 702
673 703
674 704 Non-interactive linear update
675 705
676 706 $ hg co -C 0
677 707 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
678 708 $ echo changed >> file1
679 709 $ hg rm file2
680 710 $ hg update 1 -y
681 711 local changed file1 which remote deleted
682 712 use (c)hanged version, (d)elete, or leave (u)nresolved? u
683 713 remote changed file2 which local deleted
684 714 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
685 715 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
686 716 use 'hg resolve' to retry unresolved file merges
687 717 [1]
688 718 $ status
689 719 --- status ---
690 720 A file1
691 721 C file2
692 722 C file3
693 723 --- resolve --list ---
694 724 U file1
695 725 U file2
696 726 --- debugmergestate ---
697 727 * version 2 records
698 728 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
699 729 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
730 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
700 731 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
701 732 local path: file1 (flags "")
702 733 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
703 734 other path: file1 (node null)
735 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
704 736 file: file2 (record type "C", state "u", hash null)
705 737 local path: file2 (flags "")
706 738 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
707 739 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
708 740 --- file1 ---
709 741 1
710 742 changed
711 743 --- file2 ---
712 744 2
713 745 changed
714 746 --- file3 ---
715 747 3
716 748 changed1
717 749
718 750 Choose local versions of files
719 751
720 752 $ hg co -C 0
721 753 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
722 754 $ echo changed >> file1
723 755 $ hg rm file2
724 756 $ hg update 1 --tool :local
725 757 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
726 758 $ status 2>&1 | tee $TESTTMP/local.status
727 759 --- status ---
728 760 file2: * (glob)
729 761 A file1
730 762 C file3
731 763 --- resolve --list ---
732 764 R file1
733 765 R file2
734 766 --- debugmergestate ---
735 767 * version 2 records
736 768 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
737 769 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
770 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
738 771 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
739 772 local path: file1 (flags "")
740 773 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
741 774 other path: file1 (node null)
775 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
742 776 file: file2 (record type "C", state "r", hash null)
743 777 local path: file2 (flags "")
744 778 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
745 779 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
746 780 --- file1 ---
747 781 1
748 782 changed
749 783 *** file2 does not exist
750 784 --- file3 ---
751 785 3
752 786 changed1
753 787
754 788 Choose other versions of files
755 789
756 790 $ hg co -C 0
757 791 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
758 792 $ echo changed >> file1
759 793 $ hg rm file2
760 794 $ hg update 1 --tool :other
761 795 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
762 796 $ status 2>&1 | tee $TESTTMP/other.status
763 797 --- status ---
764 798 file1: * (glob)
765 799 C file2
766 800 C file3
767 801 --- resolve --list ---
768 802 R file1
769 803 R file2
770 804 --- debugmergestate ---
771 805 * version 2 records
772 806 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
773 807 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
808 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
774 809 file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
775 810 local path: file1 (flags "")
776 811 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
777 812 other path: file1 (node null)
813 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
778 814 file: file2 (record type "C", state "r", hash null)
779 815 local path: file2 (flags "")
780 816 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
781 817 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
782 818 *** file1 does not exist
783 819 --- file2 ---
784 820 2
785 821 changed
786 822 --- file3 ---
787 823 3
788 824 changed1
789 825
790 826 Fail
791 827
792 828 $ hg co -C 0
793 829 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
794 830 $ echo changed >> file1
795 831 $ hg rm file2
796 832 $ hg update 1 --tool :fail
797 833 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
798 834 use 'hg resolve' to retry unresolved file merges
799 835 [1]
800 836 $ status 2>&1 | tee $TESTTMP/fail.status
801 837 --- status ---
802 838 A file1
803 839 C file2
804 840 C file3
805 841 --- resolve --list ---
806 842 U file1
807 843 U file2
808 844 --- debugmergestate ---
809 845 * version 2 records
810 846 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
811 847 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
848 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
812 849 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
813 850 local path: file1 (flags "")
814 851 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
815 852 other path: file1 (node null)
853 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
816 854 file: file2 (record type "C", state "u", hash null)
817 855 local path: file2 (flags "")
818 856 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
819 857 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
820 858 --- file1 ---
821 859 1
822 860 changed
823 861 --- file2 ---
824 862 2
825 863 changed
826 864 --- file3 ---
827 865 3
828 866 changed1
829 867
830 868 Force prompts with no input
831 869
832 870 $ hg co -C 0
833 871 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
834 872 $ echo changed >> file1
835 873 $ hg rm file2
836 874 $ hg update 1 --config ui.interactive=True --tool :prompt
837 875 local changed file1 which remote deleted
838 876 use (c)hanged version, (d)elete, or leave (u)nresolved?
839 877 remote changed file2 which local deleted
840 878 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
841 879 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
842 880 use 'hg resolve' to retry unresolved file merges
843 881 [1]
844 882 $ status 2>&1 | tee $TESTTMP/prompt.status
845 883 --- status ---
846 884 A file1
847 885 C file2
848 886 C file3
849 887 --- resolve --list ---
850 888 U file1
851 889 U file2
852 890 --- debugmergestate ---
853 891 * version 2 records
854 892 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
855 893 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
894 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
856 895 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
857 896 local path: file1 (flags "")
858 897 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
859 898 other path: file1 (node null)
899 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
860 900 file: file2 (record type "C", state "u", hash null)
861 901 local path: file2 (flags "")
862 902 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
863 903 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
864 904 --- file1 ---
865 905 1
866 906 changed
867 907 --- file2 ---
868 908 2
869 909 changed
870 910 --- file3 ---
871 911 3
872 912 changed1
873 913 $ cmp $TESTTMP/fail.status $TESTTMP/prompt.status || diff -U8 $TESTTMP/fail.status $TESTTMP/prompt.status
874 914
875 915 Choose to merge all files
876 916
877 917 $ hg co -C 0
878 918 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
879 919 $ echo changed >> file1
880 920 $ hg rm file2
881 921 $ hg update 1 --tool :merge3
882 922 local changed file1 which remote deleted
883 923 use (c)hanged version, (d)elete, or leave (u)nresolved? u
884 924 remote changed file2 which local deleted
885 925 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
886 926 1 files updated, 0 files merged, 0 files removed, 2 files unresolved
887 927 use 'hg resolve' to retry unresolved file merges
888 928 [1]
889 929 $ status
890 930 --- status ---
891 931 A file1
892 932 C file2
893 933 C file3
894 934 --- resolve --list ---
895 935 U file1
896 936 U file2
897 937 --- debugmergestate ---
898 938 * version 2 records
899 939 local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
900 940 other: 10f9a0a634e82080907e62f075ab119cbc565ea6
941 file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
901 942 file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
902 943 local path: file1 (flags "")
903 944 ancestor path: file1 (node b8e02f6433738021a065f94175c7cd23db5f05be)
904 945 other path: file1 (node null)
946 file extras: file2 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
905 947 file: file2 (record type "C", state "u", hash null)
906 948 local path: file2 (flags "")
907 949 ancestor path: file2 (node 5d9299349fc01ddd25d0070d149b124d8f10411e)
908 950 other path: file2 (node e7c1328648519852e723de86c0c0525acd779257)
909 951 --- file1 ---
910 952 1
911 953 changed
912 954 --- file2 ---
913 955 2
914 956 changed
915 957 --- file3 ---
916 958 3
917 959 changed1
918 960
919 961 Test transitions between different merge tools
920 962
921 963 $ testtransitions
922 964 === :merge3 -> :local ===
923 965 (no more unresolved files)
924 966 --- diff of status ---
925 967 (status identical)
926 968
927 969 === :local -> :other ===
928 970 (no more unresolved files)
929 971 --- diff of status ---
930 972 (status identical)
931 973
932 974 === :other -> :prompt ===
933 975 local changed file1 which remote deleted
934 976 use (c)hanged version, (d)elete, or leave (u)nresolved?
935 977 remote changed file2 which local deleted
936 978 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
937 979 --- diff of status ---
938 980 (status identical)
939 981
940 982 === :prompt -> :local ===
941 983 (no more unresolved files)
942 984 --- diff of status ---
943 985 (status identical)
944 986
945 987 === :local -> :fail ===
946 988 --- diff of status ---
947 989 (status identical)
948 990
949 991 === :fail -> :other ===
950 992 (no more unresolved files)
951 993 --- diff of status ---
952 994 (status identical)
953 995
954 996 === :other -> :local ===
955 997 (no more unresolved files)
956 998 --- diff of status ---
957 999 (status identical)
958 1000
959 1001 === :local -> :prompt ===
960 1002 local changed file1 which remote deleted
961 1003 use (c)hanged version, (d)elete, or leave (u)nresolved?
962 1004 remote changed file2 which local deleted
963 1005 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
964 1006 --- diff of status ---
965 1007 (status identical)
966 1008
967 1009 === :prompt -> :other ===
968 1010 (no more unresolved files)
969 1011 --- diff of status ---
970 1012 (status identical)
971 1013
972 1014 === :other -> :fail ===
973 1015 --- diff of status ---
974 1016 (status identical)
975 1017
976 1018 === :fail -> :prompt ===
977 1019 local changed file1 which remote deleted
978 1020 use (c)hanged version, (d)elete, or leave (u)nresolved?
979 1021 remote changed file2 which local deleted
980 1022 use (c)hanged version, leave (d)eleted, or leave (u)nresolved?
981 1023 --- diff of status ---
982 1024 (status identical)
983 1025
984 1026 === :prompt -> :fail ===
985 1027 --- diff of status ---
986 1028 (status identical)
987 1029
988 1030 === :fail -> :local ===
989 1031 (no more unresolved files)
990 1032 --- diff of status ---
991 1033 (status identical)
992 1034
@@ -1,352 +1,352 b''
1 1 Criss cross merging
2 2
3 3 $ hg init criss-cross
4 4 $ cd criss-cross
5 5 $ echo '0 base' > f1
6 6 $ echo '0 base' > f2
7 7 $ hg ci -Aqm '0 base'
8 8
9 9 $ echo '1 first change' > f1
10 10 $ hg ci -m '1 first change f1'
11 11
12 12 $ hg up -qr0
13 13 $ echo '2 first change' > f2
14 14 $ hg ci -qm '2 first change f2'
15 15
16 16 $ hg merge -qr 1
17 17 $ hg ci -m '3 merge'
18 18
19 19 $ hg up -qr2
20 20 $ hg merge -qr1
21 21 $ hg ci -qm '4 merge'
22 22
23 23 $ echo '5 second change' > f1
24 24 $ hg ci -m '5 second change f1'
25 25
26 26 $ hg up -r3
27 27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 28 $ echo '6 second change' > f2
29 29 $ hg ci -m '6 second change f2'
30 30
31 31 $ hg log -G
32 32 @ changeset: 6:3b08d01b0ab5
33 33 | tag: tip
34 34 | parent: 3:cf89f02107e5
35 35 | user: test
36 36 | date: Thu Jan 01 00:00:00 1970 +0000
37 37 | summary: 6 second change f2
38 38 |
39 39 | o changeset: 5:adfe50279922
40 40 | | user: test
41 41 | | date: Thu Jan 01 00:00:00 1970 +0000
42 42 | | summary: 5 second change f1
43 43 | |
44 44 | o changeset: 4:7d3e55501ae6
45 45 | |\ parent: 2:40663881a6dd
46 46 | | | parent: 1:0f6b37dbe527
47 47 | | | user: test
48 48 | | | date: Thu Jan 01 00:00:00 1970 +0000
49 49 | | | summary: 4 merge
50 50 | | |
51 51 o---+ changeset: 3:cf89f02107e5
52 52 | | | parent: 2:40663881a6dd
53 53 |/ / parent: 1:0f6b37dbe527
54 54 | | user: test
55 55 | | date: Thu Jan 01 00:00:00 1970 +0000
56 56 | | summary: 3 merge
57 57 | |
58 58 | o changeset: 2:40663881a6dd
59 59 | | parent: 0:40494bf2444c
60 60 | | user: test
61 61 | | date: Thu Jan 01 00:00:00 1970 +0000
62 62 | | summary: 2 first change f2
63 63 | |
64 64 o | changeset: 1:0f6b37dbe527
65 65 |/ user: test
66 66 | date: Thu Jan 01 00:00:00 1970 +0000
67 67 | summary: 1 first change f1
68 68 |
69 69 o changeset: 0:40494bf2444c
70 70 user: test
71 71 date: Thu Jan 01 00:00:00 1970 +0000
72 72 summary: 0 base
73 73
74 74
75 75 $ hg merge -v --debug --tool internal:dump 5 --config merge.preferancestor='!'
76 76 note: using 0f6b37dbe527 as ancestor of 3b08d01b0ab5 and adfe50279922
77 77 alternatively, use --config merge.preferancestor=40663881a6dd
78 78 searching for copies back to rev 3
79 79 resolving manifests
80 80 branchmerge: True, force: False, partial: False
81 81 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
82 82 preserving f2 for resolve of f2
83 83 f1: remote is newer -> g
84 84 getting f1
85 85 f2: versions differ -> m (premerge)
86 86 picked tool ':dump' for f2 (binary False symlink False changedelete False)
87 87 merging f2
88 my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@40494bf2444c
88 my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@0f6b37dbe527
89 89 f2: versions differ -> m (merge)
90 90 picked tool ':dump' for f2 (binary False symlink False changedelete False)
91 my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@40494bf2444c
91 my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@0f6b37dbe527
92 92 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
93 93 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
94 94 [1]
95 95
96 96 $ head *
97 97 ==> f1 <==
98 98 5 second change
99 99
100 100 ==> f2 <==
101 101 6 second change
102 102
103 103 ==> f2.base <==
104 104 0 base
105 105
106 106 ==> f2.local <==
107 107 6 second change
108 108
109 109 ==> f2.orig <==
110 110 6 second change
111 111
112 112 ==> f2.other <==
113 113 2 first change
114 114
115 115 $ hg up -qC .
116 116 $ hg merge -v --tool internal:dump 5 --config merge.preferancestor="null 40663881 3b08d"
117 117 note: using 40663881a6dd as ancestor of 3b08d01b0ab5 and adfe50279922
118 118 alternatively, use --config merge.preferancestor=0f6b37dbe527
119 119 resolving manifests
120 120 merging f1
121 121 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
122 122 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
123 123 [1]
124 124
125 125 Redo merge with merge.preferancestor="*" to enable bid merge
126 126
127 127 $ rm f*
128 128 $ hg up -qC .
129 129 $ hg merge -v --debug --tool internal:dump 5 --config merge.preferancestor="*"
130 130 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
131 131
132 132 calculating bids for ancestor 0f6b37dbe527
133 133 searching for copies back to rev 3
134 134 resolving manifests
135 135 branchmerge: True, force: False, partial: False
136 136 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
137 137 f1: remote is newer -> g
138 138 f2: versions differ -> m
139 139
140 140 calculating bids for ancestor 40663881a6dd
141 141 searching for copies back to rev 3
142 142 resolving manifests
143 143 branchmerge: True, force: False, partial: False
144 144 ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
145 145 f1: versions differ -> m
146 146 f2: remote unchanged -> k
147 147
148 148 auction for merging merge bids
149 149 f1: picking 'get' action
150 150 f2: picking 'keep' action
151 151 end of auction
152 152
153 153 f1: remote is newer -> g
154 154 getting f1
155 155 f2: remote unchanged -> k
156 156 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
157 157 (branch merge, don't forget to commit)
158 158
159 159 $ head *
160 160 ==> f1 <==
161 161 5 second change
162 162
163 163 ==> f2 <==
164 164 6 second change
165 165
166 166
167 167 The other way around:
168 168
169 169 $ hg up -C -r5
170 170 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 171 $ hg merge -v --debug --config merge.preferancestor="*"
172 172 note: merging adfe50279922+ and 3b08d01b0ab5 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
173 173
174 174 calculating bids for ancestor 0f6b37dbe527
175 175 searching for copies back to rev 3
176 176 resolving manifests
177 177 branchmerge: True, force: False, partial: False
178 178 ancestor: 0f6b37dbe527, local: adfe50279922+, remote: 3b08d01b0ab5
179 179 f1: remote unchanged -> k
180 180 f2: versions differ -> m
181 181
182 182 calculating bids for ancestor 40663881a6dd
183 183 searching for copies back to rev 3
184 184 resolving manifests
185 185 branchmerge: True, force: False, partial: False
186 186 ancestor: 40663881a6dd, local: adfe50279922+, remote: 3b08d01b0ab5
187 187 f1: versions differ -> m
188 188 f2: remote is newer -> g
189 189
190 190 auction for merging merge bids
191 191 f1: picking 'keep' action
192 192 f2: picking 'get' action
193 193 end of auction
194 194
195 195 f2: remote is newer -> g
196 196 getting f2
197 197 f1: remote unchanged -> k
198 198 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 199 (branch merge, don't forget to commit)
200 200
201 201 $ head *
202 202 ==> f1 <==
203 203 5 second change
204 204
205 205 ==> f2 <==
206 206 6 second change
207 207
208 208 Verify how the output looks and and how verbose it is:
209 209
210 210 $ hg up -qC
211 211 $ hg merge
212 212 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
213 213 (branch merge, don't forget to commit)
214 214
215 215 $ hg up -qC
216 216 $ hg merge -v
217 217 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
218 218
219 219 calculating bids for ancestor 0f6b37dbe527
220 220 resolving manifests
221 221
222 222 calculating bids for ancestor 40663881a6dd
223 223 resolving manifests
224 224
225 225 auction for merging merge bids
226 226 f1: picking 'get' action
227 227 f2: picking 'keep' action
228 228 end of auction
229 229
230 230 getting f1
231 231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 232 (branch merge, don't forget to commit)
233 233
234 234 $ hg up -qC
235 235 $ hg merge -v --debug --config merge.preferancestor="*"
236 236 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
237 237
238 238 calculating bids for ancestor 0f6b37dbe527
239 239 searching for copies back to rev 3
240 240 resolving manifests
241 241 branchmerge: True, force: False, partial: False
242 242 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
243 243 f1: remote is newer -> g
244 244 f2: versions differ -> m
245 245
246 246 calculating bids for ancestor 40663881a6dd
247 247 searching for copies back to rev 3
248 248 resolving manifests
249 249 branchmerge: True, force: False, partial: False
250 250 ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
251 251 f1: versions differ -> m
252 252 f2: remote unchanged -> k
253 253
254 254 auction for merging merge bids
255 255 f1: picking 'get' action
256 256 f2: picking 'keep' action
257 257 end of auction
258 258
259 259 f1: remote is newer -> g
260 260 getting f1
261 261 f2: remote unchanged -> k
262 262 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 263 (branch merge, don't forget to commit)
264 264
265 265 $ cd ..
266 266
267 267 http://stackoverflow.com/questions/9350005/how-do-i-specify-a-merge-base-to-use-in-a-hg-merge/9430810
268 268
269 269 $ hg init ancestor-merging
270 270 $ cd ancestor-merging
271 271 $ echo a > x
272 272 $ hg commit -A -m a x
273 273 $ hg update -q 0
274 274 $ echo b >> x
275 275 $ hg commit -m b
276 276 $ hg update -q 0
277 277 $ echo c >> x
278 278 $ hg commit -qm c
279 279 $ hg update -q 1
280 280 $ hg merge -q --tool internal:local 2
281 281 $ echo c >> x
282 282 $ hg commit -m bc
283 283 $ hg update -q 2
284 284 $ hg merge -q --tool internal:local 1
285 285 $ echo b >> x
286 286 $ hg commit -qm cb
287 287
288 288 $ hg merge --config merge.preferancestor='!'
289 289 note: using 70008a2163f6 as ancestor of 0d355fdef312 and 4b8b546a3eef
290 290 alternatively, use --config merge.preferancestor=b211bbc6eb3c
291 291 merging x
292 292 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
293 293 (branch merge, don't forget to commit)
294 294 $ cat x
295 295 a
296 296 c
297 297 b
298 298 c
299 299
300 300 $ hg up -qC .
301 301
302 302 $ hg merge --config merge.preferancestor=b211bbc6eb3c
303 303 note: using b211bbc6eb3c as ancestor of 0d355fdef312 and 4b8b546a3eef
304 304 alternatively, use --config merge.preferancestor=70008a2163f6
305 305 merging x
306 306 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
307 307 (branch merge, don't forget to commit)
308 308 $ cat x
309 309 a
310 310 b
311 311 c
312 312 b
313 313
314 314 $ hg up -qC .
315 315
316 316 $ hg merge -v --config merge.preferancestor="*"
317 317 note: merging 0d355fdef312+ and 4b8b546a3eef using bids from ancestors 70008a2163f6 and b211bbc6eb3c
318 318
319 319 calculating bids for ancestor 70008a2163f6
320 320 resolving manifests
321 321
322 322 calculating bids for ancestor b211bbc6eb3c
323 323 resolving manifests
324 324
325 325 auction for merging merge bids
326 326 x: multiple bids for merge action:
327 327 versions differ -> m
328 328 versions differ -> m
329 329 x: ambiguous merge - picked m action
330 330 end of auction
331 331
332 332 merging x
333 333 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
334 334 (branch merge, don't forget to commit)
335 335 $ cat x
336 336 a
337 337 c
338 338 b
339 339 c
340 340
341 341 Verify that the old context ancestor works with / despite preferancestor:
342 342
343 343 $ hg log -r 'ancestor(head())' --config merge.preferancestor=1 -T '{rev}\n'
344 344 1
345 345 $ hg log -r 'ancestor(head())' --config merge.preferancestor=2 -T '{rev}\n'
346 346 2
347 347 $ hg log -r 'ancestor(head())' --config merge.preferancestor=3 -T '{rev}\n'
348 348 1
349 349 $ hg log -r 'ancestor(head())' --config merge.preferancestor='1337 * - 2' -T '{rev}\n'
350 350 2
351 351
352 352 $ cd ..
@@ -1,394 +1,396 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > rebase=
4 4 >
5 5 > [phases]
6 6 > publish=False
7 7 >
8 8 > [alias]
9 9 > tglog = log -G --template "{rev}:{phase} '{desc}' {branches}\n"
10 10 > EOF
11 11
12 12
13 13 $ hg init a
14 14 $ cd a
15 15
16 16 $ touch .hg/rebasestate
17 17 $ hg sum
18 18 parent: -1:000000000000 tip (empty repository)
19 19 branch: default
20 20 commit: (clean)
21 21 update: (current)
22 22 abort: .hg/rebasestate is incomplete
23 23 [255]
24 24 $ rm .hg/rebasestate
25 25
26 26 $ echo c1 > common
27 27 $ hg add common
28 28 $ hg ci -m C1
29 29
30 30 $ echo c2 >> common
31 31 $ hg ci -m C2
32 32
33 33 $ echo c3 >> common
34 34 $ hg ci -m C3
35 35
36 36 $ hg up -q -C 1
37 37
38 38 $ echo l1 >> extra
39 39 $ hg add extra
40 40 $ hg ci -m L1
41 41 created new head
42 42
43 43 $ sed -e 's/c2/l2/' common > common.new
44 44 $ mv common.new common
45 45 $ hg ci -m L2
46 46
47 47 $ hg phase --force --secret 2
48 48
49 49 $ hg tglog
50 50 @ 4:draft 'L2'
51 51 |
52 52 o 3:draft 'L1'
53 53 |
54 54 | o 2:secret 'C3'
55 55 |/
56 56 o 1:draft 'C2'
57 57 |
58 58 o 0:draft 'C1'
59 59
60 60
61 61 Conflicting rebase:
62 62
63 63 $ hg rebase -s 3 -d 2
64 64 rebasing 3:3163e20567cc "L1"
65 65 rebasing 4:46f0b057b5c0 "L2" (tip)
66 66 merging common
67 67 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
68 68 unresolved conflicts (see hg resolve, then hg rebase --continue)
69 69 [1]
70 70
71 71 Insert unsupported advisory merge record:
72 72
73 73 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
74 74 $ hg debugmergestate
75 75 * version 2 records
76 76 local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
77 77 other: 46f0b057b5c061d276b91491c22151f78698abd2
78 78 unrecognized entry: x advisory record
79 file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
79 80 file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
80 81 local path: common (flags "")
81 82 ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6)
82 83 other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5)
83 84 $ hg resolve -l
84 85 U common
85 86
86 87 Insert unsupported mandatory merge record:
87 88
88 89 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
89 90 $ hg debugmergestate
90 91 * version 2 records
91 92 local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
92 93 other: 46f0b057b5c061d276b91491c22151f78698abd2
94 file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
93 95 file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
94 96 local path: common (flags "")
95 97 ancestor path: common (node de0a666fdd9c1a0b0698b90d85064d8bd34f74b6)
96 98 other path: common (node 2f6411de53677f6f1048fef5bf888d67a342e0a5)
97 99 unrecognized entry: X mandatory record
98 100 $ hg resolve -l
99 101 abort: unsupported merge state records: X
100 102 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
101 103 [255]
102 104 $ hg resolve -ma
103 105 abort: unsupported merge state records: X
104 106 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
105 107 [255]
106 108
107 109 Abort (should clear out unsupported merge state):
108 110
109 111 $ hg rebase --abort
110 112 saved backup bundle to $TESTTMP/a/.hg/strip-backup/3e046f2ecedb-6beef7d5-backup.hg (glob)
111 113 rebase aborted
112 114 $ hg debugmergestate
113 115 no merge state found
114 116
115 117 $ hg tglog
116 118 @ 4:draft 'L2'
117 119 |
118 120 o 3:draft 'L1'
119 121 |
120 122 | o 2:secret 'C3'
121 123 |/
122 124 o 1:draft 'C2'
123 125 |
124 126 o 0:draft 'C1'
125 127
126 128 Test safety for inconsistent rebase state, which may be created (and
127 129 forgotten) by Mercurial earlier than 2.7. This emulates Mercurial
128 130 earlier than 2.7 by renaming ".hg/rebasestate" temporarily.
129 131
130 132 $ hg rebase -s 3 -d 2
131 133 rebasing 3:3163e20567cc "L1"
132 134 rebasing 4:46f0b057b5c0 "L2" (tip)
133 135 merging common
134 136 warning: conflicts while merging common! (edit, then use 'hg resolve --mark')
135 137 unresolved conflicts (see hg resolve, then hg rebase --continue)
136 138 [1]
137 139
138 140 $ mv .hg/rebasestate .hg/rebasestate.back
139 141 $ hg update --quiet --clean 2
140 142 $ hg --config extensions.mq= strip --quiet "destination()"
141 143 $ mv .hg/rebasestate.back .hg/rebasestate
142 144
143 145 $ hg rebase --continue
144 146 abort: cannot continue inconsistent rebase
145 147 (use "hg rebase --abort" to clear broken state)
146 148 [255]
147 149 $ hg summary | grep '^rebase: '
148 150 rebase: (use "hg rebase --abort" to clear broken state)
149 151 $ hg rebase --abort
150 152 rebase aborted (no revision is removed, only broken state is cleared)
151 153
152 154 $ cd ..
153 155
154 156
155 157 Construct new repo:
156 158
157 159 $ hg init b
158 160 $ cd b
159 161
160 162 $ echo a > a
161 163 $ hg ci -Am A
162 164 adding a
163 165
164 166 $ echo b > b
165 167 $ hg ci -Am B
166 168 adding b
167 169
168 170 $ echo c > c
169 171 $ hg ci -Am C
170 172 adding c
171 173
172 174 $ hg up -q 0
173 175
174 176 $ echo b > b
175 177 $ hg ci -Am 'B bis'
176 178 adding b
177 179 created new head
178 180
179 181 $ echo c1 > c
180 182 $ hg ci -Am C1
181 183 adding c
182 184
183 185 $ hg phase --force --secret 1
184 186 $ hg phase --public 1
185 187
186 188 Rebase and abort without generating new changesets:
187 189
188 190 $ hg tglog
189 191 @ 4:draft 'C1'
190 192 |
191 193 o 3:draft 'B bis'
192 194 |
193 195 | o 2:secret 'C'
194 196 | |
195 197 | o 1:public 'B'
196 198 |/
197 199 o 0:public 'A'
198 200
199 201 $ hg rebase -b 4 -d 2
200 202 rebasing 3:a6484957d6b9 "B bis"
201 203 note: rebase of 3:a6484957d6b9 created no changes to commit
202 204 rebasing 4:145842775fec "C1" (tip)
203 205 merging c
204 206 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
205 207 unresolved conflicts (see hg resolve, then hg rebase --continue)
206 208 [1]
207 209
208 210 $ hg tglog
209 211 @ 4:draft 'C1'
210 212 |
211 213 o 3:draft 'B bis'
212 214 |
213 215 | @ 2:secret 'C'
214 216 | |
215 217 | o 1:public 'B'
216 218 |/
217 219 o 0:public 'A'
218 220
219 221 $ hg rebase -a
220 222 rebase aborted
221 223
222 224 $ hg tglog
223 225 @ 4:draft 'C1'
224 226 |
225 227 o 3:draft 'B bis'
226 228 |
227 229 | o 2:secret 'C'
228 230 | |
229 231 | o 1:public 'B'
230 232 |/
231 233 o 0:public 'A'
232 234
233 235
234 236 $ cd ..
235 237
236 238 rebase abort should not leave working copy in a merge state if tip-1 is public
237 239 (issue4082)
238 240
239 241 $ hg init abortpublic
240 242 $ cd abortpublic
241 243 $ echo a > a && hg ci -Aqm a
242 244 $ hg book master
243 245 $ hg book foo
244 246 $ echo b > b && hg ci -Aqm b
245 247 $ hg up -q master
246 248 $ echo c > c && hg ci -Aqm c
247 249 $ hg phase -p -r .
248 250 $ hg up -q foo
249 251 $ echo C > c && hg ci -Aqm C
250 252 $ hg log -G --template "{rev} {desc} {bookmarks}"
251 253 @ 3 C foo
252 254 |
253 255 | o 2 c master
254 256 | |
255 257 o | 1 b
256 258 |/
257 259 o 0 a
258 260
259 261
260 262 $ hg rebase -d master -r foo
261 263 rebasing 3:6c0f977a22d8 "C" (tip foo)
262 264 merging c
263 265 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
264 266 unresolved conflicts (see hg resolve, then hg rebase --continue)
265 267 [1]
266 268 $ hg rebase --abort
267 269 rebase aborted
268 270 $ hg log -G --template "{rev} {desc} {bookmarks}"
269 271 @ 3 C foo
270 272 |
271 273 | o 2 c master
272 274 | |
273 275 o | 1 b
274 276 |/
275 277 o 0 a
276 278
277 279 $ cd ..
278 280
279 281 Make sure we don't clobber changes in the working directory when the
280 282 user has somehow managed to update to a different revision (issue4009)
281 283
282 284 $ hg init noupdate
283 285 $ cd noupdate
284 286 $ hg book @
285 287 $ echo original > a
286 288 $ hg add a
287 289 $ hg commit -m a
288 290 $ echo x > b
289 291 $ hg add b
290 292 $ hg commit -m b1
291 293 $ hg up 0
292 294 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
293 295 (leaving bookmark @)
294 296 $ hg book foo
295 297 $ echo y > b
296 298 $ hg add b
297 299 $ hg commit -m b2
298 300 created new head
299 301
300 302 $ hg rebase -d @ -b foo --tool=internal:fail
301 303 rebasing 2:070cf4580bb5 "b2" (tip foo)
302 304 unresolved conflicts (see hg resolve, then hg rebase --continue)
303 305 [1]
304 306
305 307 $ mv .hg/rebasestate ./ # so we're allowed to hg up like in mercurial <2.6.3
306 308 $ hg up -C 0 # user does other stuff in the repo
307 309 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
308 310
309 311 $ mv rebasestate .hg/ # user upgrades to 2.7
310 312
311 313 $ echo new > a
312 314 $ hg up 1 # user gets an error saying to run hg rebase --abort
313 315 abort: rebase in progress
314 316 (use 'hg rebase --continue' or 'hg rebase --abort')
315 317 [255]
316 318
317 319 $ cat a
318 320 new
319 321 $ hg rebase --abort
320 322 rebase aborted
321 323 $ cat a
322 324 new
323 325
324 326 $ cd ..
325 327
326 328 On the other hand, make sure we *do* clobber changes whenever we
327 329 haven't somehow managed to update the repo to a different revision
328 330 during a rebase (issue4661)
329 331
330 332 $ hg ini yesupdate
331 333 $ cd yesupdate
332 334 $ echo "initial data" > foo.txt
333 335 $ hg add
334 336 adding foo.txt
335 337 $ hg ci -m "initial checkin"
336 338 $ echo "change 1" > foo.txt
337 339 $ hg ci -m "change 1"
338 340 $ hg up 0
339 341 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 342 $ echo "conflicting change 1" > foo.txt
341 343 $ hg ci -m "conflicting 1"
342 344 created new head
343 345 $ echo "conflicting change 2" > foo.txt
344 346 $ hg ci -m "conflicting 2"
345 347
346 348 $ hg rebase -d 1 --tool 'internal:fail'
347 349 rebasing 2:e4ea5cdc9789 "conflicting 1"
348 350 unresolved conflicts (see hg resolve, then hg rebase --continue)
349 351 [1]
350 352 $ hg rebase --abort
351 353 rebase aborted
352 354 $ hg summary
353 355 parent: 3:b16646383533 tip
354 356 conflicting 2
355 357 branch: default
356 358 commit: (clean)
357 359 update: 1 new changesets, 2 branch heads (merge)
358 360 phases: 4 draft
359 361 $ cd ..
360 362
361 363 test aborting a rebase succeeds after rebasing with skipped commits onto a
362 364 public changeset (issue4896)
363 365
364 366 $ hg init succeedonpublic
365 367 $ cd succeedonpublic
366 368 $ echo 'content' > root
367 369 $ hg commit -A -m 'root' -q
368 370
369 371 set up public branch
370 372 $ echo 'content' > disappear
371 373 $ hg commit -A -m 'disappear public' -q
372 374 commit will cause merge conflict on rebase
373 375 $ echo '' > root
374 376 $ hg commit -m 'remove content public' -q
375 377 $ hg phase --public
376 378
377 379 setup the draft branch that will be rebased onto public commit
378 380 $ hg up -r 0 -q
379 381 $ echo 'content' > disappear
380 382 commit will disappear
381 383 $ hg commit -A -m 'disappear draft' -q
382 384 $ echo 'addedcontADDEDentadded' > root
383 385 commit will cause merge conflict on rebase
384 386 $ hg commit -m 'add content draft' -q
385 387
386 388 $ hg rebase -d 'public()' --tool :merge -q
387 389 note: rebase of 3:0682fd3dabf5 created no changes to commit
388 390 warning: conflicts while merging root! (edit, then use 'hg resolve --mark')
389 391 unresolved conflicts (see hg resolve, then hg rebase --continue)
390 392 [1]
391 393 $ hg rebase --abort
392 394 rebase aborted
393 395 $ cd ..
394 396
@@ -1,328 +1,332 b''
1 1 test that a commit clears the merge state.
2 2
3 3 $ hg init repo
4 4 $ cd repo
5 5
6 6 $ echo foo > file1
7 7 $ echo foo > file2
8 8 $ hg commit -Am 'add files'
9 9 adding file1
10 10 adding file2
11 11
12 12 $ echo bar >> file1
13 13 $ echo bar >> file2
14 14 $ hg commit -Am 'append bar to files'
15 15
16 16 create a second head with conflicting edits
17 17
18 18 $ hg up -C 0
19 19 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 20 $ echo baz >> file1
21 21 $ echo baz >> file2
22 22 $ hg commit -Am 'append baz to files'
23 23 created new head
24 24
25 25 create a third head with no conflicting edits
26 26 $ hg up -qC 0
27 27 $ echo foo > file3
28 28 $ hg commit -Am 'add non-conflicting file'
29 29 adding file3
30 30 created new head
31 31
32 32 failing merge
33 33
34 34 $ hg up -qC 2
35 35 $ hg merge --tool=internal:fail 1
36 36 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
37 37 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
38 38 [1]
39 39
40 40 resolve -l should contain unresolved entries
41 41
42 42 $ hg resolve -l
43 43 U file1
44 44 U file2
45 45
46 46 $ hg resolve -l --no-status
47 47 file1
48 48 file2
49 49
50 50 resolving an unknown path should emit a warning, but not for -l
51 51
52 52 $ hg resolve -m does-not-exist
53 53 arguments do not match paths that need resolving
54 54 $ hg resolve -l does-not-exist
55 55
56 56 don't allow marking or unmarking driver-resolved files
57 57
58 58 $ cat > $TESTTMP/markdriver.py << EOF
59 59 > '''mark and unmark files as driver-resolved'''
60 60 > from mercurial import cmdutil, merge, scmutil
61 61 > cmdtable = {}
62 62 > command = cmdutil.command(cmdtable)
63 63 > @command('markdriver',
64 64 > [('u', 'unmark', None, '')],
65 65 > 'FILE...')
66 66 > def markdriver(ui, repo, *pats, **opts):
67 67 > wlock = repo.wlock()
68 68 > try:
69 69 > ms = merge.mergestate.read(repo)
70 70 > m = scmutil.match(repo[None], pats, opts)
71 71 > for f in ms:
72 72 > if not m(f):
73 73 > continue
74 74 > if not opts['unmark']:
75 75 > ms.mark(f, 'd')
76 76 > else:
77 77 > ms.mark(f, 'u')
78 78 > ms.commit()
79 79 > finally:
80 80 > wlock.release()
81 81 > EOF
82 82 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver file1
83 83 $ hg resolve --list
84 84 D file1
85 85 U file2
86 86 $ hg resolve --mark file1
87 87 not marking file1 as it is driver-resolved
88 88 this should not print out file1
89 89 $ hg resolve --mark --all
90 90 (no more unresolved files -- run "hg resolve --all" to conclude)
91 91 $ hg resolve --mark 'glob:file*'
92 92 (no more unresolved files -- run "hg resolve --all" to conclude)
93 93 $ hg resolve --list
94 94 D file1
95 95 R file2
96 96 $ hg resolve --unmark file1
97 97 not unmarking file1 as it is driver-resolved
98 98 (no more unresolved files -- run "hg resolve --all" to conclude)
99 99 $ hg resolve --unmark --all
100 100 $ hg resolve --list
101 101 D file1
102 102 U file2
103 103 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver --unmark file1
104 104 $ hg resolve --list
105 105 U file1
106 106 U file2
107 107
108 108 resolve the failure
109 109
110 110 $ echo resolved > file1
111 111 $ hg resolve -m file1
112 112
113 113 resolve -l should show resolved file as resolved
114 114
115 115 $ hg resolve -l
116 116 R file1
117 117 U file2
118 118
119 119 $ hg resolve -l -Tjson
120 120 [
121 121 {
122 122 "path": "file1",
123 123 "status": "R"
124 124 },
125 125 {
126 126 "path": "file2",
127 127 "status": "U"
128 128 }
129 129 ]
130 130
131 131 resolve -m without paths should mark all resolved
132 132
133 133 $ hg resolve -m
134 134 (no more unresolved files)
135 135 $ hg commit -m 'resolved'
136 136
137 137 resolve -l should be empty after commit
138 138
139 139 $ hg resolve -l
140 140
141 141 $ hg resolve -l -Tjson
142 142 [
143 143 ]
144 144
145 145 resolve --all should abort when no merge in progress
146 146
147 147 $ hg resolve --all
148 148 abort: resolve command not applicable when not merging
149 149 [255]
150 150
151 151 resolve -m should abort when no merge in progress
152 152
153 153 $ hg resolve -m
154 154 abort: resolve command not applicable when not merging
155 155 [255]
156 156
157 157 can not update or merge when there are unresolved conflicts
158 158
159 159 $ hg up -qC 0
160 160 $ echo quux >> file1
161 161 $ hg up 1
162 162 merging file1
163 163 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
164 164 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
165 165 use 'hg resolve' to retry unresolved file merges
166 166 [1]
167 167 $ hg up 0
168 168 abort: outstanding merge conflicts
169 169 [255]
170 170 $ hg merge 2
171 171 abort: outstanding merge conflicts
172 172 [255]
173 173 $ hg merge --force 2
174 174 abort: outstanding merge conflicts
175 175 [255]
176 176
177 177 set up conflict-free merge
178 178
179 179 $ hg up -qC 3
180 180 $ hg merge 1
181 181 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
182 182 (branch merge, don't forget to commit)
183 183
184 184 resolve --all should do nothing in merge without conflicts
185 185 $ hg resolve --all
186 186 (no more unresolved files)
187 187
188 188 resolve -m should do nothing in merge without conflicts
189 189
190 190 $ hg resolve -m
191 191 (no more unresolved files)
192 192
193 193 get back to conflicting state
194 194
195 195 $ hg up -qC 2
196 196 $ hg merge --tool=internal:fail 1
197 197 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
198 198 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
199 199 [1]
200 200
201 201 resolve without arguments should suggest --all
202 202 $ hg resolve
203 203 abort: no files or directories specified
204 204 (use --all to re-merge all unresolved files)
205 205 [255]
206 206
207 207 resolve --all should re-merge all unresolved files
208 208 $ hg resolve --all
209 209 merging file1
210 210 merging file2
211 211 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
212 212 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
213 213 [1]
214 214 $ cat file1.orig
215 215 foo
216 216 baz
217 217 $ cat file2.orig
218 218 foo
219 219 baz
220 220
221 221 .orig files should exists where specified
222 222 $ hg resolve --all --verbose --config 'ui.origbackuppath=.hg/origbackups'
223 223 merging file1
224 224 creating directory: $TESTTMP/repo/.hg/origbackups (glob)
225 225 merging file2
226 226 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
227 227 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
228 228 [1]
229 229 $ ls .hg/origbackups
230 230 file1.orig
231 231 file2.orig
232 232 $ grep '<<<' file1 > /dev/null
233 233 $ grep '<<<' file2 > /dev/null
234 234
235 235 resolve <file> should re-merge file
236 236 $ echo resolved > file1
237 237 $ hg resolve -q file1
238 238 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
239 239 [1]
240 240 $ grep '<<<' file1 > /dev/null
241 241
242 242 test .orig behavior with resolve
243 243
244 244 $ hg resolve -q file1 --tool "sh -c 'f --dump \"$TESTTMP/repo/file1.orig\"'"
245 245 $TESTTMP/repo/file1.orig: (glob)
246 246 >>>
247 247 foo
248 248 baz
249 249 <<<
250 250
251 251 resolve <file> should do nothing if 'file' was marked resolved
252 252 $ echo resolved > file1
253 253 $ hg resolve -m file1
254 254 $ hg resolve -q file1
255 255 $ cat file1
256 256 resolved
257 257
258 258 insert unsupported advisory merge record
259 259
260 260 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
261 261 $ hg debugmergestate
262 262 * version 2 records
263 263 local: 57653b9f834a4493f7240b0681efcb9ae7cab745
264 264 other: dc77451844e37f03f5c559e3b8529b2b48d381d1
265 265 unrecognized entry: x advisory record
266 file extras: file1 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
266 267 file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
267 268 local path: file1 (flags "")
268 269 ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
269 270 other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
271 file extras: file2 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
270 272 file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523)
271 273 local path: file2 (flags "")
272 274 ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
273 275 other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
274 276 $ hg resolve -l
275 277 R file1
276 278 U file2
277 279
278 280 insert unsupported mandatory merge record
279 281
280 282 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
281 283 $ hg debugmergestate
282 284 * version 2 records
283 285 local: 57653b9f834a4493f7240b0681efcb9ae7cab745
284 286 other: dc77451844e37f03f5c559e3b8529b2b48d381d1
287 file extras: file1 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
285 288 file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
286 289 local path: file1 (flags "")
287 290 ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
288 291 other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
292 file extras: file2 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
289 293 file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523)
290 294 local path: file2 (flags "")
291 295 ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
292 296 other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
293 297 unrecognized entry: X mandatory record
294 298 $ hg resolve -l
295 299 abort: unsupported merge state records: X
296 300 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
297 301 [255]
298 302 $ hg resolve -ma
299 303 abort: unsupported merge state records: X
300 304 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
301 305 [255]
302 306 $ hg summary
303 307 parent: 2:57653b9f834a
304 308 append baz to files
305 309 parent: 1:dc77451844e3
306 310 append bar to files
307 311 branch: default
308 312 warning: merge state has unsupported record types: X
309 313 commit: 2 modified, 2 unknown (merge)
310 314 update: 2 new changesets (update)
311 315 phases: 5 draft
312 316
313 317 update --clean shouldn't abort on unsupported records
314 318
315 319 $ hg up -qC 1
316 320 $ hg debugmergestate
317 321 no merge state found
318 322
319 323 test crashed merge with empty mergestate
320 324
321 325 $ mkdir .hg/merge
322 326 $ touch .hg/merge/state
323 327
324 328 resolve -l should be empty
325 329
326 330 $ hg resolve -l
327 331
328 332 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now