Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions src/cmds/git/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ where
if arg.contains('/') || arg.contains('\\') {
return path_exists(arg);
}
// Filename with extension (README.md) - treat as path if it exists.
// This is a safe middle-ground between "bare word" (main) and a ref.
if arg.contains('.') {
return path_exists(arg);
}
// Bare word (no separator, no special prefix) — never inject `--`
// This avoids misidentifying a ref/branch as a path even if a same-named
// file happens to exist on disk.
Expand Down Expand Up @@ -1956,6 +1961,17 @@ mod tests {
assert_eq!(normalize_diff_args_impl(&args, exists_mock(&[])), args);
}

/// Baseline: `--` already present with multiple pathspecs → no-op, args unchanged.
#[test]
fn test_normalize_diff_args_noop_when_separator_present_multiple_paths() {
let args = vec![
"--".to_string(),
"README.md".to_string(),
"src/cmds/system/README.md".to_string(),
];
assert_eq!(normalize_diff_args_impl(&args, exists_mock(&[])), args);
}

/// Core regression (issue #1215): clap ate `--` before a real file path.
/// When the path exists on disk, `--` must be re-inserted.
#[test]
Expand Down Expand Up @@ -1990,6 +2006,13 @@ mod tests {
);
}

/// Ref with explicit separator before a filename-with-extension → no-op, args unchanged.
#[test]
fn test_normalize_diff_args_noop_ref_then_separator_then_filename() {
let args = vec!["HEAD".to_string(), "--".to_string(), "README.md".to_string()];
assert_eq!(normalize_diff_args_impl(&args, exists_mock(&[])), args);
}

/// Flags before path: ["--cached", "src/foo.rs"] where src/foo.rs exists.
#[test]
fn test_normalize_diff_args_reinserts_separator_after_flag() {
Expand All @@ -2005,6 +2028,20 @@ mod tests {
);
}

/// Flag then filename-with-extension pathspec → inject separator after flag.
#[test]
fn test_normalize_diff_args_inject_after_flag_for_filename_with_extension() {
let args = vec!["--name-only".to_string(), "README.md".to_string()];
assert_eq!(
normalize_diff_args_impl(&args, exists_mock(&["README.md"])),
vec![
"--name-only".to_string(),
"--".to_string(),
"README.md".to_string()
]
);
}

/// Pure flags (no paths) → no injection.
#[test]
fn test_normalize_diff_args_no_injection_for_pure_flags() {
Expand Down Expand Up @@ -2064,6 +2101,36 @@ mod tests {
);
}

/// Filename with extension that exists on disk → inject `--`.
#[test]
fn test_normalize_diff_args_inject_for_filename_with_extension() {
let args = vec!["README.md".to_string()];
assert_eq!(
normalize_diff_args_impl(&args, exists_mock(&["README.md"])),
vec!["--".to_string(), "README.md".to_string()]
);
}

/// Multiple existing paths (including a filename-with-extension) → inject once before first path.
#[test]
fn test_normalize_diff_args_inject_for_multiple_existing_paths() {
let args = vec![
"README.md".to_string(),
"src/cmds/system/README.md".to_string(),
];
assert_eq!(
normalize_diff_args_impl(
&args,
exists_mock(&["README.md", "src/cmds/system/README.md"]),
),
vec![
"--".to_string(),
"README.md".to_string(),
"src/cmds/system/README.md".to_string()
]
);
}

#[test]
fn test_is_blob_show_arg() {
assert!(is_blob_show_arg("develop:modules/pairs_backtest.py"));
Expand Down
Loading