Skip to content

Commit cac04aa

Browse files
iamken1204iscoolkettanbenvinegar
authored
fix(git): pass --no-ext-diff when diffing untracked files (#259)
Co-authored-by: Kettan Wu <kettan@iscoollab.com> Co-authored-by: Ben Vinegar <ben@benv.ca>
1 parent 33dea3e commit cac04aa

4 files changed

Lines changed: 44 additions & 16 deletions

File tree

src/core/git.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import { describe, expect, test } from "bun:test";
2-
import { runGitText } from "./git";
2+
import { buildGitStashShowArgs, runGitText } from "./git";
33

44
describe("git command helpers", () => {
5+
test("disables external diff tools for stash patches", () => {
6+
const args = buildGitStashShowArgs({
7+
kind: "stash-show",
8+
options: { mode: "auto" },
9+
});
10+
11+
expect(args).toContain("--no-ext-diff");
12+
});
13+
514
test("reports a friendly error when git is not installed or not on PATH", () => {
615
expect(() =>
716
runGitText({

src/core/git.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,11 @@ function buildGitStatusArgs(input: VcsCommandInput) {
9999

100100
/** Build the synthetic patch used to render one untracked file as a new-file diff. */
101101
function buildGitNewFileDiffArgs(filePath: string) {
102+
// `--no-ext-diff` keeps user-configured `diff.external` tools (difftastic, delta, etc.)
103+
// from replacing the unified-diff output Pierre needs to parse this synthetic patch.
102104
return withNormalizedDiffPrefixes([
103105
"diff",
106+
"--no-ext-diff",
104107
"--no-index",
105108
"--no-color",
106109
"--",
@@ -123,7 +126,7 @@ export function buildGitShowArgs(input: ShowCommandInput) {
123126

124127
/** Build the exact `git stash show -p` arguments used for stash review. */
125128
export function buildGitStashShowArgs(input: StashShowCommandInput) {
126-
const args = ["stash", "show", "-p", "--find-renames", "--no-color"];
129+
const args = ["stash", "show", "-p", "--no-ext-diff", "--find-renames", "--no-color"];
127130

128131
if (input.ref) {
129132
args.push(input.ref);

src/core/loaders.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,29 @@ describe("loadAppBootstrap", () => {
518518
expect(paths).toHaveLength(fixtureFiles.length);
519519
});
520520

521+
test("loads untracked files even when diff.external is configured in the repo", async () => {
522+
// Regression: a user-configured `diff.external` (e.g. difftastic) silently replaces
523+
// git's unified-diff output, which left the untracked-file synthesizer with patch
524+
// text Pierre couldn't parse and threw "Expected one parsed file ..., got 0".
525+
const dir = createTempRepo("hunk-git-untracked-ext-diff-");
526+
527+
writeFileSync(join(dir, "tracked.ts"), "export const tracked = 1;\n");
528+
git(dir, "add", "tracked.ts");
529+
git(dir, "commit", "-m", "initial");
530+
531+
git(dir, "config", "diff.external", "git --version");
532+
writeFileSync(join(dir, "untracked.ts"), "export const added = true;\n");
533+
534+
const bootstrap = await loadFromRepo(dir, {
535+
kind: "vcs",
536+
staged: false,
537+
options: { mode: "auto" },
538+
});
539+
540+
expect(bootstrap.changeset.files.map((file) => file.path)).toEqual(["untracked.ts"]);
541+
expect(bootstrap.changeset.files[0]?.patch).toContain("new file mode");
542+
});
543+
521544
test("still shows an untracked agent sidecar when it lives inside the repo", async () => {
522545
const dir = createTempRepo("hunk-git-agent-sidecar-");
523546

test/cli/entrypoint.test.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -197,20 +197,13 @@ describe("CLI entrypoint contracts", () => {
197197
});
198198

199199
test("general pager mode falls back to plain text for non-diff stdin", () => {
200-
const proc = Bun.spawnSync(
201-
[
202-
"bash",
203-
"-lc",
204-
"printf '* main\\n feature/demo\\n' | HUNK_TEXT_PAGER=cat bun run src/main.tsx pager",
205-
],
206-
{
207-
cwd: process.cwd(),
208-
stdin: "ignore",
209-
stdout: "pipe",
210-
stderr: "pipe",
211-
env: process.env,
212-
},
213-
);
200+
const proc = Bun.spawnSync(["bun", "run", "src/main.tsx", "pager"], {
201+
cwd: process.cwd(),
202+
stdin: Buffer.from("* main\n feature/demo\n"),
203+
stdout: "pipe",
204+
stderr: "pipe",
205+
env: process.env,
206+
});
214207

215208
const stdout = Buffer.from(proc.stdout).toString("utf8");
216209
const stderr = Buffer.from(proc.stderr).toString("utf8");

0 commit comments

Comments
 (0)