Mercurial > hg
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 |