From 4cde0c20863bba65f4316ee5fb60b97cd8e3176a Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sun, 22 Feb 2026 07:31:30 -0800 Subject: [PATCH] Use inherited stdio for git diff/show to support external diff tools and native paging --- src/commands/diff.ts | 32 +++++++++++++++----------------- src/commands/show.ts | 27 ++++++++++++++------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/commands/diff.ts b/src/commands/diff.ts index b372585..ba03a6e 100644 --- a/src/commands/diff.ts +++ b/src/commands/diff.ts @@ -1,6 +1,5 @@ import { $ } from "bun" import * as git from "../git.ts" -import { pager } from "../fmt.ts" import { requireSession } from "./helpers.ts" export async function action(branch: string) { @@ -13,27 +12,26 @@ export async function action(branch: string) { process.exit(1) } - let diff: string + let args: string[] if (status.text().trim().length > 0) { // Show uncommitted changes (both staged and unstaged) - const result = await $`git -C ${session.worktree} diff --color=always HEAD`.nothrow().quiet() - if (result.exitCode !== 0) { - // HEAD may not exist yet (no commits); fall back to showing all tracked + untracked - const fallback = await $`git -C ${session.worktree} diff --color=always`.nothrow().quiet() - diff = fallback.text() - } else { - diff = result.text() - } + const hasHead = await $`git -C ${session.worktree} rev-parse --verify HEAD`.nothrow().quiet() + args = hasHead.exitCode === 0 ? ["diff", "HEAD"] : ["diff"] } else { // No uncommitted changes — show full branch diff vs main const main = await git.mainBranch(session.worktree) - const result = await $`git -C ${session.worktree} diff --color=always ${main}...${branch}`.nothrow().quiet() - if (result.exitCode !== 0) { - console.error("✖ git diff failed") - process.exit(1) - } - diff = result.text() + args = ["diff", `${main}...${branch}`] } - await pager(diff) + // Run git diff with inherited stdio so external diff tools (e.g. difftastic) + // see a real TTY and git can use its own pager + const proc = Bun.spawn(["git", "-C", session.worktree, ...args], { + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }) + const exitCode = await proc.exited + if (exitCode !== 0) { + process.exit(exitCode) + } } diff --git a/src/commands/show.ts b/src/commands/show.ts index 68ec167..1d7e7c6 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -1,23 +1,24 @@ -import { $ } from "bun" import * as git from "../git.ts" -import { pager } from "../fmt.ts" import { requireSession } from "./helpers.ts" export async function action(branch: string) { const { session } = await requireSession(branch) - const main = await git.mainBranch(session.worktree) - const result = await $`git -C ${session.worktree} diff --color=always ${main}...${branch}`.nothrow().quiet() - if (result.exitCode !== 0) { - console.error("git diff failed") - process.exit(1) - } - - let output = "" if (session.prompt) { - output += `PROMPT: ${session.prompt}\n\n` + process.stderr.write(`PROMPT: ${session.prompt}\n\n`) } - output += result.text() - await pager(output) + const main = await git.mainBranch(session.worktree) + + // Run git diff with inherited stdio so external diff tools (e.g. difftastic) + // see a real TTY and git can use its own pager + const proc = Bun.spawn(["git", "-C", session.worktree, "diff", `${main}...${branch}`], { + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }) + const exitCode = await proc.exited + if (exitCode !== 0) { + process.exit(exitCode) + } }