diff --git a/rust/hg-core/src/copy_tracing.rs b/rust/hg-core/src/copy_tracing.rs
index c244c13761ac1d4956ac50a6e28677fee9350acb_cnVzdC9oZy1jb3JlL3NyYy9jb3B5X3RyYWNpbmcucnM=..19884e678792b912d0f12cff15bfb21822f51e3f_cnVzdC9oZy1jb3JlL3NyYy9jb3B5X3RyYWNpbmcucnM= 100644
--- a/rust/hg-core/src/copy_tracing.rs
+++ b/rust/hg-core/src/copy_tracing.rs
@@ -4,7 +4,7 @@
 use std::collections::HashMap;
 use std::collections::HashSet;
 
-use im_rc::ordmap::OrdMap;
+use im_rc::ordmap::{DiffItem, OrdMap};
 
 pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>;
 
@@ -8,7 +8,7 @@
 
 pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>;
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 struct TimeStampedPathCopy {
     /// revision at which the copy information was added
     rev: Revision,
@@ -202,9 +202,28 @@
     changes: &ChangedFiles,
     is_ancestor: &impl Fn(Revision, Revision) -> bool,
 ) -> TimeStampedPathCopies {
-    let mut result = minor.clone();
-    for (dest, src_major) in major.into_iter() {
-        let overwrite;
-        if let Some(src_minor) = minor.get(&dest) {
-            {
+    if minor.is_empty() {
+        return major;
+    } else if major.is_empty() {
+        return minor;
+    }
+    let mut override_minor = Vec::new();
+    let mut override_major = Vec::new();
+
+    let mut to_major = |k: &HgPathBuf, v: &TimeStampedPathCopy| {
+        override_major.push((k.clone(), v.clone()))
+    };
+    let mut to_minor = |k: &HgPathBuf, v: &TimeStampedPathCopy| {
+        override_minor.push((k.clone(), v.clone()))
+    };
+
+    for d in minor.diff(&major) {
+        match d {
+            DiffItem::Add(k, v) => to_minor(k, v),
+            DiffItem::Remove(k, v) => to_major(k, v),
+            DiffItem::Update { old, new } => {
+                let (dest, src_major) = new;
+                let (_, src_minor) = old;
+                let mut pick_minor = || (to_major(dest, src_minor));
+                let mut pick_major = || (to_minor(dest, src_major));
                 if src_major.path == src_minor.path {
@@ -210,7 +229,7 @@
                 if src_major.path == src_minor.path {
-                    // we have the same value, no need to battle;
+                    // we have the same value, but from other source;
                     if src_major.rev == src_minor.rev {
                         // If the two entry are identical, `minor.diff(major)`
                         // should not have yield it.
                         unreachable!()
                     } else if is_ancestor(src_major.rev, src_minor.rev) {
@@ -212,7 +231,7 @@
                     if src_major.rev == src_minor.rev {
                         // If the two entry are identical, `minor.diff(major)`
                         // should not have yield it.
                         unreachable!()
                     } else if is_ancestor(src_major.rev, src_minor.rev) {
-                        overwrite = false;
+                        pick_minor();
                     } else {
@@ -218,6 +237,6 @@
                     } else {
-                        overwrite = true;
+                        pick_major();
                     }
                 } else if src_major.rev == src_minor.rev {
                     // We cannot get copy information for both p1 and p2 in the
                     // same rev. So this is the same value.
@@ -220,6 +239,6 @@
                     }
                 } else if src_major.rev == src_minor.rev {
                     // We cannot get copy information for both p1 and p2 in the
                     // same rev. So this is the same value.
-                    overwrite = false;
+                    unreachable!();
                 } else if src_major.path.is_none()
@@ -225,6 +244,6 @@
                 } else if src_major.path.is_none()
-                    && changes.salvaged.contains(&dest)
+                    && changes.salvaged.contains(dest)
                 {
                     // If the file is "deleted" in the major side but was
                     // salvaged by the merge, we
                     // keep the minor side alive
@@ -227,6 +246,6 @@
                 {
                     // If the file is "deleted" in the major side but was
                     // salvaged by the merge, we
                     // keep the minor side alive
-                    overwrite = false;
+                    pick_minor();
                 } else if src_minor.path.is_none()
@@ -232,6 +251,6 @@
                 } else if src_minor.path.is_none()
-                    && changes.salvaged.contains(&dest)
+                    && changes.salvaged.contains(dest)
                 {
                     // If the file is "deleted" in the minor side but was
                     // salvaged by the merge,
                     // unconditionnaly preserve the major side.
@@ -234,9 +253,9 @@
                 {
                     // If the file is "deleted" in the minor side but was
                     // salvaged by the merge,
                     // unconditionnaly preserve the major side.
-                    overwrite = true;
-                } else if changes.merged.contains(&dest) {
+                    pick_major();
+                } else if changes.merged.contains(dest) {
                     // If the file was actively merged, copy information from
                     // each side might conflict.
                     // The major side will win such conflict.
@@ -240,7 +259,7 @@
                     // If the file was actively merged, copy information from
                     // each side might conflict.
                     // The major side will win such conflict.
-                    overwrite = true;
+                    pick_major();
                 } else if is_ancestor(src_major.rev, src_minor.rev) {
                     // If the minor side is strictly newer than the major side,
                     // it should be kept.
@@ -244,7 +263,7 @@
                 } else if is_ancestor(src_major.rev, src_minor.rev) {
                     // If the minor side is strictly newer than the major side,
                     // it should be kept.
-                    overwrite = false;
+                    pick_minor();
                 } else if src_major.path.is_some() {
                     // without any special case, the "major" value win other
                     // the "minor" one.
@@ -248,7 +267,7 @@
                 } else if src_major.path.is_some() {
                     // without any special case, the "major" value win other
                     // the "minor" one.
-                    overwrite = true;
+                    pick_major();
                 } else if is_ancestor(src_minor.rev, src_major.rev) {
                     // the "major" rev is a direct ancestors of "minor", any
                     // different value should overwrite
@@ -252,6 +271,6 @@
                 } else if is_ancestor(src_minor.rev, src_major.rev) {
                     // the "major" rev is a direct ancestors of "minor", any
                     // different value should overwrite
-                    overwrite = true;
+                    pick_major();
                 } else {
                     // major version is None (so the file was deleted on that
@@ -256,6 +275,6 @@
                 } else {
                     // major version is None (so the file was deleted on that
-                    // branch) annd that branch
+                    // branch) and that branch
                     // is independant (neither minor nor major is an ancestors
                     // of the other one.) We preserve the
                     // new information about the new file.
@@ -259,6 +278,6 @@
                     // is independant (neither minor nor major is an ancestors
                     // of the other one.) We preserve the
                     // new information about the new file.
-                    overwrite = false;
+                    pick_minor();
                 }
             }
@@ -263,3 +282,16 @@
                 }
             }
+        };
+    }
+
+    let updates;
+    let mut result;
+    if override_major.is_empty() {
+        result = major
+    } else if override_minor.is_empty() {
+        result = minor
+    } else {
+        if override_minor.len() < override_major.len() {
+            updates = override_minor;
+            result = minor;
         } else {
@@ -265,4 +297,4 @@
         } else {
-            // minor had not value
-            overwrite = true;
+            updates = override_major;
+            result = major;
         }
@@ -268,6 +300,6 @@
         }
-        if overwrite {
-            result.insert(dest, src_major);
+        for (k, v) in updates {
+            result.insert(k, v);
         }
     }
     result