HASH daa02966b6ab
DATE 2026-07-18
SUBJECT web: oversized commits render a diffstat, not a hundred-megabyte patch
FILES 3 CHANGED
HASH daa02966b6ab
DATE 2026-07-18
SUBJECT web: oversized commits render a
diffstat, not a hundred-megabyte patch
FILES 3 CHANGED
┌─ ooknet-design/src/lib/git.test.ts ────────────────────────────────────────┐
│ diff --git a/ooknet-design/src/lib/git.test.ts b/ooknet-design/src/lib/git.test.ts │
│ index 67ce014..acdda46 100644 │
│ --- a/ooknet-design/src/lib/git.test.ts │
│ +++ b/ooknet-design/src/lib/git.test.ts │
│ @@ -1,5 +1,5 @@ │
│ import { describe, expect, it } from "vitest"; │
│ -import { branches, excluded, langOf, repoAvailable, repoInfo } from "./git"; │
│ +import { branches, excluded, langOf, oversizedNumstat, repoAvailable, repoInfo } │
│ from "./git"; │
│ import { toGrid } from "./ascii"; │
│ │
│ describe("toGrid", () => { │
│ @@ -27,6 +27,17 @@ describe("excluded", () => { │
│ }); │
│ }); │
│ │
│ +describe("oversizedNumstat", () => { │
│ + it("flags huge patches by lines or file count", () => { │
│ + expect(oversizedNumstat("3\t1\ta.ts\n10\t2\tb.ts\n")).toBe(false); │
│ + expect(oversizedNumstat("6000\t0\tbig.json\n")).toBe(true); │
│ + expect( │
│ + oversizedNumstat(Array.from({ length: 201 }, (_, i) => `1\t1\tf${i}.json`). │
│ join("\n")), │
│ + ).toBe(true); │
│ + expect(oversizedNumstat("-\t-\tbin.png\n")).toBe(false); │
│ + }); │
│ +}); │
│ + │
│ describe("langOf", () => { │
│ it("maps extensions to frame labels", () => { │
│ expect(langOf("src/lib/ascii.ts")).toBe("TS"); │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...et-design/src/lib/git.test.ts ───┐
│ diff --git a/ooknet-design/src/lib/git.test. │
│ ts b/ooknet-design/src/lib/git.test.ts │
│ index 67ce014..acdda46 100644 │
│ --- a/ooknet-design/src/lib/git.test.ts │
│ +++ b/ooknet-design/src/lib/git.test.ts │
│ @@ -1,5 +1,5 @@ │
│ import { describe, expect, it } from "vites │
│ t"; │
│ -import { branches, excluded, langOf, repoAv │
│ ailable, repoInfo } from "./git"; │
│ +import { branches, excluded, langOf, oversi │
│ zedNumstat, repoAvailable, repoInfo } from " │
│ ./git"; │
│ import { toGrid } from "./ascii"; │
│ │
│ describe("toGrid", () => { │
│ @@ -27,6 +27,17 @@ describe("excluded", () = │
│ > { │
│ }); │
│ }); │
│ │
│ +describe("oversizedNumstat", () => { │
│ + it("flags huge patches by lines or file c │
│ ount", () => { │
│ + expect(oversizedNumstat("3\t1\ta.ts\n10 │
│ \t2\tb.ts\n")).toBe(false); │
│ + expect(oversizedNumstat("6000\t0\tbig.j │
│ son\n")).toBe(true); │
│ + expect( │
│ + oversizedNumstat(Array.from({ length: │
│ 201 }, (_, i) => `1\t1\tf${i}.json`).join(" │
│ \n")), │
│ + ).toBe(true); │
│ + expect(oversizedNumstat("-\t-\tbin.png\ │
│ n")).toBe(false); │
│ + }); │
│ +}); │
│ + │
│ describe("langOf", () => { │
│ it("maps extensions to frame labels", () │
│ => { │
│ expect(langOf("src/lib/ascii.ts")).toBe │
│ ("TS"); │
└──────────────────────────────────────────────┘
┌─ ooknet-design/src/lib/git.ts ─────────────────────────────────────────────┐
│ diff --git a/ooknet-design/src/lib/git.ts b/ooknet-design/src/lib/git.ts │
│ index 2fc0879..af62406 100644 │
│ --- a/ooknet-design/src/lib/git.ts │
│ +++ b/ooknet-design/src/lib/git.ts │
│ @@ -207,12 +207,38 @@ export interface Commit { │
│ subject: string; │
│ body: string; │
│ files: CommitFile[]; │
│ + /** Set instead of files when the patch is too large to render. */ │
│ + stat?: string; │
│ } │
│ │
│ -/** One commit with its patch split per file, github-style. */ │
│ +/** True when a numstat says the patch is too big for a page - data │
│ + * dumps produce patches in the hundreds of megabytes. */ │
│ +export function oversizedNumstat(numstat: string): boolean { │
│ + const rows = numstat.split("\n").filter(Boolean); │
│ + let lines = 0; │
│ + for (const r of rows) { │
│ + const [a, d] = r.split("\t"); │
│ + lines += (parseInt(a, 10) || 0) + (parseInt(d, 10) || 0); │
│ + } │
│ + return rows.length > 200 || lines > 5000; │
│ +} │
│ + │
│ +/** One commit with its patch split per file, github-style. Oversized │
│ + * commits carry a diffstat summary instead of patches. */ │
│ export function readCommit(path: string, hash: string): Commit { │
│ const meta = git(path, ["show", "-s", "--format=%H|%as|%s|%b", hash]).trim(); │
│ const [full, date, subject, ...body] = meta.split("|"); │
│ + const base = { │
│ + hash: full, │
│ + date, │
│ + subject: toGrid(subject), │
│ + body: toGrid(body.join("|").trim()), │
│ + }; │
│ + const numstat = git(path, ["show", "--numstat", "--format=", hash]); │
│ + if (oversizedNumstat(numstat)) { │
│ + const stat = git(path, ["show", "--stat", "--format=", hash]); │
│ + return { ...base, files: [], stat: stat.length > MAX_BLOB ? stat.slice(0, MAX │
│ _BLOB) : stat }; │
│ + } │
│ const patch = git(path, ["show", "--patch", "--format=", hash]); │
│ const files: CommitFile[] = []; │
│ for (const chunk of patch.split(/^(?=diff --git )/m)) { │
│ @@ -223,13 +249,7 @@ export function readCommit(path: string, hash: string): Commi │
│ t { │
│ chunk.length > MAX_BLOB ? chunk.slice(0, MAX_BLOB) + "\n[diff truncated]" : │
│ chunk; │
│ files.push({ path: file, diff: trimmed }); │
│ } │
│ - return { │
│ - hash: full, │
│ - date, │
│ - subject: toGrid(subject), │
│ - body: toGrid(body.join("|").trim()), │
│ - files, │
│ - }; │
│ + return { ...base, files }; │
│ } │
│ │
│ /** Frame label for a file: the uppercased extension, same convention │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ooknet-design/src/lib/git.ts ───────┐
│ diff --git a/ooknet-design/src/lib/git.ts b/ │
│ ooknet-design/src/lib/git.ts │
│ index 2fc0879..af62406 100644 │
│ --- a/ooknet-design/src/lib/git.ts │
│ +++ b/ooknet-design/src/lib/git.ts │
│ @@ -207,12 +207,38 @@ export interface Commi │
│ t { │
│ subject: string; │
│ body: string; │
│ files: CommitFile[]; │
│ + /** Set instead of files when the patch i │
│ s too large to render. */ │
│ + stat?: string; │
│ } │
│ │
│ -/** One commit with its patch split per fil │
│ e, github-style. */ │
│ +/** True when a numstat says the patch is t │
│ oo big for a page - data │
│ + * dumps produce patches in the hundreds o │
│ f megabytes. */ │
│ +export function oversizedNumstat(numstat: s │
│ tring): boolean { │
│ + const rows = numstat.split("\n").filter(B │
│ oolean); │
│ + let lines = 0; │
│ + for (const r of rows) { │
│ + const [a, d] = r.split("\t"); │
│ + lines += (parseInt(a, 10) || 0) + (pars │
│ eInt(d, 10) || 0); │
│ + } │
│ + return rows.length > 200 || lines > 5000; │
│ +} │
│ + │
│ +/** One commit with its patch split per fil │
│ e, github-style. Oversized │
│ + * commits carry a diffstat summary instea │
│ d of patches. */ │
│ export function readCommit(path: string, ha │
│ sh: string): Commit { │
│ const meta = git(path, ["show", "-s", "-- │
│ format=%H|%as|%s|%b", hash]).trim(); │
│ const [full, date, subject, ...body] = me │
│ ta.split("|"); │
│ + const base = { │
│ + hash: full, │
│ + date, │
│ + subject: toGrid(subject), │
│ + body: toGrid(body.join("|").trim()), │
│ + }; │
│ + const numstat = git(path, ["show", "--num │
│ stat", "--format=", hash]); │
│ + if (oversizedNumstat(numstat)) { │
│ + const stat = git(path, ["show", "--stat │
│ ", "--format=", hash]); │
│ + return { ...base, files: [], stat: stat │
│ .length > MAX_BLOB ? stat.slice(0, MAX_BLOB) │
│ : stat }; │
│ + } │
│ const patch = git(path, ["show", "--patch │
│ ", "--format=", hash]); │
│ const files: CommitFile[] = []; │
│ for (const chunk of patch.split(/^(?=diff │
│ --git )/m)) { │
│ @@ -223,13 +249,7 @@ export function readCom │
│ mit(path: string, hash: string): Commit { │
│ chunk.length > MAX_BLOB ? chunk.slice │
│ (0, MAX_BLOB) + "\n[diff truncated]" : chunk │
│ ; │
│ files.push({ path: file, diff: trimmed │
│ }); │
│ } │
│ - return { │
│ - hash: full, │
│ - date, │
│ - subject: toGrid(subject), │
│ - body: toGrid(body.join("|").trim()), │
│ - files, │
│ - }; │
│ + return { ...base, files }; │
│ } │
│ │
│ /** Frame label for a file: the uppercased │
│ extension, same convention │
└──────────────────────────────────────────────┘
┌─ ooknet-design/src/pages/git/[repo]/commit/[hash].astro ───────────────────┐
│ diff --git a/ooknet-design/src/pages/git/[repo]/commit/[hash].astro b/ooknet-desig │
│ n/src/pages/git/[repo]/commit/[hash].astro │
│ index cf95bad..3c79e93 100644 │
│ --- a/ooknet-design/src/pages/git/[repo]/commit/[hash].astro │
│ +++ b/ooknet-design/src/pages/git/[repo]/commit/[hash].astro │
│ @@ -36,7 +36,14 @@ const branch = defaultBranch(repo.path); │
│ ["FILES", `${commit.files.length} CHANGED`], │
│ ]} /> │
│ <Pre>{" "}</Pre> │
│ - {commit.files.map((f) => ( │
│ + {commit.stat ? ( │
│ + <Fragment> │
│ + <Pre>*** PATCH TOO LARGE - DIFFSTAT ONLY ***</Pre> │
│ + <Pre>{" "}</Pre> │
│ + <CodeFrame code={toGrid(commit.stat)} label="DIFFSTAT" /> │
│ + <Pre>{" "}</Pre> │
│ + </Fragment> │
│ + ) : commit.files.map((f) => ( │
│ <Fragment> │
│ <CodeFrame code={toGrid(f.diff)} label={toGrid(f.path)} diff /> │
│ <Pre>{" "}</Pre> │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...it/[repo]/commit/[hash].astro ───┐
│ diff --git a/ooknet-design/src/pages/git/[re │
│ po]/commit/[hash].astro b/ooknet-design/src/ │
│ pages/git/[repo]/commit/[hash].astro │
│ index cf95bad..3c79e93 100644 │
│ --- a/ooknet-design/src/pages/git/[repo]/com │
│ mit/[hash].astro │
│ +++ b/ooknet-design/src/pages/git/[repo]/com │
│ mit/[hash].astro │
│ @@ -36,7 +36,14 @@ const branch = defaultBra │
│ nch(repo.path); │
│ ["FILES", `${commit.files.length} CHANG │
│ ED`], │
│ ]} /> │
│ <Pre>{" "}</Pre> │
│ - {commit.files.map((f) => ( │
│ + {commit.stat ? ( │
│ + <Fragment> │
│ + <Pre>*** PATCH TOO LARGE - DIFFSTAT O │
│ NLY ***</Pre> │
│ + <Pre>{" "}</Pre> │
│ + <CodeFrame code={toGrid(commit.stat)} │
│ label="DIFFSTAT" /> │
│ + <Pre>{" "}</Pre> │
│ + </Fragment> │
│ + ) : commit.files.map((f) => ( │
│ <Fragment> │
│ <CodeFrame code={toGrid(f.diff)} labe │
│ l={toGrid(f.path)} diff /> │
│ <Pre>{" "}</Pre> │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET