From bb99bf31cd6d9d857768314feb4da22c26867372 Mon Sep 17 00:00:00 2001 From: emirmrkaljevic <93012621+emirmrkaljevic@users.noreply.github.com> Date: Sun, 25 Oct 2026 15:07:00 +0100 Subject: [PATCH] mv: skip the same-file error with -n and --update=none --- src/uu/mv/src/mv.rs | 7 +++++++ tests/by-util/test_mv.rs | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/uu/mv/src/mv.rs b/src/uu/mv/src/mv.rs index 336a84e4fdb..31d52c30d91 100644 --- a/src/uu/mv/src/mv.rs +++ b/src/uu/mv/src/mv.rs @@ -575,6 +575,13 @@ fn assert_not_same_file( || source.ends_with("/.") || source.is_file()) { + // GNU mv skips the same-file check when it would not replace the + // target anyway (-n, --update=none), so this is a silent no-op. + if (opts.overwrite == OverwriteMode::NoClobber || opts.update == UpdateMode::None) + && source.file_name().is_some() + { + return Ok(()); + } return Err(MvError::SameFile(source.quote().to_string(), target_display()).into()); } else if (same_file || canonicalized_target.starts_with(canonicalized_source)) // don't error if we're moving a symlink of a directory into itself diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index 9759e142e07..08e06664a79 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -562,6 +562,31 @@ fn test_mv_same_file() { .stderr_only(format!("mv: '{file_a}' and '{file_a}' are the same file\n")); } +#[test] +fn test_mv_same_file_no_clobber() { + // GNU mv does not report "are the same file" when it would not + // replace the target anyway; it exits 0 and leaves the file alone. + let file_a = "test_mv_same_file_a"; + for args in [["-n"], ["--update=none"]] { + let (at, mut ucmd) = at_and_ucmd!(); + at.write(file_a, "a"); + ucmd.args(&args) + .arg(file_a) + .arg(file_a) + .succeeds() + .no_output(); + assert_eq!(at.read(file_a), "a"); + } + + // --update=none-fail still fails, like GNU + let (at, mut ucmd) = at_and_ucmd!(); + at.touch(file_a); + ucmd.arg("--update=none-fail") + .arg(file_a) + .arg(file_a) + .fails_with_code(1); +} + #[test] #[cfg(all(unix, not(target_os = "android")))] #[cfg_attr(