From 5cf1fbf168c48713b41218e0d837d0039582d63e Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 7 Oct 2026 13:51:16 +0200 Subject: [PATCH] Fix diff paths under a top-level a/ or b/ when diff.noprefix is set If diff.noprefix is set, pressing space on a line of a file under a top-level directory named a or b does nothing. In a stash entry's diff, the menu for jumping to a file shows such a file without its directory. We read the path of a file out of the diff header and strip the a/ or b/ in front of it. Most diff commands override diff.noprefix so that this prefix is there, but the diff of the working tree and the diff of a stash entry don't. With the config set, we strip the file's own directory instead. Use ParseableDiffPrefixes for these two commands too. Co-Authored-By: Claude Opus 5.5 (1M context) --- pkg/commands/git_commands/stash.go | 1 + pkg/commands/git_commands/stash_test.go | 12 ++++++------ pkg/commands/git_commands/working_tree.go | 1 + pkg/commands/git_commands/working_tree_test.go | 14 +++++++------- .../jump_to_a_file_of_a_stash_with_no_prefixes.go | 3 --- .../main_view/stage_diff_lines_with_no_prefixes.go | 3 --- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/pkg/commands/git_commands/stash.go b/pkg/commands/git_commands/stash.go index f904a7ac4..40c925a86 100644 --- a/pkg/commands/git_commands/stash.go +++ b/pkg/commands/git_commands/stash.go @@ -83,6 +83,7 @@ func (self *StashCommands) Hash(index int) (string, error) { func (self *StashCommands) ShowStashEntryCmdObj(index int, mode DiffMode) *oscommands.CmdObj { // "-u" is the same as "--include-untracked", but the latter fails in older git versions for some reason cmdArgs := NewGitCmd("stash").Arg("show"). + ParseableDiffPrefixes(). AddCommonDiffArgs(self.diffRendererConfigManager, self.UserConfig(), mode). Arg("-p"). Arg("--stat"). diff --git a/pkg/commands/git_commands/stash_test.go b/pkg/commands/git_commands/stash_test.go index 35b687cbd..be577e9f3 100644 --- a/pkg/commands/git_commands/stash_test.go +++ b/pkg/commands/git_commands/stash_test.go @@ -114,7 +114,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 50, ignoreWhitespace: false, - expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "--no-ext-diff", "--unified=3", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, + expected: []string{"git", "-C", "/path/to/worktree", "-c", "diff.noprefix=false", "stash", "show", "--no-ext-diff", "--unified=3", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, }, { testName: "Show diff with custom context size", @@ -122,7 +122,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { contextSize: 77, similarityThreshold: 50, ignoreWhitespace: false, - expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "--no-ext-diff", "--unified=77", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, + expected: []string{"git", "-C", "/path/to/worktree", "-c", "diff.noprefix=false", "stash", "show", "--no-ext-diff", "--unified=77", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, }, { testName: "Show diff with custom similarity threshold", @@ -130,7 +130,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 33, ignoreWhitespace: false, - expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "--no-ext-diff", "--unified=3", "--find-renames=33%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, + expected: []string{"git", "-C", "/path/to/worktree", "-c", "diff.noprefix=false", "stash", "show", "--no-ext-diff", "--unified=3", "--find-renames=33%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, }, { testName: "Show diff with external diff command", @@ -139,7 +139,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { similarityThreshold: 50, ignoreWhitespace: false, diffRendererConfig: &config.DiffRendererConfig{Type: "extDiff", Command: "difft --color=always"}, - expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "--ext-diff", "--unified=3", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, + expected: []string{"git", "-C", "/path/to/worktree", "-c", "diff.noprefix=false", "stash", "show", "--ext-diff", "--unified=3", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, }, { testName: "Show diff using git's external diff config", @@ -148,7 +148,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { similarityThreshold: 50, ignoreWhitespace: false, diffRendererConfig: &config.DiffRendererConfig{Type: "extDiff"}, - expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "--ext-diff", "--unified=3", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, + expected: []string{"git", "-C", "/path/to/worktree", "-c", "diff.noprefix=false", "stash", "show", "--ext-diff", "--unified=3", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, }, { testName: "Ignore whitespace", @@ -156,7 +156,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 50, ignoreWhitespace: true, - expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "--no-ext-diff", "--unified=3", "--ignore-all-space", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, + expected: []string{"git", "-C", "/path/to/worktree", "-c", "diff.noprefix=false", "stash", "show", "--no-ext-diff", "--unified=3", "--ignore-all-space", "--find-renames=50%", "-p", "--stat", "-u", "--color=always", "refs/stash@{5}"}, }, } diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go index 43960e252..8ebff5910 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -397,6 +397,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, mode noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile() cmdArgs := NewGitCmd("diff"). + ParseableDiffPrefixes(). AddCommonDiffArgs(self.diffRendererConfigManager, self.UserConfig(), mode). Arg("--submodule"). Arg(fmt.Sprintf("--color=%s", mode.colorArg(self.diffRendererConfigManager))). diff --git a/pkg/commands/git_commands/working_tree_test.go b/pkg/commands/git_commands/working_tree_test.go index e9e5e48d2..669d3272d 100644 --- a/pkg/commands/git_commands/working_tree_test.go +++ b/pkg/commands/git_commands/working_tree_test.go @@ -221,7 +221,7 @@ func TestWorkingTreeDiff(t *testing.T) { contextSize: 3, similarityThreshold: 50, runner: oscommands.NewFakeRunner(t). - ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--unified=3", "--find-renames=50%", "--submodule", "--color=always", "--", "test.txt"}, expectedResult, nil), + ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--unified=3", "--find-renames=50%", "--submodule", "--color=always", "--", "test.txt"}, expectedResult, nil), }, { testName: "cached", @@ -236,7 +236,7 @@ func TestWorkingTreeDiff(t *testing.T) { contextSize: 3, similarityThreshold: 50, runner: oscommands.NewFakeRunner(t). - ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--unified=3", "--find-renames=50%", "--submodule", "--color=always", "--cached", "--", "test.txt"}, expectedResult, nil), + ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--unified=3", "--find-renames=50%", "--submodule", "--color=always", "--cached", "--", "test.txt"}, expectedResult, nil), }, { testName: "plain", @@ -251,7 +251,7 @@ func TestWorkingTreeDiff(t *testing.T) { contextSize: 3, similarityThreshold: 50, runner: oscommands.NewFakeRunner(t). - ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--unified=3", "--find-renames=50%", "--submodule", "--color=never", "--", "test.txt"}, expectedResult, nil), + ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--unified=3", "--find-renames=50%", "--submodule", "--color=never", "--", "test.txt"}, expectedResult, nil), }, { testName: "File not tracked and file has no staged changes", @@ -266,7 +266,7 @@ func TestWorkingTreeDiff(t *testing.T) { contextSize: 3, similarityThreshold: 50, runner: oscommands.NewFakeRunner(t). - ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--unified=3", "--find-renames=50%", "--submodule", "--color=always", "--no-index", "--", "/dev/null", "test.txt"}, expectedResult, nil), + ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--unified=3", "--find-renames=50%", "--submodule", "--color=always", "--no-index", "--", "/dev/null", "test.txt"}, expectedResult, nil), }, { testName: "Default case (ignore whitespace)", @@ -281,7 +281,7 @@ func TestWorkingTreeDiff(t *testing.T) { contextSize: 3, similarityThreshold: 50, runner: oscommands.NewFakeRunner(t). - ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--unified=3", "--ignore-all-space", "--find-renames=50%", "--submodule", "--color=always", "--", "test.txt"}, expectedResult, nil), + ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--unified=3", "--ignore-all-space", "--find-renames=50%", "--submodule", "--color=always", "--", "test.txt"}, expectedResult, nil), }, { testName: "Show diff with custom context size", @@ -296,7 +296,7 @@ func TestWorkingTreeDiff(t *testing.T) { contextSize: 17, similarityThreshold: 50, runner: oscommands.NewFakeRunner(t). - ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--unified=17", "--find-renames=50%", "--submodule", "--color=always", "--", "test.txt"}, expectedResult, nil), + ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--unified=17", "--find-renames=50%", "--submodule", "--color=always", "--", "test.txt"}, expectedResult, nil), }, { testName: "Show diff with custom similarity threshold", @@ -311,7 +311,7 @@ func TestWorkingTreeDiff(t *testing.T) { contextSize: 3, similarityThreshold: 33, runner: oscommands.NewFakeRunner(t). - ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--unified=3", "--find-renames=33%", "--submodule", "--color=always", "--", "test.txt"}, expectedResult, nil), + ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--unified=3", "--find-renames=33%", "--submodule", "--color=always", "--", "test.txt"}, expectedResult, nil), }, } diff --git a/pkg/integration/tests/main_view/jump_to_a_file_of_a_stash_with_no_prefixes.go b/pkg/integration/tests/main_view/jump_to_a_file_of_a_stash_with_no_prefixes.go index 87462f59b..6c0616633 100644 --- a/pkg/integration/tests/main_view/jump_to_a_file_of_a_stash_with_no_prefixes.go +++ b/pkg/integration/tests/main_view/jump_to_a_file_of_a_stash_with_no_prefixes.go @@ -39,10 +39,7 @@ var JumpToAFileOfAStashWithNoPrefixes = NewIntegrationTest(NewIntegrationTestArg t.ExpectPopup().Menu(). Title(Equals("Jump to file")). Lines( - /* EXPECTED: Equals("b/file1"), - ACTUAL: */ - Equals("file1"), Equals("file2"), Equals("Cancel"), ) diff --git a/pkg/integration/tests/main_view/stage_diff_lines_with_no_prefixes.go b/pkg/integration/tests/main_view/stage_diff_lines_with_no_prefixes.go index 7da4ba77b..b02a233e9 100644 --- a/pkg/integration/tests/main_view/stage_diff_lines_with_no_prefixes.go +++ b/pkg/integration/tests/main_view/stage_diff_lines_with_no_prefixes.go @@ -41,10 +41,7 @@ var StageDiffLinesWithNoPrefixes = NewIntegrationTest(NewIntegrationTestArgs{ t.Views().Files().Lines( Contains("▼ b"), - /* EXPECTED: Contains("MM file1"), - ACTUAL: */ - Contains(" M file1"), ) }, })