comparison mercurial/copies.py @ 46563:c19c662097e1

copies: detect case when a merge decision overwrite previous data We now detect and record when a merge case required special logic (eg: thing that append during the merge, ambiguity leading to picking p1 data, etc) and we explicitly mark the result as superseding the previous data. This fixes the family of test we previously added. Differential Revision: https://phab.mercurial-scm.org/D9613
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Sat, 12 Dec 2020 19:35:08 +0100
parents c692384bb559
children 34827c95092c
comparison
equal deleted inserted replaced
46562:c692384bb559 46563:c19c662097e1
432 # This is an arbitrary choice made anew when implementing 432 # This is an arbitrary choice made anew when implementing
433 # changeset based copies. It was made without regards with 433 # changeset based copies. It was made without regards with
434 # potential filelog related behavior. 434 # potential filelog related behavior.
435 assert parent == 2 435 assert parent == 2
436 current_copies = _merge_copies_dict( 436 current_copies = _merge_copies_dict(
437 newcopies, current_copies, isancestor, changes 437 newcopies,
438 current_copies,
439 isancestor,
440 changes,
441 current_rev,
438 ) 442 )
439 all_copies[current_rev] = current_copies 443 all_copies[current_rev] = current_copies
440 444
441 # filter out internal details and return a {dest: source mapping} 445 # filter out internal details and return a {dest: source mapping}
442 final_copies = {} 446 final_copies = {}
454 PICK_MINOR = 0 458 PICK_MINOR = 0
455 PICK_MAJOR = 1 459 PICK_MAJOR = 1
456 PICK_EITHER = 2 460 PICK_EITHER = 2
457 461
458 462
459 def _merge_copies_dict(minor, major, isancestor, changes): 463 def _merge_copies_dict(minor, major, isancestor, changes, current_merge):
460 """merge two copies-mapping together, minor and major 464 """merge two copies-mapping together, minor and major
461 465
462 In case of conflict, value from "major" will be picked. 466 In case of conflict, value from "major" will be picked.
463 467
464 - `isancestors(low_rev, high_rev)`: callable return True if `low_rev` is an 468 - `isancestors(low_rev, high_rev)`: callable return True if `low_rev` is an
472 for dest, value in major.items(): 476 for dest, value in major.items():
473 other = minor.get(dest) 477 other = minor.get(dest)
474 if other is None: 478 if other is None:
475 minor[dest] = value 479 minor[dest] = value
476 else: 480 else:
477 pick = _compare_values(changes, isancestor, dest, other, value) 481 pick, overwrite = _compare_values(
478 if pick == PICK_MAJOR: 482 changes, isancestor, dest, other, value
483 )
484 if overwrite:
485 if pick == PICK_MAJOR:
486 minor[dest] = (current_merge, value[1])
487 else:
488 minor[dest] = (current_merge, other[1])
489 elif pick == PICK_MAJOR:
479 minor[dest] = value 490 minor[dest] = value
480 return minor 491 return minor
481 492
482 493
483 def _compare_values(changes, isancestor, dest, minor, major): 494 def _compare_values(changes, isancestor, dest, minor, major):
484 """compare two value within a _merge_copies_dict loop iteration 495 """compare two value within a _merge_copies_dict loop iteration
485 496
486 return pick 497 return (pick, overwrite).
487 498
488 - pick is one of PICK_MINOR, PICK_MAJOR or PICK_EITHER 499 - pick is one of PICK_MINOR, PICK_MAJOR or PICK_EITHER
500 - overwrite is True if pick is a return of an ambiguity that needs resolution.
489 """ 501 """
490 major_tt, major_value = major 502 major_tt, major_value = major
491 minor_tt, minor_value = minor 503 minor_tt, minor_value = minor
492 504
493 if major_tt == minor_tt: 505 if major_tt == minor_tt:
494 # if it comes from the same revision it must be the same value 506 # if it comes from the same revision it must be the same value
495 assert major_value == minor_value 507 assert major_value == minor_value
496 return PICK_EITHER 508 return PICK_EITHER, False
497 elif ( 509 elif (
498 changes is not None 510 changes is not None
499 and minor_value is not None 511 and minor_value is not None
500 and major_value is None 512 and major_value is None
501 and dest in changes.salvaged 513 and dest in changes.salvaged
502 ): 514 ):
503 # In this case, a deletion was reverted, the "alive" value overwrite 515 # In this case, a deletion was reverted, the "alive" value overwrite
504 # the deleted one. 516 # the deleted one.
505 return PICK_MINOR 517 return PICK_MINOR, True
506 elif ( 518 elif (
507 changes is not None 519 changes is not None
508 and major_value is not None 520 and major_value is not None
509 and minor_value is None 521 and minor_value is None
510 and dest in changes.salvaged 522 and dest in changes.salvaged
511 ): 523 ):
512 # In this case, a deletion was reverted, the "alive" value overwrite 524 # In this case, a deletion was reverted, the "alive" value overwrite
513 # the deleted one. 525 # the deleted one.
514 return PICK_MAJOR 526 return PICK_MAJOR, True
515 elif isancestor(minor_tt, major_tt): 527 elif isancestor(minor_tt, major_tt):
516 if changes is not None and dest in changes.merged: 528 if changes is not None and dest in changes.merged:
517 # change to dest happened on the branch without copy-source change, 529 # change to dest happened on the branch without copy-source change,
518 # so both source are valid and "major" wins. 530 # so both source are valid and "major" wins.
519 return PICK_MAJOR 531 return PICK_MAJOR, True
520 else: 532 else:
521 return PICK_MAJOR 533 return PICK_MAJOR, False
522 elif isancestor(major_tt, minor_tt): 534 elif isancestor(major_tt, minor_tt):
523 if changes is not None and dest in changes.merged: 535 if changes is not None and dest in changes.merged:
524 # change to dest happened on the branch without copy-source change, 536 # change to dest happened on the branch without copy-source change,
525 # so both source are valid and "major" wins. 537 # so both source are valid and "major" wins.
526 return PICK_MAJOR 538 return PICK_MAJOR, True
527 else: 539 else:
528 return PICK_MINOR 540 return PICK_MINOR, False
529 elif minor_value is None: 541 elif minor_value is None:
530 # in case of conflict, the "alive" side wins. 542 # in case of conflict, the "alive" side wins.
531 return PICK_MAJOR 543 return PICK_MAJOR, True
532 elif major_value is None: 544 elif major_value is None:
533 # in case of conflict, the "alive" side wins. 545 # in case of conflict, the "alive" side wins.
534 return PICK_MINOR 546 return PICK_MINOR, True
535 else: 547 else:
536 # in case of conflict where both side are alive, major wins. 548 # in case of conflict where both side are alive, major wins.
537 return PICK_MAJOR 549 return PICK_MAJOR, True
538 550
539 551
540 def _revinfo_getter_extra(repo): 552 def _revinfo_getter_extra(repo):
541 """return a function that return multiple data given a <rev>"i 553 """return a function that return multiple data given a <rev>"i
542 554