Patch Diff Review
Review .patch and .diff files as native VS Code comparisons with native inline comments. You don't need to
clone anything, sign in or use the network. When you want more context, load the complete file for one patched
file from GitHub or GitLab at the patch's base commit. Copy your notes as text or as spreadsheet-ready TSV.
It works in desktop VS Code and in VS Code for the Web from the same package. It has no webview: everything is a
diff editor, a comment thread, a tree, a Quick Pick or a command.
Getting started
- Open a patch, for example the output of
git format-patch -1 HEAD.
- Run Patch Diff Review: Review Active Document, or right-click the patch in the Explorer and choose
Open Patch as Native Review.
- The Patch Diff Review view in the Explorer lists the files. Each one opens as a side-by-side comparison of the
lines in the patch. Gaps are marked
⋯ N unchanged lines not included in the patch ⋯; these markers are never
treated as source.
- To add a note, select lines and run Patch Diff Review: Add Note to Selection (
Ctrl+Alt+N), or click + in
the gutter. Set the severity and category from the thread's title actions.
- Run Patch Diff Review: Load Full Context (
Ctrl+Alt+L) to replace one file's excerpt with the complete file.
Your notes stay attached to the same source lines.
- Run Patch Diff Review: Copy Selected Comments… (
Ctrl+Alt+E), pick notes in the multi-select list, and choose
Text or TSV.
Notes are saved automatically to <patch>.review.json next to the patch, for example
change.patch.review.json. The format is portable between desktop and web.
What it understands
git format-patch output: single commits and series, base-commit: trailers, quoted and unicode paths,
renames, copies, additions, deletions, mode changes, and \ No newline at end of file.
git diff output and plain diff -u output.
- Binary patches and combined-merge diffs (
diff --cc) are rejected with a clear message rather than misread.
Load Full Context
The base commit is the patch's explicit base-commit: if it has one. Otherwise it is the parent of the first
commit in the series; a format-patch's From <hash> line is the commit itself, never its base. For a file in a
later commit of a series, the earlier commits are replayed in memory (following renames). The patch is then
applied strictly: no fuzz or offset search, and git blob ids are checked when the patch includes them. A wrong
base, a network error, an authentication failure, a rate limit or a cancellation leaves the review unchanged.
The repository is found locally. The extension searches the patch folder C, then C/.. and C/../.., for
the patch's commit hashes in TSV, CSV, JSON, JSONL, TOML or text files, and takes repository URLs from the same
record or from nearby lines. Clone, pull request, merge request, commit, tree and blob URLs all work, including
GitLab subgroups. One clear match is used automatically. Several matches produce a picker, and no match produces
a prompt. The search only looks inside workspace folders or folders you authorize with Set Discovery Root….
It is bounded and cancellable, and it reports when it stopped early.
Public repositories need no sign-in. For private ones, use Set Access Token… (stored in VS Code's secret
storage) or Sign in with GitHub when prompted. Self-hosted GitLab and GitHub Enterprise servers must be
approved explicitly.
No repository at all? Use Use Local Base File… to pick the original file from disk.
Commands
| Command |
What it does |
| Patch Diff Review: Open Patch… |
Pick a patch file to review |
| Patch Diff Review: Review Active Document |
Review the patch in the active editor (also untitled editors) |
| Patch Diff Review: Review Clipboard |
Review a patch from the clipboard |
| Patch Diff Review: Open File Comparison |
Open one file's comparison |
| Patch Diff Review: Open All Changes |
Open all files in VS Code's multi-file diff editor |
| Patch Diff Review: Load Full Context |
Download one file at the base commit and apply the patch in memory |
| Patch Diff Review: Load Full Context for All Files |
The same, for every file of the review |
| Patch Diff Review: Use Local Base File… |
Reconstruct the file from a local copy of its original |
| Patch Diff Review: Add Note to Selection |
Start a note on the selected lines; several selections make one multi-range note |
| Patch Diff Review: Add Selection to Existing Note… |
Add another range to a note |
| Patch Diff Review: Copy Selected Comments… |
Multi-select notes, then copy them as text or TSV |
| Patch Diff Review: Copy All Comments |
Copy every note with the default format |
| Patch Diff Review: Save Review / Save Review As… / Open Review… |
Explicit save and open of the review file |
| Patch Diff Review: Set Repository… / Set Base Commit… |
Override the repository or base |
| Patch Diff Review: Find Repository Near Patch |
Run discovery again and show where the match came from |
| Patch Diff Review: Set Discovery Root… |
Allow discovery inside a folder |
| Patch Diff Review: Set Access Token… / Remove Access Token… |
Manage per-host tokens |
| Patch Diff Review: Show Unplaced Notes… |
Show notes from an older patch revision that no longer match |
| Patch Diff Review: Show Output |
Open the log |
Every command also accepts explicit arguments. For example, patchReview.loadFullContext accepts
{ "reviewId", "fileId" }, so you can bind it to keys or call it from other extensions.
src/cache.ts:42 `return cached;` Do not return an expired entry.
src/cache.ts:73-75 `if (expired) {\n refresh();\n}` src/cache.ts:91 `return cached;` Both paths need the same freshness check.
TSV uses real tab characters, one row per range (Location⇥Code⇥Comment), with optional Note ID, Side,
Severity, Category and State columns. There is also a text-layout TSV variant. Tabs and newlines inside a field
are escaped as \t and \n. Original-side ranges are marked (original). Spreadsheet-safe mode, on by default,
prefixes cells that start with =, +, -, @, a tab or a carriage return with '. If the clipboard isn't
available, the export opens in an editor.
Settings
All settings are under patchReview.*:
authorName, autoSave, severities, categories
export.format, export.header, export.codeBackticks, export.order, export.spreadsheetSafe,
export.extraColumns, export.includeReplies
discovery.enabled, discovery.searchParents, discovery.reviewDirectory, discovery.maxFiles,
discovery.maxFileSize, discovery.maxDepth
network.maxRetryWaitSeconds, network.maxConcurrentRequests, hosts
Workspace Trust, offline use and the web
In Restricted Mode, reviewing, notes, saving and export all work, and discovery is limited to the patch folder.
Network access and self-hosted servers need trust.
Reviewing and exporting never need the network. In VS Code for the Web, Load Full Context uses the browser's
fetch, which works because GitHub and GitLab allow cross-origin requests. Self-hosted servers must allow CORS
too. When the extension is installed, the same review file opens on desktop and on the web.
Cold start offline is verified by npm run verify:offline: a fresh browser profile (empty cache, no service
worker) loads VS Code for the Web with every request outside the serving origin aborted. The extension activates,
reviews the demo patch with its saved notes, and exports them. Loading the workbench while its own server is
unreachable depends on VS Code for the Web's offline support and is not covered.
Accessibility
Every action is a command, so you can reach it from the keyboard and rebind it. The tree's labels spell out each
file's status, loading state and note count; nothing is conveyed by colour alone. Comparisons are standard diff
editors, so the Accessible Diff Viewer (F7) and diff navigation work as usual.
Limitations
- The extension doesn't apply patches to your working tree, stage anything, or post comments to GitHub or
GitLab.
- Notes from an earlier revision of a patch are placed only where the code still matches exactly. Other notes
are listed under Show Unplaced Notes… and are never dropped.
- Excerpt views show line numbers within the excerpt. Exports and saved notes always use real source line
numbers.
Development
The repository uses a dev container (.devcontainer/, Node LTS). Useful commands:
npm run dev:web serves a hot-reloading VS Code for the Web. It runs esbuild in watch mode, and a dev-only
reloader that isn't part of the VSIX refreshes connected browsers after every rebuild.
npm run check runs every static gate. npm run check:all also runs end-to-end tests on desktop (latest and
minimum supported VS Code), in the desktop web-worker host, and in headless Chromium, plus mutation testing.
- Every file type is linted with zero warnings allowed: TypeScript (ESLint strictTypeChecked, two compilers),
JSON/JSONC and YAML (ESLint), Markdown (markdownlint, all rules), spelling (cspell,
.cspell/project-words.txt),
shell (shellcheck enable=all, shfmt), workflows (actionlint), the Dockerfile (hadolint), TOML (taplo),
.editorconfig, JSON Schemas (schemas/review.schema.json for review sidecars, the dev container schema) and
byte hygiene with SPDX headers. The binary linters are pinned, SHA-256-verified downloads in .tools/bin
(npm run tools:install), so CI and the dev container run identical versions. Byte-exact test fixtures are
excluded on purpose; the reasons are in scripts/lint/hygiene.mts.
npm run package builds the universal VSIX.
Releases are built once by .github/workflows/release.yml. The same VSIX is published to the Visual Studio
Marketplace and Open VSX and attached to the GitHub release.
License
CC0 1.0 Universal, dedicated by Mehmet Oguz Derin. See THIRD_PARTY_NOTICES.md,
PRIVACY.md and SECURITY.md.