Skip to content

fix(workingdiff): diff committed trees with one git process - #71

Merged
akonwi merged 1 commit into
mainfrom
fix/committed-diff-tree
Oct 10, 2026
Merged

akonwi merged 1 commit into
mainfrom
fix/committed-diff-tree

Conversation

@akonwi

@akonwi akonwi commented Oct 10, 2026

Copy link
Copy Markdown
Owner

Fixes #68.

Problem

Observing a commit or branch diff target read both endpoint trees in full, starting one git cat-file tree process per directory. Cost scaled with repository size rather than change size: in this repository (306 directories) two walks took ~8.4 s against the 8 s observation budget, so every commit target failed with context deadline exceeded. Reading a file from a committed observation re-walked both full trees as well.

Change

  • diffCommittedTrees runs a single git diff-tree -r -z --raw --no-renames --ignore-submodules=none <base> <head> and returns only changed entries. The empty-tree base uses git's well-known empty tree OID for the repository's object format.
  • The call is bracketed by validateObjectStoreAuthority, the same before/after loose-object and pack check mergeBase uses, so unsafe object storage is still rejected.
  • revalidateCommittedFile (file reads) uses the same comparison restricted to the requested path.
  • Downstream classification is unchanged; it already only consumed differing paths.

Behavior notes

  • Tree object bytes are no longer re-hashed against their OIDs; git's diff-tree output is trusted, as ls-tree already is for working-tree observation.
  • Unsupported paths are counted only among changed paths, so invalid paths in untouched directories no longer mark an observation incomplete.
  • Repository size no longer triggers the traversal limit; only a change whose raw diff exceeds 16 MiB fails, currently as a generic repository_unavailable rather than limit_exceeded.

Validation

  • New regression test: a repository with 300 nested directories and a one-file change; observe and read each run exactly one diff-tree and at most 10 git processes, counted by a git wrapper on PATH. The test fails on main with context deadline exceeded.
  • Parser tests for added, deleted, modified, symlink, file-to-submodule, and unsupported-path records, plus rejection of malformed records.
  • Against this repository, every commit and branch target observes in ~110–270 ms.
  • gofmt -l ., go build ./..., go vet ./..., go test ./..., go test -race ./internal/workingdiff/.

#69 and #70 (error propagation for diff failures) are not addressed here.

Observing a commit or branch target walked both endpoint trees with one
`git cat-file tree` process per directory, so cost grew with repository
size and moderately sized repositories exceeded the 8 s observation
budget. Compare the trees with a single `git diff-tree` that returns only
changed entries, bracketed by the object store authority check used for
merge-base, and use the same path-limited comparison when revalidating a
file on read.

Fixes #68
@akonwi
akonwi merged commit b93bb5a into main Oct 10, 2026
3 checks passed
@akonwi
akonwi deleted the fix/committed-diff-tree branch October 10, 2026 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Committed diff targets time out: tree walk starts a git process per directory

1 participant