##// END OF EJS Templates
merge: make 'keep' message more descriptive...
Martin von Zweigbergk -
r23482:208ec8ca default
parent child Browse files
Show More
@@ -1,1165 +1,1165 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 import struct
9 9
10 10 from node import nullid, nullrev, hex, bin
11 11 from i18n import _
12 12 from mercurial import obsolete
13 13 import error as errormod, util, filemerge, copies, subrepo, worker
14 14 import errno, os, shutil
15 15
16 16 _pack = struct.pack
17 17 _unpack = struct.unpack
18 18
19 19 def _droponode(data):
20 20 # used for compatibility for v1
21 21 bits = data.split('\0')
22 22 bits = bits[:-2] + bits[-1:]
23 23 return '\0'.join(bits)
24 24
25 25 class mergestate(object):
26 26 '''track 3-way merge state of individual files
27 27
28 28 it is stored on disk when needed. Two file are used, one with an old
29 29 format, one with a new format. Both contains similar data, but the new
30 30 format can store new kind of field.
31 31
32 32 Current new format is a list of arbitrary record of the form:
33 33
34 34 [type][length][content]
35 35
36 36 Type is a single character, length is a 4 bytes integer, content is an
37 37 arbitrary suites of bytes of length `length`.
38 38
39 39 Type should be a letter. Capital letter are mandatory record, Mercurial
40 40 should abort if they are unknown. lower case record can be safely ignored.
41 41
42 42 Currently known record:
43 43
44 44 L: the node of the "local" part of the merge (hexified version)
45 45 O: the node of the "other" part of the merge (hexified version)
46 46 F: a file to be merged entry
47 47 '''
48 48 statepathv1 = 'merge/state'
49 49 statepathv2 = 'merge/state2'
50 50
51 51 def __init__(self, repo):
52 52 self._repo = repo
53 53 self._dirty = False
54 54 self._read()
55 55
56 56 def reset(self, node=None, other=None):
57 57 self._state = {}
58 58 self._local = None
59 59 self._other = None
60 60 if node:
61 61 self._local = node
62 62 self._other = other
63 63 shutil.rmtree(self._repo.join('merge'), True)
64 64 self._dirty = False
65 65
66 66 def _read(self):
67 67 """Analyse each record content to restore a serialized state from disk
68 68
69 69 This function process "record" entry produced by the de-serialization
70 70 of on disk file.
71 71 """
72 72 self._state = {}
73 73 self._local = None
74 74 self._other = None
75 75 records = self._readrecords()
76 76 for rtype, record in records:
77 77 if rtype == 'L':
78 78 self._local = bin(record)
79 79 elif rtype == 'O':
80 80 self._other = bin(record)
81 81 elif rtype == 'F':
82 82 bits = record.split('\0')
83 83 self._state[bits[0]] = bits[1:]
84 84 elif not rtype.islower():
85 85 raise util.Abort(_('unsupported merge state record: %s')
86 86 % rtype)
87 87 self._dirty = False
88 88
89 89 def _readrecords(self):
90 90 """Read merge state from disk and return a list of record (TYPE, data)
91 91
92 92 We read data from both v1 and v2 files and decide which one to use.
93 93
94 94 V1 has been used by version prior to 2.9.1 and contains less data than
95 95 v2. We read both versions and check if no data in v2 contradicts
96 96 v1. If there is not contradiction we can safely assume that both v1
97 97 and v2 were written at the same time and use the extract data in v2. If
98 98 there is contradiction we ignore v2 content as we assume an old version
99 99 of Mercurial has overwritten the mergestate file and left an old v2
100 100 file around.
101 101
102 102 returns list of record [(TYPE, data), ...]"""
103 103 v1records = self._readrecordsv1()
104 104 v2records = self._readrecordsv2()
105 105 oldv2 = set() # old format version of v2 record
106 106 for rec in v2records:
107 107 if rec[0] == 'L':
108 108 oldv2.add(rec)
109 109 elif rec[0] == 'F':
110 110 # drop the onode data (not contained in v1)
111 111 oldv2.add(('F', _droponode(rec[1])))
112 112 for rec in v1records:
113 113 if rec not in oldv2:
114 114 # v1 file is newer than v2 file, use it
115 115 # we have to infer the "other" changeset of the merge
116 116 # we cannot do better than that with v1 of the format
117 117 mctx = self._repo[None].parents()[-1]
118 118 v1records.append(('O', mctx.hex()))
119 119 # add place holder "other" file node information
120 120 # nobody is using it yet so we do no need to fetch the data
121 121 # if mctx was wrong `mctx[bits[-2]]` may fails.
122 122 for idx, r in enumerate(v1records):
123 123 if r[0] == 'F':
124 124 bits = r[1].split('\0')
125 125 bits.insert(-2, '')
126 126 v1records[idx] = (r[0], '\0'.join(bits))
127 127 return v1records
128 128 else:
129 129 return v2records
130 130
131 131 def _readrecordsv1(self):
132 132 """read on disk merge state for version 1 file
133 133
134 134 returns list of record [(TYPE, data), ...]
135 135
136 136 Note: the "F" data from this file are one entry short
137 137 (no "other file node" entry)
138 138 """
139 139 records = []
140 140 try:
141 141 f = self._repo.opener(self.statepathv1)
142 142 for i, l in enumerate(f):
143 143 if i == 0:
144 144 records.append(('L', l[:-1]))
145 145 else:
146 146 records.append(('F', l[:-1]))
147 147 f.close()
148 148 except IOError, err:
149 149 if err.errno != errno.ENOENT:
150 150 raise
151 151 return records
152 152
153 153 def _readrecordsv2(self):
154 154 """read on disk merge state for version 2 file
155 155
156 156 returns list of record [(TYPE, data), ...]
157 157 """
158 158 records = []
159 159 try:
160 160 f = self._repo.opener(self.statepathv2)
161 161 data = f.read()
162 162 off = 0
163 163 end = len(data)
164 164 while off < end:
165 165 rtype = data[off]
166 166 off += 1
167 167 length = _unpack('>I', data[off:(off + 4)])[0]
168 168 off += 4
169 169 record = data[off:(off + length)]
170 170 off += length
171 171 records.append((rtype, record))
172 172 f.close()
173 173 except IOError, err:
174 174 if err.errno != errno.ENOENT:
175 175 raise
176 176 return records
177 177
178 178 def active(self):
179 179 """Whether mergestate is active.
180 180
181 181 Returns True if there appears to be mergestate. This is a rough proxy
182 182 for "is a merge in progress."
183 183 """
184 184 # Check local variables before looking at filesystem for performance
185 185 # reasons.
186 186 return bool(self._local) or bool(self._state) or \
187 187 self._repo.opener.exists(self.statepathv1) or \
188 188 self._repo.opener.exists(self.statepathv2)
189 189
190 190 def commit(self):
191 191 """Write current state on disk (if necessary)"""
192 192 if self._dirty:
193 193 records = []
194 194 records.append(('L', hex(self._local)))
195 195 records.append(('O', hex(self._other)))
196 196 for d, v in self._state.iteritems():
197 197 records.append(('F', '\0'.join([d] + v)))
198 198 self._writerecords(records)
199 199 self._dirty = False
200 200
201 201 def _writerecords(self, records):
202 202 """Write current state on disk (both v1 and v2)"""
203 203 self._writerecordsv1(records)
204 204 self._writerecordsv2(records)
205 205
206 206 def _writerecordsv1(self, records):
207 207 """Write current state on disk in a version 1 file"""
208 208 f = self._repo.opener(self.statepathv1, 'w')
209 209 irecords = iter(records)
210 210 lrecords = irecords.next()
211 211 assert lrecords[0] == 'L'
212 212 f.write(hex(self._local) + '\n')
213 213 for rtype, data in irecords:
214 214 if rtype == 'F':
215 215 f.write('%s\n' % _droponode(data))
216 216 f.close()
217 217
218 218 def _writerecordsv2(self, records):
219 219 """Write current state on disk in a version 2 file"""
220 220 f = self._repo.opener(self.statepathv2, 'w')
221 221 for key, data in records:
222 222 assert len(key) == 1
223 223 format = '>sI%is' % len(data)
224 224 f.write(_pack(format, key, len(data), data))
225 225 f.close()
226 226
227 227 def add(self, fcl, fco, fca, fd):
228 228 """add a new (potentially?) conflicting file the merge state
229 229 fcl: file context for local,
230 230 fco: file context for remote,
231 231 fca: file context for ancestors,
232 232 fd: file path of the resulting merge.
233 233
234 234 note: also write the local version to the `.hg/merge` directory.
235 235 """
236 236 hash = util.sha1(fcl.path()).hexdigest()
237 237 self._repo.opener.write('merge/' + hash, fcl.data())
238 238 self._state[fd] = ['u', hash, fcl.path(),
239 239 fca.path(), hex(fca.filenode()),
240 240 fco.path(), hex(fco.filenode()),
241 241 fcl.flags()]
242 242 self._dirty = True
243 243
244 244 def __contains__(self, dfile):
245 245 return dfile in self._state
246 246
247 247 def __getitem__(self, dfile):
248 248 return self._state[dfile][0]
249 249
250 250 def __iter__(self):
251 251 return iter(sorted(self._state))
252 252
253 253 def files(self):
254 254 return self._state.keys()
255 255
256 256 def mark(self, dfile, state):
257 257 self._state[dfile][0] = state
258 258 self._dirty = True
259 259
260 260 def unresolved(self):
261 261 """Obtain the paths of unresolved files."""
262 262
263 263 for f, entry in self._state.items():
264 264 if entry[0] == 'u':
265 265 yield f
266 266
267 267 def resolve(self, dfile, wctx, labels=None):
268 268 """rerun merge process for file path `dfile`"""
269 269 if self[dfile] == 'r':
270 270 return 0
271 271 stateentry = self._state[dfile]
272 272 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
273 273 octx = self._repo[self._other]
274 274 fcd = wctx[dfile]
275 275 fco = octx[ofile]
276 276 fca = self._repo.filectx(afile, fileid=anode)
277 277 # "premerge" x flags
278 278 flo = fco.flags()
279 279 fla = fca.flags()
280 280 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
281 281 if fca.node() == nullid:
282 282 self._repo.ui.warn(_('warning: cannot merge flags for %s\n') %
283 283 afile)
284 284 elif flags == fla:
285 285 flags = flo
286 286 # restore local
287 287 f = self._repo.opener('merge/' + hash)
288 288 self._repo.wwrite(dfile, f.read(), flags)
289 289 f.close()
290 290 r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca,
291 291 labels=labels)
292 292 if r is None:
293 293 # no real conflict
294 294 del self._state[dfile]
295 295 self._dirty = True
296 296 elif not r:
297 297 self.mark(dfile, 'r')
298 298 return r
299 299
300 300 def _checkunknownfile(repo, wctx, mctx, f):
301 301 return (os.path.isfile(repo.wjoin(f))
302 302 and repo.wopener.audit.check(f)
303 303 and repo.dirstate.normalize(f) not in repo.dirstate
304 304 and mctx[f].cmp(wctx[f]))
305 305
306 306 def _forgetremoved(wctx, mctx, branchmerge):
307 307 """
308 308 Forget removed files
309 309
310 310 If we're jumping between revisions (as opposed to merging), and if
311 311 neither the working directory nor the target rev has the file,
312 312 then we need to remove it from the dirstate, to prevent the
313 313 dirstate from listing the file when it is no longer in the
314 314 manifest.
315 315
316 316 If we're merging, and the other revision has removed a file
317 317 that is not present in the working directory, we need to mark it
318 318 as removed.
319 319 """
320 320
321 321 ractions = []
322 322 factions = xactions = []
323 323 if branchmerge:
324 324 xactions = ractions
325 325 for f in wctx.deleted():
326 326 if f not in mctx:
327 327 xactions.append((f, None, "forget deleted"))
328 328
329 329 if not branchmerge:
330 330 for f in wctx.removed():
331 331 if f not in mctx:
332 332 factions.append((f, None, "forget removed"))
333 333
334 334 return ractions, factions
335 335
336 336 def _checkcollision(repo, wmf, actions):
337 337 # build provisional merged manifest up
338 338 pmmf = set(wmf)
339 339
340 340 if actions:
341 341 # k, dr, e and rd are no-op
342 342 for m in 'a', 'f', 'g', 'cd', 'dc':
343 343 for f, args, msg in actions[m]:
344 344 pmmf.add(f)
345 345 for f, args, msg in actions['r']:
346 346 pmmf.discard(f)
347 347 for f, args, msg in actions['dm']:
348 348 f2, flags = args
349 349 pmmf.discard(f2)
350 350 pmmf.add(f)
351 351 for f, args, msg in actions['dg']:
352 352 pmmf.add(f)
353 353 for f, args, msg in actions['m']:
354 354 f1, f2, fa, move, anc = args
355 355 if move:
356 356 pmmf.discard(f1)
357 357 pmmf.add(f)
358 358
359 359 # check case-folding collision in provisional merged manifest
360 360 foldmap = {}
361 361 for f in sorted(pmmf):
362 362 fold = util.normcase(f)
363 363 if fold in foldmap:
364 364 raise util.Abort(_("case-folding collision between %s and %s")
365 365 % (f, foldmap[fold]))
366 366 foldmap[fold] = f
367 367
368 368 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
369 369 acceptremote, followcopies):
370 370 """
371 371 Merge p1 and p2 with ancestor pa and generate merge action list
372 372
373 373 branchmerge and force are as passed in to update
374 374 partial = function to filter file lists
375 375 acceptremote = accept the incoming changes without prompting
376 376 """
377 377
378 378 actions = dict((m, []) for m in 'a f g cd dc r dm dg m dr e rd k'.split())
379 379 copy, movewithdir = {}, {}
380 380
381 381 # manifests fetched in order are going to be faster, so prime the caches
382 382 [x.manifest() for x in
383 383 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
384 384
385 385 if followcopies:
386 386 ret = copies.mergecopies(repo, wctx, p2, pa)
387 387 copy, movewithdir, diverge, renamedelete = ret
388 388 for of, fl in diverge.iteritems():
389 389 actions['dr'].append((of, (fl,), "divergent renames"))
390 390 for of, fl in renamedelete.iteritems():
391 391 actions['rd'].append((of, (fl,), "rename and delete"))
392 392
393 393 repo.ui.note(_("resolving manifests\n"))
394 394 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
395 395 % (bool(branchmerge), bool(force), bool(partial)))
396 396 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
397 397
398 398 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
399 399 copied = set(copy.values())
400 400 copied.update(movewithdir.values())
401 401
402 402 if '.hgsubstate' in m1:
403 403 # check whether sub state is modified
404 404 for s in sorted(wctx.substate):
405 405 if wctx.sub(s).dirty():
406 406 m1['.hgsubstate'] += '+'
407 407 break
408 408
409 409 aborts = []
410 410 # Compare manifests
411 411 diff = m1.diff(m2)
412 412
413 413 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
414 414 if partial and not partial(f):
415 415 continue
416 416 if n1 and n2: # file exists on both local and remote side
417 417 if f not in ma:
418 418 fa = copy.get(f, None)
419 419 if fa is not None:
420 420 actions['m'].append((f, (f, f, fa, False, pa.node()),
421 421 "both renamed from " + fa))
422 422 else:
423 423 actions['m'].append((f, (f, f, None, False, pa.node()),
424 424 "both created"))
425 425 else:
426 426 a = ma[f]
427 427 fla = ma.flags(f)
428 428 nol = 'l' not in fl1 + fl2 + fla
429 429 if n2 == a and fl2 == fla:
430 actions['k'].append((f, (), "keep")) # remote unchanged
430 actions['k'].append((f, (), "remote unchanged"))
431 431 elif n1 == a and fl1 == fla: # local unchanged - use remote
432 432 if n1 == n2: # optimization: keep local content
433 433 actions['e'].append((f, (fl2,), "update permissions"))
434 434 else:
435 435 actions['g'].append((f, (fl2,), "remote is newer"))
436 436 elif nol and n2 == a: # remote only changed 'x'
437 437 actions['e'].append((f, (fl2,), "update permissions"))
438 438 elif nol and n1 == a: # local only changed 'x'
439 439 actions['g'].append((f, (fl1,), "remote is newer"))
440 440 else: # both changed something
441 441 actions['m'].append((f, (f, f, f, False, pa.node()),
442 442 "versions differ"))
443 443 elif n1: # file exists only on local side
444 444 if f in copied:
445 445 pass # we'll deal with it on m2 side
446 446 elif f in movewithdir: # directory rename, move local
447 447 f2 = movewithdir[f]
448 448 if f2 in m2:
449 449 actions['m'].append((f2, (f, f2, None, True, pa.node()),
450 450 "remote directory rename, both created"))
451 451 else:
452 452 actions['dm'].append((f2, (f, fl1),
453 453 "remote directory rename - move from " + f))
454 454 elif f in copy:
455 455 f2 = copy[f]
456 456 actions['m'].append((f, (f, f2, f2, False, pa.node()),
457 457 "local copied/moved from " + f2))
458 458 elif f in ma: # clean, a different, no remote
459 459 if n1 != ma[f]:
460 460 if acceptremote:
461 461 actions['r'].append((f, None, "remote delete"))
462 462 else:
463 463 actions['cd'].append((f, None,
464 464 "prompt changed/deleted"))
465 465 elif n1[20:] == 'a':
466 466 # This extra 'a' is added by working copy manifest to mark
467 467 # the file as locally added. We should forget it instead of
468 468 # deleting it.
469 469 actions['f'].append((f, None, "remote deleted"))
470 470 else:
471 471 actions['r'].append((f, None, "other deleted"))
472 472 elif n2: # file exists only on remote side
473 473 if f in copied:
474 474 pass # we'll deal with it on m1 side
475 475 elif f in movewithdir:
476 476 f2 = movewithdir[f]
477 477 if f2 in m1:
478 478 actions['m'].append((f2, (f2, f, None, False, pa.node()),
479 479 "local directory rename, both created"))
480 480 else:
481 481 actions['dg'].append((f2, (f, fl2),
482 482 "local directory rename - get from " + f))
483 483 elif f in copy:
484 484 f2 = copy[f]
485 485 if f2 in m2:
486 486 actions['m'].append((f, (f2, f, f2, False, pa.node()),
487 487 "remote copied from " + f2))
488 488 else:
489 489 actions['m'].append((f, (f2, f, f2, True, pa.node()),
490 490 "remote moved from " + f2))
491 491 elif f not in ma:
492 492 # local unknown, remote created: the logic is described by the
493 493 # following table:
494 494 #
495 495 # force branchmerge different | action
496 496 # n * n | get
497 497 # n * y | abort
498 498 # y n * | get
499 499 # y y n | get
500 500 # y y y | merge
501 501 #
502 502 # Checking whether the files are different is expensive, so we
503 503 # don't do that when we can avoid it.
504 504 if force and not branchmerge:
505 505 actions['g'].append((f, (fl2,), "remote created"))
506 506 else:
507 507 different = _checkunknownfile(repo, wctx, p2, f)
508 508 if force and branchmerge and different:
509 509 actions['m'].append((f, (f, f, None, False, pa.node()),
510 510 "remote differs from untracked local"))
511 511 elif not force and different:
512 512 aborts.append((f, 'ud'))
513 513 else:
514 514 actions['g'].append((f, (fl2,), "remote created"))
515 515 elif n2 != ma[f]:
516 516 different = _checkunknownfile(repo, wctx, p2, f)
517 517 if not force and different:
518 518 aborts.append((f, 'ud'))
519 519 else:
520 520 if acceptremote:
521 521 actions['g'].append((f, (fl2,), "remote recreating"))
522 522 else:
523 523 actions['dc'].append((f, (fl2,),
524 524 "prompt deleted/changed"))
525 525
526 526 for f, m in sorted(aborts):
527 527 if m == 'ud':
528 528 repo.ui.warn(_("%s: untracked file differs\n") % f)
529 529 else: assert False, m
530 530 if aborts:
531 531 raise util.Abort(_("untracked files in working directory differ "
532 532 "from files in requested revision"))
533 533
534 534 if not util.checkcase(repo.path):
535 535 # check collision between files only in p2 for clean update
536 536 if (not branchmerge and
537 537 (force or not wctx.dirty(missing=True, branch=False))):
538 538 _checkcollision(repo, m2, None)
539 539 else:
540 540 _checkcollision(repo, m1, actions)
541 541
542 542 return actions
543 543
544 544 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
545 545 acceptremote, followcopies):
546 546 "Calculate the actions needed to merge mctx into wctx using ancestors"
547 547
548 548 if len(ancestors) == 1: # default
549 549 actions = manifestmerge(repo, wctx, mctx, ancestors[0],
550 550 branchmerge, force,
551 551 partial, acceptremote, followcopies)
552 552
553 553 else: # only when merge.preferancestor=* - the default
554 554 repo.ui.note(
555 555 _("note: merging %s and %s using bids from ancestors %s\n") %
556 556 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
557 557
558 558 # Call for bids
559 559 fbids = {} # mapping filename to bids (action method to list af actions)
560 560 for ancestor in ancestors:
561 561 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
562 562 actions = manifestmerge(repo, wctx, mctx, ancestor,
563 563 branchmerge, force,
564 564 partial, acceptremote, followcopies)
565 565 for m, l in sorted(actions.items()):
566 566 for a in l:
567 567 f, args, msg = a
568 568 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
569 569 if f in fbids:
570 570 d = fbids[f]
571 571 if m in d:
572 572 d[m].append(a)
573 573 else:
574 574 d[m] = [a]
575 575 else:
576 576 fbids[f] = {m: [a]}
577 577
578 578 # Pick the best bid for each file
579 579 repo.ui.note(_('\nauction for merging merge bids\n'))
580 580 actions = dict((m, []) for m in actions.keys())
581 581 for f, bids in sorted(fbids.items()):
582 582 # bids is a mapping from action method to list af actions
583 583 # Consensus?
584 584 if len(bids) == 1: # all bids are the same kind of method
585 585 m, l = bids.items()[0]
586 586 if util.all(a == l[0] for a in l[1:]): # len(bids) is > 1
587 587 repo.ui.note(" %s: consensus for %s\n" % (f, m))
588 588 actions[m].append(l[0])
589 589 continue
590 590 # If keep is an option, just do it.
591 591 if 'k' in bids:
592 592 repo.ui.note(" %s: picking 'keep' action\n" % f)
593 593 actions['k'].append(bids['k'][0])
594 594 continue
595 595 # If there are gets and they all agree [how could they not?], do it.
596 596 if 'g' in bids:
597 597 ga0 = bids['g'][0]
598 598 if util.all(a == ga0 for a in bids['g'][1:]):
599 599 repo.ui.note(" %s: picking 'get' action\n" % f)
600 600 actions['g'].append(ga0)
601 601 continue
602 602 # TODO: Consider other simple actions such as mode changes
603 603 # Handle inefficient democrazy.
604 604 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
605 605 for m, l in sorted(bids.items()):
606 606 for _f, args, msg in l:
607 607 repo.ui.note(' %s -> %s\n' % (msg, m))
608 608 # Pick random action. TODO: Instead, prompt user when resolving
609 609 m, l = bids.items()[0]
610 610 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
611 611 (f, m))
612 612 actions[m].append(l[0])
613 613 continue
614 614 repo.ui.note(_('end of auction\n\n'))
615 615
616 616 # Prompt and create actions. TODO: Move this towards resolve phase.
617 617 for f, args, msg in sorted(actions['cd']):
618 618 if f in ancestors[0] and not wctx[f].cmp(ancestors[0][f]):
619 619 # local did change but ended up with same content
620 620 actions['r'].append((f, None, "prompt same"))
621 621 elif repo.ui.promptchoice(
622 622 _("local changed %s which remote deleted\n"
623 623 "use (c)hanged version or (d)elete?"
624 624 "$$ &Changed $$ &Delete") % f, 0):
625 625 actions['r'].append((f, None, "prompt delete"))
626 626 else:
627 627 actions['a'].append((f, None, "prompt keep"))
628 628 del actions['cd'][:]
629 629
630 630 for f, args, msg in sorted(actions['dc']):
631 631 flags, = args
632 632 if f in ancestors[0] and not mctx[f].cmp(ancestors[0][f]):
633 633 # remote did change but ended up with same content
634 634 pass # don't get = keep local deleted
635 635 elif repo.ui.promptchoice(
636 636 _("remote changed %s which local deleted\n"
637 637 "use (c)hanged version or leave (d)eleted?"
638 638 "$$ &Changed $$ &Deleted") % f, 0) == 0:
639 639 actions['g'].append((f, (flags,), "prompt recreating"))
640 640 del actions['dc'][:]
641 641
642 642 if wctx.rev() is None:
643 643 ractions, factions = _forgetremoved(wctx, mctx, branchmerge)
644 644 actions['r'].extend(ractions)
645 645 actions['f'].extend(factions)
646 646
647 647 return actions
648 648
649 649 def batchremove(repo, actions):
650 650 """apply removes to the working directory
651 651
652 652 yields tuples for progress updates
653 653 """
654 654 verbose = repo.ui.verbose
655 655 unlink = util.unlinkpath
656 656 wjoin = repo.wjoin
657 657 audit = repo.wopener.audit
658 658 i = 0
659 659 for f, args, msg in actions:
660 660 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
661 661 if verbose:
662 662 repo.ui.note(_("removing %s\n") % f)
663 663 audit(f)
664 664 try:
665 665 unlink(wjoin(f), ignoremissing=True)
666 666 except OSError, inst:
667 667 repo.ui.warn(_("update failed to remove %s: %s!\n") %
668 668 (f, inst.strerror))
669 669 if i == 100:
670 670 yield i, f
671 671 i = 0
672 672 i += 1
673 673 if i > 0:
674 674 yield i, f
675 675
676 676 def batchget(repo, mctx, actions):
677 677 """apply gets to the working directory
678 678
679 679 mctx is the context to get from
680 680
681 681 yields tuples for progress updates
682 682 """
683 683 verbose = repo.ui.verbose
684 684 fctx = mctx.filectx
685 685 wwrite = repo.wwrite
686 686 i = 0
687 687 for f, args, msg in actions:
688 688 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
689 689 if verbose:
690 690 repo.ui.note(_("getting %s\n") % f)
691 691 wwrite(f, fctx(f).data(), args[0])
692 692 if i == 100:
693 693 yield i, f
694 694 i = 0
695 695 i += 1
696 696 if i > 0:
697 697 yield i, f
698 698
699 699 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
700 700 """apply the merge action list to the working directory
701 701
702 702 wctx is the working copy context
703 703 mctx is the context to be merged into the working copy
704 704
705 705 Return a tuple of counts (updated, merged, removed, unresolved) that
706 706 describes how many files were affected by the update.
707 707 """
708 708
709 709 updated, merged, removed, unresolved = 0, 0, 0, 0
710 710 ms = mergestate(repo)
711 711 ms.reset(wctx.p1().node(), mctx.node())
712 712 moves = []
713 713 for m, l in actions.items():
714 714 l.sort()
715 715
716 716 # prescan for merges
717 717 for f, args, msg in actions['m']:
718 718 f1, f2, fa, move, anc = args
719 719 if f == '.hgsubstate': # merged internally
720 720 continue
721 721 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
722 722 fcl = wctx[f1]
723 723 fco = mctx[f2]
724 724 actx = repo[anc]
725 725 if fa in actx:
726 726 fca = actx[fa]
727 727 else:
728 728 fca = repo.filectx(f1, fileid=nullrev)
729 729 ms.add(fcl, fco, fca, f)
730 730 if f1 != f and move:
731 731 moves.append(f1)
732 732
733 733 audit = repo.wopener.audit
734 734 _updating = _('updating')
735 735 _files = _('files')
736 736 progress = repo.ui.progress
737 737
738 738 # remove renamed files after safely stored
739 739 for f in moves:
740 740 if os.path.lexists(repo.wjoin(f)):
741 741 repo.ui.debug("removing %s\n" % f)
742 742 audit(f)
743 743 util.unlinkpath(repo.wjoin(f))
744 744
745 745 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
746 746
747 747 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
748 748 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
749 749
750 750 # remove in parallel (must come first)
751 751 z = 0
752 752 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
753 753 for i, item in prog:
754 754 z += i
755 755 progress(_updating, z, item=item, total=numupdates, unit=_files)
756 756 removed = len(actions['r'])
757 757
758 758 # get in parallel
759 759 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
760 760 for i, item in prog:
761 761 z += i
762 762 progress(_updating, z, item=item, total=numupdates, unit=_files)
763 763 updated = len(actions['g'])
764 764
765 765 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
766 766 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
767 767
768 768 # forget (manifest only, just log it) (must come first)
769 769 for f, args, msg in actions['f']:
770 770 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
771 771 z += 1
772 772 progress(_updating, z, item=f, total=numupdates, unit=_files)
773 773
774 774 # re-add (manifest only, just log it)
775 775 for f, args, msg in actions['a']:
776 776 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
777 777 z += 1
778 778 progress(_updating, z, item=f, total=numupdates, unit=_files)
779 779
780 780 # keep (noop, just log it)
781 781 for f, args, msg in actions['k']:
782 782 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
783 783 # no progress
784 784
785 785 # merge
786 786 for f, args, msg in actions['m']:
787 787 repo.ui.debug(" %s: %s -> m\n" % (f, msg))
788 788 z += 1
789 789 progress(_updating, z, item=f, total=numupdates, unit=_files)
790 790 if f == '.hgsubstate': # subrepo states need updating
791 791 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
792 792 overwrite)
793 793 continue
794 794 audit(f)
795 795 r = ms.resolve(f, wctx, labels=labels)
796 796 if r is not None and r > 0:
797 797 unresolved += 1
798 798 else:
799 799 if r is None:
800 800 updated += 1
801 801 else:
802 802 merged += 1
803 803
804 804 # directory rename, move local
805 805 for f, args, msg in actions['dm']:
806 806 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
807 807 z += 1
808 808 progress(_updating, z, item=f, total=numupdates, unit=_files)
809 809 f0, flags = args
810 810 repo.ui.note(_("moving %s to %s\n") % (f0, f))
811 811 audit(f)
812 812 repo.wwrite(f, wctx.filectx(f0).data(), flags)
813 813 util.unlinkpath(repo.wjoin(f0))
814 814 updated += 1
815 815
816 816 # local directory rename, get
817 817 for f, args, msg in actions['dg']:
818 818 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
819 819 z += 1
820 820 progress(_updating, z, item=f, total=numupdates, unit=_files)
821 821 f0, flags = args
822 822 repo.ui.note(_("getting %s to %s\n") % (f0, f))
823 823 repo.wwrite(f, mctx.filectx(f0).data(), flags)
824 824 updated += 1
825 825
826 826 # divergent renames
827 827 for f, args, msg in actions['dr']:
828 828 repo.ui.debug(" %s: %s -> dr\n" % (f, msg))
829 829 z += 1
830 830 progress(_updating, z, item=f, total=numupdates, unit=_files)
831 831 fl, = args
832 832 repo.ui.warn(_("note: possible conflict - %s was renamed "
833 833 "multiple times to:\n") % f)
834 834 for nf in fl:
835 835 repo.ui.warn(" %s\n" % nf)
836 836
837 837 # rename and delete
838 838 for f, args, msg in actions['rd']:
839 839 repo.ui.debug(" %s: %s -> rd\n" % (f, msg))
840 840 z += 1
841 841 progress(_updating, z, item=f, total=numupdates, unit=_files)
842 842 fl, = args
843 843 repo.ui.warn(_("note: possible conflict - %s was deleted "
844 844 "and renamed to:\n") % f)
845 845 for nf in fl:
846 846 repo.ui.warn(" %s\n" % nf)
847 847
848 848 # exec
849 849 for f, args, msg in actions['e']:
850 850 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
851 851 z += 1
852 852 progress(_updating, z, item=f, total=numupdates, unit=_files)
853 853 flags, = args
854 854 audit(f)
855 855 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
856 856 updated += 1
857 857
858 858 ms.commit()
859 859 progress(_updating, None, total=numupdates, unit=_files)
860 860
861 861 return updated, merged, removed, unresolved
862 862
863 863 def recordupdates(repo, actions, branchmerge):
864 864 "record merge actions to the dirstate"
865 865 # remove (must come first)
866 866 for f, args, msg in actions['r']:
867 867 if branchmerge:
868 868 repo.dirstate.remove(f)
869 869 else:
870 870 repo.dirstate.drop(f)
871 871
872 872 # forget (must come first)
873 873 for f, args, msg in actions['f']:
874 874 repo.dirstate.drop(f)
875 875
876 876 # re-add
877 877 for f, args, msg in actions['a']:
878 878 if not branchmerge:
879 879 repo.dirstate.add(f)
880 880
881 881 # exec change
882 882 for f, args, msg in actions['e']:
883 883 repo.dirstate.normallookup(f)
884 884
885 885 # keep
886 886 for f, args, msg in actions['k']:
887 887 pass
888 888
889 889 # get
890 890 for f, args, msg in actions['g']:
891 891 if branchmerge:
892 892 repo.dirstate.otherparent(f)
893 893 else:
894 894 repo.dirstate.normal(f)
895 895
896 896 # merge
897 897 for f, args, msg in actions['m']:
898 898 f1, f2, fa, move, anc = args
899 899 if branchmerge:
900 900 # We've done a branch merge, mark this file as merged
901 901 # so that we properly record the merger later
902 902 repo.dirstate.merge(f)
903 903 if f1 != f2: # copy/rename
904 904 if move:
905 905 repo.dirstate.remove(f1)
906 906 if f1 != f:
907 907 repo.dirstate.copy(f1, f)
908 908 else:
909 909 repo.dirstate.copy(f2, f)
910 910 else:
911 911 # We've update-merged a locally modified file, so
912 912 # we set the dirstate to emulate a normal checkout
913 913 # of that file some time in the past. Thus our
914 914 # merge will appear as a normal local file
915 915 # modification.
916 916 if f2 == f: # file not locally copied/moved
917 917 repo.dirstate.normallookup(f)
918 918 if move:
919 919 repo.dirstate.drop(f1)
920 920
921 921 # directory rename, move local
922 922 for f, args, msg in actions['dm']:
923 923 f0, flag = args
924 924 if branchmerge:
925 925 repo.dirstate.add(f)
926 926 repo.dirstate.remove(f0)
927 927 repo.dirstate.copy(f0, f)
928 928 else:
929 929 repo.dirstate.normal(f)
930 930 repo.dirstate.drop(f0)
931 931
932 932 # directory rename, get
933 933 for f, args, msg in actions['dg']:
934 934 f0, flag = args
935 935 if branchmerge:
936 936 repo.dirstate.add(f)
937 937 repo.dirstate.copy(f0, f)
938 938 else:
939 939 repo.dirstate.normal(f)
940 940
941 941 def update(repo, node, branchmerge, force, partial, ancestor=None,
942 942 mergeancestor=False, labels=None):
943 943 """
944 944 Perform a merge between the working directory and the given node
945 945
946 946 node = the node to update to, or None if unspecified
947 947 branchmerge = whether to merge between branches
948 948 force = whether to force branch merging or file overwriting
949 949 partial = a function to filter file lists (dirstate not updated)
950 950 mergeancestor = whether it is merging with an ancestor. If true,
951 951 we should accept the incoming changes for any prompts that occur.
952 952 If false, merging with an ancestor (fast-forward) is only allowed
953 953 between different named branches. This flag is used by rebase extension
954 954 as a temporary fix and should be avoided in general.
955 955
956 956 The table below shows all the behaviors of the update command
957 957 given the -c and -C or no options, whether the working directory
958 958 is dirty, whether a revision is specified, and the relationship of
959 959 the parent rev to the target rev (linear, on the same named
960 960 branch, or on another named branch).
961 961
962 962 This logic is tested by test-update-branches.t.
963 963
964 964 -c -C dirty rev | linear same cross
965 965 n n n n | ok (1) x
966 966 n n n y | ok ok ok
967 967 n n y n | merge (2) (2)
968 968 n n y y | merge (3) (3)
969 969 n y * * | --- discard ---
970 970 y n y * | --- (4) ---
971 971 y n n * | --- ok ---
972 972 y y * * | --- (5) ---
973 973
974 974 x = can't happen
975 975 * = don't-care
976 976 1 = abort: not a linear update (merge or update --check to force update)
977 977 2 = abort: uncommitted changes (commit and merge, or update --clean to
978 978 discard changes)
979 979 3 = abort: uncommitted changes (commit or update --clean to discard changes)
980 980 4 = abort: uncommitted changes (checked in commands.py)
981 981 5 = incompatible options (checked in commands.py)
982 982
983 983 Return the same tuple as applyupdates().
984 984 """
985 985
986 986 onode = node
987 987 wlock = repo.wlock()
988 988 try:
989 989 wc = repo[None]
990 990 pl = wc.parents()
991 991 p1 = pl[0]
992 992 pas = [None]
993 993 if ancestor is not None:
994 994 pas = [repo[ancestor]]
995 995
996 996 if node is None:
997 997 # Here is where we should consider bookmarks, divergent bookmarks,
998 998 # foreground changesets (successors), and tip of current branch;
999 999 # but currently we are only checking the branch tips.
1000 1000 try:
1001 1001 node = repo.branchtip(wc.branch())
1002 1002 except errormod.RepoLookupError:
1003 1003 if wc.branch() == 'default': # no default branch!
1004 1004 node = repo.lookup('tip') # update to tip
1005 1005 else:
1006 1006 raise util.Abort(_("branch %s not found") % wc.branch())
1007 1007
1008 1008 if p1.obsolete() and not p1.children():
1009 1009 # allow updating to successors
1010 1010 successors = obsolete.successorssets(repo, p1.node())
1011 1011
1012 1012 # behavior of certain cases is as follows,
1013 1013 #
1014 1014 # divergent changesets: update to highest rev, similar to what
1015 1015 # is currently done when there are more than one head
1016 1016 # (i.e. 'tip')
1017 1017 #
1018 1018 # replaced changesets: same as divergent except we know there
1019 1019 # is no conflict
1020 1020 #
1021 1021 # pruned changeset: no update is done; though, we could
1022 1022 # consider updating to the first non-obsolete parent,
1023 1023 # similar to what is current done for 'hg prune'
1024 1024
1025 1025 if successors:
1026 1026 # flatten the list here handles both divergent (len > 1)
1027 1027 # and the usual case (len = 1)
1028 1028 successors = [n for sub in successors for n in sub]
1029 1029
1030 1030 # get the max revision for the given successors set,
1031 1031 # i.e. the 'tip' of a set
1032 1032 node = repo.revs('max(%ln)', successors).first()
1033 1033 pas = [p1]
1034 1034
1035 1035 overwrite = force and not branchmerge
1036 1036
1037 1037 p2 = repo[node]
1038 1038 if pas[0] is None:
1039 1039 if repo.ui.config('merge', 'preferancestor', '*') == '*':
1040 1040 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1041 1041 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1042 1042 else:
1043 1043 pas = [p1.ancestor(p2, warn=branchmerge)]
1044 1044
1045 1045 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1046 1046
1047 1047 ### check phase
1048 1048 if not overwrite and len(pl) > 1:
1049 1049 raise util.Abort(_("outstanding uncommitted merge"))
1050 1050 if branchmerge:
1051 1051 if pas == [p2]:
1052 1052 raise util.Abort(_("merging with a working directory ancestor"
1053 1053 " has no effect"))
1054 1054 elif pas == [p1]:
1055 1055 if not mergeancestor and p1.branch() == p2.branch():
1056 1056 raise util.Abort(_("nothing to merge"),
1057 1057 hint=_("use 'hg update' "
1058 1058 "or check 'hg heads'"))
1059 1059 if not force and (wc.files() or wc.deleted()):
1060 1060 raise util.Abort(_("uncommitted changes"),
1061 1061 hint=_("use 'hg status' to list changes"))
1062 1062 for s in sorted(wc.substate):
1063 1063 if wc.sub(s).dirty():
1064 1064 raise util.Abort(_("uncommitted changes in "
1065 1065 "subrepository '%s'") % s)
1066 1066
1067 1067 elif not overwrite:
1068 1068 if p1 == p2: # no-op update
1069 1069 # call the hooks and exit early
1070 1070 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1071 1071 repo.hook('update', parent1=xp2, parent2='', error=0)
1072 1072 return 0, 0, 0, 0
1073 1073
1074 1074 if pas not in ([p1], [p2]): # nonlinear
1075 1075 dirty = wc.dirty(missing=True)
1076 1076 if dirty or onode is None:
1077 1077 # Branching is a bit strange to ensure we do the minimal
1078 1078 # amount of call to obsolete.background.
1079 1079 foreground = obsolete.foreground(repo, [p1.node()])
1080 1080 # note: the <node> variable contains a random identifier
1081 1081 if repo[node].node() in foreground:
1082 1082 pas = [p1] # allow updating to successors
1083 1083 elif dirty:
1084 1084 msg = _("uncommitted changes")
1085 1085 if onode is None:
1086 1086 hint = _("commit and merge, or update --clean to"
1087 1087 " discard changes")
1088 1088 else:
1089 1089 hint = _("commit or update --clean to discard"
1090 1090 " changes")
1091 1091 raise util.Abort(msg, hint=hint)
1092 1092 else: # node is none
1093 1093 msg = _("not a linear update")
1094 1094 hint = _("merge or update --check to force update")
1095 1095 raise util.Abort(msg, hint=hint)
1096 1096 else:
1097 1097 # Allow jumping branches if clean and specific rev given
1098 1098 pas = [p1]
1099 1099
1100 1100 followcopies = False
1101 1101 if overwrite:
1102 1102 pas = [wc]
1103 1103 elif pas == [p2]: # backwards
1104 1104 pas = [wc.p1()]
1105 1105 elif not branchmerge and not wc.dirty(missing=True):
1106 1106 pass
1107 1107 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1108 1108 followcopies = True
1109 1109
1110 1110 ### calculate phase
1111 1111 actions = calculateupdates(repo, wc, p2, pas, branchmerge, force,
1112 1112 partial, mergeancestor, followcopies)
1113 1113
1114 1114 ### apply phase
1115 1115 if not branchmerge: # just jump to the new rev
1116 1116 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1117 1117 if not partial:
1118 1118 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1119 1119 # note that we're in the middle of an update
1120 1120 repo.vfs.write('updatestate', p2.hex())
1121 1121
1122 1122 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1123 1123
1124 1124 if not partial:
1125 1125 repo.dirstate.beginparentchange()
1126 1126 repo.setparents(fp1, fp2)
1127 1127 recordupdates(repo, actions, branchmerge)
1128 1128 # update completed, clear state
1129 1129 util.unlink(repo.join('updatestate'))
1130 1130
1131 1131 if not branchmerge:
1132 1132 repo.dirstate.setbranch(p2.branch())
1133 1133 repo.dirstate.endparentchange()
1134 1134 finally:
1135 1135 wlock.release()
1136 1136
1137 1137 if not partial:
1138 1138 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1139 1139 return stats
1140 1140
1141 1141 def graft(repo, ctx, pctx, labels):
1142 1142 """Do a graft-like merge.
1143 1143
1144 1144 This is a merge where the merge ancestor is chosen such that one
1145 1145 or more changesets are grafted onto the current changeset. In
1146 1146 addition to the merge, this fixes up the dirstate to include only
1147 1147 a single parent and tries to duplicate any renames/copies
1148 1148 appropriately.
1149 1149
1150 1150 ctx - changeset to rebase
1151 1151 pctx - merge base, usually ctx.p1()
1152 1152 labels - merge labels eg ['local', 'graft']
1153 1153
1154 1154 """
1155 1155
1156 1156 stats = update(repo, ctx.node(), True, True, False, pctx.node(),
1157 1157 labels=labels)
1158 1158 # drop the second merge parent
1159 1159 repo.dirstate.beginparentchange()
1160 1160 repo.setparents(repo['.'].node(), nullid)
1161 1161 repo.dirstate.write()
1162 1162 # fix up dirstate for copies and renames
1163 1163 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1164 1164 repo.dirstate.endparentchange()
1165 1165 return stats
@@ -1,712 +1,712 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
54 54 skipping ancestor revision 2
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
61 61 skipping ancestor revision 2
62 62 [255]
63 63
64 64 $ hg graft -r 1 2
65 65 skipping ancestor revision 2
66 66 skipping ancestor revision 1
67 67 [255]
68 68
69 69 Can't graft with dirty wd:
70 70
71 71 $ hg up -q 0
72 72 $ echo foo > a
73 73 $ hg graft 1
74 74 abort: uncommitted changes
75 75 [255]
76 76 $ hg revert a
77 77
78 78 Graft a rename:
79 79 (this also tests that editor is invoked if '--edit' is specified)
80 80
81 81 $ hg status --rev "2^1" --rev 2
82 82 A b
83 83 R a
84 84 $ HGEDITOR=cat hg graft 2 -u foo --edit
85 85 grafting revision 2
86 86 merging a and b to b
87 87 2
88 88
89 89
90 90 HG: Enter commit message. Lines beginning with 'HG:' are removed.
91 91 HG: Leave message empty to abort commit.
92 92 HG: --
93 93 HG: user: foo
94 94 HG: branch 'default'
95 95 HG: added b
96 96 HG: removed a
97 97 $ hg export tip --git
98 98 # HG changeset patch
99 99 # User foo
100 100 # Date 0 0
101 101 # Thu Jan 01 00:00:00 1970 +0000
102 102 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
103 103 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
104 104 2
105 105
106 106 diff --git a/a b/b
107 107 rename from a
108 108 rename to b
109 109
110 110 Look for extra:source
111 111
112 112 $ hg log --debug -r tip
113 113 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
114 114 tag: tip
115 115 phase: draft
116 116 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
117 117 parent: -1:0000000000000000000000000000000000000000
118 118 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
119 119 user: foo
120 120 date: Thu Jan 01 00:00:00 1970 +0000
121 121 files+: b
122 122 files-: a
123 123 extra: branch=default
124 124 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
125 125 description:
126 126 2
127 127
128 128
129 129
130 130 Graft out of order, skipping a merge and a duplicate
131 131 (this also tests that editor is not invoked if '--edit' is not specified)
132 132
133 133 $ hg graft 1 5 4 3 'merge()' 2 -n
134 134 skipping ungraftable merge revision 6
135 135 skipping revision 2 (already grafted to 7)
136 136 grafting revision 1
137 137 grafting revision 5
138 138 grafting revision 4
139 139 grafting revision 3
140 140
141 141 $ HGEDITOR=cat hg graft 1 5 4 3 'merge()' 2 --debug
142 142 skipping ungraftable merge revision 6
143 143 scanning for duplicate grafts
144 144 skipping revision 2 (already grafted to 7)
145 145 grafting revision 1
146 146 searching for copies back to rev 1
147 147 unmatched files in local:
148 148 b
149 149 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
150 150 src: 'a' -> dst: 'b' *
151 151 checking for directory renames
152 152 resolving manifests
153 153 branchmerge: True, force: True, partial: False
154 154 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
155 155 preserving b for resolve of b
156 156 b: local copied/moved from a -> m
157 157 updating: b 1/1 files (100.00%)
158 158 picked tool 'internal:merge' for b (binary False symlink 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 b
163 163 grafting revision 5
164 164 searching for copies back to rev 1
165 165 resolving manifests
166 166 branchmerge: True, force: True, partial: False
167 167 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
168 168 e: remote is newer -> g
169 169 getting e
170 170 updating: e 1/1 files (100.00%)
171 b: keep -> k
171 b: remote unchanged -> k
172 172 e
173 173 grafting revision 4
174 174 searching for copies back to rev 1
175 175 resolving manifests
176 176 branchmerge: True, force: True, partial: False
177 177 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
178 178 preserving e for resolve of e
179 179 d: remote is newer -> g
180 180 getting d
181 181 updating: d 1/2 files (50.00%)
182 b: keep -> k
182 b: remote unchanged -> k
183 183 e: versions differ -> m
184 184 updating: e 2/2 files (100.00%)
185 185 picked tool 'internal:merge' for e (binary False symlink False)
186 186 merging e
187 187 my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
188 188 warning: conflicts during merge.
189 189 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
190 190 abort: unresolved conflicts, can't continue
191 191 (use hg resolve and hg graft --continue)
192 192 [255]
193 193
194 194 Commit while interrupted should fail:
195 195
196 196 $ hg ci -m 'commit interrupted graft'
197 197 abort: graft in progress
198 198 (use 'hg graft --continue' or 'hg update' to abort)
199 199 [255]
200 200
201 201 Abort the graft and try committing:
202 202
203 203 $ hg up -C .
204 204 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
205 205 $ echo c >> e
206 206 $ hg ci -mtest
207 207
208 208 $ hg strip . --config extensions.mq=
209 209 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 210 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
211 211
212 212 Graft again:
213 213
214 214 $ hg graft 1 5 4 3 'merge()' 2
215 215 skipping ungraftable merge revision 6
216 216 skipping revision 2 (already grafted to 7)
217 217 skipping revision 1 (already grafted to 8)
218 218 skipping revision 5 (already grafted to 9)
219 219 grafting revision 4
220 220 merging e
221 221 warning: conflicts during merge.
222 222 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
223 223 abort: unresolved conflicts, can't continue
224 224 (use hg resolve and hg graft --continue)
225 225 [255]
226 226
227 227 Continue without resolve should fail:
228 228
229 229 $ hg graft -c
230 230 grafting revision 4
231 231 abort: unresolved merge conflicts (see hg help resolve)
232 232 [255]
233 233
234 234 Fix up:
235 235
236 236 $ echo b > e
237 237 $ hg resolve -m e
238 238 (no more unresolved files)
239 239
240 240 Continue with a revision should fail:
241 241
242 242 $ hg graft -c 6
243 243 abort: can't specify --continue and revisions
244 244 [255]
245 245
246 246 $ hg graft -c -r 6
247 247 abort: can't specify --continue and revisions
248 248 [255]
249 249
250 250 Continue for real, clobber usernames
251 251
252 252 $ hg graft -c -U
253 253 grafting revision 4
254 254 grafting revision 3
255 255
256 256 Compare with original:
257 257
258 258 $ hg diff -r 6
259 259 $ hg status --rev 0:. -C
260 260 M d
261 261 M e
262 262 A b
263 263 a
264 264 A c
265 265 a
266 266 R a
267 267
268 268 View graph:
269 269
270 270 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
271 271 @ test@11.draft: 3
272 272 |
273 273 o test@10.draft: 4
274 274 |
275 275 o test@9.draft: 5
276 276 |
277 277 o bar@8.draft: 1
278 278 |
279 279 o foo@7.draft: 2
280 280 |
281 281 | o test@6.secret: 6
282 282 | |\
283 283 | | o test@5.draft: 5
284 284 | | |
285 285 | o | test@4.draft: 4
286 286 | |/
287 287 | o baz@3.public: 3
288 288 | |
289 289 | o test@2.public: 2
290 290 | |
291 291 | o bar@1.public: 1
292 292 |/
293 293 o test@0.public: 0
294 294
295 295 Graft again onto another branch should preserve the original source
296 296 $ hg up -q 0
297 297 $ echo 'g'>g
298 298 $ hg add g
299 299 $ hg ci -m 7
300 300 created new head
301 301 $ hg graft 7
302 302 grafting revision 7
303 303
304 304 $ hg log -r 7 --template '{rev}:{node}\n'
305 305 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
306 306 $ hg log -r 2 --template '{rev}:{node}\n'
307 307 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
308 308
309 309 $ hg log --debug -r tip
310 310 changeset: 13:9db0f28fd3747e92c57d015f53b5593aeec53c2d
311 311 tag: tip
312 312 phase: draft
313 313 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
314 314 parent: -1:0000000000000000000000000000000000000000
315 315 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
316 316 user: foo
317 317 date: Thu Jan 01 00:00:00 1970 +0000
318 318 files+: b
319 319 files-: a
320 320 extra: branch=default
321 321 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
322 322 description:
323 323 2
324 324
325 325
326 326 Disallow grafting an already grafted cset onto its original branch
327 327 $ hg up -q 6
328 328 $ hg graft 7
329 329 skipping already grafted revision 7 (was grafted from 2)
330 330 [255]
331 331
332 332 Disallow grafting already grafted csets with the same origin onto each other
333 333 $ hg up -q 13
334 334 $ hg graft 2
335 335 skipping revision 2 (already grafted to 13)
336 336 [255]
337 337 $ hg graft 7
338 338 skipping already grafted revision 7 (13 also has origin 2)
339 339 [255]
340 340
341 341 $ hg up -q 7
342 342 $ hg graft 2
343 343 skipping revision 2 (already grafted to 7)
344 344 [255]
345 345 $ hg graft tip
346 346 skipping already grafted revision 13 (7 also has origin 2)
347 347 [255]
348 348
349 349 Graft with --log
350 350
351 351 $ hg up -Cq 1
352 352 $ hg graft 3 --log -u foo
353 353 grafting revision 3
354 354 warning: can't find ancestor for 'c' copied from 'b'!
355 355 $ hg log --template '{rev} {parents} {desc}\n' -r tip
356 356 14 1:5d205f8b35b6 3
357 357 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
358 358
359 359 Resolve conflicted graft
360 360 $ hg up -q 0
361 361 $ echo b > a
362 362 $ hg ci -m 8
363 363 created new head
364 364 $ echo c > a
365 365 $ hg ci -m 9
366 366 $ hg graft 1 --tool internal:fail
367 367 grafting revision 1
368 368 abort: unresolved conflicts, can't continue
369 369 (use hg resolve and hg graft --continue)
370 370 [255]
371 371 $ hg resolve --all
372 372 merging a
373 373 warning: conflicts during merge.
374 374 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
375 375 [1]
376 376 $ cat a
377 377 <<<<<<< local: aaa4406d4f0a - test: 9
378 378 c
379 379 =======
380 380 b
381 381 >>>>>>> other: 5d205f8b35b6 - bar: 1
382 382 $ echo b > a
383 383 $ hg resolve -m a
384 384 (no more unresolved files)
385 385 $ hg graft -c
386 386 grafting revision 1
387 387 $ hg export tip --git
388 388 # HG changeset patch
389 389 # User bar
390 390 # Date 0 0
391 391 # Thu Jan 01 00:00:00 1970 +0000
392 392 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
393 393 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
394 394 1
395 395
396 396 diff --git a/a b/a
397 397 --- a/a
398 398 +++ b/a
399 399 @@ -1,1 +1,1 @@
400 400 -c
401 401 +b
402 402
403 403 Resolve conflicted graft with rename
404 404 $ echo c > a
405 405 $ hg ci -m 10
406 406 $ hg graft 2 --tool internal:fail
407 407 grafting revision 2
408 408 abort: unresolved conflicts, can't continue
409 409 (use hg resolve and hg graft --continue)
410 410 [255]
411 411 $ hg resolve --all
412 412 merging a and b to b
413 413 (no more unresolved files)
414 414 $ hg graft -c
415 415 grafting revision 2
416 416 $ hg export tip --git
417 417 # HG changeset patch
418 418 # User test
419 419 # Date 0 0
420 420 # Thu Jan 01 00:00:00 1970 +0000
421 421 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
422 422 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
423 423 2
424 424
425 425 diff --git a/a b/b
426 426 rename from a
427 427 rename to b
428 428
429 429 Test simple origin(), with and without args
430 430 $ hg log -r 'origin()'
431 431 changeset: 1:5d205f8b35b6
432 432 user: bar
433 433 date: Thu Jan 01 00:00:00 1970 +0000
434 434 summary: 1
435 435
436 436 changeset: 2:5c095ad7e90f
437 437 user: test
438 438 date: Thu Jan 01 00:00:00 1970 +0000
439 439 summary: 2
440 440
441 441 changeset: 3:4c60f11aa304
442 442 user: baz
443 443 date: Thu Jan 01 00:00:00 1970 +0000
444 444 summary: 3
445 445
446 446 changeset: 4:9c233e8e184d
447 447 user: test
448 448 date: Thu Jan 01 00:00:00 1970 +0000
449 449 summary: 4
450 450
451 451 changeset: 5:97f8bfe72746
452 452 branch: stable
453 453 parent: 3:4c60f11aa304
454 454 user: test
455 455 date: Thu Jan 01 00:00:00 1970 +0000
456 456 summary: 5
457 457
458 458 $ hg log -r 'origin(7)'
459 459 changeset: 2:5c095ad7e90f
460 460 user: test
461 461 date: Thu Jan 01 00:00:00 1970 +0000
462 462 summary: 2
463 463
464 464 Now transplant a graft to test following through copies
465 465 $ hg up -q 0
466 466 $ hg branch -q dev
467 467 $ hg ci -qm "dev branch"
468 468 $ hg --config extensions.transplant= transplant -q 7
469 469 $ hg log -r 'origin(.)'
470 470 changeset: 2:5c095ad7e90f
471 471 user: test
472 472 date: Thu Jan 01 00:00:00 1970 +0000
473 473 summary: 2
474 474
475 475 Test that the graft and transplant markers in extra are converted, allowing
476 476 origin() to still work. Note that these recheck the immediately preceeding two
477 477 tests.
478 478 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
479 479
480 480 The graft case
481 481 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
482 482 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
483 483 branch=default
484 484 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
485 485 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
486 486 $ hg -R ../converted log -r 'origin(7)'
487 487 changeset: 2:e0213322b2c1
488 488 user: test
489 489 date: Thu Jan 01 00:00:00 1970 +0000
490 490 summary: 2
491 491
492 492 Test that template correctly expands more than one 'extra' (issue4362)
493 493 $ hg -R ../converted log -r 7 --template "{extras % ' Extra: {extra}\n'}"
494 494 Extra: branch=default
495 495 Extra: convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
496 496 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
497 497
498 498 The transplant case
499 499 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
500 500 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
501 501 branch=dev
502 502 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
503 503 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
504 504 `h\x9b (esc)
505 505 $ hg -R ../converted log -r 'origin(tip)'
506 506 changeset: 2:e0213322b2c1
507 507 user: test
508 508 date: Thu Jan 01 00:00:00 1970 +0000
509 509 summary: 2
510 510
511 511
512 512 Test simple destination
513 513 $ hg log -r 'destination()'
514 514 changeset: 7:ef0ef43d49e7
515 515 parent: 0:68795b066622
516 516 user: foo
517 517 date: Thu Jan 01 00:00:00 1970 +0000
518 518 summary: 2
519 519
520 520 changeset: 8:6b9e5368ca4e
521 521 user: bar
522 522 date: Thu Jan 01 00:00:00 1970 +0000
523 523 summary: 1
524 524
525 525 changeset: 9:1905859650ec
526 526 user: test
527 527 date: Thu Jan 01 00:00:00 1970 +0000
528 528 summary: 5
529 529
530 530 changeset: 10:52dc0b4c6907
531 531 user: test
532 532 date: Thu Jan 01 00:00:00 1970 +0000
533 533 summary: 4
534 534
535 535 changeset: 11:882b35362a6b
536 536 user: test
537 537 date: Thu Jan 01 00:00:00 1970 +0000
538 538 summary: 3
539 539
540 540 changeset: 13:9db0f28fd374
541 541 user: foo
542 542 date: Thu Jan 01 00:00:00 1970 +0000
543 543 summary: 2
544 544
545 545 changeset: 14:f64defefacee
546 546 parent: 1:5d205f8b35b6
547 547 user: foo
548 548 date: Thu Jan 01 00:00:00 1970 +0000
549 549 summary: 3
550 550
551 551 changeset: 17:f67661df0c48
552 552 user: bar
553 553 date: Thu Jan 01 00:00:00 1970 +0000
554 554 summary: 1
555 555
556 556 changeset: 19:9627f653b421
557 557 user: test
558 558 date: Thu Jan 01 00:00:00 1970 +0000
559 559 summary: 2
560 560
561 561 changeset: 21:7e61b508e709
562 562 branch: dev
563 563 tag: tip
564 564 user: foo
565 565 date: Thu Jan 01 00:00:00 1970 +0000
566 566 summary: 2
567 567
568 568 $ hg log -r 'destination(2)'
569 569 changeset: 7:ef0ef43d49e7
570 570 parent: 0:68795b066622
571 571 user: foo
572 572 date: Thu Jan 01 00:00:00 1970 +0000
573 573 summary: 2
574 574
575 575 changeset: 13:9db0f28fd374
576 576 user: foo
577 577 date: Thu Jan 01 00:00:00 1970 +0000
578 578 summary: 2
579 579
580 580 changeset: 19:9627f653b421
581 581 user: test
582 582 date: Thu Jan 01 00:00:00 1970 +0000
583 583 summary: 2
584 584
585 585 changeset: 21:7e61b508e709
586 586 branch: dev
587 587 tag: tip
588 588 user: foo
589 589 date: Thu Jan 01 00:00:00 1970 +0000
590 590 summary: 2
591 591
592 592 Transplants of grafts can find a destination...
593 593 $ hg log -r 'destination(7)'
594 594 changeset: 21:7e61b508e709
595 595 branch: dev
596 596 tag: tip
597 597 user: foo
598 598 date: Thu Jan 01 00:00:00 1970 +0000
599 599 summary: 2
600 600
601 601 ... grafts of grafts unfortunately can't
602 602 $ hg graft -q 13
603 603 $ hg log -r 'destination(13)'
604 604 All copies of a cset
605 605 $ hg log -r 'origin(13) or destination(origin(13))'
606 606 changeset: 2:5c095ad7e90f
607 607 user: test
608 608 date: Thu Jan 01 00:00:00 1970 +0000
609 609 summary: 2
610 610
611 611 changeset: 7:ef0ef43d49e7
612 612 parent: 0:68795b066622
613 613 user: foo
614 614 date: Thu Jan 01 00:00:00 1970 +0000
615 615 summary: 2
616 616
617 617 changeset: 13:9db0f28fd374
618 618 user: foo
619 619 date: Thu Jan 01 00:00:00 1970 +0000
620 620 summary: 2
621 621
622 622 changeset: 19:9627f653b421
623 623 user: test
624 624 date: Thu Jan 01 00:00:00 1970 +0000
625 625 summary: 2
626 626
627 627 changeset: 21:7e61b508e709
628 628 branch: dev
629 629 user: foo
630 630 date: Thu Jan 01 00:00:00 1970 +0000
631 631 summary: 2
632 632
633 633 changeset: 22:1313d0a825e2
634 634 branch: dev
635 635 tag: tip
636 636 user: foo
637 637 date: Thu Jan 01 00:00:00 1970 +0000
638 638 summary: 2
639 639
640 640
641 641 graft works on complex revset
642 642
643 643 $ hg graft 'origin(13) or destination(origin(13))'
644 644 skipping ancestor revision 21
645 645 skipping ancestor revision 22
646 646 skipping revision 2 (already grafted to 22)
647 647 grafting revision 7
648 648 grafting revision 13
649 649 grafting revision 19
650 650 merging b
651 651
652 652 graft with --force (still doesn't graft merges)
653 653
654 654 $ hg graft 19 0 6
655 655 skipping ungraftable merge revision 6
656 656 skipping ancestor revision 0
657 657 skipping already grafted revision 19 (22 also has origin 2)
658 658 [255]
659 659 $ hg graft 19 0 6 --force
660 660 skipping ungraftable merge revision 6
661 661 grafting revision 19
662 662 merging b
663 663 grafting revision 0
664 664
665 665 graft --force after backout
666 666
667 667 $ echo abc > a
668 668 $ hg ci -m 28
669 669 $ hg backout 28
670 670 reverting a
671 671 changeset 29:484c03b8dfa4 backs out changeset 28:6c56f0f7f033
672 672 $ hg graft 28
673 673 skipping ancestor revision 28
674 674 [255]
675 675 $ hg graft 28 --force
676 676 grafting revision 28
677 677 merging a
678 678 $ cat a
679 679 abc
680 680
681 681 graft --continue after --force
682 682
683 683 $ echo def > a
684 684 $ hg ci -m 31
685 685 $ hg graft 28 --force --tool internal:fail
686 686 grafting revision 28
687 687 abort: unresolved conflicts, can't continue
688 688 (use hg resolve and hg graft --continue)
689 689 [255]
690 690 $ hg resolve --all
691 691 merging a
692 692 warning: conflicts during merge.
693 693 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
694 694 [1]
695 695 $ echo abc > a
696 696 $ hg resolve -m a
697 697 (no more unresolved files)
698 698 $ hg graft -c
699 699 grafting revision 28
700 700 $ cat a
701 701 abc
702 702
703 703 Continue testing same origin policy, using revision numbers from test above
704 704 but do some destructive editing of the repo:
705 705
706 706 $ hg up -qC 7
707 707 $ hg tag -l -r 13 tmp
708 708 $ hg --config extensions.mq= strip 2
709 709 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-backup.hg (glob)
710 710 $ hg graft tmp
711 711 skipping already grafted revision 8 (2 also has unknown origin 5c095ad7e90f871700f02dd1fa5012cb4498a2d4)
712 712 [255]
@@ -1,102 +1,102 b''
1 1 http://mercurial.selenic.com/bts/issue672
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 updating: 1 1/2 files (50.00%)
40 40 1a: remote created -> g
41 41 getting 1a
42 42 updating: 1a 2/2 files (100.00%)
43 2: keep -> k
43 2: remote unchanged -> k
44 44 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
45 45 (branch merge, don't forget to commit)
46 46
47 47 $ hg ci -m merge1 # 3
48 48
49 49 $ hg co -C 2
50 50 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 51
52 52 $ echo hello >> 1
53 53 $ hg ci -m unrelated2 # 4
54 54 created new head
55 55
56 56 $ hg co -C 3
57 57 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
58 58
59 59 $ hg merge -y --debug 4
60 60 searching for copies back to rev 1
61 61 unmatched files in local:
62 62 1a
63 63 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
64 64 src: '1' -> dst: '1a' *
65 65 checking for directory renames
66 66 resolving manifests
67 67 branchmerge: True, force: False, partial: False
68 68 ancestor: c64f439569a9, local: e327dca35ac8+, remote: 746e9549ea96
69 69 preserving 1a for resolve of 1a
70 70 1a: local copied/moved from 1 -> m
71 71 updating: 1a 1/1 files (100.00%)
72 72 picked tool 'internal:merge' for 1a (binary False symlink False)
73 73 merging 1a and 1 to 1a
74 74 my 1a@e327dca35ac8+ other 1@746e9549ea96 ancestor 1@81f4b099af3d
75 75 premerge successful
76 76 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
77 77 (branch merge, don't forget to commit)
78 78
79 79 $ hg co -C 4
80 80 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
81 81
82 82 $ hg merge -y --debug 3
83 83 searching for copies back to rev 1
84 84 unmatched files in other:
85 85 1a
86 86 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
87 87 src: '1' -> dst: '1a' *
88 88 checking for directory renames
89 89 resolving manifests
90 90 branchmerge: True, force: False, partial: False
91 91 ancestor: c64f439569a9, local: 746e9549ea96+, remote: e327dca35ac8
92 92 preserving 1 for resolve of 1a
93 93 removing 1
94 94 1a: remote moved from 1 -> m
95 95 updating: 1a 1/1 files (100.00%)
96 96 picked tool 'internal:merge' for 1a (binary False symlink False)
97 97 merging 1 and 1a to 1a
98 98 my 1a@746e9549ea96+ other 1a@e327dca35ac8 ancestor 1@81f4b099af3d
99 99 premerge successful
100 100 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
101 101 (branch merge, don't forget to commit)
102 102
@@ -1,354 +1,354 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 updating: f1 1/2 files (50.00%)
86 86 f2: versions differ -> m
87 87 updating: f2 2/2 files (100.00%)
88 88 picked tool 'internal:dump' for f2 (binary False symlink False)
89 89 merging f2
90 90 my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@40494bf2444c
91 91 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
92 92 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
93 93 [1]
94 94
95 95 $ head *
96 96 ==> f1 <==
97 97 5 second change
98 98
99 99 ==> f2 <==
100 100 6 second change
101 101
102 102 ==> f2.base <==
103 103 0 base
104 104
105 105 ==> f2.local <==
106 106 6 second change
107 107
108 108 ==> f2.orig <==
109 109 6 second change
110 110
111 111 ==> f2.other <==
112 112 2 first change
113 113
114 114 $ hg up -qC .
115 115 $ hg merge -v --tool internal:dump 5 --config merge.preferancestor="null 40663881 3b08d"
116 116 note: using 40663881a6dd as ancestor of 3b08d01b0ab5 and adfe50279922
117 117 alternatively, use --config merge.preferancestor=0f6b37dbe527
118 118 resolving manifests
119 119 merging f1
120 120 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
121 121 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
122 122 [1]
123 123
124 124 Redo merge with merge.preferancestor="*" to enable bid merge
125 125
126 126 $ rm f*
127 127 $ hg up -qC .
128 128 $ hg merge -v --debug --tool internal:dump 5 --config merge.preferancestor="*"
129 129 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
130 130
131 131 calculating bids for ancestor 0f6b37dbe527
132 132 searching for copies back to rev 3
133 133 resolving manifests
134 134 branchmerge: True, force: False, partial: False
135 135 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
136 136 f1: remote is newer -> g
137 137 f2: versions differ -> m
138 138
139 139 calculating bids for ancestor 40663881a6dd
140 140 searching for copies back to rev 3
141 141 resolving manifests
142 142 branchmerge: True, force: False, partial: False
143 143 ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
144 f2: keep -> k
144 f2: remote unchanged -> k
145 145 f1: versions differ -> m
146 146
147 147 auction for merging merge bids
148 148 f1: picking 'get' action
149 149 f2: picking 'keep' action
150 150 end of auction
151 151
152 152 f1: remote is newer -> g
153 153 getting f1
154 154 updating: f1 1/1 files (100.00%)
155 f2: keep -> k
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 f1: keep -> k
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 f2: remote is newer -> g
188 188 f1: versions differ -> m
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 updating: f2 1/1 files (100.00%)
198 f1: keep -> k
198 f1: remote unchanged -> k
199 199 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 200 (branch merge, don't forget to commit)
201 201
202 202 $ head *
203 203 ==> f1 <==
204 204 5 second change
205 205
206 206 ==> f2 <==
207 207 6 second change
208 208
209 209 Verify how the output looks and and how verbose it is:
210 210
211 211 $ hg up -qC
212 212 $ hg merge
213 213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
214 214 (branch merge, don't forget to commit)
215 215
216 216 $ hg up -qC
217 217 $ hg merge -v
218 218 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
219 219
220 220 calculating bids for ancestor 0f6b37dbe527
221 221 resolving manifests
222 222
223 223 calculating bids for ancestor 40663881a6dd
224 224 resolving manifests
225 225
226 226 auction for merging merge bids
227 227 f1: picking 'get' action
228 228 f2: picking 'keep' action
229 229 end of auction
230 230
231 231 getting f1
232 232 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 233 (branch merge, don't forget to commit)
234 234
235 235 $ hg up -qC
236 236 $ hg merge -v --debug --config merge.preferancestor="*"
237 237 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
238 238
239 239 calculating bids for ancestor 0f6b37dbe527
240 240 searching for copies back to rev 3
241 241 resolving manifests
242 242 branchmerge: True, force: False, partial: False
243 243 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
244 244 f1: remote is newer -> g
245 245 f2: versions differ -> m
246 246
247 247 calculating bids for ancestor 40663881a6dd
248 248 searching for copies back to rev 3
249 249 resolving manifests
250 250 branchmerge: True, force: False, partial: False
251 251 ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
252 f2: keep -> k
252 f2: remote unchanged -> k
253 253 f1: versions differ -> m
254 254
255 255 auction for merging merge bids
256 256 f1: picking 'get' action
257 257 f2: picking 'keep' action
258 258 end of auction
259 259
260 260 f1: remote is newer -> g
261 261 getting f1
262 262 updating: f1 1/1 files (100.00%)
263 f2: keep -> k
263 f2: remote unchanged -> k
264 264 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
265 265 (branch merge, don't forget to commit)
266 266
267 267 $ cd ..
268 268
269 269 http://stackoverflow.com/questions/9350005/how-do-i-specify-a-merge-base-to-use-in-a-hg-merge/9430810
270 270
271 271 $ hg init ancestor-merging
272 272 $ cd ancestor-merging
273 273 $ echo a > x
274 274 $ hg commit -A -m a x
275 275 $ hg update -q 0
276 276 $ echo b >> x
277 277 $ hg commit -m b
278 278 $ hg update -q 0
279 279 $ echo c >> x
280 280 $ hg commit -qm c
281 281 $ hg update -q 1
282 282 $ hg merge -q --tool internal:local 2
283 283 $ echo c >> x
284 284 $ hg commit -m bc
285 285 $ hg update -q 2
286 286 $ hg merge -q --tool internal:local 1
287 287 $ echo b >> x
288 288 $ hg commit -qm cb
289 289
290 290 $ hg merge --config merge.preferancestor='!'
291 291 note: using 70008a2163f6 as ancestor of 0d355fdef312 and 4b8b546a3eef
292 292 alternatively, use --config merge.preferancestor=b211bbc6eb3c
293 293 merging x
294 294 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
295 295 (branch merge, don't forget to commit)
296 296 $ cat x
297 297 a
298 298 c
299 299 b
300 300 c
301 301
302 302 $ hg up -qC .
303 303
304 304 $ hg merge --config merge.preferancestor=b211bbc6eb3c
305 305 note: using b211bbc6eb3c as ancestor of 0d355fdef312 and 4b8b546a3eef
306 306 alternatively, use --config merge.preferancestor=70008a2163f6
307 307 merging x
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 $ cat x
311 311 a
312 312 b
313 313 c
314 314 b
315 315
316 316 $ hg up -qC .
317 317
318 318 $ hg merge -v --config merge.preferancestor="*"
319 319 note: merging 0d355fdef312+ and 4b8b546a3eef using bids from ancestors 70008a2163f6 and b211bbc6eb3c
320 320
321 321 calculating bids for ancestor 70008a2163f6
322 322 resolving manifests
323 323
324 324 calculating bids for ancestor b211bbc6eb3c
325 325 resolving manifests
326 326
327 327 auction for merging merge bids
328 328 x: multiple bids for merge action:
329 329 versions differ -> m
330 330 versions differ -> m
331 331 x: ambiguous merge - picked m action
332 332 end of auction
333 333
334 334 merging x
335 335 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
336 336 (branch merge, don't forget to commit)
337 337 $ cat x
338 338 a
339 339 c
340 340 b
341 341 c
342 342
343 343 Verify that the old context ancestor works with / despite preferancestor:
344 344
345 345 $ hg log -r 'ancestor(head())' --config merge.preferancestor=1 -T '{rev}\n'
346 346 1
347 347 $ hg log -r 'ancestor(head())' --config merge.preferancestor=2 -T '{rev}\n'
348 348 2
349 349 $ hg log -r 'ancestor(head())' --config merge.preferancestor=3 -T '{rev}\n'
350 350 1
351 351 $ hg log -r 'ancestor(head())' --config merge.preferancestor='1337 * - 2' -T '{rev}\n'
352 352 2
353 353
354 354 $ cd ..
@@ -1,962 +1,962 b''
1 1
2 2 $ mkdir -p t
3 3 $ cd t
4 4 $ cat <<EOF > merge
5 5 > import sys, os
6 6 > f = open(sys.argv[1], "wb")
7 7 > f.write("merge %s %s %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
8 8 > f.close()
9 9 > EOF
10 10
11 11 perform a test merge with possible renaming
12 12 args:
13 13 $1 = action in local branch
14 14 $2 = action in remote branch
15 15 $3 = action in working dir
16 16 $4 = expected result
17 17
18 18 $ tm()
19 19 > {
20 20 > hg init t
21 21 > cd t
22 22 > echo "[merge]" >> .hg/hgrc
23 23 > echo "followcopies = 1" >> .hg/hgrc
24 24 >
25 25 > # base
26 26 > echo base > a
27 27 > echo base > rev # used to force commits
28 28 > hg add a rev
29 29 > hg ci -m "base"
30 30 >
31 31 > # remote
32 32 > echo remote > rev
33 33 > if [ "$2" != "" ] ; then $2 ; fi
34 34 > hg ci -m "remote"
35 35 >
36 36 > # local
37 37 > hg co -q 0
38 38 > echo local > rev
39 39 > if [ "$1" != "" ] ; then $1 ; fi
40 40 > hg ci -m "local"
41 41 >
42 42 > # working dir
43 43 > echo local > rev
44 44 > if [ "$3" != "" ] ; then $3 ; fi
45 45 >
46 46 > # merge
47 47 > echo "--------------"
48 48 > echo "test L:$1 R:$2 W:$3 - $4"
49 49 > echo "--------------"
50 50 > hg merge -y --debug --traceback --tool="python ../merge"
51 51 >
52 52 > echo "--------------"
53 53 > hg status -camC -X rev
54 54 >
55 55 > hg ci -m "merge"
56 56 >
57 57 > echo "--------------"
58 58 > echo
59 59 >
60 60 > cd ..
61 61 > rm -r t
62 62 > }
63 63 $ up() {
64 64 > cp rev $1
65 65 > hg add $1 2> /dev/null
66 66 > if [ "$2" != "" ] ; then
67 67 > cp rev $2
68 68 > hg add $2 2> /dev/null
69 69 > fi
70 70 > }
71 71 $ uc() { up $1; hg cp $1 $2; } # update + copy
72 72 $ um() { up $1; hg mv $1 $2; }
73 73 $ nc() { hg cp $1 $2; } # just copy
74 74 $ nm() { hg mv $1 $2; } # just move
75 75 $ tm "up a " "nc a b" " " "1 get local a to b"
76 76 created new head
77 77 --------------
78 78 test L:up a R:nc a b W: - 1 get local a to b
79 79 --------------
80 80 searching for copies back to rev 1
81 81 unmatched files in other:
82 82 b
83 83 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
84 84 src: 'a' -> dst: 'b' *
85 85 checking for directory renames
86 86 resolving manifests
87 87 branchmerge: True, force: False, partial: False
88 88 ancestor: 924404dff337, local: e300d1c794ec+, remote: 4ce40f5aca24
89 89 preserving a for resolve of b
90 90 preserving rev for resolve of rev
91 a: keep -> k
91 a: remote unchanged -> k
92 92 b: remote copied from a -> m
93 93 updating: b 1/2 files (50.00%)
94 94 picked tool 'python ../merge' for b (binary False symlink False)
95 95 merging a and b to b
96 96 my b@e300d1c794ec+ other b@4ce40f5aca24 ancestor a@924404dff337
97 97 premerge successful
98 98 rev: versions differ -> m
99 99 updating: rev 2/2 files (100.00%)
100 100 picked tool 'python ../merge' for rev (binary False symlink False)
101 101 merging rev
102 102 my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
103 103 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
104 104 (branch merge, don't forget to commit)
105 105 --------------
106 106 M b
107 107 a
108 108 C a
109 109 --------------
110 110
111 111 $ tm "nc a b" "up a " " " "2 get rem change to a and b"
112 112 created new head
113 113 --------------
114 114 test L:nc a b R:up a W: - 2 get rem change to a and b
115 115 --------------
116 116 searching for copies back to rev 1
117 117 unmatched files in local:
118 118 b
119 119 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
120 120 src: 'a' -> dst: 'b' *
121 121 checking for directory renames
122 122 resolving manifests
123 123 branchmerge: True, force: False, partial: False
124 124 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: f4db7e329e71
125 125 preserving b for resolve of b
126 126 preserving rev for resolve of rev
127 127 a: remote is newer -> g
128 128 getting a
129 129 updating: a 1/3 files (33.33%)
130 130 b: local copied/moved from a -> m
131 131 updating: b 2/3 files (66.67%)
132 132 picked tool 'python ../merge' for b (binary False symlink False)
133 133 merging b and a to b
134 134 my b@86a2aa42fc76+ other a@f4db7e329e71 ancestor a@924404dff337
135 135 premerge successful
136 136 rev: versions differ -> m
137 137 updating: rev 3/3 files (100.00%)
138 138 picked tool 'python ../merge' for rev (binary False symlink False)
139 139 merging rev
140 140 my rev@86a2aa42fc76+ other rev@f4db7e329e71 ancestor rev@924404dff337
141 141 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
142 142 (branch merge, don't forget to commit)
143 143 --------------
144 144 M a
145 145 M b
146 146 a
147 147 --------------
148 148
149 149 $ tm "up a " "nm a b" " " "3 get local a change to b, remove a"
150 150 created new head
151 151 --------------
152 152 test L:up a R:nm a b W: - 3 get local a change to b, remove a
153 153 --------------
154 154 searching for copies back to rev 1
155 155 unmatched files in other:
156 156 b
157 157 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
158 158 src: 'a' -> dst: 'b' *
159 159 checking for directory renames
160 160 resolving manifests
161 161 branchmerge: True, force: False, partial: False
162 162 ancestor: 924404dff337, local: e300d1c794ec+, remote: bdb19105162a
163 163 preserving a for resolve of b
164 164 preserving rev for resolve of rev
165 165 removing a
166 166 b: remote moved from a -> m
167 167 updating: b 1/2 files (50.00%)
168 168 picked tool 'python ../merge' for b (binary False symlink False)
169 169 merging a and b to b
170 170 my b@e300d1c794ec+ other b@bdb19105162a ancestor a@924404dff337
171 171 premerge successful
172 172 rev: versions differ -> m
173 173 updating: rev 2/2 files (100.00%)
174 174 picked tool 'python ../merge' for rev (binary False symlink False)
175 175 merging rev
176 176 my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
177 177 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
178 178 (branch merge, don't forget to commit)
179 179 --------------
180 180 M b
181 181 a
182 182 --------------
183 183
184 184 $ tm "nm a b" "up a " " " "4 get remote change to b"
185 185 created new head
186 186 --------------
187 187 test L:nm a b R:up a W: - 4 get remote change to b
188 188 --------------
189 189 searching for copies back to rev 1
190 190 unmatched files in local:
191 191 b
192 192 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
193 193 src: 'a' -> dst: 'b' *
194 194 checking for directory renames
195 195 resolving manifests
196 196 branchmerge: True, force: False, partial: False
197 197 ancestor: 924404dff337, local: 02963e448370+, remote: f4db7e329e71
198 198 preserving b for resolve of b
199 199 preserving rev for resolve of rev
200 200 b: local copied/moved from a -> m
201 201 updating: b 1/2 files (50.00%)
202 202 picked tool 'python ../merge' for b (binary False symlink False)
203 203 merging b and a to b
204 204 my b@02963e448370+ other a@f4db7e329e71 ancestor a@924404dff337
205 205 premerge successful
206 206 rev: versions differ -> m
207 207 updating: rev 2/2 files (100.00%)
208 208 picked tool 'python ../merge' for rev (binary False symlink False)
209 209 merging rev
210 210 my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
211 211 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
212 212 (branch merge, don't forget to commit)
213 213 --------------
214 214 M b
215 215 a
216 216 --------------
217 217
218 218 $ tm " " "nc a b" " " "5 get b"
219 219 created new head
220 220 --------------
221 221 test L: R:nc a b W: - 5 get b
222 222 --------------
223 223 searching for copies back to rev 1
224 224 unmatched files in other:
225 225 b
226 226 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
227 227 src: 'a' -> dst: 'b'
228 228 checking for directory renames
229 229 resolving manifests
230 230 branchmerge: True, force: False, partial: False
231 231 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: 4ce40f5aca24
232 232 preserving rev for resolve of rev
233 233 b: remote created -> g
234 234 getting b
235 235 updating: b 1/2 files (50.00%)
236 236 rev: versions differ -> m
237 237 updating: rev 2/2 files (100.00%)
238 238 picked tool 'python ../merge' for rev (binary False symlink False)
239 239 merging rev
240 240 my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
241 241 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
242 242 (branch merge, don't forget to commit)
243 243 --------------
244 244 M b
245 245 C a
246 246 --------------
247 247
248 248 $ tm "nc a b" " " " " "6 nothing"
249 249 created new head
250 250 --------------
251 251 test L:nc a b R: W: - 6 nothing
252 252 --------------
253 253 searching for copies back to rev 1
254 254 unmatched files in local:
255 255 b
256 256 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
257 257 src: 'a' -> dst: 'b'
258 258 checking for directory renames
259 259 resolving manifests
260 260 branchmerge: True, force: False, partial: False
261 261 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 97c705ade336
262 262 preserving rev for resolve of rev
263 263 rev: versions differ -> m
264 264 updating: rev 1/1 files (100.00%)
265 265 picked tool 'python ../merge' for rev (binary False symlink False)
266 266 merging rev
267 267 my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
268 268 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
269 269 (branch merge, don't forget to commit)
270 270 --------------
271 271 C a
272 272 C b
273 273 --------------
274 274
275 275 $ tm " " "nm a b" " " "7 get b"
276 276 created new head
277 277 --------------
278 278 test L: R:nm a b W: - 7 get b
279 279 --------------
280 280 searching for copies back to rev 1
281 281 unmatched files in other:
282 282 b
283 283 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
284 284 src: 'a' -> dst: 'b'
285 285 checking for directory renames
286 286 resolving manifests
287 287 branchmerge: True, force: False, partial: False
288 288 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: bdb19105162a
289 289 preserving rev for resolve of rev
290 290 a: other deleted -> r
291 291 removing a
292 292 updating: a 1/3 files (33.33%)
293 293 b: remote created -> g
294 294 getting b
295 295 updating: b 2/3 files (66.67%)
296 296 rev: versions differ -> m
297 297 updating: rev 3/3 files (100.00%)
298 298 picked tool 'python ../merge' for rev (binary False symlink False)
299 299 merging rev
300 300 my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
301 301 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
302 302 (branch merge, don't forget to commit)
303 303 --------------
304 304 M b
305 305 --------------
306 306
307 307 $ tm "nm a b" " " " " "8 nothing"
308 308 created new head
309 309 --------------
310 310 test L:nm a b R: W: - 8 nothing
311 311 --------------
312 312 searching for copies back to rev 1
313 313 unmatched files in local:
314 314 b
315 315 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
316 316 src: 'a' -> dst: 'b'
317 317 checking for directory renames
318 318 resolving manifests
319 319 branchmerge: True, force: False, partial: False
320 320 ancestor: 924404dff337, local: 02963e448370+, remote: 97c705ade336
321 321 preserving rev for resolve of rev
322 322 rev: versions differ -> m
323 323 updating: rev 1/1 files (100.00%)
324 324 picked tool 'python ../merge' for rev (binary False symlink False)
325 325 merging rev
326 326 my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
327 327 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
328 328 (branch merge, don't forget to commit)
329 329 --------------
330 330 C b
331 331 --------------
332 332
333 333 $ tm "um a b" "um a b" " " "9 do merge with ancestor in a"
334 334 created new head
335 335 --------------
336 336 test L:um a b R:um a b W: - 9 do merge with ancestor in a
337 337 --------------
338 338 searching for copies back to rev 1
339 339 unmatched files new in both:
340 340 b
341 341 resolving manifests
342 342 branchmerge: True, force: False, partial: False
343 343 ancestor: 924404dff337, local: 62e7bf090eba+, remote: 49b6d8032493
344 344 preserving b for resolve of b
345 345 preserving rev for resolve of rev
346 346 b: both renamed from a -> m
347 347 updating: b 1/2 files (50.00%)
348 348 picked tool 'python ../merge' for b (binary False symlink False)
349 349 merging b
350 350 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
351 351 rev: versions differ -> m
352 352 updating: rev 2/2 files (100.00%)
353 353 picked tool 'python ../merge' for rev (binary False symlink False)
354 354 merging rev
355 355 my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
356 356 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
357 357 (branch merge, don't forget to commit)
358 358 --------------
359 359 M b
360 360 --------------
361 361
362 362
363 363 m "um a c" "um x c" " " "10 do merge with no ancestor"
364 364
365 365 $ tm "nm a b" "nm a c" " " "11 get c, keep b"
366 366 created new head
367 367 --------------
368 368 test L:nm a b R:nm a c W: - 11 get c, keep b
369 369 --------------
370 370 searching for copies back to rev 1
371 371 unmatched files in local:
372 372 b
373 373 unmatched files in other:
374 374 c
375 375 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
376 376 src: 'a' -> dst: 'b' !
377 377 src: 'a' -> dst: 'c' !
378 378 checking for directory renames
379 379 resolving manifests
380 380 branchmerge: True, force: False, partial: False
381 381 ancestor: 924404dff337, local: 02963e448370+, remote: fe905ef2c33e
382 382 preserving rev for resolve of rev
383 383 c: remote created -> g
384 384 getting c
385 385 updating: c 1/3 files (33.33%)
386 386 rev: versions differ -> m
387 387 updating: rev 2/3 files (66.67%)
388 388 picked tool 'python ../merge' for rev (binary False symlink False)
389 389 merging rev
390 390 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
391 391 a: divergent renames -> dr
392 392 updating: a 3/3 files (100.00%)
393 393 note: possible conflict - a was renamed multiple times to:
394 394 b
395 395 c
396 396 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
397 397 (branch merge, don't forget to commit)
398 398 --------------
399 399 M c
400 400 C b
401 401 --------------
402 402
403 403 $ tm "nc a b" "up b " " " "12 merge b no ancestor"
404 404 created new head
405 405 --------------
406 406 test L:nc a b R:up b W: - 12 merge b no ancestor
407 407 --------------
408 408 searching for copies back to rev 1
409 409 unmatched files new in both:
410 410 b
411 411 resolving manifests
412 412 branchmerge: True, force: False, partial: False
413 413 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: af30c7647fc7
414 414 preserving b for resolve of b
415 415 preserving rev for resolve of rev
416 416 b: both created -> m
417 417 updating: b 1/2 files (50.00%)
418 418 picked tool 'python ../merge' for b (binary False symlink False)
419 419 merging b
420 420 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
421 421 rev: versions differ -> m
422 422 updating: rev 2/2 files (100.00%)
423 423 picked tool 'python ../merge' for rev (binary False symlink False)
424 424 merging rev
425 425 my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
426 426 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
427 427 (branch merge, don't forget to commit)
428 428 --------------
429 429 M b
430 430 C a
431 431 --------------
432 432
433 433 $ tm "up b " "nm a b" " " "13 merge b no ancestor"
434 434 created new head
435 435 --------------
436 436 test L:up b R:nm a b W: - 13 merge b no ancestor
437 437 --------------
438 438 searching for copies back to rev 1
439 439 unmatched files new in both:
440 440 b
441 441 resolving manifests
442 442 branchmerge: True, force: False, partial: False
443 443 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
444 444 preserving b for resolve of b
445 445 preserving rev for resolve of rev
446 446 a: other deleted -> r
447 447 removing a
448 448 updating: a 1/3 files (33.33%)
449 449 b: both created -> m
450 450 updating: b 2/3 files (66.67%)
451 451 picked tool 'python ../merge' for b (binary False symlink False)
452 452 merging b
453 453 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
454 454 rev: versions differ -> m
455 455 updating: rev 3/3 files (100.00%)
456 456 picked tool 'python ../merge' for rev (binary False symlink False)
457 457 merging rev
458 458 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
459 459 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
460 460 (branch merge, don't forget to commit)
461 461 --------------
462 462 M b
463 463 --------------
464 464
465 465 $ tm "nc a b" "up a b" " " "14 merge b no ancestor"
466 466 created new head
467 467 --------------
468 468 test L:nc a b R:up a b W: - 14 merge b no ancestor
469 469 --------------
470 470 searching for copies back to rev 1
471 471 unmatched files new in both:
472 472 b
473 473 resolving manifests
474 474 branchmerge: True, force: False, partial: False
475 475 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
476 476 preserving b for resolve of b
477 477 preserving rev for resolve of rev
478 478 a: remote is newer -> g
479 479 getting a
480 480 updating: a 1/3 files (33.33%)
481 481 b: both created -> m
482 482 updating: b 2/3 files (66.67%)
483 483 picked tool 'python ../merge' for b (binary False symlink False)
484 484 merging b
485 485 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
486 486 rev: versions differ -> m
487 487 updating: rev 3/3 files (100.00%)
488 488 picked tool 'python ../merge' for rev (binary False symlink False)
489 489 merging rev
490 490 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
491 491 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
492 492 (branch merge, don't forget to commit)
493 493 --------------
494 494 M a
495 495 M b
496 496 --------------
497 497
498 498 $ tm "up b " "nm a b" " " "15 merge b no ancestor, remove a"
499 499 created new head
500 500 --------------
501 501 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
502 502 --------------
503 503 searching for copies back to rev 1
504 504 unmatched files new in both:
505 505 b
506 506 resolving manifests
507 507 branchmerge: True, force: False, partial: False
508 508 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
509 509 preserving b for resolve of b
510 510 preserving rev for resolve of rev
511 511 a: other deleted -> r
512 512 removing a
513 513 updating: a 1/3 files (33.33%)
514 514 b: both created -> m
515 515 updating: b 2/3 files (66.67%)
516 516 picked tool 'python ../merge' for b (binary False symlink False)
517 517 merging b
518 518 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
519 519 rev: versions differ -> m
520 520 updating: rev 3/3 files (100.00%)
521 521 picked tool 'python ../merge' for rev (binary False symlink False)
522 522 merging rev
523 523 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
524 524 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
525 525 (branch merge, don't forget to commit)
526 526 --------------
527 527 M b
528 528 --------------
529 529
530 530 $ tm "nc a b" "up a b" " " "16 get a, merge b no ancestor"
531 531 created new head
532 532 --------------
533 533 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
534 534 --------------
535 535 searching for copies back to rev 1
536 536 unmatched files new in both:
537 537 b
538 538 resolving manifests
539 539 branchmerge: True, force: False, partial: False
540 540 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
541 541 preserving b for resolve of b
542 542 preserving rev for resolve of rev
543 543 a: remote is newer -> g
544 544 getting a
545 545 updating: a 1/3 files (33.33%)
546 546 b: both created -> m
547 547 updating: b 2/3 files (66.67%)
548 548 picked tool 'python ../merge' for b (binary False symlink False)
549 549 merging b
550 550 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
551 551 rev: versions differ -> m
552 552 updating: rev 3/3 files (100.00%)
553 553 picked tool 'python ../merge' for rev (binary False symlink False)
554 554 merging rev
555 555 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
556 556 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
557 557 (branch merge, don't forget to commit)
558 558 --------------
559 559 M a
560 560 M b
561 561 --------------
562 562
563 563 $ tm "up a b" "nc a b" " " "17 keep a, merge b no ancestor"
564 564 created new head
565 565 --------------
566 566 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
567 567 --------------
568 568 searching for copies back to rev 1
569 569 unmatched files new in both:
570 570 b
571 571 resolving manifests
572 572 branchmerge: True, force: False, partial: False
573 573 ancestor: 924404dff337, local: 0b76e65c8289+, remote: 4ce40f5aca24
574 574 preserving b for resolve of b
575 575 preserving rev for resolve of rev
576 a: keep -> k
576 a: remote unchanged -> k
577 577 b: both created -> m
578 578 updating: b 1/2 files (50.00%)
579 579 picked tool 'python ../merge' for b (binary False symlink False)
580 580 merging b
581 581 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
582 582 rev: versions differ -> m
583 583 updating: rev 2/2 files (100.00%)
584 584 picked tool 'python ../merge' for rev (binary False symlink False)
585 585 merging rev
586 586 my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
587 587 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
588 588 (branch merge, don't forget to commit)
589 589 --------------
590 590 M b
591 591 C a
592 592 --------------
593 593
594 594 $ tm "nm a b" "up a b" " " "18 merge b no ancestor"
595 595 created new head
596 596 --------------
597 597 test L:nm a b R:up a b W: - 18 merge b no ancestor
598 598 --------------
599 599 searching for copies back to rev 1
600 600 unmatched files new in both:
601 601 b
602 602 resolving manifests
603 603 branchmerge: True, force: False, partial: False
604 604 ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
605 605 remote changed a which local deleted
606 606 use (c)hanged version or leave (d)eleted? c
607 607 preserving b for resolve of b
608 608 preserving rev for resolve of rev
609 609 a: prompt recreating -> g
610 610 getting a
611 611 updating: a 1/3 files (33.33%)
612 612 b: both created -> m
613 613 updating: b 2/3 files (66.67%)
614 614 picked tool 'python ../merge' for b (binary False symlink False)
615 615 merging b
616 616 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
617 617 rev: versions differ -> m
618 618 updating: rev 3/3 files (100.00%)
619 619 picked tool 'python ../merge' for rev (binary False symlink False)
620 620 merging rev
621 621 my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
622 622 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
623 623 (branch merge, don't forget to commit)
624 624 --------------
625 625 M a
626 626 M b
627 627 --------------
628 628
629 629 $ tm "up a b" "nm a b" " " "19 merge b no ancestor, prompt remove a"
630 630 created new head
631 631 --------------
632 632 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
633 633 --------------
634 634 searching for copies back to rev 1
635 635 unmatched files new in both:
636 636 b
637 637 resolving manifests
638 638 branchmerge: True, force: False, partial: False
639 639 ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
640 640 local changed a which remote deleted
641 641 use (c)hanged version or (d)elete? c
642 642 preserving b for resolve of b
643 643 preserving rev for resolve of rev
644 644 a: prompt keep -> a
645 645 updating: a 1/3 files (33.33%)
646 646 b: both created -> m
647 647 updating: b 2/3 files (66.67%)
648 648 picked tool 'python ../merge' for b (binary False symlink False)
649 649 merging b
650 650 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
651 651 rev: versions differ -> m
652 652 updating: rev 3/3 files (100.00%)
653 653 picked tool 'python ../merge' for rev (binary False symlink False)
654 654 merging rev
655 655 my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
656 656 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
657 657 (branch merge, don't forget to commit)
658 658 --------------
659 659 M b
660 660 C a
661 661 --------------
662 662
663 663 $ tm "up a " "um a b" " " "20 merge a and b to b, remove a"
664 664 created new head
665 665 --------------
666 666 test L:up a R:um a b W: - 20 merge a and b to b, remove a
667 667 --------------
668 668 searching for copies back to rev 1
669 669 unmatched files in other:
670 670 b
671 671 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
672 672 src: 'a' -> dst: 'b' *
673 673 checking for directory renames
674 674 resolving manifests
675 675 branchmerge: True, force: False, partial: False
676 676 ancestor: 924404dff337, local: e300d1c794ec+, remote: 49b6d8032493
677 677 preserving a for resolve of b
678 678 preserving rev for resolve of rev
679 679 removing a
680 680 b: remote moved from a -> m
681 681 updating: b 1/2 files (50.00%)
682 682 picked tool 'python ../merge' for b (binary False symlink False)
683 683 merging a and b to b
684 684 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
685 685 rev: versions differ -> m
686 686 updating: rev 2/2 files (100.00%)
687 687 picked tool 'python ../merge' for rev (binary False symlink False)
688 688 merging rev
689 689 my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
690 690 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
691 691 (branch merge, don't forget to commit)
692 692 --------------
693 693 M b
694 694 a
695 695 --------------
696 696
697 697 $ tm "um a b" "up a " " " "21 merge a and b to b"
698 698 created new head
699 699 --------------
700 700 test L:um a b R:up a W: - 21 merge a and b to b
701 701 --------------
702 702 searching for copies back to rev 1
703 703 unmatched files in local:
704 704 b
705 705 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
706 706 src: 'a' -> dst: 'b' *
707 707 checking for directory renames
708 708 resolving manifests
709 709 branchmerge: True, force: False, partial: False
710 710 ancestor: 924404dff337, local: 62e7bf090eba+, remote: f4db7e329e71
711 711 preserving b for resolve of b
712 712 preserving rev for resolve of rev
713 713 b: local copied/moved from a -> m
714 714 updating: b 1/2 files (50.00%)
715 715 picked tool 'python ../merge' for b (binary False symlink False)
716 716 merging b and a to b
717 717 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
718 718 rev: versions differ -> m
719 719 updating: rev 2/2 files (100.00%)
720 720 picked tool 'python ../merge' for rev (binary False symlink False)
721 721 merging rev
722 722 my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
723 723 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
724 724 (branch merge, don't forget to commit)
725 725 --------------
726 726 M b
727 727 a
728 728 --------------
729 729
730 730
731 731 m "nm a b" "um x a" " " "22 get a, keep b"
732 732
733 733 $ tm "nm a b" "up a c" " " "23 get c, keep b"
734 734 created new head
735 735 --------------
736 736 test L:nm a b R:up a c W: - 23 get c, keep b
737 737 --------------
738 738 searching for copies back to rev 1
739 739 unmatched files in local:
740 740 b
741 741 unmatched files in other:
742 742 c
743 743 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
744 744 src: 'a' -> dst: 'b' *
745 745 checking for directory renames
746 746 resolving manifests
747 747 branchmerge: True, force: False, partial: False
748 748 ancestor: 924404dff337, local: 02963e448370+, remote: 2b958612230f
749 749 preserving b for resolve of b
750 750 preserving rev for resolve of rev
751 751 c: remote created -> g
752 752 getting c
753 753 updating: c 1/3 files (33.33%)
754 754 b: local copied/moved from a -> m
755 755 updating: b 2/3 files (66.67%)
756 756 picked tool 'python ../merge' for b (binary False symlink False)
757 757 merging b and a to b
758 758 my b@02963e448370+ other a@2b958612230f ancestor a@924404dff337
759 759 premerge successful
760 760 rev: versions differ -> m
761 761 updating: rev 3/3 files (100.00%)
762 762 picked tool 'python ../merge' for rev (binary False symlink False)
763 763 merging rev
764 764 my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
765 765 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
766 766 (branch merge, don't forget to commit)
767 767 --------------
768 768 M b
769 769 a
770 770 M c
771 771 --------------
772 772
773 773
774 774 $ cd ..
775 775
776 776
777 777 Systematic and terse testing of merge merges and ancestor calculation:
778 778
779 779 Expected result:
780 780
781 781 \ a m1 m2 dst
782 782 0 - f f f "versions differ"
783 783 1 f g g g "versions differ"
784 784 2 f f f f "versions differ"
785 785 3 f f g f+g "remote copied to " + f
786 786 4 f f g g "remote moved to " + f
787 787 5 f g f f+g "local copied to " + f2
788 788 6 f g f g "local moved to " + f2
789 789 7 - (f) f f "remote differs from untracked local"
790 790 8 f (f) f f "remote differs from untracked local"
791 791
792 792 $ hg init ancestortest
793 793 $ cd ancestortest
794 794 $ for x in 1 2 3 4 5 6 8; do mkdir $x; echo a > $x/f; done
795 795 $ hg ci -Aqm "a"
796 796 $ mkdir 0
797 797 $ touch 0/f
798 798 $ hg mv 1/f 1/g
799 799 $ hg cp 5/f 5/g
800 800 $ hg mv 6/f 6/g
801 801 $ hg rm 8/f
802 802 $ for x in */*; do echo m1 > $x; done
803 803 $ hg ci -Aqm "m1"
804 804 $ hg up -qr0
805 805 $ mkdir 0 7
806 806 $ touch 0/f 7/f
807 807 $ hg mv 1/f 1/g
808 808 $ hg cp 3/f 3/g
809 809 $ hg mv 4/f 4/g
810 810 $ for x in */*; do echo m2 > $x; done
811 811 $ hg ci -Aqm "m2"
812 812 $ hg up -qr1
813 813 $ mkdir 7 8
814 814 $ echo m > 7/f
815 815 $ echo m > 8/f
816 816 $ hg merge -f --tool internal:dump -v --debug -r2 | sed '/^updating:/,$d' 2> /dev/null
817 817 searching for copies back to rev 1
818 818 unmatched files in local:
819 819 5/g
820 820 6/g
821 821 unmatched files in other:
822 822 3/g
823 823 4/g
824 824 7/f
825 825 unmatched files new in both:
826 826 0/f
827 827 1/g
828 828 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
829 829 src: '3/f' -> dst: '3/g' *
830 830 src: '4/f' -> dst: '4/g' *
831 831 src: '5/f' -> dst: '5/g' *
832 832 src: '6/f' -> dst: '6/g' *
833 833 checking for directory renames
834 834 resolving manifests
835 835 branchmerge: True, force: True, partial: False
836 836 ancestor: e6cb3cf11019, local: ec44bf929ab5+, remote: c62e34d0b898
837 837 remote changed 8/f which local deleted
838 838 use (c)hanged version or leave (d)eleted? c
839 839 preserving 0/f for resolve of 0/f
840 840 preserving 1/g for resolve of 1/g
841 841 preserving 2/f for resolve of 2/f
842 842 preserving 3/f for resolve of 3/f
843 843 preserving 3/f for resolve of 3/g
844 844 preserving 4/f for resolve of 4/g
845 845 preserving 5/f for resolve of 5/f
846 846 preserving 5/g for resolve of 5/g
847 847 preserving 6/g for resolve of 6/g
848 848 preserving 7/f for resolve of 7/f
849 849 removing 4/f
850 850 8/f: prompt recreating -> g
851 851 getting 8/f
852 852 $ hg mani
853 853 0/f
854 854 1/g
855 855 2/f
856 856 3/f
857 857 4/f
858 858 5/f
859 859 5/g
860 860 6/g
861 861 $ for f in */*; do echo $f:; cat $f; done
862 862 0/f:
863 863 m1
864 864 0/f.base:
865 865 0/f.local:
866 866 m1
867 867 0/f.orig:
868 868 m1
869 869 0/f.other:
870 870 m2
871 871 1/g:
872 872 m1
873 873 1/g.base:
874 874 a
875 875 1/g.local:
876 876 m1
877 877 1/g.orig:
878 878 m1
879 879 1/g.other:
880 880 m2
881 881 2/f:
882 882 m1
883 883 2/f.base:
884 884 a
885 885 2/f.local:
886 886 m1
887 887 2/f.orig:
888 888 m1
889 889 2/f.other:
890 890 m2
891 891 3/f:
892 892 m1
893 893 3/f.base:
894 894 a
895 895 3/f.local:
896 896 m1
897 897 3/f.orig:
898 898 m1
899 899 3/f.other:
900 900 m2
901 901 3/g:
902 902 m1
903 903 3/g.base:
904 904 a
905 905 3/g.local:
906 906 m1
907 907 3/g.orig:
908 908 m1
909 909 3/g.other:
910 910 m2
911 911 4/g:
912 912 m1
913 913 4/g.base:
914 914 a
915 915 4/g.local:
916 916 m1
917 917 4/g.orig:
918 918 m1
919 919 4/g.other:
920 920 m2
921 921 5/f:
922 922 m1
923 923 5/f.base:
924 924 a
925 925 5/f.local:
926 926 m1
927 927 5/f.orig:
928 928 m1
929 929 5/f.other:
930 930 m2
931 931 5/g:
932 932 m1
933 933 5/g.base:
934 934 a
935 935 5/g.local:
936 936 m1
937 937 5/g.orig:
938 938 m1
939 939 5/g.other:
940 940 m2
941 941 6/g:
942 942 m1
943 943 6/g.base:
944 944 a
945 945 6/g.local:
946 946 m1
947 947 6/g.orig:
948 948 m1
949 949 6/g.other:
950 950 m2
951 951 7/f:
952 952 m
953 953 7/f.base:
954 954 7/f.local:
955 955 m
956 956 7/f.orig:
957 957 m
958 958 7/f.other:
959 959 m2
960 960 8/f:
961 961 m2
962 962 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now