372 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2) |
372 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2) |
373 u1u, u2u = u1r, u2r |
373 u1u, u2u = u1r, u2r |
374 bothnew = sorted(addedinm1 & addedinm2) |
374 bothnew = sorted(addedinm1 & addedinm2) |
375 |
375 |
376 for f in u1u: |
376 for f in u1u: |
377 _checkcopies(c1, f, m1, m2, base, limit, data1) |
377 _checkcopies(c1, f, m1, m2, base, tca, limit, data1) |
378 |
378 |
379 for f in u2u: |
379 for f in u2u: |
380 _checkcopies(c2, f, m2, m1, base, limit, data2) |
380 _checkcopies(c2, f, m2, m1, base, tca, limit, data2) |
381 |
381 |
382 copy = dict(data1['copy'].items() + data2['copy'].items()) |
382 copy = dict(data1['copy'].items() + data2['copy'].items()) |
383 fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items()) |
383 fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items()) |
384 |
384 |
385 renamedelete = {} |
385 renamedelete = {} |
403 bothdata = {'copy': {}, |
403 bothdata = {'copy': {}, |
404 'fullcopy': {}, |
404 'fullcopy': {}, |
405 'diverge': bothdiverge, |
405 'diverge': bothdiverge, |
406 } |
406 } |
407 for f in bothnew: |
407 for f in bothnew: |
408 _checkcopies(c1, f, m1, m2, base, limit, bothdata) |
408 _checkcopies(c1, f, m1, m2, base, tca, limit, bothdata) |
409 _checkcopies(c2, f, m2, m1, base, limit, bothdata) |
409 _checkcopies(c2, f, m2, m1, base, tca, limit, bothdata) |
410 for of, fl in bothdiverge.items(): |
410 for of, fl in bothdiverge.items(): |
411 if len(fl) == 2 and fl[0] == fl[1]: |
411 if len(fl) == 2 and fl[0] == fl[1]: |
412 copy[fl[0]] = of # not actually divergent, just matching renames |
412 copy[fl[0]] = of # not actually divergent, just matching renames |
413 |
413 |
414 if fullcopy and repo.ui.debugflag: |
414 if fullcopy and repo.ui.debugflag: |
519 elif f1r == f2r or f1r < limit or f2r < limit: |
519 elif f1r == f2r or f1r < limit or f2r < limit: |
520 return False # copy no longer relevant |
520 return False # copy no longer relevant |
521 except StopIteration: |
521 except StopIteration: |
522 return False |
522 return False |
523 |
523 |
524 def _checkcopies(ctx, f, m1, m2, base, limit, data): |
524 def _checkcopies(ctx, f, m1, m2, base, tca, limit, data): |
525 """ |
525 """ |
526 check possible copies of f from m1 to m2 |
526 check possible copies of f from m1 to m2 |
527 |
527 |
528 ctx = starting context for f in m1 |
528 ctx = starting context for f in m1 |
529 f = the filename to check (as in m1) |
529 f = the filename to check (as in m1) |
530 m1 = the source manifest |
530 m1 = the source manifest |
531 m2 = the destination manifest |
531 m2 = the destination manifest |
532 base = the changectx used as a merge base |
532 base = the changectx used as a merge base |
|
533 tca = topological common ancestor for graft-like scenarios |
533 limit = the rev number to not search beyond |
534 limit = the rev number to not search beyond |
534 data = dictionary of dictionary to store copy data. (see mergecopies) |
535 data = dictionary of dictionary to store copy data. (see mergecopies) |
535 |
536 |
536 note: limit is only an optimization, and there is no guarantee that |
537 note: limit is only an optimization, and there is no guarantee that |
537 irrelevant revisions will not be limited |
538 irrelevant revisions will not be limited |
538 there is no easy way to make this algorithm stop in a guaranteed way |
539 there is no easy way to make this algorithm stop in a guaranteed way |
539 once it "goes behind a certain revision". |
540 once it "goes behind a certain revision". |
540 """ |
541 """ |
541 |
542 |
542 mb = base.manifest() |
543 mb = base.manifest() |
|
544 # Might be true if this call is about finding backward renames, |
|
545 # This happens in the case of grafts because the DAG is then rotated. |
|
546 # If the file exists in both the base and the source, we are not looking |
|
547 # for a rename on the source side, but on the part of the DAG that is |
|
548 # traversed backwards. |
|
549 # |
|
550 # In the case there is both backward and forward renames (before and after |
|
551 # the base) this is more complicated as we must detect a divergence. This |
|
552 # is currently broken and hopefully some later code update will make that |
|
553 # work (we use 'backwards = False' in that case) |
|
554 backwards = base != tca and f in mb |
543 getfctx = _makegetfctx(ctx) |
555 getfctx = _makegetfctx(ctx) |
544 |
556 |
545 of = None |
557 of = None |
546 seen = set([f]) |
558 seen = set([f]) |
547 for oc in getfctx(f, m1[f]).ancestors(): |
559 for oc in getfctx(f, m1[f]).ancestors(): |
552 if ocr < limit: |
564 if ocr < limit: |
553 break |
565 break |
554 continue |
566 continue |
555 seen.add(of) |
567 seen.add(of) |
556 |
568 |
557 data['fullcopy'][f] = of # remember for dir rename detection |
569 # remember for dir rename detection |
|
570 if backwards: |
|
571 data['fullcopy'][of] = f # grafting backwards through renames |
|
572 else: |
|
573 data['fullcopy'][f] = of |
558 if of not in m2: |
574 if of not in m2: |
559 continue # no match, keep looking |
575 continue # no match, keep looking |
560 if m2[of] == mb.get(of): |
576 if m2[of] == mb.get(of): |
561 return # no merge needed, quit early |
577 return # no merge needed, quit early |
562 c2 = getfctx(of, m2[of]) |
578 c2 = getfctx(of, m2[of]) |
563 # c2 might be a plain new file on added on destination side that is |
579 # c2 might be a plain new file on added on destination side that is |
564 # unrelated to the droids we are looking for. |
580 # unrelated to the droids we are looking for. |
565 cr = _related(oc, c2, base.rev()) |
581 cr = _related(oc, c2, tca.rev()) |
566 if cr and (of == f or of == c2.path()): # non-divergent |
582 if cr and (of == f or of == c2.path()): # non-divergent |
567 if of in mb: |
583 if backwards: |
|
584 data['copy'][of] = f |
|
585 elif of in mb: |
568 data['copy'][f] = of |
586 data['copy'][f] = of |
569 return |
587 return |
570 |
588 |
571 if of in mb: |
589 if of in mb: |
572 data['diverge'].setdefault(of, []).append(f) |
590 data['diverge'].setdefault(of, []).append(f) |