comparison rust/hg-core/src/copy_tracing.rs @ 46126:61afe6215aef

copies-rust: extract conflicting value comparison in its own function First, that logic is complicated enough to be in it own function. Second, we want to start adding alternative path within the merge code so we need this logic easily accessible in multiple places. Differential Revision: https://phab.mercurial-scm.org/D9424
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Sat, 21 Nov 2020 09:30:34 +0100
parents dacb771f6dd2
children 94300498491e
comparison
equal deleted inserted replaced
46125:ceaf1646f420 46126:61afe6215aef
455 455
456 /// merge two copies-mapping together, minor and major 456 /// merge two copies-mapping together, minor and major
457 /// 457 ///
458 /// In case of conflict, value from "major" will be picked, unless in some 458 /// In case of conflict, value from "major" will be picked, unless in some
459 /// cases. See inline documentation for details. 459 /// cases. See inline documentation for details.
460 #[allow(clippy::if_same_then_else)]
461 fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>( 460 fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>(
462 minor: TimeStampedPathCopies, 461 minor: TimeStampedPathCopies,
463 major: TimeStampedPathCopies, 462 major: TimeStampedPathCopies,
464 changes: &ChangedFiles, 463 changes: &ChangedFiles,
465 oracle: &mut AncestorOracle<A>, 464 oracle: &mut AncestorOracle<A>,
498 DiffItem::Add(k, v) => to_minor(k, v), 497 DiffItem::Add(k, v) => to_minor(k, v),
499 DiffItem::Remove(k, v) => to_major(k, v), 498 DiffItem::Remove(k, v) => to_major(k, v),
500 DiffItem::Update { old, new } => { 499 DiffItem::Update { old, new } => {
501 let (dest, src_major) = new; 500 let (dest, src_major) = new;
502 let (_, src_minor) = old; 501 let (_, src_minor) = old;
503 let mut pick_minor = || (to_major(dest, src_minor)); 502 match compare_value(
504 let mut pick_major = || (to_minor(dest, src_major)); 503 changes, oracle, dest, src_minor, src_major,
505 if src_major.path == src_minor.path { 504 ) {
506 // we have the same value, but from other source; 505 MergePick::Major => to_minor(dest, src_major),
507 if src_major.rev == src_minor.rev { 506 MergePick::Minor => to_major(dest, src_minor),
508 // If the two entry are identical, no need to do 507 // If the two entry are identical, no need to do
509 // anything (but diff should not have yield them) 508 // anything (but diff should not have yield them)
510 unreachable!(); 509 MergePick::Any => unreachable!(),
511 } else if oracle.is_ancestor(src_major.rev, src_minor.rev)
512 {
513 pick_minor();
514 } else {
515 pick_major();
516 }
517 } else if src_major.rev == src_minor.rev {
518 // We cannot get copy information for both p1 and p2 in the
519 // same rev. So this is the same value.
520 unreachable!();
521 } else {
522 let action = changes.get_merge_case(&dest);
523 if src_major.path.is_none()
524 && action == MergeCase::Salvaged
525 {
526 // If the file is "deleted" in the major side but was
527 // salvaged by the merge, we keep the minor side alive
528 pick_minor();
529 } else if src_minor.path.is_none()
530 && action == MergeCase::Salvaged
531 {
532 // If the file is "deleted" in the minor side but was
533 // salvaged by the merge, unconditionnaly preserve the
534 // major side.
535 pick_major();
536 } else if action == MergeCase::Merged {
537 // If the file was actively merged, copy information
538 // from each side might conflict. The major side will
539 // win such conflict.
540 pick_major();
541 } else if oracle.is_ancestor(src_major.rev, src_minor.rev)
542 {
543 // If the minor side is strictly newer than the major
544 // side, it should be kept.
545 pick_minor();
546 } else if src_major.path.is_some() {
547 // without any special case, the "major" value win
548 // other the "minor" one.
549 pick_major();
550 } else if oracle.is_ancestor(src_minor.rev, src_major.rev)
551 {
552 // the "major" rev is a direct ancestors of "minor",
553 // any different value should
554 // overwrite
555 pick_major();
556 } else {
557 // major version is None (so the file was deleted on
558 // that branch) and that branch is independant (neither
559 // minor nor major is an ancestors of the other one.)
560 // We preserve the new
561 // information about the new file.
562 pick_minor();
563 }
564 } 510 }
565 } 511 }
566 }; 512 };
567 } 513 }
568 514
584 result.insert(k, v); 530 result.insert(k, v);
585 } 531 }
586 } 532 }
587 result 533 result
588 } 534 }
535
536 /// represent the side that should prevail when merging two
537 /// TimeStampedPathCopies
538 enum MergePick {
539 /// The "major" (p1) side prevails
540 Major,
541 /// The "minor" (p2) side prevails
542 Minor,
543 /// Any side could be used (because they are the same)
544 Any,
545 }
546
547 /// decide which side prevails in case of conflicting values
548 #[allow(clippy::if_same_then_else)]
549 fn compare_value<A: Fn(Revision, Revision) -> bool>(
550 changes: &ChangedFiles,
551 oracle: &mut AncestorOracle<A>,
552 dest: &HgPathBuf,
553 src_minor: &TimeStampedPathCopy,
554 src_major: &TimeStampedPathCopy,
555 ) -> MergePick {
556 if src_major.path == src_minor.path {
557 // we have the same value, but from other source;
558 if src_major.rev == src_minor.rev {
559 // If the two entry are identical, they are both valid
560 MergePick::Any
561 } else if oracle.is_ancestor(src_major.rev, src_minor.rev) {
562 MergePick::Minor
563 } else {
564 MergePick::Major
565 }
566 } else if src_major.rev == src_minor.rev {
567 // We cannot get copy information for both p1 and p2 in the
568 // same rev. So this is the same value.
569 unreachable!(
570 "conflict information from p1 and p2 in the same revision"
571 );
572 } else {
573 let action = changes.get_merge_case(&dest);
574 if src_major.path.is_none() && action == MergeCase::Salvaged {
575 // If the file is "deleted" in the major side but was
576 // salvaged by the merge, we keep the minor side alive
577 MergePick::Minor
578 } else if src_minor.path.is_none() && action == MergeCase::Salvaged {
579 // If the file is "deleted" in the minor side but was
580 // salvaged by the merge, unconditionnaly preserve the
581 // major side.
582 MergePick::Major
583 } else if action == MergeCase::Merged {
584 // If the file was actively merged, copy information
585 // from each side might conflict. The major side will
586 // win such conflict.
587 MergePick::Major
588 } else if oracle.is_ancestor(src_major.rev, src_minor.rev) {
589 // If the minor side is strictly newer than the major
590 // side, it should be kept.
591 MergePick::Minor
592 } else if src_major.path.is_some() {
593 // without any special case, the "major" value win
594 // other the "minor" one.
595 MergePick::Major
596 } else if oracle.is_ancestor(src_minor.rev, src_major.rev) {
597 // the "major" rev is a direct ancestors of "minor",
598 // any different value should
599 // overwrite
600 MergePick::Major
601 } else {
602 // major version is None (so the file was deleted on
603 // that branch) and that branch is independant (neither
604 // minor nor major is an ancestors of the other one.)
605 // We preserve the new
606 // information about the new file.
607 MergePick::Minor
608 }
609 }
610 }