##// END OF EJS Templates
copies: calculate mergecopies() based on pathcopies()...
Martin von Zweigbergk -
r42408:57203e02 default
parent child Browse files
Show More
@@ -373,57 +373,6 b' def _computenonoverlap(repo, c1, c2, add'
373
373
374 return u1, u2
374 return u1, u2
375
375
376 def _makegetfctx(ctx):
377 """return a 'getfctx' function suitable for _checkcopies usage
378
379 We have to re-setup the function building 'filectx' for each
380 '_checkcopies' to ensure the linkrev adjustment is properly setup for
381 each. Linkrev adjustment is important to avoid bug in rename
382 detection. Moreover, having a proper '_ancestrycontext' setup ensures
383 the performance impact of this adjustment is kept limited. Without it,
384 each file could do a full dag traversal making the time complexity of
385 the operation explode (see issue4537).
386
387 This function exists here mostly to limit the impact on stable. Feel
388 free to refactor on default.
389 """
390 rev = ctx.rev()
391 repo = ctx._repo
392 ac = getattr(ctx, '_ancestrycontext', None)
393 if ac is None:
394 revs = [rev]
395 if rev is None:
396 revs = [p.rev() for p in ctx.parents()]
397 ac = repo.changelog.ancestors(revs, inclusive=True)
398 ctx._ancestrycontext = ac
399 def makectx(f, n):
400 if n in node.wdirfilenodeids: # in a working context?
401 if ctx.rev() is None:
402 return ctx.filectx(f)
403 return repo[None][f]
404 fctx = repo.filectx(f, fileid=n)
405 # setup only needed for filectx not create from a changectx
406 fctx._ancestrycontext = ac
407 fctx._descendantrev = rev
408 return fctx
409 return util.lrucachefunc(makectx)
410
411 def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
412 """combine partial copy paths"""
413 remainder = {}
414 for f in copyfrom:
415 if f in copyto:
416 finalcopy[copyto[f]] = copyfrom[f]
417 del copyto[f]
418 for f in incompletediverge:
419 assert f not in diverge
420 ic = incompletediverge[f]
421 if ic[0] in copyto:
422 diverge[f] = [copyto[ic[0]], ic[1]]
423 else:
424 remainder[f] = ic
425 return remainder
426
427 def mergecopies(repo, c1, c2, base):
376 def mergecopies(repo, c1, c2, base):
428 """
377 """
429 Finds moves and copies between context c1 and c2 that are relevant for
378 Finds moves and copies between context c1 and c2 that are relevant for
@@ -518,6 +467,23 b' def _isfullcopytraceable(repo, c1, base)'
518 return commits < sourcecommitlimit
467 return commits < sourcecommitlimit
519 return False
468 return False
520
469
470 def _checksinglesidecopies(src, dsts1, m1, m2, mb, c2, base,
471 copy, renamedelete):
472 if src not in m2:
473 # deleted on side 2
474 if src not in m1:
475 # renamed on side 1, deleted on side 2
476 renamedelete[src] = dsts1
477 elif m2[src] != mb[src]:
478 if not _related(c2[src], base[src]):
479 return
480 # modified on side 2
481 for dst in dsts1:
482 if dst not in m2:
483 # dst not added on side 2 (handle as regular
484 # "both created" case in manifestmerge otherwise)
485 copy[dst] = src
486
521 def _fullcopytracing(repo, c1, c2, base):
487 def _fullcopytracing(repo, c1, c2, base):
522 """ The full copytracing algorithm which finds all the new files that were
488 """ The full copytracing algorithm which finds all the new files that were
523 added from merge base up to the top commit and for each file it checks if
489 added from merge base up to the top commit and for each file it checks if
@@ -526,168 +492,73 b' def _fullcopytracing(repo, c1, c2, base)'
526 This is pretty slow when a lot of changesets are involved but will track all
492 This is pretty slow when a lot of changesets are involved but will track all
527 the copies.
493 the copies.
528 """
494 """
529 # In certain scenarios (e.g. graft, update or rebase), base can be
530 # overridden We still need to know a real common ancestor in this case We
531 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there
532 # can be multiple common ancestors, e.g. in case of bidmerge. Because our
533 # caller may not know if the revision passed in lieu of the CA is a genuine
534 # common ancestor or not without explicitly checking it, it's better to
535 # determine that here.
536 #
537 # base.isancestorof(wc) is False, work around that
538 _c1 = c1.p1() if c1.rev() is None else c1
539 _c2 = c2.p1() if c2.rev() is None else c2
540 # an endpoint is "dirty" if it isn't a descendant of the merge base
541 # if we have a dirty endpoint, we need to trigger graft logic, and also
542 # keep track of which endpoint is dirty
543 dirtyc1 = not base.isancestorof(_c1)
544 dirtyc2 = not base.isancestorof(_c2)
545 graft = dirtyc1 or dirtyc2
546 tca = base
547 if graft:
548 tca = _c1.ancestor(_c2)
549
550 limit = _findlimit(repo, c1, c2)
551
552 m1 = c1.manifest()
495 m1 = c1.manifest()
553 m2 = c2.manifest()
496 m2 = c2.manifest()
554 mb = base.manifest()
497 mb = base.manifest()
555
498
556 # gather data from _checkcopies:
499 copies1 = pathcopies(base, c1)
557 # - diverge = record all diverges in this dict
500 copies2 = pathcopies(base, c2)
558 # - copy = record all non-divergent copies in this dict
501
559 # - fullcopy = record all copies in this dict
502 inversecopies1 = {}
560 # - incomplete = record non-divergent partial copies here
503 inversecopies2 = {}
561 # - incompletediverge = record divergent partial copies here
504 for dst, src in copies1.items():
562 diverge = {} # divergence data is shared
505 inversecopies1.setdefault(src, []).append(dst)
563 incompletediverge = {}
506 for dst, src in copies2.items():
564 data1 = {'copy': {},
507 inversecopies2.setdefault(src, []).append(dst)
565 'fullcopy': {},
508
566 'incomplete': {},
509 copy = {}
567 'diverge': diverge,
510 diverge = {}
568 'incompletediverge': incompletediverge,
511 renamedelete = {}
569 }
512 allsources = set(inversecopies1) | set(inversecopies2)
570 data2 = {'copy': {},
513 for src in allsources:
571 'fullcopy': {},
514 dsts1 = inversecopies1.get(src)
572 'incomplete': {},
515 dsts2 = inversecopies2.get(src)
573 'diverge': diverge,
516 if dsts1 and dsts2:
574 'incompletediverge': incompletediverge,
517 # copied/renamed on both sides
575 }
518 if src not in m1 and src not in m2:
519 # renamed on both sides
520 dsts1 = set(dsts1)
521 dsts2 = set(dsts2)
522 # If there's some overlap in the rename destinations, we
523 # consider it not divergent. For example, if side 1 copies 'a'
524 # to 'b' and 'c' and deletes 'a', and side 2 copies 'a' to 'c'
525 # and 'd' and deletes 'a'.
526 if dsts1 & dsts2:
527 for dst in (dsts1 & dsts2):
528 copy[dst] = src
529 else:
530 diverge[src] = sorted(dsts1 | dsts2)
531 elif src in m1 and src in m2:
532 # copied on both sides
533 dsts1 = set(dsts1)
534 dsts2 = set(dsts2)
535 for dst in (dsts1 & dsts2):
536 copy[dst] = src
537 # TODO: Handle cases where it was renamed on one side and copied
538 # on the other side
539 elif dsts1:
540 # copied/renamed only on side 1
541 _checksinglesidecopies(src, dsts1, m1, m2, mb, c2, base,
542 copy, renamedelete)
543 elif dsts2:
544 # copied/renamed only on side 2
545 _checksinglesidecopies(src, dsts2, m2, m1, mb, c1, base,
546 copy, renamedelete)
547
548 renamedeleteset = set()
549 divergeset = set()
550 for src, dsts in diverge.items():
551 divergeset.update(dsts)
552 for src, dsts in renamedelete.items():
553 renamedeleteset.update(dsts)
576
554
577 # find interesting file sets from manifests
555 # find interesting file sets from manifests
578 addedinm1 = m1.filesnotin(mb, repo.narrowmatch())
556 addedinm1 = m1.filesnotin(mb, repo.narrowmatch())
579 addedinm2 = m2.filesnotin(mb, repo.narrowmatch())
557 addedinm2 = m2.filesnotin(mb, repo.narrowmatch())
580 bothnew = sorted(addedinm1 & addedinm2)
558 u1, u2 = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
581 if tca == base:
582 # unmatched file from base
583 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
584 u1u, u2u = u1r, u2r
585 else:
586 # unmatched file from base (DAG rotation in the graft case)
587 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
588 # unmatched file from topological common ancestors (no DAG rotation)
589 # need to recompute this for directory move handling when grafting
590 mta = tca.manifest()
591 u1u, u2u = _computenonoverlap(repo, c1, c2,
592 m1.filesnotin(mta, repo.narrowmatch()),
593 m2.filesnotin(mta, repo.narrowmatch()),
594 debug=False)
595
596 for f in u1u:
597 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, data1)
598
599 for f in u2u:
600 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, data2)
601
602 copy = dict(data1['copy'])
603 copy.update(data2['copy'])
604 fullcopy = dict(data1['fullcopy'])
605 fullcopy.update(data2['fullcopy'])
606
607 if dirtyc1:
608 _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
609 incompletediverge)
610 if dirtyc2:
611 _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
612 incompletediverge)
613
614 renamedelete = {}
615 renamedeleteset = set()
616 divergeset = set()
617 for of, fl in list(diverge.items()):
618 if len(fl) == 1 or of in c1 or of in c2:
619 del diverge[of] # not actually divergent, or not a rename
620 if of not in c1 and of not in c2:
621 # renamed on one side, deleted on the other side, but filter
622 # out files that have been renamed and then deleted
623 renamedelete[of] = [f for f in fl if f in c1 or f in c2]
624 renamedeleteset.update(fl) # reverse map for below
625 else:
626 divergeset.update(fl) # reverse map for below
627
559
628 bothdiverge = {}
560 fullcopy = copies1.copy()
629 bothincompletediverge = {}
561 fullcopy.update(copies2)
630 remainder = {}
631 both1 = {'copy': {},
632 'fullcopy': {},
633 'incomplete': {},
634 'diverge': bothdiverge,
635 'incompletediverge': bothincompletediverge
636 }
637 both2 = {'copy': {},
638 'fullcopy': {},
639 'incomplete': {},
640 'diverge': bothdiverge,
641 'incompletediverge': bothincompletediverge
642 }
643 for f in bothnew:
644 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, both1)
645 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, both2)
646 if dirtyc1 and dirtyc2:
647 remainder = _combinecopies(both2['incomplete'], both1['incomplete'],
648 copy, bothdiverge, bothincompletediverge)
649 remainder1 = _combinecopies(both1['incomplete'], both2['incomplete'],
650 copy, bothdiverge, bothincompletediverge)
651 remainder.update(remainder1)
652 elif dirtyc1:
653 # incomplete copies may only be found on the "dirty" side for bothnew
654 assert not both2['incomplete']
655 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
656 bothincompletediverge)
657 elif dirtyc2:
658 assert not both1['incomplete']
659 remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
660 bothincompletediverge)
661 else:
662 # incomplete copies and divergences can't happen outside grafts
663 assert not both1['incomplete']
664 assert not both2['incomplete']
665 assert not bothincompletediverge
666 for f in remainder:
667 assert f not in bothdiverge
668 ic = remainder[f]
669 if ic[0] in (m1 if dirtyc1 else m2):
670 # backed-out rename on one side, but watch out for deleted files
671 bothdiverge[f] = ic
672 for of, fl in bothdiverge.items():
673 if len(fl) == 2 and fl[0] == fl[1]:
674 copy[fl[0]] = of # not actually divergent, just matching renames
675
676 # Sometimes we get invalid copies here (the "and not remotebase" in
677 # _checkcopies() seems suspicious). Filter them out.
678 for dst, src in fullcopy.copy().items():
679 if src not in mb:
680 del fullcopy[dst]
681 # Sometimes we forget to add entries from "copy" to "fullcopy", so fix
682 # that up here
683 for dst, src in copy.items():
684 fullcopy[dst] = src
685 # Sometimes we forget to add entries from "diverge" to "fullcopy", so fix
686 # that up here
687 for src, dsts in diverge.items():
688 for dst in dsts:
689 fullcopy[dst] = src
690
691 if not fullcopy:
562 if not fullcopy:
692 return copy, {}, diverge, renamedelete, {}
563 return copy, {}, diverge, renamedelete, {}
693
564
@@ -752,7 +623,7 b' def _fullcopytracing(repo, c1, c2, base)'
752
623
753 movewithdir = {}
624 movewithdir = {}
754 # check unaccounted nonoverlapping files against directory moves
625 # check unaccounted nonoverlapping files against directory moves
755 for f in u1r + u2r:
626 for f in u1 + u2:
756 if f not in fullcopy:
627 if f not in fullcopy:
757 for d in dirmove:
628 for d in dirmove:
758 if f.startswith(d):
629 if f.startswith(d):
@@ -899,99 +770,6 b' def _related(f1, f2):'
899 except StopIteration:
770 except StopIteration:
900 return False
771 return False
901
772
902 def _checkcopies(srcctx, dstctx, f, base, tca, remotebase, limit, data):
903 """
904 check possible copies of f from msrc to mdst
905
906 srcctx = starting context for f in msrc
907 dstctx = destination context for f in mdst
908 f = the filename to check (as in msrc)
909 base = the changectx used as a merge base
910 tca = topological common ancestor for graft-like scenarios
911 remotebase = True if base is outside tca::srcctx, False otherwise
912 limit = the rev number to not search beyond
913 data = dictionary of dictionary to store copy data. (see mergecopies)
914
915 note: limit is only an optimization, and provides no guarantee that
916 irrelevant revisions will not be visited
917 there is no easy way to make this algorithm stop in a guaranteed way
918 once it "goes behind a certain revision".
919 """
920
921 msrc = srcctx.manifest()
922 mdst = dstctx.manifest()
923 mb = base.manifest()
924 mta = tca.manifest()
925 # Might be true if this call is about finding backward renames,
926 # This happens in the case of grafts because the DAG is then rotated.
927 # If the file exists in both the base and the source, we are not looking
928 # for a rename on the source side, but on the part of the DAG that is
929 # traversed backwards.
930 #
931 # In the case there is both backward and forward renames (before and after
932 # the base) this is more complicated as we must detect a divergence.
933 # We use 'backwards = False' in that case.
934 backwards = not remotebase and base != tca and f in mb
935 getsrcfctx = _makegetfctx(srcctx)
936 getdstfctx = _makegetfctx(dstctx)
937
938 if msrc[f] == mb.get(f) and not remotebase:
939 # Nothing to merge
940 return
941
942 of = None
943 seen = {f}
944 for oc in getsrcfctx(f, msrc[f]).ancestors():
945 of = oc.path()
946 if of in seen:
947 # check limit late - grab last rename before
948 if oc.linkrev() < limit:
949 break
950 continue
951 seen.add(of)
952
953 # remember for dir rename detection
954 if backwards:
955 data['fullcopy'][of] = f # grafting backwards through renames
956 else:
957 data['fullcopy'][f] = of
958 if of not in mdst:
959 continue # no match, keep looking
960 if mdst[of] == mb.get(of):
961 return # no merge needed, quit early
962 c2 = getdstfctx(of, mdst[of])
963 # c2 might be a plain new file on added on destination side that is
964 # unrelated to the droids we are looking for.
965 cr = _related(oc, c2)
966 if cr and (of == f or of == c2.path()): # non-divergent
967 if backwards:
968 data['copy'][of] = f
969 elif of in mb:
970 data['copy'][f] = of
971 elif remotebase: # special case: a <- b <- a -> b "ping-pong" rename
972 data['copy'][of] = f
973 del data['fullcopy'][f]
974 data['fullcopy'][of] = f
975 else: # divergence w.r.t. graft CA on one side of topological CA
976 for sf in seen:
977 if sf in mb:
978 assert sf not in data['diverge']
979 data['diverge'][sf] = [f, of]
980 break
981 return
982
983 if of in mta:
984 if backwards or remotebase:
985 data['incomplete'][of] = f
986 else:
987 for sf in seen:
988 if sf in mb:
989 if tca == base:
990 data['diverge'].setdefault(sf, []).append(f)
991 else:
992 data['incompletediverge'][sf] = [of, f]
993 return
994
995 def duplicatecopies(repo, wctx, rev, fromrev, skiprev=None):
773 def duplicatecopies(repo, wctx, rev, fromrev, skiprev=None):
996 """reproduce copies from fromrev to rev in the dirstate
774 """reproduce copies from fromrev to rev in the dirstate
997
775
@@ -273,37 +273,10 b' annotate after merge with -l'
273 > EOF
273 > EOF
274 $ hg ci -mc -d '3 0'
274 $ hg ci -mc -d '3 0'
275 created new head
275 created new head
276 BROKEN: 'a' was copied to 'b' on both sides. We should not get a merge conflict here
277 $ hg merge
276 $ hg merge
278 merging b
277 merging b
279 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
278 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
280 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
279 (branch merge, don't forget to commit)
281 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
282 [1]
283 $ cat b
284 <<<<<<< working copy: b80e3e32f75a - test: c
285 a
286 z
287 a
288 ||||||| base
289 =======
290 a
291 a
292 a
293 b4
294 c
295 b5
296 >>>>>>> merge rev: 64afcdf8e29e - test: mergeb
297 $ cat <<EOF > b
298 > a
299 > z
300 > a
301 > b4
302 > c
303 > b5
304 > EOF
305 $ hg resolve --mark -q
306 $ rm b.orig
307 $ echo d >> b
280 $ echo d >> b
308 $ hg ci -mmerge2 -d '4 0'
281 $ hg ci -mmerge2 -d '4 0'
309
282
@@ -787,12 +787,11 b' Amend a merge changeset (with renames du'
787 Update to p1 with 'aaa' modified. 'aaa' was renamed from 'aa' in p2. 'aa' exists
787 Update to p1 with 'aaa' modified. 'aaa' was renamed from 'aa' in p2. 'aa' exists
788 in p1 too, but it was recorded as copied from p2.
788 in p1 too, but it was recorded as copied from p2.
789 $ echo modified >> aaa
789 $ echo modified >> aaa
790 BROKEN: should not be follow the rename back to 'aa' here, since the rename
791 happened compared to p2
792 $ hg co -m '.^' -t :merge3
790 $ hg co -m '.^' -t :merge3
793 merging aaa and aa to aa
791 file 'aaa' was deleted in other [destination] but was modified in local [working copy].
794 warning: conflicts while merging aa! (edit, then use 'hg resolve --mark')
792 What do you want to do?
795 0 files updated, 0 files merged, 1 files removed, 1 files unresolved
793 use (c)hanged version, (d)elete, or leave (u)nresolved? u
794 1 files updated, 0 files merged, 1 files removed, 1 files unresolved
796 use 'hg resolve' to retry unresolved file merges
795 use 'hg resolve' to retry unresolved file merges
797 [1]
796 [1]
798 $ hg co -C tip
797 $ hg co -C tip
@@ -549,9 +549,6 b' test reflect that for this particular ca'
549
549
550 Grafting revision 4 on top of revision 2, showing that it respect the rename:
550 Grafting revision 4 on top of revision 2, showing that it respect the rename:
551
551
552 TODO: Make this work with copy info in changesets (probably by writing a
553 changeset-centric version of copies.mergecopies())
554 #if no-changeset
555 $ hg up 2 -q
552 $ hg up 2 -q
556 $ hg graft -r 4 --base 3 --hidden
553 $ hg graft -r 4 --base 3 --hidden
557 grafting 4:af28412ec03c "added d, modified b" (tip)
554 grafting 4:af28412ec03c "added d, modified b" (tip)
@@ -560,15 +557,14 b' changeset-centric version of copies.merg'
560 $ hg l -l1 -p
557 $ hg l -l1 -p
561 @ 5 added d, modified b
558 @ 5 added d, modified b
562 | b1
559 | b1
563 ~ diff -r 5a4825cc2926 -r 94a2f1a0e8e2 b1
560 ~ diff -r 5a4825cc2926 -r 94a2f1a0e8e2 b1 (no-changeset !)
561 ~ diff -r f5474f5023a8 -r ef7c02d69f3d b1 (changeset !)
564 --- a/b1 Thu Jan 01 00:00:00 1970 +0000
562 --- a/b1 Thu Jan 01 00:00:00 1970 +0000
565 +++ b/b1 Thu Jan 01 00:00:00 1970 +0000
563 +++ b/b1 Thu Jan 01 00:00:00 1970 +0000
566 @@ -1,1 +1,2 @@
564 @@ -1,1 +1,2 @@
567 b
565 b
568 +baba
566 +baba
569
567
570 #endif
571
572 Test to make sure that fullcopytracing algorithm don't fail when both the merging csets are dirty
568 Test to make sure that fullcopytracing algorithm don't fail when both the merging csets are dirty
573 (a dirty cset is one who is not the descendant of merge base)
569 (a dirty cset is one who is not the descendant of merge base)
574 -------------------------------------------------------------------------------------------------
570 -------------------------------------------------------------------------------------------------
@@ -273,37 +273,10 b' annotate after merge with -l'
273 > EOF
273 > EOF
274 $ hg ci -mc -d '3 0'
274 $ hg ci -mc -d '3 0'
275 created new head
275 created new head
276 BROKEN: 'a' was copied to 'b' on both sides. We should not get a merge conflict here
277 $ hg merge
276 $ hg merge
278 merging b
277 merging b
279 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
278 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
280 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
279 (branch merge, don't forget to commit)
281 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
282 [1]
283 $ cat b
284 <<<<<<< working copy: b80e3e32f75a - test: c
285 a
286 z
287 a
288 ||||||| base
289 =======
290 a
291 a
292 a
293 b4
294 c
295 b5
296 >>>>>>> merge rev: 64afcdf8e29e - test: mergeb
297 $ cat <<EOF > b
298 > a
299 > z
300 > a
301 > b4
302 > c
303 > b5
304 > EOF
305 $ hg resolve --mark -q
306 $ rm b.orig
307 $ echo d >> b
280 $ echo d >> b
308 $ hg ci -mmerge2 -d '4 0'
281 $ hg ci -mmerge2 -d '4 0'
309
282
@@ -75,6 +75,8 b' Specifying child as --base revision fail'
75
75
76 $ hg graft -r 2 --base 3
76 $ hg graft -r 2 --base 3
77 grafting 2:5c095ad7e90f "2"
77 grafting 2:5c095ad7e90f "2"
78 note: possible conflict - c was deleted and renamed to:
79 a
78 note: graft of 2:5c095ad7e90f created no changes to commit
80 note: graft of 2:5c095ad7e90f created no changes to commit
79
81
80 Can't continue without starting:
82 Can't continue without starting:
@@ -220,6 +222,9 b' Graft out of order, skipping a merge and'
220 committing changelog
222 committing changelog
221 updating the branch cache
223 updating the branch cache
222 grafting 5:97f8bfe72746 "5"
224 grafting 5:97f8bfe72746 "5"
225 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
226 src: 'c' -> dst: 'b'
227 checking for directory renames
223 resolving manifests
228 resolving manifests
224 branchmerge: True, force: True, partial: False
229 branchmerge: True, force: True, partial: False
225 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
230 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
@@ -233,6 +238,9 b' Graft out of order, skipping a merge and'
233 $ HGEDITOR=cat hg graft 4 3 --log --debug
238 $ HGEDITOR=cat hg graft 4 3 --log --debug
234 scanning for duplicate grafts
239 scanning for duplicate grafts
235 grafting 4:9c233e8e184d "4"
240 grafting 4:9c233e8e184d "4"
241 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
242 src: 'c' -> dst: 'b'
243 checking for directory renames
236 resolving manifests
244 resolving manifests
237 branchmerge: True, force: True, partial: False
245 branchmerge: True, force: True, partial: False
238 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
246 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
@@ -1129,7 +1137,6 b' and A.3 with a local content change to b'
1129 grafting 2:f58c7e2b28fa "C0"
1137 grafting 2:f58c7e2b28fa "C0"
1130 merging f1e and f1b to f1e
1138 merging f1e and f1b to f1e
1131 merging f2a and f2c to f2c
1139 merging f2a and f2c to f2c
1132 merging f5b and f5a to f5a
1133
1140
1134 Test the cases A.1 (f4x) and A.7 (f3x).
1141 Test the cases A.1 (f4x) and A.7 (f3x).
1135
1142
@@ -1688,13 +1688,8 b' Check debug output for copy tracing'
1688 Check that merging across the rename works
1688 Check that merging across the rename works
1689
1689
1690 $ echo modified >> renamed
1690 $ echo modified >> renamed
1691 BROKEN: This should propagate the change to 'f'
1692 $ hg co -m 4
1691 $ hg co -m 4
1693 file 'renamed' was deleted in other [destination] but was modified in local [working copy].
1692 merging renamed and f to f
1694 What do you want to do?
1693 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
1695 use (c)hanged version, (d)elete, or leave (u)nresolved? u
1696 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1697 use 'hg resolve' to retry unresolved file merges
1698 [1]
1699
1694
1700 $ cd ..
1695 $ cd ..
@@ -433,6 +433,9 b' m "um a c" "um x c" " " "10 do merg'
433 --------------
433 --------------
434 test L:nc a b R:up b W: - 12 merge b no ancestor
434 test L:nc a b R:up b W: - 12 merge b no ancestor
435 --------------
435 --------------
436 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
437 src: 'a' -> dst: 'b'
438 checking for directory renames
436 resolving manifests
439 resolving manifests
437 branchmerge: True, force: False, partial: False
440 branchmerge: True, force: False, partial: False
438 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: af30c7647fc7
441 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: af30c7647fc7
@@ -469,6 +472,9 b' m "um a c" "um x c" " " "10 do merg'
469 --------------
472 --------------
470 test L:up b R:nm a b W: - 13 merge b no ancestor
473 test L:up b R:nm a b W: - 13 merge b no ancestor
471 --------------
474 --------------
475 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
476 src: 'a' -> dst: 'b'
477 checking for directory renames
472 resolving manifests
478 resolving manifests
473 branchmerge: True, force: False, partial: False
479 branchmerge: True, force: False, partial: False
474 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
480 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
@@ -506,6 +512,9 b' m "um a c" "um x c" " " "10 do merg'
506 --------------
512 --------------
507 test L:nc a b R:up a b W: - 14 merge b no ancestor
513 test L:nc a b R:up a b W: - 14 merge b no ancestor
508 --------------
514 --------------
515 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
516 src: 'a' -> dst: 'b'
517 checking for directory renames
509 resolving manifests
518 resolving manifests
510 branchmerge: True, force: False, partial: False
519 branchmerge: True, force: False, partial: False
511 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
520 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
@@ -543,6 +552,9 b' m "um a c" "um x c" " " "10 do merg'
543 --------------
552 --------------
544 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
553 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
545 --------------
554 --------------
555 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
556 src: 'a' -> dst: 'b'
557 checking for directory renames
546 resolving manifests
558 resolving manifests
547 branchmerge: True, force: False, partial: False
559 branchmerge: True, force: False, partial: False
548 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
560 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
@@ -580,6 +592,9 b' m "um a c" "um x c" " " "10 do merg'
580 --------------
592 --------------
581 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
593 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
582 --------------
594 --------------
595 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
596 src: 'a' -> dst: 'b'
597 checking for directory renames
583 resolving manifests
598 resolving manifests
584 branchmerge: True, force: False, partial: False
599 branchmerge: True, force: False, partial: False
585 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
600 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
@@ -617,6 +632,9 b' m "um a c" "um x c" " " "10 do merg'
617 --------------
632 --------------
618 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
633 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
619 --------------
634 --------------
635 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
636 src: 'a' -> dst: 'b'
637 checking for directory renames
620 resolving manifests
638 resolving manifests
621 branchmerge: True, force: False, partial: False
639 branchmerge: True, force: False, partial: False
622 ancestor: 924404dff337, local: 0b76e65c8289+, remote: 4ce40f5aca24
640 ancestor: 924404dff337, local: 0b76e65c8289+, remote: 4ce40f5aca24
@@ -653,6 +671,9 b' m "um a c" "um x c" " " "10 do merg'
653 --------------
671 --------------
654 test L:nm a b R:up a b W: - 18 merge b no ancestor
672 test L:nm a b R:up a b W: - 18 merge b no ancestor
655 --------------
673 --------------
674 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
675 src: 'a' -> dst: 'b'
676 checking for directory renames
656 resolving manifests
677 resolving manifests
657 branchmerge: True, force: False, partial: False
678 branchmerge: True, force: False, partial: False
658 ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
679 ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
@@ -695,6 +716,9 b' m "um a c" "um x c" " " "10 do merg'
695 --------------
716 --------------
696 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
717 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
697 --------------
718 --------------
719 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
720 src: 'a' -> dst: 'b'
721 checking for directory renames
698 resolving manifests
722 resolving manifests
699 branchmerge: True, force: False, partial: False
723 branchmerge: True, force: False, partial: False
700 ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
724 ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
General Comments 0
You need to be logged in to leave comments. Login now