feat: add diffBuffers, TreeBuilder, diffTreeToTree, findBlob and Diff.toPatch - #168
Conversation
….toPatch Closes the feature request in #167: - diffBuffers(old, oldPath, new, newPath, options?) — repo-free diff of two raw buffers via git2::Patch::from_buffers, returning unified patch text, materialized hunks/lines and stats (git diff --no-index equivalent) - Diff.toPatch() — render any Diff as unified-diff text - repo.treebuilder() / TreeBuilder — insert/remove/get/write/clear/len/isEmpty - repo.diffTreeToTree(oldTree?, newTree?, options?) - repo.findBlob(oid) — plus BlobParent::Repository variant Refs #167
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_e3412d32-647d-422b-baaf-f955940d56ca) |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6fe672424c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…er compat - diffBuffers routes through libgit2-sys git_patch_from_buffers so a null side passes a real NULL pointer: absent files now produce added/deleted deltas with /dev/null and 'new file mode'/'deleted file mode' headers (creating an empty file is a change, not a no-op) - diffBuffers result.patch and Diff.toPatch() return Buffer instead of lossy UTF-8 strings, preserving non-UTF-8 content exactly - index.js keeps main's Node >=10-compatible loader (no node:fs/optional chaining, exact-value NAPI_RS_FORCE_WASI check) with only the new exports - libgit2_sys::init() moved to #[module_init] at module load - rustfmt clean; regression tests for file creation/deletion and non-UTF-8 content
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_6166e028-a8e3-46b1-a99f-9942cd4cda38) |
|
Thank you! |
Closes #167
Issue #167 asks for diffing arbitrary strings like
git diff --no-index. The reporter suggestedTreeBuilder+diffTreeToTreeas a workaround after findinggit_diff_blobsis callback-based. This PR implements both the direct API and the workaround path.New API surface
diffBuffers(old, oldPath, new, newPath, options?)git2::Patch::from_buffers. Returns{ patch, hunks, stats }— unified patch text plus eagerly materialized hunks/lines (thePatchborrows the input buffers, so everything is copied out).nullon either side = added/deleted file.Diff.toPatch()Diffas unified-diff text, including sigils (+/-/space) matching libgit2'sdiff_print.c.repo.treebuilder(source?)→TreeBuilderinsert(name, oid, filemode)/remove/get/write/clear/len/isEmpty— the reporter's literal request.repo.diffTreeToTree(oldTree?, newTree?, options?)nullside = empty tree.repo.findBlob(oid)BlobParent::Repositoryvariant).Reporter's use case, now possible
The synthetic-tree route also works end to end:
repo.blob()→treebuilder.insert(..., 0o100644)→write()→diffTreeToTree→toPatch().Tests
__test__/buffer-diff.spec.mjs— identical/modified/null-side buffers, stats,toPatchon a workdir diff__test__/tree-builder.spec.mjs— builder round-trip,findBlob, the issue-167 two-tree diff flowNote
Medium Risk
Additive native surface with one unsafe libgit2 patch call; behavior is well-tested but touches ODB writes and diff output consumers may rely on exact patch bytes.
Overview
Adds in-memory and tree-based diffing (closes #167): compare arbitrary byte buffers like
git diff --no-index, build synthetic trees in the ODB, and emit standard unified patches.diffBuffersis a repo-free entry point that returns unifiedpatchbytes, structured hunks/lines, and stats. It callsgit_patch_from_buffersdirectly sonullbuffers mean absent files (/dev/null, add/delete) rather than empty content; results are fully copied out for JS.Diff.toPatch()prints any existingDiffas raw patch bytes, prepending+/-/space sigils to match libgit2’s patch format.On
Repository:treebuilder(source?)+TreeBuilder(insert/write/etc.),diffTreeToTree, andfindBlob(oid)(newBlobParent::Repository). Together they support blob → single-entry tree → tree diff without touching the workdir.Also wires libgit2 init at native module load and adds AVA coverage for buffer diffs, tree builder round-trips, and workdir
toPatch.Reviewed by Cursor Bugbot for commit 497de0c. Bugbot is set up for automated code reviews on this repo. Configure here.