From 6bfef1e06fd91972adf9f8201f277cff5f27358a Mon Sep 17 00:00:00 2001 From: Joshua Segaran Date: Wed, 21 Oct 2026 23:57:54 +0000 Subject: [PATCH] git: give a deleted file's PATCH_FILE record no new path --- crates/git/src/diffs.rs | 11 ++++++++- crates/server/src/yas_git.rs | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/crates/git/src/diffs.rs b/crates/git/src/diffs.rs index beea3837..3041611e 100644 --- a/crates/git/src/diffs.rs +++ b/crates/git/src/diffs.rs @@ -1171,6 +1171,15 @@ fn record_old_path(change: &Change) -> Vec { if old.is_empty() { new } else { old } } +/// The new path a `PATCH_FILE` record reports: none when there is no new +/// side, as for a deletion. +fn record_new_path(change: &Change) -> Vec { + if change.new.is_none() { + return Vec::new(); + } + change_new_path(change) +} + /// Split a rename's NUL-joined path back into (old, new). fn rename_paths(change: &Change) -> (Vec, Vec) { if change.st == b'R' @@ -1751,7 +1760,7 @@ impl RepoHandle { similarity: change.similarity, flags: file_flags, old_path: &crate::escape_bstr(&record_old_path(change)), - new_path: &crate::escape_bstr(&change_new_path(change)), + new_path: &crate::escape_bstr(&record_new_path(change)), }, ); if !binary { diff --git a/crates/server/src/yas_git.rs b/crates/server/src/yas_git.rs index 0f93bb0b..1c83787a 100644 --- a/crates/server/src/yas_git.rs +++ b/crates/server/src/yas_git.rs @@ -2182,6 +2182,49 @@ mod tests { } } + #[test] + fn structured_patch_of_a_deletion_encodes() { + let directory = tempfile::tempdir().unwrap(); + git(directory.path(), &["init", "-q"]); + std::fs::write(directory.path().join("gone.txt"), b"gone\n").unwrap(); + git(directory.path(), &["add", "gone.txt"]); + std::fs::remove_file(directory.path().join("gone.txt")).unwrap(); + let (repository, _) = yas_git::native::open_path(directory.path()).unwrap(); + let page = run_query( + Some(&repository), + yas_wire::schema::git::OBJECT_SHA1 as u8, + &query(wire::QueryBody::Patch { + left: wire::QueryEndpoint::Index, + right: wire::QueryEndpoint::Worktree, + path: None, + context_lines: 3, + rename_threshold: 0, + max_bytes: 1024 * 1024, + flags: 0, + }), + None, + &yas_git::Cancel::default(), + ) + .unwrap(); + let [QueryItem::Record(file), QueryItem::Record(row)] = page.records.as_slice() else { + panic!("unexpected deletion patch page: {:?}", page.records); + }; + assert_eq!( + file, + &wire::QueryRecord::PatchFile(wire::PatchFileRecord { + status: yas_wire::schema::git::DIFF_DELETED as u8, + similarity_percent: 0, + flags: 0, + old_path: Some(fs_wire::Path { + components: vec![b"gone.txt".to_vec()], + }), + new_path: None, + }) + ); + file.encode_typed().unwrap(); + row.encode_typed().unwrap(); + } + #[test] fn typed_queries_cover_repository_reads_without_exposing_legacy_packets() { let directory = tempfile::tempdir().unwrap();