Skip to content

refactor(core): speed up diff calculation significantly #20731

Open
natewill wants to merge 5 commits intoanomalyco:devfrom
natewill:difffull-performance
Open

refactor(core): speed up diff calculation significantly #20731
natewill wants to merge 5 commits intoanomalyco:devfrom
natewill:difffull-performance

Conversation

@natewill
Copy link
Copy Markdown
Contributor

@natewill natewill commented Apr 2, 2026

Issue for this PR

Closes #20734
Closes #11486

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

This PR speeds up the Snapshot.diffFull function, somewhat similar to how #20564 and #20551 speed up revert.

Currently, diffFull handles one file at a time when when loading blob contents. This means for n files it's spawning 2n git processes for git show from: and git show to:. Similar to the old revert function, each git process has significant overhead (10-20ms) per process, making the entire function very slow.

This change batches files by using git cat-file --batch to do all of the work for git show in one git command. This reduces the work for git show from 2n to a constant factor of 1, while preserving the existing single-file path as a fallback if the batched operation fails.

On my machine, a Snapshot.diffFull for a 1000 file diffFull went 13.68s to ~0.34s which is a 40x speed up. This function is ran frequently in the application, making this speedup worthwhile.

How did you verify your code works?

  • Ran targeted bun test tests for Snapshot.diffFull(), including:
    • interleaved added / modified / deleted / binary diffs
    • made sure it preserved diff ordering
    • tests on existing baseline diffFull scenarios

All of these passed

Screenshots / recordings

Not a UI change

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

const diffFull = Effect.fnUntraced(function* (from: string, to: string) {
return yield* locked(
Effect.gen(function* () {
const catFile = Effect.fnUntraced(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can’t use the normal git() helper here because git cat-file --batch needs us to write refs to stdin and read raw stdout bytes back, and the normal helper just treats everything like plain text.

@natewill natewill marked this pull request as ready for review April 2, 2026 19:04
const out = new Map<string, string>()
const dec = new TextDecoder()
let i = 0
for (const ref of refs) {
Copy link
Copy Markdown
Contributor Author

@natewill natewill Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each batch entry is either "<ref> missing" for added/deleted files or "<id> blob <byte_size>\n<file_contents>\n".

kitlangton added a commit that referenced this pull request Apr 4, 2026
Derived from #20731.

Co-authored-by: Nate Williams <50088025+natewill@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] diff calculation is slow [PERF] /undo /redo really slow on larger repos and/or long histories

1 participant