fix: force standard diff prefixes to prevent diff.noprefix/mnemonicPrefix from breaking parsing (#82)

Add --src-prefix=a/ --dst-prefix=b/ to all git diff/show calls so that
user config (diff.noprefix, diff.mnemonicPrefix) cannot alter the prefix
format the parser depends on. Also add missing ModeCommit test coverage.
This commit is contained in:
kite 2026-06-09 18:08:11 +08:00
parent c9fae8d4e9
commit cf32900ca1
2 changed files with 31 additions and 4 deletions

View file

@ -115,14 +115,14 @@ func (p *Provider) GetDiff(ctx context.Context) ([]model.Diff, error) {
if base == "" {
return nil, fmt.Errorf("cannot find merge-base between %s and %s", p.from, p.to)
}
out, err := p.runGit(ctx, "diff", "--no-ext-diff", "--no-textconv", "--no-color", "-U"+fmt.Sprint(DiffContextLines), base, p.to, "--")
out, err := p.runGit(ctx, "diff", "--no-ext-diff", "--no-textconv", "--src-prefix=a/", "--dst-prefix=b/", "--no-color", "-U"+fmt.Sprint(DiffContextLines), base, p.to, "--")
if err != nil {
return nil, fmt.Errorf("git diff failed: %w", err)
}
combined.WriteString(out)
case ModeCommit:
out, err := p.runGit(ctx, "show", "--no-ext-diff", "--no-textconv", "--no-color", "-U"+fmt.Sprint(DiffContextLines), p.commit)
out, err := p.runGit(ctx, "show", "--no-ext-diff", "--no-textconv", "--src-prefix=a/", "--dst-prefix=b/", "--no-color", "-U"+fmt.Sprint(DiffContextLines), p.commit)
if err != nil {
return nil, fmt.Errorf("git show failed: %w", err)
}
@ -265,14 +265,14 @@ func (p *Provider) computeMergeBase(ctx context.Context, from, to string) string
}
func (p *Provider) workspaceTrackedDiff(ctx context.Context) (string, error) {
out, err := p.runGit(ctx, "diff", "--no-ext-diff", "--no-textconv", "HEAD", "--no-color", "-U"+fmt.Sprint(DiffContextLines), "--")
out, err := p.runGit(ctx, "diff", "--no-ext-diff", "--no-textconv", "--src-prefix=a/", "--dst-prefix=b/", "HEAD", "--no-color", "-U"+fmt.Sprint(DiffContextLines), "--")
if err == nil && out != "" {
return out, nil
}
if ctx.Err() != nil {
return "", ctx.Err()
}
return p.runGit(ctx, "diff", "--no-ext-diff", "--no-textconv", "--staged", "--no-color", "-U"+fmt.Sprint(DiffContextLines), "--")
return p.runGit(ctx, "diff", "--no-ext-diff", "--no-textconv", "--src-prefix=a/", "--dst-prefix=b/", "--staged", "--no-color", "-U"+fmt.Sprint(DiffContextLines), "--")
}
func (p *Provider) untrackedFileDiffs(ctx context.Context) ([]string, error) {

View file

@ -97,6 +97,33 @@ func TestWorkspaceDiffSurvivesExternalDiffTool(t *testing.T) {
}
}
// TestCommitDiffSurvivesExternalDiffTool covers the ModeCommit call site
// (git show <commit>), which likewise must pass --no-ext-diff so that a
// user's external diff tool does not break single-commit analysis.
func TestCommitDiffSurvivesExternalDiffTool(t *testing.T) {
repo := initRepoWithChange(t)
runGitTest(t, repo, "add", "sample.txt")
runGitTest(t, repo, "commit", "-q", "-m", "second commit")
garbage := writeGarbageExternalDiff(t)
t.Setenv("GIT_EXTERNAL_DIFF", garbage)
runner := gitcmd.New(0)
provider := NewCommitProvider(repo, "HEAD", runner)
diffs, err := provider.GetDiff(context.Background())
if err != nil {
t.Fatalf("GetDiff (commit) returned error: %v", err)
}
if len(diffs) == 0 {
t.Fatalf("expected at least one parsed commit diff with an external diff "+
"tool active, got 0 -- git show call site must pass "+
"--no-ext-diff (issue #82). GIT_EXTERNAL_DIFF=%s", garbage)
}
}
// TestRangeDiffSurvivesExternalDiffTool covers the ModeRange call site
// (git diff <base> <to>), which likewise must pass --no-ext-diff so that a
// user's external diff tool does not break range comparisons.