##// END OF EJS Templates
merge: change priority / ordering of merge actions...
Mads Kiilerich -
r21389:e7419720 default
parent child Browse files
Show More
@@ -1,1109 +1,1112 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, util, filemerge, copies, subrepo, worker, dicthelpers
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):
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 if r is None:
292 292 # no real conflict
293 293 del self._state[dfile]
294 294 self._dirty = True
295 295 elif not r:
296 296 self.mark(dfile, 'r')
297 297 return r
298 298
299 299 def _checkunknownfile(repo, wctx, mctx, f):
300 300 return (not repo.dirstate._ignore(f)
301 301 and 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 _checkunknown(repo, wctx, mctx):
307 307 "check for collisions between unknown files and files in mctx"
308 308
309 309 error = False
310 310 for f in mctx:
311 311 if f not in wctx and _checkunknownfile(repo, wctx, mctx, f):
312 312 error = True
313 313 wctx._repo.ui.warn(_("%s: untracked file differs\n") % f)
314 314 if error:
315 315 raise util.Abort(_("untracked files in working directory differ "
316 316 "from files in requested revision"))
317 317
318 318 def _forgetremoved(wctx, mctx, branchmerge):
319 319 """
320 320 Forget removed files
321 321
322 322 If we're jumping between revisions (as opposed to merging), and if
323 323 neither the working directory nor the target rev has the file,
324 324 then we need to remove it from the dirstate, to prevent the
325 325 dirstate from listing the file when it is no longer in the
326 326 manifest.
327 327
328 328 If we're merging, and the other revision has removed a file
329 329 that is not present in the working directory, we need to mark it
330 330 as removed.
331 331 """
332 332
333 333 actions = []
334 334 state = branchmerge and 'r' or 'f'
335 335 for f in wctx.deleted():
336 336 if f not in mctx:
337 337 actions.append((f, state, None, "forget deleted"))
338 338
339 339 if not branchmerge:
340 340 for f in wctx.removed():
341 341 if f not in mctx:
342 342 actions.append((f, "f", None, "forget removed"))
343 343
344 344 return actions
345 345
346 346 def _checkcollision(repo, wmf, actions):
347 347 # build provisional merged manifest up
348 348 pmmf = set(wmf)
349 349
350 350 def addop(f, args):
351 351 pmmf.add(f)
352 352 def removeop(f, args):
353 353 pmmf.discard(f)
354 354 def nop(f, args):
355 355 pass
356 356
357 357 def renamemoveop(f, args):
358 358 f2, flags = args
359 359 pmmf.discard(f2)
360 360 pmmf.add(f)
361 361 def renamegetop(f, args):
362 362 f2, flags = args
363 363 pmmf.add(f)
364 364 def mergeop(f, args):
365 365 f1, f2, fa, move, anc = args
366 366 if move:
367 367 pmmf.discard(f1)
368 368 pmmf.add(f)
369 369
370 370 opmap = {
371 371 "a": addop,
372 372 "dm": renamemoveop,
373 373 "dg": renamegetop,
374 374 "dr": nop,
375 375 "e": nop,
376 376 "k": nop,
377 377 "f": addop, # untracked file should be kept in working directory
378 378 "g": addop,
379 379 "m": mergeop,
380 380 "r": removeop,
381 381 "rd": nop,
382 382 "cd": addop,
383 383 "dc": addop,
384 384 }
385 385 for f, m, args, msg in actions:
386 386 op = opmap.get(m)
387 387 assert op, m
388 388 op(f, args)
389 389
390 390 # check case-folding collision in provisional merged manifest
391 391 foldmap = {}
392 392 for f in sorted(pmmf):
393 393 fold = util.normcase(f)
394 394 if fold in foldmap:
395 395 raise util.Abort(_("case-folding collision between %s and %s")
396 396 % (f, foldmap[fold]))
397 397 foldmap[fold] = f
398 398
399 399 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
400 400 acceptremote, followcopies):
401 401 """
402 402 Merge p1 and p2 with ancestor pa and generate merge action list
403 403
404 404 branchmerge and force are as passed in to update
405 405 partial = function to filter file lists
406 406 acceptremote = accept the incoming changes without prompting
407 407 """
408 408
409 409 actions, copy, movewithdir = [], {}, {}
410 410
411 411 # manifests fetched in order are going to be faster, so prime the caches
412 412 [x.manifest() for x in
413 413 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
414 414
415 415 if followcopies:
416 416 ret = copies.mergecopies(repo, wctx, p2, pa)
417 417 copy, movewithdir, diverge, renamedelete = ret
418 418 for of, fl in diverge.iteritems():
419 419 actions.append((of, "dr", (fl,), "divergent renames"))
420 420 for of, fl in renamedelete.iteritems():
421 421 actions.append((of, "rd", (fl,), "rename and delete"))
422 422
423 423 repo.ui.note(_("resolving manifests\n"))
424 424 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
425 425 % (bool(branchmerge), bool(force), bool(partial)))
426 426 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
427 427
428 428 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
429 429 copied = set(copy.values())
430 430 copied.update(movewithdir.values())
431 431
432 432 if '.hgsubstate' in m1:
433 433 # check whether sub state is modified
434 434 for s in sorted(wctx.substate):
435 435 if wctx.sub(s).dirty():
436 436 m1['.hgsubstate'] += "+"
437 437 break
438 438
439 439 aborts = []
440 440 # Compare manifests
441 441 fdiff = dicthelpers.diff(m1, m2)
442 442 flagsdiff = m1.flagsdiff(m2)
443 443 diff12 = dicthelpers.join(fdiff, flagsdiff)
444 444
445 445 for f, (n12, fl12) in diff12.iteritems():
446 446 if n12:
447 447 n1, n2 = n12
448 448 else: # file contents didn't change, but flags did
449 449 n1 = n2 = m1.get(f, None)
450 450 if n1 is None:
451 451 # Since n1 == n2, the file isn't present in m2 either. This
452 452 # means that the file was removed or deleted locally and
453 453 # removed remotely, but that residual entries remain in flags.
454 454 # This can happen in manifests generated by workingctx.
455 455 continue
456 456 if fl12:
457 457 fl1, fl2 = fl12
458 458 else: # flags didn't change, file contents did
459 459 fl1 = fl2 = m1.flags(f)
460 460
461 461 if partial and not partial(f):
462 462 continue
463 463 if n1 and n2:
464 464 fa = f
465 465 a = ma.get(f, nullid)
466 466 if a == nullid:
467 467 fa = copy.get(f, f)
468 468 # Note: f as default is wrong - we can't really make a 3-way
469 469 # merge without an ancestor file.
470 470 fla = ma.flags(fa)
471 471 nol = 'l' not in fl1 + fl2 + fla
472 472 if n2 == a and fl2 == fla:
473 473 actions.append((f, "k", (), "keep")) # remote unchanged
474 474 elif n1 == a and fl1 == fla: # local unchanged - use remote
475 475 if n1 == n2: # optimization: keep local content
476 476 actions.append((f, "e", (fl2,), "update permissions"))
477 477 else:
478 478 actions.append((f, "g", (fl2,), "remote is newer"))
479 479 elif nol and n2 == a: # remote only changed 'x'
480 480 actions.append((f, "e", (fl2,), "update permissions"))
481 481 elif nol and n1 == a: # local only changed 'x'
482 482 actions.append((f, "g", (fl1,), "remote is newer"))
483 483 else: # both changed something
484 484 actions.append((f, "m", (f, f, fa, False, pa.node()),
485 485 "versions differ"))
486 486 elif f in copied: # files we'll deal with on m2 side
487 487 pass
488 488 elif n1 and f in movewithdir: # directory rename, move local
489 489 f2 = movewithdir[f]
490 490 actions.append((f2, "dm", (f, fl1),
491 491 "remote directory rename - move from " + f))
492 492 elif n1 and f in copy:
493 493 f2 = copy[f]
494 494 actions.append((f, "m", (f, f2, f2, False, pa.node()),
495 495 "local copied/moved from " + f2))
496 496 elif n1 and f in ma: # clean, a different, no remote
497 497 if n1 != ma[f]:
498 498 if acceptremote:
499 499 actions.append((f, "r", None, "remote delete"))
500 500 else:
501 501 actions.append((f, "cd", None, "prompt changed/deleted"))
502 502 elif n1[20:] == "a": # added, no remote
503 503 actions.append((f, "f", None, "remote deleted"))
504 504 else:
505 505 actions.append((f, "r", None, "other deleted"))
506 506 elif n2 and f in movewithdir:
507 507 f2 = movewithdir[f]
508 508 actions.append((f2, "dg", (f, fl2),
509 509 "local directory rename - get from " + f))
510 510 elif n2 and f in copy:
511 511 f2 = copy[f]
512 512 if f2 in m2:
513 513 actions.append((f, "m", (f2, f, f2, False, pa.node()),
514 514 "remote copied from " + f2))
515 515 else:
516 516 actions.append((f, "m", (f2, f, f2, True, pa.node()),
517 517 "remote moved from " + f2))
518 518 elif n2 and f not in ma:
519 519 # local unknown, remote created: the logic is described by the
520 520 # following table:
521 521 #
522 522 # force branchmerge different | action
523 523 # n * n | get
524 524 # n * y | abort
525 525 # y n * | get
526 526 # y y n | get
527 527 # y y y | merge
528 528 #
529 529 # Checking whether the files are different is expensive, so we
530 530 # don't do that when we can avoid it.
531 531 if force and not branchmerge:
532 532 actions.append((f, "g", (fl2,), "remote created"))
533 533 else:
534 534 different = _checkunknownfile(repo, wctx, p2, f)
535 535 if force and branchmerge and different:
536 536 # FIXME: This is wrong - f is not in ma ...
537 537 actions.append((f, "m", (f, f, f, False, pa.node()),
538 538 "remote differs from untracked local"))
539 539 elif not force and different:
540 540 aborts.append((f, "ud"))
541 541 else:
542 542 actions.append((f, "g", (fl2,), "remote created"))
543 543 elif n2 and n2 != ma[f]:
544 544 different = _checkunknownfile(repo, wctx, p2, f)
545 545 if not force and different:
546 546 aborts.append((f, "ud"))
547 547 else:
548 548 # if different: old untracked f may be overwritten and lost
549 549 if acceptremote:
550 550 actions.append((f, "g", (m2.flags(f),),
551 551 "remote recreating"))
552 552 else:
553 553 actions.append((f, "dc", (m2.flags(f),),
554 554 "prompt deleted/changed"))
555 555
556 556 for f, m in sorted(aborts):
557 557 if m == "ud":
558 558 repo.ui.warn(_("%s: untracked file differs\n") % f)
559 559 else: assert False, m
560 560 if aborts:
561 561 raise util.Abort(_("untracked files in working directory differ "
562 562 "from files in requested revision"))
563 563
564 564 if not util.checkcase(repo.path):
565 565 # check collision between files only in p2 for clean update
566 566 if (not branchmerge and
567 567 (force or not wctx.dirty(missing=True, branch=False))):
568 568 _checkcollision(repo, m2, [])
569 569 else:
570 570 _checkcollision(repo, m1, actions)
571 571
572 572 return actions
573 573
574 actionpriority = dict((m, p) for p, m in enumerate(
575 ['r', 'f', 'g', 'a', 'k', 'm', 'dm', 'dg', 'dr', 'cd', 'dc', 'rd', 'e']))
576
574 577 def actionkey(a):
575 return a[1] in "rf" and -1 or 0, a
578 return actionpriority[a[1]], a
576 579
577 580 def getremove(repo, mctx, overwrite, args):
578 581 """apply usually-non-interactive updates to the working directory
579 582
580 583 mctx is the context to be merged into the working copy
581 584
582 585 yields tuples for progress updates
583 586 """
584 587 verbose = repo.ui.verbose
585 588 unlink = util.unlinkpath
586 589 wjoin = repo.wjoin
587 590 fctx = mctx.filectx
588 591 wwrite = repo.wwrite
589 592 audit = repo.wopener.audit
590 593 i = 0
591 594 for arg in args:
592 595 f = arg[0]
593 596 if arg[1] == 'r':
594 597 if verbose:
595 598 repo.ui.note(_("removing %s\n") % f)
596 599 audit(f)
597 600 try:
598 601 unlink(wjoin(f), ignoremissing=True)
599 602 except OSError, inst:
600 603 repo.ui.warn(_("update failed to remove %s: %s!\n") %
601 604 (f, inst.strerror))
602 605 else:
603 606 if verbose:
604 607 repo.ui.note(_("getting %s\n") % f)
605 608 wwrite(f, fctx(f).data(), arg[2][0])
606 609 if i == 100:
607 610 yield i, f
608 611 i = 0
609 612 i += 1
610 613 if i > 0:
611 614 yield i, f
612 615
613 616 def applyupdates(repo, actions, wctx, mctx, overwrite):
614 617 """apply the merge action list to the working directory
615 618
616 619 wctx is the working copy context
617 620 mctx is the context to be merged into the working copy
618 621
619 622 Return a tuple of counts (updated, merged, removed, unresolved) that
620 623 describes how many files were affected by the update.
621 624 """
622 625
623 626 updated, merged, removed, unresolved = 0, 0, 0, 0
624 627 ms = mergestate(repo)
625 628 ms.reset(wctx.p1().node(), mctx.node())
626 629 moves = []
627 630 actions.sort(key=actionkey)
628 631
629 632 # prescan for merges
630 633 for a in actions:
631 634 f, m, args, msg = a
632 635 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
633 636 if m == "m": # merge
634 637 f1, f2, fa, move, anc = args
635 638 if f == '.hgsubstate': # merged internally
636 639 continue
637 640 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
638 641 fcl = wctx[f1]
639 642 fco = mctx[f2]
640 643 actx = repo[anc]
641 644 if fa in actx:
642 645 fca = actx[fa]
643 646 else:
644 647 fca = repo.filectx(f1, fileid=nullrev)
645 648 ms.add(fcl, fco, fca, f)
646 649 if f1 != f and move:
647 650 moves.append(f1)
648 651
649 652 audit = repo.wopener.audit
650 653
651 654 # remove renamed files after safely stored
652 655 for f in moves:
653 656 if os.path.lexists(repo.wjoin(f)):
654 657 repo.ui.debug("removing %s\n" % f)
655 658 audit(f)
656 659 util.unlinkpath(repo.wjoin(f))
657 660
658 661 numupdates = len([a for a in actions if a[1] != 'k'])
659 662 workeractions = [a for a in actions if a[1] in 'gr']
660 663 updateactions = [a for a in workeractions if a[1] == 'g']
661 664 updated = len(updateactions)
662 665 removeactions = [a for a in workeractions if a[1] == 'r']
663 666 removed = len(removeactions)
664 667 actions = [a for a in actions if a[1] not in 'grk']
665 668
666 669 hgsub = [a[1] for a in workeractions if a[0] == '.hgsubstate']
667 670 if hgsub and hgsub[0] == 'r':
668 671 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
669 672
670 673 z = 0
671 674 prog = worker.worker(repo.ui, 0.001, getremove, (repo, mctx, overwrite),
672 675 removeactions)
673 676 for i, item in prog:
674 677 z += i
675 678 repo.ui.progress(_('updating'), z, item=item, total=numupdates,
676 679 unit=_('files'))
677 680 prog = worker.worker(repo.ui, 0.001, getremove, (repo, mctx, overwrite),
678 681 updateactions)
679 682 for i, item in prog:
680 683 z += i
681 684 repo.ui.progress(_('updating'), z, item=item, total=numupdates,
682 685 unit=_('files'))
683 686
684 687 if hgsub and hgsub[0] == 'g':
685 688 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
686 689
687 690 _updating = _('updating')
688 691 _files = _('files')
689 692 progress = repo.ui.progress
690 693
691 694 for i, a in enumerate(actions):
692 695 f, m, args, msg = a
693 696 progress(_updating, z + i + 1, item=f, total=numupdates, unit=_files)
694 697 if m == "m": # merge
695 698 f1, f2, fa, move, anc = args
696 699 if f == '.hgsubstate': # subrepo states need updating
697 700 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
698 701 overwrite)
699 702 continue
700 703 audit(f)
701 704 r = ms.resolve(f, wctx)
702 705 if r is not None and r > 0:
703 706 unresolved += 1
704 707 else:
705 708 if r is None:
706 709 updated += 1
707 710 else:
708 711 merged += 1
709 712 elif m == "dm": # directory rename, move local
710 713 f0, flags = args
711 714 repo.ui.note(_("moving %s to %s\n") % (f0, f))
712 715 audit(f)
713 716 repo.wwrite(f, wctx.filectx(f0).data(), flags)
714 717 util.unlinkpath(repo.wjoin(f0))
715 718 updated += 1
716 719 elif m == "dg": # local directory rename, get
717 720 f0, flags = args
718 721 repo.ui.note(_("getting %s to %s\n") % (f0, f))
719 722 repo.wwrite(f, mctx.filectx(f0).data(), flags)
720 723 updated += 1
721 724 elif m == "dr": # divergent renames
722 725 fl, = args
723 726 repo.ui.warn(_("note: possible conflict - %s was renamed "
724 727 "multiple times to:\n") % f)
725 728 for nf in fl:
726 729 repo.ui.warn(" %s\n" % nf)
727 730 elif m == "rd": # rename and delete
728 731 fl, = args
729 732 repo.ui.warn(_("note: possible conflict - %s was deleted "
730 733 "and renamed to:\n") % f)
731 734 for nf in fl:
732 735 repo.ui.warn(" %s\n" % nf)
733 736 elif m == "e": # exec
734 737 flags, = args
735 738 audit(f)
736 739 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
737 740 updated += 1
738 741 ms.commit()
739 742 progress(_updating, None, total=numupdates, unit=_files)
740 743
741 744 return updated, merged, removed, unresolved
742 745
743 746 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
744 747 acceptremote, followcopies):
745 748 "Calculate the actions needed to merge mctx into wctx using ancestors"
746 749
747 750 if len(ancestors) == 1: # default
748 751 actions = manifestmerge(repo, wctx, mctx, ancestors[0],
749 752 branchmerge, force,
750 753 partial, acceptremote, followcopies)
751 754
752 755 else: # only when merge.preferancestor=* - experimentalish code
753 756 repo.ui.status(
754 757 _("note: merging %s and %s using bids from ancestors %s\n") %
755 758 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
756 759
757 760 # Call for bids
758 761 fbids = {} # mapping filename to list af action bids
759 762 for ancestor in ancestors:
760 763 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
761 764 actions = manifestmerge(repo, wctx, mctx, ancestor,
762 765 branchmerge, force,
763 766 partial, acceptremote, followcopies)
764 767 for a in sorted(actions):
765 768 f, m, args, msg = a
766 769 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
767 770 if f in fbids:
768 771 fbids[f].append(a)
769 772 else:
770 773 fbids[f] = [a]
771 774
772 775 # Pick the best bid for each file
773 776 repo.ui.note(_('\nauction for merging merge bids\n'))
774 777 actions = []
775 778 for f, bidsl in sorted(fbids.items()):
776 779 # Consensus?
777 780 a0 = bidsl[0]
778 781 if util.all(a == a0 for a in bidsl[1:]): # len(bidsl) is > 1
779 782 repo.ui.note(" %s: consensus for %s\n" % (f, a0[1]))
780 783 actions.append(a0)
781 784 continue
782 785 # Group bids by kind of action
783 786 bids = {}
784 787 for a in bidsl:
785 788 m = a[1]
786 789 if m in bids:
787 790 bids[m].append(a)
788 791 else:
789 792 bids[m] = [a]
790 793 # If keep is an option, just do it.
791 794 if "k" in bids:
792 795 repo.ui.note(" %s: picking 'keep' action\n" % f)
793 796 actions.append(bids["k"][0])
794 797 continue
795 798 # If all gets agree [how could they not?], just do it.
796 799 if "g" in bids:
797 800 ga0 = bids["g"][0]
798 801 if util.all(a == ga0 for a in bids["g"][1:]):
799 802 repo.ui.note(" %s: picking 'get' action\n" % f)
800 803 actions.append(ga0)
801 804 continue
802 805 # TODO: Consider other simple actions such as mode changes
803 806 # Handle inefficient democrazy.
804 807 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
805 808 for _f, m, args, msg in bidsl:
806 809 repo.ui.note(' %s -> %s\n' % (msg, m))
807 810 # Pick random action. TODO: Instead, prompt user when resolving
808 811 a0 = bidsl[0]
809 812 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
810 813 (f, a0[1]))
811 814 actions.append(a0)
812 815 continue
813 816 repo.ui.note(_('end of auction\n\n'))
814 817
815 818 # Filter out prompts.
816 819 newactions, prompts = [], []
817 820 for a in actions:
818 821 if a[1] in ("cd", "dc"):
819 822 prompts.append(a)
820 823 else:
821 824 newactions.append(a)
822 825 # Prompt and create actions. TODO: Move this towards resolve phase.
823 826 for f, m, args, msg in sorted(prompts):
824 827 if m == "cd":
825 828 if repo.ui.promptchoice(
826 829 _("local changed %s which remote deleted\n"
827 830 "use (c)hanged version or (d)elete?"
828 831 "$$ &Changed $$ &Delete") % f, 0):
829 832 newactions.append((f, "r", None, "prompt delete"))
830 833 else:
831 834 newactions.append((f, "a", None, "prompt keep"))
832 835 elif m == "dc":
833 836 flags, = args
834 837 if repo.ui.promptchoice(
835 838 _("remote changed %s which local deleted\n"
836 839 "use (c)hanged version or leave (d)eleted?"
837 840 "$$ &Changed $$ &Deleted") % f, 0) == 0:
838 841 newactions.append((f, "g", (flags,), "prompt recreating"))
839 842 else: assert False, m
840 843
841 844 if wctx.rev() is None:
842 845 newactions += _forgetremoved(wctx, mctx, branchmerge)
843 846
844 847 return newactions
845 848
846 849 def recordupdates(repo, actions, branchmerge):
847 850 "record merge actions to the dirstate"
848 851
849 852 for a in actions:
850 853 f, m, args, msg = a
851 if m == "r": # remove
854 if m == "r": # remove (must come first)
852 855 if branchmerge:
853 856 repo.dirstate.remove(f)
854 857 else:
855 858 repo.dirstate.drop(f)
859 elif m == "f": # forget (must come first)
860 repo.dirstate.drop(f)
856 861 elif m == "a": # re-add
857 862 if not branchmerge:
858 863 repo.dirstate.add(f)
859 elif m == "f": # forget
860 repo.dirstate.drop(f)
861 864 elif m == "e": # exec change
862 865 repo.dirstate.normallookup(f)
863 866 elif m == "k": # keep
864 867 pass
865 868 elif m == "g": # get
866 869 if branchmerge:
867 870 repo.dirstate.otherparent(f)
868 871 else:
869 872 repo.dirstate.normal(f)
870 873 elif m == "m": # merge
871 874 f1, f2, fa, move, anc = args
872 875 if branchmerge:
873 876 # We've done a branch merge, mark this file as merged
874 877 # so that we properly record the merger later
875 878 repo.dirstate.merge(f)
876 879 if f1 != f2: # copy/rename
877 880 if move:
878 881 repo.dirstate.remove(f1)
879 882 if f1 != f:
880 883 repo.dirstate.copy(f1, f)
881 884 else:
882 885 repo.dirstate.copy(f2, f)
883 886 else:
884 887 # We've update-merged a locally modified file, so
885 888 # we set the dirstate to emulate a normal checkout
886 889 # of that file some time in the past. Thus our
887 890 # merge will appear as a normal local file
888 891 # modification.
889 892 if f2 == f: # file not locally copied/moved
890 893 repo.dirstate.normallookup(f)
891 894 if move:
892 895 repo.dirstate.drop(f1)
893 896 elif m == "dm": # directory rename, move local
894 897 f0, flag = args
895 898 if f0 not in repo.dirstate:
896 899 # untracked file moved
897 900 continue
898 901 if branchmerge:
899 902 repo.dirstate.add(f)
900 903 repo.dirstate.remove(f0)
901 904 repo.dirstate.copy(f0, f)
902 905 else:
903 906 repo.dirstate.normal(f)
904 907 repo.dirstate.drop(f0)
905 908 elif m == "dg": # directory rename, get
906 909 f0, flag = args
907 910 if branchmerge:
908 911 repo.dirstate.add(f)
909 912 repo.dirstate.copy(f0, f)
910 913 else:
911 914 repo.dirstate.normal(f)
912 915
913 916 def update(repo, node, branchmerge, force, partial, ancestor=None,
914 917 mergeancestor=False):
915 918 """
916 919 Perform a merge between the working directory and the given node
917 920
918 921 node = the node to update to, or None if unspecified
919 922 branchmerge = whether to merge between branches
920 923 force = whether to force branch merging or file overwriting
921 924 partial = a function to filter file lists (dirstate not updated)
922 925 mergeancestor = whether it is merging with an ancestor. If true,
923 926 we should accept the incoming changes for any prompts that occur.
924 927 If false, merging with an ancestor (fast-forward) is only allowed
925 928 between different named branches. This flag is used by rebase extension
926 929 as a temporary fix and should be avoided in general.
927 930
928 931 The table below shows all the behaviors of the update command
929 932 given the -c and -C or no options, whether the working directory
930 933 is dirty, whether a revision is specified, and the relationship of
931 934 the parent rev to the target rev (linear, on the same named
932 935 branch, or on another named branch).
933 936
934 937 This logic is tested by test-update-branches.t.
935 938
936 939 -c -C dirty rev | linear same cross
937 940 n n n n | ok (1) x
938 941 n n n y | ok ok ok
939 942 n n y n | merge (2) (2)
940 943 n n y y | merge (3) (3)
941 944 n y * * | --- discard ---
942 945 y n y * | --- (4) ---
943 946 y n n * | --- ok ---
944 947 y y * * | --- (5) ---
945 948
946 949 x = can't happen
947 950 * = don't-care
948 951 1 = abort: not a linear update (merge or update --check to force update)
949 952 2 = abort: uncommitted changes (commit and merge, or update --clean to
950 953 discard changes)
951 954 3 = abort: uncommitted changes (commit or update --clean to discard changes)
952 955 4 = abort: uncommitted changes (checked in commands.py)
953 956 5 = incompatible options (checked in commands.py)
954 957
955 958 Return the same tuple as applyupdates().
956 959 """
957 960
958 961 onode = node
959 962 wlock = repo.wlock()
960 963 try:
961 964 wc = repo[None]
962 965 pl = wc.parents()
963 966 p1 = pl[0]
964 967 pas = [None]
965 968 if ancestor:
966 969 pas = [repo[ancestor]]
967 970
968 971 if node is None:
969 972 # Here is where we should consider bookmarks, divergent bookmarks,
970 973 # foreground changesets (successors), and tip of current branch;
971 974 # but currently we are only checking the branch tips.
972 975 try:
973 976 node = repo.branchtip(wc.branch())
974 977 except error.RepoLookupError:
975 978 if wc.branch() == "default": # no default branch!
976 979 node = repo.lookup("tip") # update to tip
977 980 else:
978 981 raise util.Abort(_("branch %s not found") % wc.branch())
979 982
980 983 if p1.obsolete() and not p1.children():
981 984 # allow updating to successors
982 985 successors = obsolete.successorssets(repo, p1.node())
983 986
984 987 # behavior of certain cases is as follows,
985 988 #
986 989 # divergent changesets: update to highest rev, similar to what
987 990 # is currently done when there are more than one head
988 991 # (i.e. 'tip')
989 992 #
990 993 # replaced changesets: same as divergent except we know there
991 994 # is no conflict
992 995 #
993 996 # pruned changeset: no update is done; though, we could
994 997 # consider updating to the first non-obsolete parent,
995 998 # similar to what is current done for 'hg prune'
996 999
997 1000 if successors:
998 1001 # flatten the list here handles both divergent (len > 1)
999 1002 # and the usual case (len = 1)
1000 1003 successors = [n for sub in successors for n in sub]
1001 1004
1002 1005 # get the max revision for the given successors set,
1003 1006 # i.e. the 'tip' of a set
1004 1007 node = repo.revs("max(%ln)", successors)[0]
1005 1008 pas = [p1]
1006 1009
1007 1010 overwrite = force and not branchmerge
1008 1011
1009 1012 p2 = repo[node]
1010 1013 if pas[0] is None:
1011 1014 if repo.ui.config("merge", "preferancestor") == '*':
1012 1015 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1013 1016 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1014 1017 else:
1015 1018 pas = [p1.ancestor(p2, warn=True)]
1016 1019
1017 1020 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1018 1021
1019 1022 ### check phase
1020 1023 if not overwrite and len(pl) > 1:
1021 1024 raise util.Abort(_("outstanding uncommitted merges"))
1022 1025 if branchmerge:
1023 1026 if pas == [p2]:
1024 1027 raise util.Abort(_("merging with a working directory ancestor"
1025 1028 " has no effect"))
1026 1029 elif pas == [p1]:
1027 1030 if not mergeancestor and p1.branch() == p2.branch():
1028 1031 raise util.Abort(_("nothing to merge"),
1029 1032 hint=_("use 'hg update' "
1030 1033 "or check 'hg heads'"))
1031 1034 if not force and (wc.files() or wc.deleted()):
1032 1035 raise util.Abort(_("uncommitted changes"),
1033 1036 hint=_("use 'hg status' to list changes"))
1034 1037 for s in sorted(wc.substate):
1035 1038 if wc.sub(s).dirty():
1036 1039 raise util.Abort(_("uncommitted changes in "
1037 1040 "subrepository '%s'") % s)
1038 1041
1039 1042 elif not overwrite:
1040 1043 if p1 == p2: # no-op update
1041 1044 # call the hooks and exit early
1042 1045 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1043 1046 repo.hook('update', parent1=xp2, parent2='', error=0)
1044 1047 return 0, 0, 0, 0
1045 1048
1046 1049 if pas not in ([p1], [p2]): # nonlinear
1047 1050 dirty = wc.dirty(missing=True)
1048 1051 if dirty or onode is None:
1049 1052 # Branching is a bit strange to ensure we do the minimal
1050 1053 # amount of call to obsolete.background.
1051 1054 foreground = obsolete.foreground(repo, [p1.node()])
1052 1055 # note: the <node> variable contains a random identifier
1053 1056 if repo[node].node() in foreground:
1054 1057 pas = [p1] # allow updating to successors
1055 1058 elif dirty:
1056 1059 msg = _("uncommitted changes")
1057 1060 if onode is None:
1058 1061 hint = _("commit and merge, or update --clean to"
1059 1062 " discard changes")
1060 1063 else:
1061 1064 hint = _("commit or update --clean to discard"
1062 1065 " changes")
1063 1066 raise util.Abort(msg, hint=hint)
1064 1067 else: # node is none
1065 1068 msg = _("not a linear update")
1066 1069 hint = _("merge or update --check to force update")
1067 1070 raise util.Abort(msg, hint=hint)
1068 1071 else:
1069 1072 # Allow jumping branches if clean and specific rev given
1070 1073 pas = [p1]
1071 1074
1072 1075 followcopies = False
1073 1076 if overwrite:
1074 1077 pas = [wc]
1075 1078 elif pas == [p2]: # backwards
1076 1079 pas = [wc.p1()]
1077 1080 elif not branchmerge and not wc.dirty(missing=True):
1078 1081 pass
1079 1082 elif pas[0] and repo.ui.configbool("merge", "followcopies", True):
1080 1083 followcopies = True
1081 1084
1082 1085 ### calculate phase
1083 1086 actions = calculateupdates(repo, wc, p2, pas, branchmerge, force,
1084 1087 partial, mergeancestor, followcopies)
1085 1088
1086 1089 ### apply phase
1087 1090 if not branchmerge: # just jump to the new rev
1088 1091 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1089 1092 if not partial:
1090 1093 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1091 1094 # note that we're in the middle of an update
1092 1095 repo.vfs.write('updatestate', p2.hex())
1093 1096
1094 1097 stats = applyupdates(repo, actions, wc, p2, overwrite)
1095 1098
1096 1099 if not partial:
1097 1100 repo.setparents(fp1, fp2)
1098 1101 recordupdates(repo, actions, branchmerge)
1099 1102 # update completed, clear state
1100 1103 util.unlink(repo.join('updatestate'))
1101 1104
1102 1105 if not branchmerge:
1103 1106 repo.dirstate.setbranch(p2.branch())
1104 1107 finally:
1105 1108 wlock.release()
1106 1109
1107 1110 if not partial:
1108 1111 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1109 1112 return stats
@@ -1,587 +1,587 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
80 80 $ hg graft 2 -u foo
81 81 grafting revision 2
82 82 merging a and b to b
83 83 $ hg export tip --git
84 84 # HG changeset patch
85 85 # User foo
86 86 # Date 0 0
87 87 # Thu Jan 01 00:00:00 1970 +0000
88 88 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
89 89 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
90 90 2
91 91
92 92 diff --git a/a b/b
93 93 rename from a
94 94 rename to b
95 95
96 96 Look for extra:source
97 97
98 98 $ hg log --debug -r tip
99 99 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
100 100 tag: tip
101 101 phase: draft
102 102 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
103 103 parent: -1:0000000000000000000000000000000000000000
104 104 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
105 105 user: foo
106 106 date: Thu Jan 01 00:00:00 1970 +0000
107 107 files+: b
108 108 files-: a
109 109 extra: branch=default
110 110 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
111 111 description:
112 112 2
113 113
114 114
115 115
116 116 Graft out of order, skipping a merge and a duplicate
117 117
118 118 $ hg graft 1 5 4 3 'merge()' 2 -n
119 119 skipping ungraftable merge revision 6
120 120 skipping revision 2 (already grafted to 7)
121 121 grafting revision 1
122 122 grafting revision 5
123 123 grafting revision 4
124 124 grafting revision 3
125 125
126 126 $ hg graft 1 5 4 3 'merge()' 2 --debug
127 127 skipping ungraftable merge revision 6
128 128 scanning for duplicate grafts
129 129 skipping revision 2 (already grafted to 7)
130 130 grafting revision 1
131 131 searching for copies back to rev 1
132 132 unmatched files in local:
133 133 b
134 134 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
135 135 src: 'a' -> dst: 'b' *
136 136 checking for directory renames
137 137 resolving manifests
138 138 branchmerge: True, force: True, partial: False
139 139 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
140 140 b: local copied/moved from a -> m
141 141 preserving b for resolve of b
142 142 updating: b 1/1 files (100.00%)
143 143 picked tool 'internal:merge' for b (binary False symlink False)
144 144 merging b and a to b
145 145 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
146 146 premerge successful
147 147 b
148 148 grafting revision 5
149 149 searching for copies back to rev 1
150 150 resolving manifests
151 151 branchmerge: True, force: True, partial: False
152 152 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
153 e: remote is newer -> g
153 154 b: keep -> k
154 e: remote is newer -> g
155 155 getting e
156 156 updating: e 1/1 files (100.00%)
157 157 e
158 158 grafting revision 4
159 159 searching for copies back to rev 1
160 160 resolving manifests
161 161 branchmerge: True, force: True, partial: False
162 162 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
163 d: remote is newer -> g
163 164 b: keep -> k
164 d: remote is newer -> g
165 165 e: versions differ -> m
166 166 preserving e for resolve of e
167 167 getting d
168 168 updating: d 1/2 files (50.00%)
169 169 updating: e 2/2 files (100.00%)
170 170 picked tool 'internal:merge' for e (binary False symlink False)
171 171 merging e
172 172 my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
173 173 warning: conflicts during merge.
174 174 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
175 175 abort: unresolved conflicts, can't continue
176 176 (use hg resolve and hg graft --continue)
177 177 [255]
178 178
179 179 Commit while interrupted should fail:
180 180
181 181 $ hg ci -m 'commit interrupted graft'
182 182 abort: graft in progress
183 183 (use 'hg graft --continue' or 'hg update' to abort)
184 184 [255]
185 185
186 186 Abort the graft and try committing:
187 187
188 188 $ hg up -C .
189 189 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 190 $ echo c >> e
191 191 $ hg ci -mtest
192 192
193 193 $ hg strip . --config extensions.mq=
194 194 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
195 195 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
196 196
197 197 Graft again:
198 198
199 199 $ hg graft 1 5 4 3 'merge()' 2
200 200 skipping ungraftable merge revision 6
201 201 skipping revision 2 (already grafted to 7)
202 202 skipping revision 1 (already grafted to 8)
203 203 skipping revision 5 (already grafted to 9)
204 204 grafting revision 4
205 205 merging e
206 206 warning: conflicts during merge.
207 207 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
208 208 abort: unresolved conflicts, can't continue
209 209 (use hg resolve and hg graft --continue)
210 210 [255]
211 211
212 212 Continue without resolve should fail:
213 213
214 214 $ hg graft -c
215 215 grafting revision 4
216 216 abort: unresolved merge conflicts (see hg help resolve)
217 217 [255]
218 218
219 219 Fix up:
220 220
221 221 $ echo b > e
222 222 $ hg resolve -m e
223 223 no more unresolved files
224 224
225 225 Continue with a revision should fail:
226 226
227 227 $ hg graft -c 6
228 228 abort: can't specify --continue and revisions
229 229 [255]
230 230
231 231 $ hg graft -c -r 6
232 232 abort: can't specify --continue and revisions
233 233 [255]
234 234
235 235 Continue for real, clobber usernames
236 236
237 237 $ hg graft -c -U
238 238 grafting revision 4
239 239 grafting revision 3
240 240
241 241 Compare with original:
242 242
243 243 $ hg diff -r 6
244 244 $ hg status --rev 0:. -C
245 245 M d
246 246 M e
247 247 A b
248 248 a
249 249 A c
250 250 a
251 251 R a
252 252
253 253 View graph:
254 254
255 255 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
256 256 @ test@11.draft: 3
257 257 |
258 258 o test@10.draft: 4
259 259 |
260 260 o test@9.draft: 5
261 261 |
262 262 o bar@8.draft: 1
263 263 |
264 264 o foo@7.draft: 2
265 265 |
266 266 | o test@6.secret: 6
267 267 | |\
268 268 | | o test@5.draft: 5
269 269 | | |
270 270 | o | test@4.draft: 4
271 271 | |/
272 272 | o baz@3.public: 3
273 273 | |
274 274 | o test@2.public: 2
275 275 | |
276 276 | o bar@1.public: 1
277 277 |/
278 278 o test@0.public: 0
279 279
280 280 Graft again onto another branch should preserve the original source
281 281 $ hg up -q 0
282 282 $ echo 'g'>g
283 283 $ hg add g
284 284 $ hg ci -m 7
285 285 created new head
286 286 $ hg graft 7
287 287 grafting revision 7
288 288
289 289 $ hg log -r 7 --template '{rev}:{node}\n'
290 290 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
291 291 $ hg log -r 2 --template '{rev}:{node}\n'
292 292 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
293 293
294 294 $ hg log --debug -r tip
295 295 changeset: 13:9db0f28fd3747e92c57d015f53b5593aeec53c2d
296 296 tag: tip
297 297 phase: draft
298 298 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
299 299 parent: -1:0000000000000000000000000000000000000000
300 300 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
301 301 user: foo
302 302 date: Thu Jan 01 00:00:00 1970 +0000
303 303 files+: b
304 304 files-: a
305 305 extra: branch=default
306 306 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
307 307 description:
308 308 2
309 309
310 310
311 311 Disallow grafting an already grafted cset onto its original branch
312 312 $ hg up -q 6
313 313 $ hg graft 7
314 314 skipping already grafted revision 7 (was grafted from 2)
315 315 [255]
316 316
317 317 Disallow grafting already grafted csets with the same origin onto each other
318 318 $ hg up -q 13
319 319 $ hg graft 2
320 320 skipping revision 2 (already grafted to 13)
321 321 [255]
322 322 $ hg graft 7
323 323 skipping already grafted revision 7 (13 also has origin 2)
324 324 [255]
325 325
326 326 $ hg up -q 7
327 327 $ hg graft 2
328 328 skipping revision 2 (already grafted to 7)
329 329 [255]
330 330 $ hg graft tip
331 331 skipping already grafted revision 13 (7 also has origin 2)
332 332 [255]
333 333
334 334 Graft with --log
335 335
336 336 $ hg up -Cq 1
337 337 $ hg graft 3 --log -u foo
338 338 grafting revision 3
339 339 warning: can't find ancestor for 'c' copied from 'b'!
340 340 $ hg log --template '{rev} {parents} {desc}\n' -r tip
341 341 14 1:5d205f8b35b6 3
342 342 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
343 343
344 344 Resolve conflicted graft
345 345 $ hg up -q 0
346 346 $ echo b > a
347 347 $ hg ci -m 8
348 348 created new head
349 349 $ echo a > a
350 350 $ hg ci -m 9
351 351 $ hg graft 1 --tool internal:fail
352 352 grafting revision 1
353 353 abort: unresolved conflicts, can't continue
354 354 (use hg resolve and hg graft --continue)
355 355 [255]
356 356 $ hg resolve --all
357 357 merging a
358 358 no more unresolved files
359 359 $ hg graft -c
360 360 grafting revision 1
361 361 $ hg export tip --git
362 362 # HG changeset patch
363 363 # User bar
364 364 # Date 0 0
365 365 # Thu Jan 01 00:00:00 1970 +0000
366 366 # Node ID 64ecd9071ce83c6e62f538d8ce7709d53f32ebf7
367 367 # Parent 4bdb9a9d0b84ffee1d30f0dfc7744cade17aa19c
368 368 1
369 369
370 370 diff --git a/a b/a
371 371 --- a/a
372 372 +++ b/a
373 373 @@ -1,1 +1,1 @@
374 374 -a
375 375 +b
376 376
377 377 Resolve conflicted graft with rename
378 378 $ echo c > a
379 379 $ hg ci -m 10
380 380 $ hg graft 2 --tool internal:fail
381 381 grafting revision 2
382 382 abort: unresolved conflicts, can't continue
383 383 (use hg resolve and hg graft --continue)
384 384 [255]
385 385 $ hg resolve --all
386 386 merging a and b to b
387 387 no more unresolved files
388 388 $ hg graft -c
389 389 grafting revision 2
390 390 $ hg export tip --git
391 391 # HG changeset patch
392 392 # User test
393 393 # Date 0 0
394 394 # Thu Jan 01 00:00:00 1970 +0000
395 395 # Node ID 2e80e1351d6ed50302fe1e05f8bd1d4d412b6e11
396 396 # Parent e5a51ae854a8bbaaf25cc5c6a57ff46042dadbb4
397 397 2
398 398
399 399 diff --git a/a b/b
400 400 rename from a
401 401 rename to b
402 402
403 403 Test simple origin(), with and without args
404 404 $ hg log -r 'origin()'
405 405 changeset: 1:5d205f8b35b6
406 406 user: bar
407 407 date: Thu Jan 01 00:00:00 1970 +0000
408 408 summary: 1
409 409
410 410 changeset: 2:5c095ad7e90f
411 411 user: test
412 412 date: Thu Jan 01 00:00:00 1970 +0000
413 413 summary: 2
414 414
415 415 changeset: 3:4c60f11aa304
416 416 user: baz
417 417 date: Thu Jan 01 00:00:00 1970 +0000
418 418 summary: 3
419 419
420 420 changeset: 4:9c233e8e184d
421 421 user: test
422 422 date: Thu Jan 01 00:00:00 1970 +0000
423 423 summary: 4
424 424
425 425 changeset: 5:97f8bfe72746
426 426 branch: stable
427 427 parent: 3:4c60f11aa304
428 428 user: test
429 429 date: Thu Jan 01 00:00:00 1970 +0000
430 430 summary: 5
431 431
432 432 $ hg log -r 'origin(7)'
433 433 changeset: 2:5c095ad7e90f
434 434 user: test
435 435 date: Thu Jan 01 00:00:00 1970 +0000
436 436 summary: 2
437 437
438 438 Now transplant a graft to test following through copies
439 439 $ hg up -q 0
440 440 $ hg branch -q dev
441 441 $ hg ci -qm "dev branch"
442 442 $ hg --config extensions.transplant= transplant -q 7
443 443 $ hg log -r 'origin(.)'
444 444 changeset: 2:5c095ad7e90f
445 445 user: test
446 446 date: Thu Jan 01 00:00:00 1970 +0000
447 447 summary: 2
448 448
449 449 Test simple destination
450 450 $ hg log -r 'destination()'
451 451 changeset: 7:ef0ef43d49e7
452 452 parent: 0:68795b066622
453 453 user: foo
454 454 date: Thu Jan 01 00:00:00 1970 +0000
455 455 summary: 2
456 456
457 457 changeset: 8:6b9e5368ca4e
458 458 user: bar
459 459 date: Thu Jan 01 00:00:00 1970 +0000
460 460 summary: 1
461 461
462 462 changeset: 9:1905859650ec
463 463 user: test
464 464 date: Thu Jan 01 00:00:00 1970 +0000
465 465 summary: 5
466 466
467 467 changeset: 10:52dc0b4c6907
468 468 user: test
469 469 date: Thu Jan 01 00:00:00 1970 +0000
470 470 summary: 4
471 471
472 472 changeset: 11:882b35362a6b
473 473 user: test
474 474 date: Thu Jan 01 00:00:00 1970 +0000
475 475 summary: 3
476 476
477 477 changeset: 13:9db0f28fd374
478 478 user: foo
479 479 date: Thu Jan 01 00:00:00 1970 +0000
480 480 summary: 2
481 481
482 482 changeset: 14:f64defefacee
483 483 parent: 1:5d205f8b35b6
484 484 user: foo
485 485 date: Thu Jan 01 00:00:00 1970 +0000
486 486 summary: 3
487 487
488 488 changeset: 17:64ecd9071ce8
489 489 user: bar
490 490 date: Thu Jan 01 00:00:00 1970 +0000
491 491 summary: 1
492 492
493 493 changeset: 19:2e80e1351d6e
494 494 user: test
495 495 date: Thu Jan 01 00:00:00 1970 +0000
496 496 summary: 2
497 497
498 498 changeset: 21:7e61b508e709
499 499 branch: dev
500 500 tag: tip
501 501 user: foo
502 502 date: Thu Jan 01 00:00:00 1970 +0000
503 503 summary: 2
504 504
505 505 $ hg log -r 'destination(2)'
506 506 changeset: 7:ef0ef43d49e7
507 507 parent: 0:68795b066622
508 508 user: foo
509 509 date: Thu Jan 01 00:00:00 1970 +0000
510 510 summary: 2
511 511
512 512 changeset: 13:9db0f28fd374
513 513 user: foo
514 514 date: Thu Jan 01 00:00:00 1970 +0000
515 515 summary: 2
516 516
517 517 changeset: 19:2e80e1351d6e
518 518 user: test
519 519 date: Thu Jan 01 00:00:00 1970 +0000
520 520 summary: 2
521 521
522 522 changeset: 21:7e61b508e709
523 523 branch: dev
524 524 tag: tip
525 525 user: foo
526 526 date: Thu Jan 01 00:00:00 1970 +0000
527 527 summary: 2
528 528
529 529 Transplants of grafts can find a destination...
530 530 $ hg log -r 'destination(7)'
531 531 changeset: 21:7e61b508e709
532 532 branch: dev
533 533 tag: tip
534 534 user: foo
535 535 date: Thu Jan 01 00:00:00 1970 +0000
536 536 summary: 2
537 537
538 538 ... grafts of grafts unfortunately can't
539 539 $ hg graft -q 13
540 540 $ hg log -r 'destination(13)'
541 541 All copies of a cset
542 542 $ hg log -r 'origin(13) or destination(origin(13))'
543 543 changeset: 2:5c095ad7e90f
544 544 user: test
545 545 date: Thu Jan 01 00:00:00 1970 +0000
546 546 summary: 2
547 547
548 548 changeset: 7:ef0ef43d49e7
549 549 parent: 0:68795b066622
550 550 user: foo
551 551 date: Thu Jan 01 00:00:00 1970 +0000
552 552 summary: 2
553 553
554 554 changeset: 13:9db0f28fd374
555 555 user: foo
556 556 date: Thu Jan 01 00:00:00 1970 +0000
557 557 summary: 2
558 558
559 559 changeset: 19:2e80e1351d6e
560 560 user: test
561 561 date: Thu Jan 01 00:00:00 1970 +0000
562 562 summary: 2
563 563
564 564 changeset: 21:7e61b508e709
565 565 branch: dev
566 566 user: foo
567 567 date: Thu Jan 01 00:00:00 1970 +0000
568 568 summary: 2
569 569
570 570 changeset: 22:1313d0a825e2
571 571 branch: dev
572 572 tag: tip
573 573 user: foo
574 574 date: Thu Jan 01 00:00:00 1970 +0000
575 575 summary: 2
576 576
577 577
578 578 graft works on complex revset
579 579
580 580 $ hg graft 'origin(13) or destination(origin(13))'
581 581 skipping ancestor revision 21
582 582 skipping ancestor revision 22
583 583 skipping revision 2 (already grafted to 22)
584 584 grafting revision 7
585 585 grafting revision 13
586 586 grafting revision 19
587 587 merging b
@@ -1,348 +1,348 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 note: using 0f6b37dbe527 as ancestor of adfe50279922 and cf89f02107e5
28 28 alternatively, use --config merge.preferancestor=40663881a6dd
29 29 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 30 $ echo '6 second change' > f2
31 31 $ hg ci -m '6 second change f2'
32 32
33 33 $ hg log -G
34 34 @ changeset: 6:3b08d01b0ab5
35 35 | tag: tip
36 36 | parent: 3:cf89f02107e5
37 37 | user: test
38 38 | date: Thu Jan 01 00:00:00 1970 +0000
39 39 | summary: 6 second change f2
40 40 |
41 41 | o changeset: 5:adfe50279922
42 42 | | user: test
43 43 | | date: Thu Jan 01 00:00:00 1970 +0000
44 44 | | summary: 5 second change f1
45 45 | |
46 46 | o changeset: 4:7d3e55501ae6
47 47 | |\ parent: 2:40663881a6dd
48 48 | | | parent: 1:0f6b37dbe527
49 49 | | | user: test
50 50 | | | date: Thu Jan 01 00:00:00 1970 +0000
51 51 | | | summary: 4 merge
52 52 | | |
53 53 o---+ changeset: 3:cf89f02107e5
54 54 | | | parent: 2:40663881a6dd
55 55 |/ / parent: 1:0f6b37dbe527
56 56 | | user: test
57 57 | | date: Thu Jan 01 00:00:00 1970 +0000
58 58 | | summary: 3 merge
59 59 | |
60 60 | o changeset: 2:40663881a6dd
61 61 | | parent: 0:40494bf2444c
62 62 | | user: test
63 63 | | date: Thu Jan 01 00:00:00 1970 +0000
64 64 | | summary: 2 first change f2
65 65 | |
66 66 o | changeset: 1:0f6b37dbe527
67 67 |/ user: test
68 68 | date: Thu Jan 01 00:00:00 1970 +0000
69 69 | summary: 1 first change f1
70 70 |
71 71 o changeset: 0:40494bf2444c
72 72 user: test
73 73 date: Thu Jan 01 00:00:00 1970 +0000
74 74 summary: 0 base
75 75
76 76
77 77 $ hg merge -v --debug --tool internal:dump 5
78 78 note: using 0f6b37dbe527 as ancestor of 3b08d01b0ab5 and adfe50279922
79 79 alternatively, use --config merge.preferancestor=40663881a6dd
80 80 searching for copies back to rev 3
81 81 resolving manifests
82 82 branchmerge: True, force: False, partial: False
83 83 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
84 84 f1: remote is newer -> g
85 85 f2: versions differ -> m
86 86 preserving f2 for resolve of f2
87 87 getting f1
88 88 updating: f1 1/2 files (50.00%)
89 89 updating: f2 2/2 files (100.00%)
90 90 picked tool 'internal:dump' for f2 (binary False symlink False)
91 91 merging f2
92 92 my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@40494bf2444c
93 93 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
94 94 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
95 95 [1]
96 96
97 97 $ head *
98 98 ==> f1 <==
99 99 5 second change
100 100
101 101 ==> f2 <==
102 102 6 second change
103 103
104 104 ==> f2.base <==
105 105 0 base
106 106
107 107 ==> f2.local <==
108 108 6 second change
109 109
110 110 ==> f2.orig <==
111 111 6 second change
112 112
113 113 ==> f2.other <==
114 114 2 first change
115 115
116 116 $ hg up -qC .
117 117 $ hg merge -v --tool internal:dump 5 --config merge.preferancestor="null 40663881 3b08d"
118 118 note: using 40663881a6dd as ancestor of 3b08d01b0ab5 and adfe50279922
119 119 alternatively, use --config merge.preferancestor=0f6b37dbe527
120 120 resolving manifests
121 121 merging f1
122 122 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
123 123 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
124 124 [1]
125 125
126 126 Redo merge with merge.preferancestor="*" to enable bid merge
127 127
128 128 $ rm f*
129 129 $ hg up -qC .
130 130 $ hg merge -v --debug --tool internal:dump 5 --config merge.preferancestor="*"
131 131 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
132 132
133 133 calculating bids for ancestor 0f6b37dbe527
134 134 searching for copies back to rev 3
135 135 resolving manifests
136 136 branchmerge: True, force: False, partial: False
137 137 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
138 138 f1: remote is newer -> g
139 139 f2: versions differ -> m
140 140
141 141 calculating bids for ancestor 40663881a6dd
142 142 searching for copies back to rev 3
143 143 resolving manifests
144 144 branchmerge: True, force: False, partial: False
145 145 ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
146 146 f1: versions differ -> m
147 147 f2: keep -> k
148 148
149 149 auction for merging merge bids
150 150 f1: picking 'get' action
151 151 f2: picking 'keep' action
152 152 end of auction
153 153
154 154 f1: remote is newer -> g
155 155 f2: keep -> k
156 156 getting f1
157 157 updating: f1 1/1 files (100.00%)
158 158 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
159 159 (branch merge, don't forget to commit)
160 160
161 161 $ head *
162 162 ==> f1 <==
163 163 5 second change
164 164
165 165 ==> f2 <==
166 166 6 second change
167 167
168 168
169 169 The other way around:
170 170
171 171 $ hg up -C -r5
172 172 note: using 0f6b37dbe527 as ancestor of 3b08d01b0ab5 and adfe50279922
173 173 alternatively, use --config merge.preferancestor=40663881a6dd
174 174 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 175 $ hg merge -v --debug --config merge.preferancestor="*"
176 176 note: merging adfe50279922+ and 3b08d01b0ab5 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
177 177
178 178 calculating bids for ancestor 0f6b37dbe527
179 179 searching for copies back to rev 3
180 180 resolving manifests
181 181 branchmerge: True, force: False, partial: False
182 182 ancestor: 0f6b37dbe527, local: adfe50279922+, remote: 3b08d01b0ab5
183 183 f1: keep -> k
184 184 f2: versions differ -> m
185 185
186 186 calculating bids for ancestor 40663881a6dd
187 187 searching for copies back to rev 3
188 188 resolving manifests
189 189 branchmerge: True, force: False, partial: False
190 190 ancestor: 40663881a6dd, local: adfe50279922+, remote: 3b08d01b0ab5
191 191 f1: versions differ -> m
192 192 f2: remote is newer -> g
193 193
194 194 auction for merging merge bids
195 195 f1: picking 'keep' action
196 196 f2: picking 'get' action
197 197 end of auction
198 198
199 f2: remote is newer -> g
199 200 f1: keep -> k
200 f2: remote is newer -> g
201 201 getting f2
202 202 updating: f2 1/1 files (100.00%)
203 203 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
204 204 (branch merge, don't forget to commit)
205 205
206 206 $ head *
207 207 ==> f1 <==
208 208 5 second change
209 209
210 210 ==> f2 <==
211 211 6 second change
212 212
213 213 Verify how the output looks and and how verbose it is:
214 214
215 215 $ hg up -qC
216 216 $ hg merge --config merge.preferancestor="*"
217 217 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
218 218 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
219 219 (branch merge, don't forget to commit)
220 220
221 221 $ hg up -qC
222 222 $ hg merge -v --config merge.preferancestor="*"
223 223 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
224 224
225 225 calculating bids for ancestor 0f6b37dbe527
226 226 resolving manifests
227 227
228 228 calculating bids for ancestor 40663881a6dd
229 229 resolving manifests
230 230
231 231 auction for merging merge bids
232 232 f1: picking 'get' action
233 233 f2: picking 'keep' action
234 234 end of auction
235 235
236 236 getting f1
237 237 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
238 238 (branch merge, don't forget to commit)
239 239
240 240 $ hg up -qC
241 241 $ hg merge -v --debug --config merge.preferancestor="*"
242 242 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
243 243
244 244 calculating bids for ancestor 0f6b37dbe527
245 245 searching for copies back to rev 3
246 246 resolving manifests
247 247 branchmerge: True, force: False, partial: False
248 248 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
249 249 f1: remote is newer -> g
250 250 f2: versions differ -> m
251 251
252 252 calculating bids for ancestor 40663881a6dd
253 253 searching for copies back to rev 3
254 254 resolving manifests
255 255 branchmerge: True, force: False, partial: False
256 256 ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
257 257 f1: versions differ -> m
258 258 f2: keep -> k
259 259
260 260 auction for merging merge bids
261 261 f1: picking 'get' action
262 262 f2: picking 'keep' action
263 263 end of auction
264 264
265 265 f1: remote is newer -> g
266 266 f2: keep -> k
267 267 getting f1
268 268 updating: f1 1/1 files (100.00%)
269 269 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
270 270 (branch merge, don't forget to commit)
271 271
272 272 $ cd ..
273 273
274 274 http://stackoverflow.com/questions/9350005/how-do-i-specify-a-merge-base-to-use-in-a-hg-merge/9430810
275 275
276 276 $ hg init ancestor-merging
277 277 $ cd ancestor-merging
278 278 $ echo a > x
279 279 $ hg commit -A -m a x
280 280 $ hg update -q 0
281 281 $ echo b >> x
282 282 $ hg commit -m b
283 283 $ hg update -q 0
284 284 $ echo c >> x
285 285 $ hg commit -qm c
286 286 $ hg update -q 1
287 287 $ hg merge -q --tool internal:local 2
288 288 $ echo c >> x
289 289 $ hg commit -m bc
290 290 $ hg update -q 2
291 291 $ hg merge -q --tool internal:local 1
292 292 $ echo b >> x
293 293 $ hg commit -qm cb
294 294
295 295 $ hg merge
296 296 note: using 70008a2163f6 as ancestor of 0d355fdef312 and 4b8b546a3eef
297 297 alternatively, use --config merge.preferancestor=b211bbc6eb3c
298 298 merging x
299 299 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
300 300 (branch merge, don't forget to commit)
301 301 $ cat x
302 302 a
303 303 c
304 304 b
305 305 c
306 306
307 307 $ hg up -qC .
308 308
309 309 $ hg merge --config merge.preferancestor=b211bbc6eb3c
310 310 note: using b211bbc6eb3c as ancestor of 0d355fdef312 and 4b8b546a3eef
311 311 alternatively, use --config merge.preferancestor=70008a2163f6
312 312 merging x
313 313 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
314 314 (branch merge, don't forget to commit)
315 315 $ cat x
316 316 a
317 317 b
318 318 c
319 319 b
320 320
321 321 $ hg up -qC .
322 322
323 323 $ hg merge -v --config merge.preferancestor="*"
324 324 note: merging 0d355fdef312+ and 4b8b546a3eef using bids from ancestors 70008a2163f6 and b211bbc6eb3c
325 325
326 326 calculating bids for ancestor 70008a2163f6
327 327 resolving manifests
328 328
329 329 calculating bids for ancestor b211bbc6eb3c
330 330 resolving manifests
331 331
332 332 auction for merging merge bids
333 333 x: multiple bids for merge action:
334 334 versions differ -> m
335 335 versions differ -> m
336 336 x: ambiguous merge - picked m action
337 337 end of auction
338 338
339 339 merging x
340 340 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
341 341 (branch merge, don't forget to commit)
342 342 $ cat x
343 343 a
344 344 c
345 345 b
346 346 c
347 347
348 348 $ cd ..
@@ -1,195 +1,195 b''
1 1 $ hg init
2 2
3 3 $ echo "[merge]" >> .hg/hgrc
4 4 $ echo "followcopies = 1" >> .hg/hgrc
5 5
6 6 $ echo foo > a
7 7 $ echo foo > a2
8 8 $ hg add a a2
9 9 $ hg ci -m "start"
10 10
11 11 $ hg mv a b
12 12 $ hg mv a2 b2
13 13 $ hg ci -m "rename"
14 14
15 15 $ hg co 0
16 16 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
17 17
18 18 $ echo blahblah > a
19 19 $ echo blahblah > a2
20 20 $ hg mv a2 c2
21 21 $ hg ci -m "modify"
22 22 created new head
23 23
24 24 $ hg merge -y --debug
25 25 searching for copies back to rev 1
26 26 unmatched files in local:
27 27 c2
28 28 unmatched files in other:
29 29 b
30 30 b2
31 31 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
32 32 src: 'a' -> dst: 'b' *
33 33 src: 'a2' -> dst: 'b2' !
34 34 src: 'a2' -> dst: 'c2' !
35 35 checking for directory renames
36 36 resolving manifests
37 37 branchmerge: True, force: False, partial: False
38 38 ancestor: af1939970a1c, local: 044f8520aeeb+, remote: 85c198ef2f6c
39 a2: divergent renames -> dr
39 b2: remote created -> g
40 40 b: remote moved from a -> m
41 41 preserving a for resolve of b
42 b2: remote created -> g
42 a2: divergent renames -> dr
43 43 removing a
44 44 getting b2
45 45 updating: b2 1/3 files (33.33%)
46 updating: a2 2/3 files (66.67%)
47 note: possible conflict - a2 was renamed multiple times to:
48 c2
49 b2
50 updating: b 3/3 files (100.00%)
46 updating: b 2/3 files (66.67%)
51 47 picked tool 'internal:merge' for b (binary False symlink False)
52 48 merging a and b to b
53 49 my b@044f8520aeeb+ other b@85c198ef2f6c ancestor a@af1939970a1c
54 50 premerge successful
51 updating: a2 3/3 files (100.00%)
52 note: possible conflict - a2 was renamed multiple times to:
53 c2
54 b2
55 55 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
56 56 (branch merge, don't forget to commit)
57 57
58 58 $ hg status -AC
59 59 M b
60 60 a
61 61 M b2
62 62 R a
63 63 C c2
64 64
65 65 $ cat b
66 66 blahblah
67 67
68 68 $ hg ci -m "merge"
69 69
70 70 $ hg debugindex b
71 71 rev offset length ..... linkrev nodeid p1 p2 (re)
72 72 0 0 67 ..... 1 57eacc201a7f 000000000000 000000000000 (re)
73 73 1 67 72 ..... 3 4727ba907962 000000000000 57eacc201a7f (re)
74 74
75 75 $ hg debugrename b
76 76 b renamed from a:dd03b83622e78778b403775d0d074b9ac7387a66
77 77
78 78 This used to trigger a "divergent renames" warning, despite no renames
79 79
80 80 $ hg cp b b3
81 81 $ hg cp b b4
82 82 $ hg ci -A -m 'copy b twice'
83 83 $ hg up eb92d88a9712
84 84 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
85 85 $ hg up
86 86 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 87 $ hg rm b3 b4
88 88 $ hg ci -m 'clean up a bit of our mess'
89 89
90 90 We'd rather not warn on divergent renames done in the same changeset (issue2113)
91 91
92 92 $ hg cp b b3
93 93 $ hg mv b b4
94 94 $ hg ci -A -m 'divergent renames in same changeset'
95 95 $ hg up c761c6948de0
96 96 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
97 97 $ hg up
98 98 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
99 99
100 100 Check for issue2642
101 101
102 102 $ hg init t
103 103 $ cd t
104 104
105 105 $ echo c0 > f1
106 106 $ hg ci -Aqm0
107 107
108 108 $ hg up null -q
109 109 $ echo c1 > f1 # backport
110 110 $ hg ci -Aqm1
111 111 $ hg mv f1 f2
112 112 $ hg ci -qm2
113 113
114 114 $ hg up 0 -q
115 115 $ hg merge 1 -q --tool internal:local
116 116 $ hg ci -qm3
117 117
118 118 $ hg merge 2
119 119 merging f1 and f2 to f2
120 120 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
121 121 (branch merge, don't forget to commit)
122 122
123 123 $ cat f2
124 124 c0
125 125
126 126 $ cd ..
127 127
128 128 Check for issue2089
129 129
130 130 $ hg init repo2089
131 131 $ cd repo2089
132 132
133 133 $ echo c0 > f1
134 134 $ hg ci -Aqm0
135 135
136 136 $ hg up null -q
137 137 $ echo c1 > f1
138 138 $ hg ci -Aqm1
139 139
140 140 $ hg up 0 -q
141 141 $ hg merge 1 -q --tool internal:local
142 142 $ echo c2 > f1
143 143 $ hg ci -qm2
144 144
145 145 $ hg up 1 -q
146 146 $ hg mv f1 f2
147 147 $ hg ci -Aqm3
148 148
149 149 $ hg up 2 -q
150 150 $ hg merge 3
151 151 merging f1 and f2 to f2
152 152 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
153 153 (branch merge, don't forget to commit)
154 154
155 155 $ cat f2
156 156 c2
157 157
158 158 $ cd ..
159 159
160 160 Check for issue3074
161 161
162 162 $ hg init repo3074
163 163 $ cd repo3074
164 164 $ echo foo > file
165 165 $ hg add file
166 166 $ hg commit -m "added file"
167 167 $ hg mv file newfile
168 168 $ hg commit -m "renamed file"
169 169 $ hg update 0
170 170 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
171 171 $ hg rm file
172 172 $ hg commit -m "deleted file"
173 173 created new head
174 174 $ hg merge --debug
175 175 searching for copies back to rev 1
176 176 unmatched files in other:
177 177 newfile
178 178 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
179 179 src: 'file' -> dst: 'newfile' %
180 180 checking for directory renames
181 181 resolving manifests
182 182 branchmerge: True, force: False, partial: False
183 183 ancestor: 19d7f95df299, local: 0084274f6b67+, remote: 5d32493049f0
184 newfile: remote created -> g
184 185 file: rename and delete -> rd
185 newfile: remote created -> g
186 186 getting newfile
187 187 updating: newfile 1/2 files (50.00%)
188 188 updating: file 2/2 files (100.00%)
189 189 note: possible conflict - file was deleted and renamed to:
190 190 newfile
191 191 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 192 (branch merge, don't forget to commit)
193 193 $ hg status
194 194 M newfile
195 195 $ cd ..
@@ -1,972 +1,972 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 a: keep -> k
90 90 b: remote copied from a -> m
91 91 preserving a for resolve of b
92 92 rev: versions differ -> m
93 93 preserving rev for resolve of rev
94 94 updating: b 1/2 files (50.00%)
95 95 picked tool 'python ../merge' for b (binary False symlink False)
96 96 merging a and b to b
97 97 my b@e300d1c794ec+ other b@4ce40f5aca24 ancestor a@924404dff337
98 98 premerge successful
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 a: remote is newer -> g
126 126 b: local copied/moved from a -> m
127 127 preserving b for resolve of b
128 128 rev: versions differ -> m
129 129 preserving rev for resolve of rev
130 130 getting a
131 131 updating: a 1/3 files (33.33%)
132 132 updating: b 2/3 files (66.67%)
133 133 picked tool 'python ../merge' for b (binary False symlink False)
134 134 merging b and a to b
135 135 my b@86a2aa42fc76+ other a@f4db7e329e71 ancestor a@924404dff337
136 136 premerge successful
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 b: remote moved from a -> m
164 164 preserving a for resolve of b
165 165 rev: versions differ -> m
166 166 preserving rev for resolve of rev
167 167 removing a
168 168 updating: b 1/2 files (50.00%)
169 169 picked tool 'python ../merge' for b (binary False symlink False)
170 170 merging a and b to b
171 171 my b@e300d1c794ec+ other b@bdb19105162a ancestor a@924404dff337
172 172 premerge successful
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 b: local copied/moved from a -> m
199 199 preserving b for resolve of b
200 200 rev: versions differ -> m
201 201 preserving rev for resolve of rev
202 202 updating: b 1/2 files (50.00%)
203 203 picked tool 'python ../merge' for b (binary False symlink False)
204 204 merging b and a to b
205 205 my b@02963e448370+ other a@f4db7e329e71 ancestor a@924404dff337
206 206 premerge successful
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 b: remote created -> g
233 233 rev: versions differ -> m
234 234 preserving rev for resolve of rev
235 235 getting b
236 236 updating: b 1/2 files (50.00%)
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 rev: versions differ -> m
263 263 preserving rev for resolve of rev
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 a: other deleted -> r
290 290 b: remote created -> g
291 291 rev: versions differ -> m
292 292 preserving rev for resolve of rev
293 293 removing a
294 294 updating: a 1/3 files (33.33%)
295 295 getting b
296 296 updating: b 2/3 files (66.67%)
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 rev: versions differ -> m
322 322 preserving rev for resolve of rev
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 b: versions differ -> m
345 345 preserving b for resolve of b
346 346 rev: versions differ -> m
347 347 preserving rev for resolve of rev
348 348 updating: b 1/2 files (50.00%)
349 349 picked tool 'python ../merge' for b (binary False symlink False)
350 350 merging b
351 351 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
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 a: divergent renames -> dr
383 382 c: remote created -> g
384 383 rev: versions differ -> m
385 384 preserving rev for resolve of rev
385 a: divergent renames -> dr
386 386 getting c
387 387 updating: c 1/3 files (33.33%)
388 updating: a 2/3 files (66.67%)
388 updating: rev 2/3 files (66.67%)
389 picked tool 'python ../merge' for rev (binary False symlink False)
390 merging rev
391 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
392 updating: a 3/3 files (100.00%)
389 393 note: possible conflict - a was renamed multiple times to:
390 394 b
391 395 c
392 updating: rev 3/3 files (100.00%)
393 picked tool 'python ../merge' for rev (binary False symlink False)
394 merging rev
395 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
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 b: versions differ -> m
415 415 preserving b for resolve of b
416 416 rev: versions differ -> m
417 417 preserving rev for resolve of rev
418 418 updating: b 1/2 files (50.00%)
419 419 picked tool 'python ../merge' for b (binary False symlink False)
420 420 merging b
421 421 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
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 a: other deleted -> r
445 445 b: versions differ -> m
446 446 preserving b for resolve of b
447 447 rev: versions differ -> m
448 448 preserving rev for resolve of rev
449 449 removing a
450 450 updating: a 1/3 files (33.33%)
451 451 updating: b 2/3 files (66.67%)
452 452 picked tool 'python ../merge' for b (binary False symlink False)
453 453 merging b
454 454 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
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 a: remote is newer -> g
477 477 b: versions differ -> m
478 478 preserving b for resolve of b
479 479 rev: versions differ -> m
480 480 preserving rev for resolve of rev
481 481 getting a
482 482 updating: a 1/3 files (33.33%)
483 483 updating: b 2/3 files (66.67%)
484 484 picked tool 'python ../merge' for b (binary False symlink False)
485 485 merging b
486 486 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
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 a: other deleted -> r
510 510 b: versions differ -> m
511 511 preserving b for resolve of b
512 512 rev: versions differ -> m
513 513 preserving rev for resolve of rev
514 514 removing a
515 515 updating: a 1/3 files (33.33%)
516 516 updating: b 2/3 files (66.67%)
517 517 picked tool 'python ../merge' for b (binary False symlink False)
518 518 merging b
519 519 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
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 a: remote is newer -> g
542 542 b: versions differ -> m
543 543 preserving b for resolve of b
544 544 rev: versions differ -> m
545 545 preserving rev for resolve of rev
546 546 getting a
547 547 updating: a 1/3 files (33.33%)
548 548 updating: b 2/3 files (66.67%)
549 549 picked tool 'python ../merge' for b (binary False symlink False)
550 550 merging b
551 551 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
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 a: keep -> k
575 575 b: versions differ -> m
576 576 preserving b for resolve of b
577 577 rev: versions differ -> m
578 578 preserving rev for resolve of rev
579 579 updating: b 1/2 files (50.00%)
580 580 picked tool 'python ../merge' for b (binary False symlink False)
581 581 merging b
582 582 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
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 a: prompt recreating -> g
608 608 b: versions differ -> m
609 609 preserving b for resolve of b
610 610 rev: versions differ -> m
611 611 preserving rev for resolve of rev
612 612 getting a
613 613 updating: a 1/3 files (33.33%)
614 614 updating: b 2/3 files (66.67%)
615 615 picked tool 'python ../merge' for b (binary False symlink False)
616 616 merging b
617 617 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
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 a: prompt keep -> a
643 643 b: versions differ -> m
644 644 preserving b for resolve of b
645 645 rev: versions differ -> m
646 646 preserving rev for resolve of rev
647 647 updating: a 1/3 files (33.33%)
648 648 updating: b 2/3 files (66.67%)
649 649 picked tool 'python ../merge' for b (binary False symlink False)
650 650 merging b
651 651 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
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 b: remote moved from a -> m
678 678 preserving a for resolve of b
679 679 rev: versions differ -> m
680 680 preserving rev for resolve of rev
681 681 removing a
682 682 updating: b 1/2 files (50.00%)
683 683 picked tool 'python ../merge' for b (binary False symlink False)
684 684 merging a and b to b
685 685 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
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 b: local copied/moved from a -> m
712 712 preserving b for resolve of b
713 713 rev: versions differ -> m
714 714 preserving rev for resolve of rev
715 715 updating: b 1/2 files (50.00%)
716 716 picked tool 'python ../merge' for b (binary False symlink False)
717 717 merging b and a to b
718 718 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
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 c: remote created -> g
749 750 b: local copied/moved from a -> m
750 751 preserving b for resolve of b
751 c: remote created -> g
752 752 rev: versions differ -> m
753 753 preserving rev for resolve of rev
754 754 getting c
755 755 updating: c 1/3 files (33.33%)
756 756 updating: b 2/3 files (66.67%)
757 757 picked tool 'python ../merge' for b (binary False symlink False)
758 758 merging b and a to b
759 759 my b@02963e448370+ other a@2b958612230f ancestor a@924404dff337
760 760 premerge successful
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 8/f: prompt recreating -> g
839 840 0/f: versions differ -> m
840 841 preserving 0/f for resolve of 0/f
841 842 1/g: versions differ -> m
842 843 preserving 1/g for resolve of 1/g
843 844 2/f: versions differ -> m
844 845 preserving 2/f for resolve of 2/f
845 846 3/f: versions differ -> m
846 847 preserving 3/f for resolve of 3/f
847 848 3/g: remote copied from 3/f -> m
848 849 preserving 3/f for resolve of 3/g
849 850 4/g: remote moved from 4/f -> m
850 851 preserving 4/f for resolve of 4/g
851 852 5/f: versions differ -> m
852 853 preserving 5/f for resolve of 5/f
853 854 5/g: local copied/moved from 5/f -> m
854 855 preserving 5/g for resolve of 5/g
855 856 6/g: local copied/moved from 6/f -> m
856 857 preserving 6/g for resolve of 6/g
857 858 7/f: remote differs from untracked local -> m
858 859 preserving 7/f for resolve of 7/f
859 8/f: prompt recreating -> g
860 860 removing 4/f
861 861 getting 8/f
862 862 $ hg mani
863 863 0/f
864 864 1/g
865 865 2/f
866 866 3/f
867 867 4/f
868 868 5/f
869 869 5/g
870 870 6/g
871 871 $ for f in */*; do echo $f:; cat $f; done
872 872 0/f:
873 873 m1
874 874 0/f.base:
875 875 0/f.local:
876 876 m1
877 877 0/f.orig:
878 878 m1
879 879 0/f.other:
880 880 m2
881 881 1/g:
882 882 m1
883 883 1/g.base:
884 884 a
885 885 1/g.local:
886 886 m1
887 887 1/g.orig:
888 888 m1
889 889 1/g.other:
890 890 m2
891 891 2/f:
892 892 m1
893 893 2/f.base:
894 894 a
895 895 2/f.local:
896 896 m1
897 897 2/f.orig:
898 898 m1
899 899 2/f.other:
900 900 m2
901 901 3/f:
902 902 m1
903 903 3/f.base:
904 904 a
905 905 3/f.local:
906 906 m1
907 907 3/f.orig:
908 908 m1
909 909 3/f.other:
910 910 m2
911 911 3/g:
912 912 m1
913 913 3/g.base:
914 914 a
915 915 3/g.local:
916 916 m1
917 917 3/g.orig:
918 918 m1
919 919 3/g.other:
920 920 m2
921 921 4/g:
922 922 m1
923 923 4/g.base:
924 924 a
925 925 4/g.local:
926 926 m1
927 927 4/g.orig:
928 928 m1
929 929 4/g.other:
930 930 m2
931 931 5/f:
932 932 m1
933 933 5/f.base:
934 934 a
935 935 5/f.local:
936 936 m1
937 937 5/f.orig:
938 938 m1
939 939 5/f.other:
940 940 m2
941 941 5/g:
942 942 m1
943 943 5/g.base:
944 944 a
945 945 5/g.local:
946 946 m1
947 947 5/g.orig:
948 948 m1
949 949 5/g.other:
950 950 m2
951 951 6/g:
952 952 m1
953 953 6/g.base:
954 954 a
955 955 6/g.local:
956 956 m1
957 957 6/g.orig:
958 958 m1
959 959 6/g.other:
960 960 m2
961 961 7/f:
962 962 m
963 963 7/f.base:
964 964 7/f.local:
965 965 m
966 966 7/f.orig:
967 967 m
968 968 7/f.other:
969 969 m2
970 970 8/f:
971 971 m2
972 972 $ cd ..
@@ -1,241 +1,241 b''
1 1 $ HGMERGE=true; export HGMERGE
2 2
3 3 $ hg init r1
4 4 $ cd r1
5 5 $ echo a > a
6 6 $ hg addremove
7 7 adding a
8 8 $ hg commit -m "1"
9 9
10 10 $ hg clone . ../r2
11 11 updating to branch default
12 12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 13 $ cd ../r2
14 14 $ hg up
15 15 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 16 $ echo abc > a
17 17 $ hg diff --nodates
18 18 diff -r c19d34741b0a a
19 19 --- a/a
20 20 +++ b/a
21 21 @@ -1,1 +1,1 @@
22 22 -a
23 23 +abc
24 24
25 25 $ cd ../r1
26 26 $ echo b > b
27 27 $ echo a2 > a
28 28 $ hg addremove
29 29 adding b
30 30 $ hg commit -m "2"
31 31
32 32 $ cd ../r2
33 33 $ hg -q pull ../r1
34 34 $ hg status
35 35 M a
36 36 $ hg parents
37 37 changeset: 0:c19d34741b0a
38 38 user: test
39 39 date: Thu Jan 01 00:00:00 1970 +0000
40 40 summary: 1
41 41
42 42 $ hg --debug up
43 43 searching for copies back to rev 1
44 44 unmatched files in other:
45 45 b
46 46 resolving manifests
47 47 branchmerge: False, force: False, partial: False
48 48 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
49 b: remote created -> g
49 50 a: versions differ -> m
50 51 preserving a for resolve of a
51 b: remote created -> g
52 52 getting b
53 53 updating: b 1/2 files (50.00%)
54 54 updating: a 2/2 files (100.00%)
55 55 picked tool 'true' for a (binary False symlink False)
56 56 merging a
57 57 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
58 58 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
59 59 $ hg parents
60 60 changeset: 1:1e71731e6fbb
61 61 tag: tip
62 62 user: test
63 63 date: Thu Jan 01 00:00:00 1970 +0000
64 64 summary: 2
65 65
66 66 $ hg --debug up 0
67 67 resolving manifests
68 68 branchmerge: False, force: False, partial: False
69 69 ancestor: 1e71731e6fbb, local: 1e71731e6fbb+, remote: c19d34741b0a
70 70 b: other deleted -> r
71 71 a: versions differ -> m
72 72 preserving a for resolve of a
73 73 removing b
74 74 updating: b 1/2 files (50.00%)
75 75 updating: a 2/2 files (100.00%)
76 76 picked tool 'true' for a (binary False symlink False)
77 77 merging a
78 78 my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
79 79 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
80 80 $ hg parents
81 81 changeset: 0:c19d34741b0a
82 82 user: test
83 83 date: Thu Jan 01 00:00:00 1970 +0000
84 84 summary: 1
85 85
86 86 $ hg --debug merge
87 87 abort: nothing to merge
88 88 (use 'hg update' instead)
89 89 [255]
90 90 $ hg parents
91 91 changeset: 0:c19d34741b0a
92 92 user: test
93 93 date: Thu Jan 01 00:00:00 1970 +0000
94 94 summary: 1
95 95
96 96 $ hg --debug up
97 97 searching for copies back to rev 1
98 98 unmatched files in other:
99 99 b
100 100 resolving manifests
101 101 branchmerge: False, force: False, partial: False
102 102 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
103 b: remote created -> g
103 104 a: versions differ -> m
104 105 preserving a for resolve of a
105 b: remote created -> g
106 106 getting b
107 107 updating: b 1/2 files (50.00%)
108 108 updating: a 2/2 files (100.00%)
109 109 picked tool 'true' for a (binary False symlink False)
110 110 merging a
111 111 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
112 112 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
113 113 $ hg parents
114 114 changeset: 1:1e71731e6fbb
115 115 tag: tip
116 116 user: test
117 117 date: Thu Jan 01 00:00:00 1970 +0000
118 118 summary: 2
119 119
120 120 $ hg -v history
121 121 changeset: 1:1e71731e6fbb
122 122 tag: tip
123 123 user: test
124 124 date: Thu Jan 01 00:00:00 1970 +0000
125 125 files: a b
126 126 description:
127 127 2
128 128
129 129
130 130 changeset: 0:c19d34741b0a
131 131 user: test
132 132 date: Thu Jan 01 00:00:00 1970 +0000
133 133 files: a
134 134 description:
135 135 1
136 136
137 137
138 138 $ hg diff --nodates
139 139 diff -r 1e71731e6fbb a
140 140 --- a/a
141 141 +++ b/a
142 142 @@ -1,1 +1,1 @@
143 143 -a2
144 144 +abc
145 145
146 146
147 147 create a second head
148 148
149 149 $ cd ../r1
150 150 $ hg up 0
151 151 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
152 152 $ echo b2 > b
153 153 $ echo a3 > a
154 154 $ hg addremove
155 155 adding b
156 156 $ hg commit -m "3"
157 157 created new head
158 158
159 159 $ cd ../r2
160 160 $ hg -q pull ../r1
161 161 $ hg status
162 162 M a
163 163 $ hg parents
164 164 changeset: 1:1e71731e6fbb
165 165 user: test
166 166 date: Thu Jan 01 00:00:00 1970 +0000
167 167 summary: 2
168 168
169 169 $ hg --debug up
170 170 abort: uncommitted changes
171 171 (commit and merge, or update --clean to discard changes)
172 172 [255]
173 173 $ hg --debug merge
174 174 abort: uncommitted changes
175 175 (use 'hg status' to list changes)
176 176 [255]
177 177 $ hg --debug merge -f
178 178 searching for copies back to rev 1
179 179 unmatched files new in both:
180 180 b
181 181 resolving manifests
182 182 branchmerge: True, force: True, partial: False
183 183 ancestor: c19d34741b0a, local: 1e71731e6fbb+, remote: 83c51d0caff4
184 184 a: versions differ -> m
185 185 preserving a for resolve of a
186 186 b: versions differ -> m
187 187 preserving b for resolve of b
188 188 updating: a 1/2 files (50.00%)
189 189 picked tool 'true' for a (binary False symlink False)
190 190 merging a
191 191 my a@1e71731e6fbb+ other a@83c51d0caff4 ancestor a@c19d34741b0a
192 192 updating: b 2/2 files (100.00%)
193 193 picked tool 'true' for b (binary False symlink False)
194 194 merging b
195 195 my b@1e71731e6fbb+ other b@83c51d0caff4 ancestor b@000000000000
196 196 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
197 197 (branch merge, don't forget to commit)
198 198 $ hg parents
199 199 changeset: 1:1e71731e6fbb
200 200 user: test
201 201 date: Thu Jan 01 00:00:00 1970 +0000
202 202 summary: 2
203 203
204 204 changeset: 2:83c51d0caff4
205 205 tag: tip
206 206 parent: 0:c19d34741b0a
207 207 user: test
208 208 date: Thu Jan 01 00:00:00 1970 +0000
209 209 summary: 3
210 210
211 211 $ hg diff --nodates
212 212 diff -r 1e71731e6fbb a
213 213 --- a/a
214 214 +++ b/a
215 215 @@ -1,1 +1,1 @@
216 216 -a2
217 217 +abc
218 218
219 219
220 220 test a local add
221 221
222 222 $ cd ..
223 223 $ hg init a
224 224 $ hg init b
225 225 $ echo a > a/a
226 226 $ echo a > b/a
227 227 $ hg --cwd a commit -A -m a
228 228 adding a
229 229 $ cd b
230 230 $ hg add a
231 231 $ hg pull -u ../a
232 232 pulling from ../a
233 233 requesting all changes
234 234 adding changesets
235 235 adding manifests
236 236 adding file changes
237 237 added 1 changesets with 1 changes to 1 files
238 238 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 239 $ hg st
240 240
241 241 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now