Skip to content

Add Git support, and otherwise variously improve & fix parsePatch (and other unified diff format functions) - #672

Merged
ExplodingCabbage merged 73 commits into
masterfrom
git-support-attempt-2-with-claude-opus
Apr 1, 2026
Merged

Add Git support, and otherwise variously improve & fix parsePatch (and other unified diff format functions)#672
ExplodingCabbage merged 73 commits into
masterfrom
git-support-attempt-2-with-claude-opus

Conversation

@ExplodingCabbage

@ExplodingCabbageExplodingCabbage commented Mar 3, 2026

Copy link
Copy Markdown
Collaborator

See the release notes for more detail on what's changed here.

The code (but not the prose and comments) were written pretty much exclusively by Claude Opus 4.6. I rewrote the release notes and most of the docs from scratch and significantly edited most of the comments, because Opus is stupid about writing prose, and I had to handhold it through a lot of modifications to the code to get to the point that everything was correct. Still, feels like without AI adding support for Git's diff format would've felt like too big a task to even try to take on, and each of the many, many points where we discovered an additional complication we hadn't considered or yet another pre-existing bug would've further dashed my morale. With AI, it's done!

@ExplodingCabbage
ExplodingCabbageforce-pushed the git-support-attempt-2-with-claude-opus branch from ea3046c to bfaa2e2CompareMarch 9, 2026 14:51
@ExplodingCabbageExplodingCabbage changed the title Another try at adding Git support, this time with Claude Opus 4.6Add Git support, and otherwise variously improve & fix parsePatch (and other unified diff format functions)Mar 23, 2026
@ExplodingCabbage
ExplodingCabbage marked this pull request as ready for review March 30, 2026 10:56
@ExplodingCabbage

Copy link
Copy Markdown
CollaboratorAuthor

I suppose it's worth letting Copilot review before I merge this. Let's see if I get anything useful from it...

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR expands jsdiff’s unified-diff tooling to understand and emit Git-style patches (including extended headers for renames/copies/creates/deletes/mode changes), while also improving robustness around parsing/formatting edge cases and adding extensive test coverage and documentation updates.

Changes:

  • Add parsing/formatting/reversing support for diff --git patches (extended headers, hunkless patches, quoting/escaping).
  • Make parsePatch more tolerant of real-world “garbage” between/after diffs and add stricter validation for unpaired ---/+++ headers and hunk line-count spillover.
  • Update types/docs/release notes and add new tests (including a README example-backed integration test).

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
test/patch/reverse.jsAdds/updates reversePatch expectations for Git rename/copy/create/delete/mode-change cases.
test/patch/readme-rename-example.jsNew Node-only test that executes the README Git-patch example against real files.
test/patch/parse.jsAdds extensive parsePatch coverage for GNU diff, SVN noise, trailing garbage, and Git extended headers/quoting edge cases.
test/patch/create.jsAdds formatPatch tests for undefined filenames, non-mutation, and Git header emission/round-tripping.
src/types.tsExtends StructuredPatch to allow undefined filenames and adds Git-related metadata fields.
src/patch/reverse.tsUpdates reversePatch to handle Git prefixes, modes, create/delete flags, and copy/rename semantics.
src/patch/parse.tsEnhances parsePatch to recognize Git diffs + extended headers and tolerate interspersed non-diff content.
src/patch/create.tsEnhances formatPatch to emit Git-style headers/extended headers and to quote filenames when needed.
release-notes.mdDocuments new behavior, breaking type change, and Git diff support.
karma.conf.jsExcludes the new Node-dependent README example test from browser runs.
README.mdDocuments Git patch behavior/fields and adds an applyPatches example for renames/copies/mode changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadtest/patch/readme-rename-example.js Outdated
Comment threadsrc/patch/create.ts
Comment threadsrc/patch/parse.ts
Comment threadsrc/patch/create.ts Outdated
Comment on lines +382 to +389
let gitOldName = patch.oldFileName ?? '';
let gitNewName = patch.newFileName ?? '';
if (patch.isCreate && gitOldName === '/dev/null') {
gitOldName = gitNewName.replace(/^b\//, 'a/');
} else if (patch.isDelete && gitNewName === '/dev/null') {
gitNewName = gitOldName.replace(/^a\//, 'b/');
}
ret.push('diff --git ' + quoteFileNameIfNeeded(gitOldName) + ' ' + quoteFileNameIfNeeded(gitNewName));

CopilotAIMar 30, 2026

Copy link

Choose a reason for hiding this comment

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

When patch.isGit is true but oldFileName/newFileName are undefined, this emits diff --git (empty paths) plus potentially other extended headers. That output isn’t a valid Git/unified diff and is probably worse than omitting headers or throwing. Consider either (a) skipping the git header when filenames are missing, aligning with the “silently skip headers when filenames are undefined” behavior, or (b) throwing a clear error for isGit patches without filenames.

Copilot uses AI. Check for mistakes.
Sign up for freeto 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.

2 participants

@ExplodingCabbage