diff --git a/crates/fff-core/src/git.rs b/crates/fff-core/src/git.rs index 9514b628..3cfc6942 100644 --- a/crates/fff-core/src/git.rs +++ b/crates/fff-core/src/git.rs @@ -159,7 +159,9 @@ pub fn format_git_status_opt(status: Option) -> Option<&'static str> { Some("staged_deleted") } else if status.contains(Status::IGNORED) { Some("ignored") - } else if status.contains(Status::CURRENT) || status.is_empty() { + // `Status::CURRENT` is 0, so `contains` is true for every status: + // testing it here labelled conflicted/typechanged files "clean". + } else if status.is_empty() { Some("clean") } else { None @@ -192,6 +194,35 @@ mod tests { assert!(out.status.success(), "git {args:?} failed"); } + #[test] + fn unclassified_status_is_not_reported_as_clean() { + // A merge-conflicted file must not claim to be clean. + assert_eq!(format_git_status_opt(Some(Status::CONFLICTED)), None); + assert_eq!(format_git_status(Some(Status::CONFLICTED)), "unknown"); + assert_eq!(format_git_status(Some(Status::WT_TYPECHANGE)), "unknown"); + + // Every already-classified state keeps its label. + assert_eq!(format_git_status_opt(None), Some("clean")); + assert_eq!(format_git_status_opt(Some(Status::empty())), Some("clean")); + assert_eq!(format_git_status_opt(Some(Status::CURRENT)), Some("clean")); + assert_eq!( + format_git_status_opt(Some(Status::WT_NEW)), + Some("untracked") + ); + assert_eq!( + format_git_status_opt(Some(Status::WT_MODIFIED)), + Some("modified") + ); + assert_eq!( + format_git_status_opt(Some(Status::INDEX_MODIFIED)), + Some("staged_modified") + ); + assert_eq!( + format_git_status_opt(Some(Status::IGNORED)), + Some("ignored") + ); + } + /// Regression: on case-insensitive filesystems libgit2 returns /// statuses in a case-insensitive order. Our previous sorted-`Vec` + /// `binary_search_by(Path::cmp)` lookup silently missed entries