From ca0fffb927b9bd94b884b7180f3d8779c3583a98 Mon Sep 17 00:00:00 2001 From: morgankrey Date: Tue, 24 Feb 2026 14:16:24 -0600 Subject: [PATCH] git: Fix panic on duplicate status entries in git status parsing (#49191) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 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> --- crates/git/src/status.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/git/src/status.rs b/crates/git/src/status.rs index 2cf7cc7c1810620f1cf1aaea831fb337810c83d8..be8b0a3a588b40638a895d610cc4b5735d4ae51d 100644 --- a/crates/git/src/status.rs +++ b/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() +