mirror of
https://github.com/zed-industries/zed.git
synced 2026-07-10 00:13:29 +00:00
Show type-changed files in commit diffs (#60422)
# Objective
Zed ignores files marked by Git as type-changed (T), causing commits
containing only these changes to show 0 Changed Files.
For example, commit d7cc949e61 changes
crates/eval_utils/LICENSE-GPL from a regular file to a symlink, but Zed
displays no changes.
## Solution
Handle TypeChanged files like modified files by loading both their old
and new contents.
## Testing
- Added parser coverage for the T status.
- Added a repository test for a regular-file-to-symlink change.
- Ran cargo test -p git.
- Ran ./script/clippy -p git.
- Manually verified the example commit on macOS.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and [icon](https://github.com/zed-
industries/zed/blob/main/crates/icons/README.md) guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
Before:
<img width="200" alt="image"
src="https://github.com/user-attachments/assets/277c5938-5c2c-47b7-902d-9061a14c062a"
/>
After:
<img width="200" alt="image"
src="https://github.com/user-attachments/assets/f99d0005-0712-4843-814e-d73b11f64782"
/>
———
Release Notes:
- Fixed type-changed files not appearing in Git Graph and commit views.
This commit is contained in:
parent
b4d9194fce
commit
04de6dab7c
2 changed files with 60 additions and 2 deletions
|
|
@ -109,6 +109,7 @@ pub fn parse_git_diff_name_status(content: &str) -> impl Iterator<Item = (&str,
|
|||
let path = parts.next()?;
|
||||
let status = match status_str {
|
||||
"M" => StatusCode::Modified,
|
||||
"T" => StatusCode::TypeChanged,
|
||||
"A" => StatusCode::Added,
|
||||
"D" => StatusCode::Deleted,
|
||||
_ => continue,
|
||||
|
|
@ -127,6 +128,7 @@ mod tests {
|
|||
fn test_parse_git_diff_name_status() {
|
||||
let input = concat!(
|
||||
"M\x00Cargo.lock\x00",
|
||||
"T\x00LICENSE-GPL\x00",
|
||||
"M\x00crates/project/Cargo.toml\x00",
|
||||
"M\x00crates/project/src/buffer_store.rs\x00",
|
||||
"D\x00crates/project/src/git.rs\x00",
|
||||
|
|
@ -142,6 +144,7 @@ mod tests {
|
|||
output,
|
||||
&[
|
||||
("Cargo.lock", StatusCode::Modified),
|
||||
("LICENSE-GPL", StatusCode::TypeChanged),
|
||||
("crates/project/Cargo.toml", StatusCode::Modified),
|
||||
("crates/project/src/buffer_store.rs", StatusCode::Modified),
|
||||
("crates/project/src/git.rs", StatusCode::Deleted),
|
||||
|
|
|
|||
|
|
@ -1445,7 +1445,7 @@ impl GitRepository for RealGitRepository {
|
|||
};
|
||||
|
||||
match status_code {
|
||||
StatusCode::Modified => {
|
||||
StatusCode::Modified | StatusCode::TypeChanged => {
|
||||
stdin.write_all(commit.as_bytes()).await?;
|
||||
stdin.write_all(b":").await?;
|
||||
stdin.write_all(path.as_bytes()).await?;
|
||||
|
|
@ -1491,7 +1491,7 @@ impl GitRepository for RealGitRepository {
|
|||
};
|
||||
|
||||
match status_code {
|
||||
StatusCode::Modified => {
|
||||
StatusCode::Modified | StatusCode::TypeChanged => {
|
||||
info_line.clear();
|
||||
stdout.read_line(&mut info_line).await?;
|
||||
let len = info_line.trim_end().parse().with_context(|| {
|
||||
|
|
@ -4031,6 +4031,61 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_load_commit_with_type_changed_file(cx: &mut TestAppContext) {
|
||||
disable_git_global_config();
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let repo_dir = tempfile::tempdir().expect("failed to create temporary repository");
|
||||
git_init_repo(repo_dir.path());
|
||||
fs::write(repo_dir.path().join("file.txt"), "regular contents\n")
|
||||
.expect("failed to write regular file");
|
||||
git_command(repo_dir.path(), ["add", "file.txt"]);
|
||||
git_command(repo_dir.path(), ["commit", "-m", "initial"]);
|
||||
|
||||
let repository = RealGitRepository::new(
|
||||
&repo_dir.path().join(".git"),
|
||||
None,
|
||||
Some("git".into()),
|
||||
cx.executor(),
|
||||
)
|
||||
.expect("failed to open repository");
|
||||
fs::write(repo_dir.path().join("file.txt"), "target")
|
||||
.expect("failed to write symlink target");
|
||||
|
||||
let symlink_blob = repository
|
||||
.git_binary()
|
||||
.run(&["hash-object", "-w", "file.txt"])
|
||||
.await
|
||||
.expect("failed to write symlink blob");
|
||||
git_command(
|
||||
repo_dir.path(),
|
||||
[
|
||||
OsString::from("update-index"),
|
||||
OsString::from("--cacheinfo"),
|
||||
OsString::from("120000"),
|
||||
OsString::from(symlink_blob),
|
||||
OsString::from("file.txt"),
|
||||
],
|
||||
);
|
||||
git_command(repo_dir.path(), ["commit", "-m", "type change"]);
|
||||
|
||||
let commit_diff = repository
|
||||
.load_commit("HEAD".to_string(), cx.to_async())
|
||||
.await
|
||||
.expect("failed to load type-changed commit");
|
||||
assert_eq!(commit_diff.files.len(), 1);
|
||||
|
||||
let file = commit_diff
|
||||
.files
|
||||
.first()
|
||||
.expect("type-changed file should be present");
|
||||
assert_eq!(file.path.as_unix_str(), "file.txt");
|
||||
assert_eq!(file.old_text.as_deref(), Some("regular contents\n"));
|
||||
assert_eq!(file.new_text.as_deref(), Some("target"));
|
||||
assert_eq!(file.status(), CommitFileStatus::Modified);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_check_access(cx: &mut TestAppContext) {
|
||||
disable_git_global_config();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue