Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

#144

Read a change's file list without its patch, and never cut a diff

merged · by keenan 8d ago · merged into main at 87bef95c by keenan 8d ago

keenan opened this 8d ago

Why

The Files tab of a change request built its tree, its file count and its landing summary by parsing one git diff capped at 512 KiB. When a change carries a large file the cut lands inside that file, and every path named after the cut is missing from the tree — with no notice that anything was left out.

#143 is the case that found it: deleting the old 546 KB Prism bundle alone exceeds the cap, so the tab said “6 changed” for a change of 302 files, and 296 of them could not be reviewed in the browser at all.

What

The cap existed so a page would not render every hunk of a broad change. But these pages already render exactly one file at a time, so the cap was not protecting them — it was hiding the inventory.

  • DiffInventory reads git diff --raw --numstat -z: every path with its status, both sides of a rename, and its line counts, in one walk of the trees and with no hunks. The changed-file tree, the file count and the landing summary read it.
  • DiffPaths reads the patch of the one file the Files tab shows, and the commit page keeps its per-file ShowPatchPath. Both return the whole patch.
  • Diff is whole too, for compare. No caller passes a byte bound any more, and diffCap and the “showing the first 512 KiB” notes are gone.

So a page is as large as the file it shows, and the inventory is the whole change however large it is. Opening a broad change gets cheaper as well: the tree no longer needs the patches of every file to list them.

Checks

  • vole workflow run verify — all steps pass, including go test -race ./....
  • TestDiffInventoryCountsEveryFile — statuses, line counts, a rename’s two paths and a binary file, in both the range form and the two-revision form a landed request uses.
  • TestRequestFilesListsEveryChangedFile — a 600 KiB file that sorts first, and three files after it: the tree counts and links all four. This is the regression for #143.
  • TestCommitPageShowsTheWholeOfOneFilesPatch — the end of a 513 KiB file is on the page, and the file after it still has its row.

Left as it was

Compare still renders every file of a range on one page. It is uncapped now too, so a large comparison is one large page; making it per-file is a separate change, and worth doing if it turns out to matter.

Discussion (1)

keenan 8d ago

Two fixups, both found while previewing this branch on a local instance:

  • bef0c09 — opening a deleted file answered 500. pathspec() handed git both sides, and a deletion has no new side, so git refused the empty pathspec. The commit page already had this bug on main; the per-file read this branch gives the Files tab would have spread it to every deleted file in a change.
  • e411131 — a deleted file’s diff header read gone.txt → gone.txt, because “moved” was tested as “an old path and a different new one”, which is also true of a deletion.

New tests: TestPathspecNamesTheSideThatExists, TestCommitPageShowsADeletedFile, and the request Files test now carries a deletion and opens it.