Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion src/command/diff/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,13 @@ pub fn get_new_content(filename: &str, refs: &DiffRefs, backend: &dyn VcsBackend
.unwrap_or_default(),
DiffRefs::WorkingTree => {
// Read from working tree (actual filesystem)
fs::read_to_string(filename).unwrap_or_default()
// Resolve path relative to repository root, not current working directory
if let Some(repo_root) = backend.repo_root() {
let full_path = repo_root.join(filename);
fs::read_to_string(&full_path).unwrap_or_default()
} else {
fs::read_to_string(filename).unwrap_or_default()
}
}
}
}
Expand Down Expand Up @@ -476,4 +482,33 @@ mod tests {
let _ = std::env::set_current_dir(&original);
let _ = fs::remove_dir_all(&dir);
}

#[test]
fn test_get_new_content_from_subdirectory() {
let _lock = crate::vcs::test_utils::cwd_lock()
.lock()
.unwrap_or_else(|e| e.into_inner());
let dir = make_temp_dir("git-diff-subdir");
let original = std::env::current_dir().expect("get cwd");

git(&dir, &["init"]);
git(&dir, &["config", "user.email", "test@example.com"]);
git(&dir, &["config", "user.name", "Test User"]);

fs::create_dir(dir.join("src")).expect("create src dir");
fs::write(dir.join("src/file.txt"), "original content\n").expect("write file");
git(&dir, &["add", "."]);
git(&dir, &["commit", "-m", "first"]);

fs::write(dir.join("src/file.txt"), "modified content\n").expect("modify file");

// Run diff from subdirectory
std::env::set_current_dir(dir.join("src")).expect("change to src dir");
let backend = GitBackend::from_cwd().expect("should open repo");
let content = get_new_content("src/file.txt", &DiffRefs::WorkingTree, &backend);
assert_eq!(content, "modified content\n");

let _ = std::env::set_current_dir(&original);
let _ = fs::remove_dir_all(&dir);
}
}
3 changes: 3 additions & 0 deletions src/vcs/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,7 @@ pub trait VcsBackend {

/// Get the name of this VCS backend ("git" or "jj").
fn name(&self) -> &'static str;

/// Get the root path of the repository (working directory).
fn repo_root(&self) -> Option<&Path>;
}
4 changes: 4 additions & 0 deletions src/vcs/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,10 @@ impl VcsBackend for GitBackend {
fn name(&self) -> &'static str {
"git"
}

fn repo_root(&self) -> Option<&Path> {
self.repo.workdir()
}
}

#[cfg(test)]
Expand Down
4 changes: 4 additions & 0 deletions src/vcs/jj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,10 @@ impl VcsBackend for JjBackend {
fn name(&self) -> &'static str {
"jj"
}

fn repo_root(&self) -> Option<&Path> {
Some(&self.workspace_path)
}
}

#[cfg(test)]
Expand Down