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