git: Fix panic on duplicate status entries in git status parsing (#49191)

morgankrey and factory-droid[bot] created

## Summary

Fixes **ZED-2XA** — "Unexpected duplicated status entries: Untracked and
Untracked" crash.

**Impact:** 22 occurrences, 3 users affected (Sentry). The panic was
introduced in #23483 (2025-01-22) which added the `dedup_by` logic for
handling deleted-in-index + untracked file combinations.

No related GitHub issues were found filed against this crash.

## Root Cause

`GitStatus::from_str` sorts entries by path and then calls `dedup_by` to
merge duplicate entries. The only handled case was `(INDEX_DELETED,
Untracked)` — all other duplicates hit a catch-all `panic!`. In
practice, git can produce duplicate `??` (untracked) entries for the
same path, which triggered this crash.

## Fix

- Identical duplicate statuses (e.g., `Untracked, Untracked`) are now
silently deduplicated (keep one)
- Other unexpected duplicate combinations log a warning instead of
crashing
- Added a regression test that parses `"?? file.txt\0?? file.txt"` and
verifies it produces a single entry

## Verification

- Reproduction test passes: `cargo test -p git --
test_duplicate_untracked_entries`
- Full crate tests pass: `cargo test -p git` (20/20)
- Clippy clean: `./script/clippy`

Release Notes:

- Fixed a crash when git produces duplicate status entries for the same
file path

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

Change summary

crates/git/src/status.rs | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)

Detailed changes

crates/git/src/status.rs 🔗

@@ -475,7 +475,12 @@ impl FromStr for GitStatus {
                     }
                     .into();
                 }
-                _ => panic!("Unexpected duplicated status entries: {a_status:?} and {b_status:?}"),
+                (x, y) if x == y => {}
+                _ => {
+                    log::warn!(
+                        "Unexpected duplicated status entries: {a_status:?} and {b_status:?}"
+                    );
+                }
             }
             true
         });
@@ -580,9 +585,19 @@ mod tests {
 
     use crate::{
         repository::RepoPath,
-        status::{TreeDiff, TreeDiffStatus},
+        status::{FileStatus, GitStatus, TreeDiff, TreeDiffStatus},
     };
 
+    #[test]
+    fn test_duplicate_untracked_entries() {
+        // Regression test for ZED-2XA: git can produce duplicate untracked entries
+        // for the same path. This should deduplicate them instead of panicking.
+        let input = "?? file.txt\0?? file.txt";
+        let status: GitStatus = input.parse().unwrap();
+        assert_eq!(status.entries.len(), 1);
+        assert_eq!(status.entries[0].1, FileStatus::Untracked);
+    }
+
     #[test]
     fn test_tree_diff_parsing() {
         let input = ":000000 100644 0000000000000000000000000000000000000000 0062c311b8727c3a2e3cd7a41bc9904feacf8f98 A\x00.zed/settings.json\x00".to_owned() +