diff --git a/src/command/diff/git.rs b/src/command/diff/git.rs index b7d2bae6..150e4463 100644 --- a/src/command/diff/git.rs +++ b/src/command/diff/git.rs @@ -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() + } } } } @@ -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); + } } diff --git a/src/vcs/backend.rs b/src/vcs/backend.rs index 43743a90..f4250353 100644 --- a/src/vcs/backend.rs +++ b/src/vcs/backend.rs @@ -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>; } diff --git a/src/vcs/git.rs b/src/vcs/git.rs index 5d537a86..98b70dd8 100644 --- a/src/vcs/git.rs +++ b/src/vcs/git.rs @@ -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)] diff --git a/src/vcs/jj.rs b/src/vcs/jj.rs index 3b95af7b..925a63e5 100644 --- a/src/vcs/jj.rs +++ b/src/vcs/jj.rs @@ -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)]