A VS Code extension that tracks which changed files you have already reviewed during code review. Mark a file as reviewed from the Explorer or the Source Control pane, see a tick next to it, and have that tick turn into a "changed since review" warning when the file changes again — instead of silently disappearing.
Reviewed state is stored in a committed file in the repository, so your
reviewed marks travel with your work across machines via git push / git pull.
This extension is built for local desktop use on a Git repo. There is no
telemetry. Virtual workspaces (e.g. GitHub Repositories) are not supported; in
Restricted Mode (untrusted workspaces) the extension runs but ignores the
workspace-level scmReviewed.stateFile setting.
The extension icon (
images/icon.png) is a generated placeholder — replace it with real artwork before a public release.
What it does
- Review & Stage / Mark / Unmark as Reviewed from the right-click menu in both the SCM (Source Control) changes list and the Explorer.
- Tick decoration (
✓) next to reviewed files. Because it uses aFileDecorationProvider, the same tick appears in the Explorer, the Source Control pane, and on editor tabs. It has two states:- Green ✓ — reviewed and the content still matches.
- Amber ✓ — reviewed, but the file changed afterward (re-review). The mark is kept, not dropped, so you can see "I looked at this, then it changed."
- Staging awareness. Because VS Code doesn't let extensions block the native Stage buttons, the extension warns after the fact: if you stage a file (via the normal Stage / Stage All buttons) that isn't reviewed — or that changed since review — you get a notification so you know it still needs a look, even after you push. There's also a Review & Stage action that marks reviewed and stages in one step (no warning, since you just reviewed it).
- Committed, portable state: stored in
.vscode/file-reviews.json(path configurable). Commit it and your reviewed marks appear on any machine after a pull. - Multi-select support in both panes, plus folder operations (whole subtree or immediate children only).
- Bulk commands: mark all currently-changed files, or clear all marks.
- A Reviewed Files tree view in the Explorer (green check / amber warning per file) and a "List Reviewed Files" quick pick.
Commands
All commands are under the SCM Reviewed category in the Command Palette.
| Command | Where |
|---|---|
| Review & Stage | Explorer + SCM context menu (file/multi-select) |
| Mark as Reviewed | Explorer + SCM context menu (file/multi-select) |
| Unmark as Reviewed | Explorer + SCM context menu (file/multi-select) |
| Mark All Files in Folder as Reviewed | Explorer folder context menu (recursive) |
| Unmark All Files in Folder | Explorer folder context menu (recursive) |
| Mark Immediate Children as Reviewed | Explorer folder context menu (top level only) |
| Unmark Immediate Children | Explorer folder context menu (top level only) |
| SCM Reviewed: Mark All Currently Changed Files as Reviewed | Command Palette |
| SCM Reviewed: Clear All Reviewed Marks | Command Palette / Reviewed Files view title |
| SCM Reviewed: List Reviewed Files | Command Palette |
| SCM Reviewed: Refresh Reviewed Files | Reviewed Files view title (reloads the repo file) |
Settings
| Setting | Default | Effect |
|---|---|---|
scmReviewed.showExplorerDecorations |
true |
Show the tick decoration. Also governs the tick in the SCM pane, since both share VS Code's file-decoration mechanism. |
scmReviewed.showScmContextMenu |
true |
Show Review & Stage / Mark / Unmark in the Source Control resource context menu. |
scmReviewed.warnOnStagingUnreviewed |
true |
Warn after staging files (via the native Stage buttons) that are unreviewed or changed since review. |
scmReviewed.stateFile |
.vscode/file-reviews.json |
Workspace-relative path of the committed file storing reviewed state. Absolute paths and .. segments are rejected (with a warning) and the default is used instead. |
Known limitations
- Concurrent writes to the state file are last-writer-wins. A local mark
racing an external update (e.g. a
git pullthat changesfile-reviews.json) can drop entries from one side. - Multi-root workspaces store state in the first workspace folder only. Marks for files in other roots are tracked, but they are all persisted to the first folder's state file.
How reviewed-state and invalidation work
When you mark a file reviewed, the extension reads its bytes and computes a
Git blob hash — sha1("blob <byteLength>\0" + content), the exact value
git hash-object produces. That hash is stored alongside the file path:
type ReviewedEntry = {
relativePath: string; // workspace-relative, forward-slashed
contentHash: string; // git blob hash at mark time
markedAt: number; // epoch ms
};
These entries live in .vscode/file-reviews.json (sorted, so diffs stay small).
Because the fingerprint is a deterministic Git blob hash, a machine that pulls the
file computes staleness identically — a file reviewed on one machine shows green
on another if the content matches, amber if it changed.
The mark is re-checked (file re-hashed, compared) when:
- the file is saved in the editor,
- the file changes on disk by any tool —
git checkout, an external formatter, a pull, etc., - the extension activates (catches edits made while it was inactive),
- the state file changes externally (e.g. after a pull) — the whole set reloads,
- you run Refresh Reviewed Files.
If the recomputed hash differs (or the file is gone), the entry is kept but flagged stale → the tick goes amber. It only disappears when you explicitly Unmark it (or Clear All). Validation is targeted at the file that changed — the whole workspace is never re-hashed on every keystroke. Unsaved editor edits don't flip the tick, because the fingerprint reflects on-disk content; a save (or any disk write) is what re-checks it. Renames preserve the mark.
The staging workflow
The intent: you sometimes push work-in-progress to back it up or continue on another machine without having reviewed everything, and you want to keep track of what still needs review.
- Review & Stage (context menu) — marks the file reviewed at its current content and stages it in one action.
- Native Stage buttons still work as usual. When you use them, the extension
checks what just got staged; anything unreviewed or stale raises a warning
notification listing the files, with Mark Reviewed / List Reviewed
actions. Toggle this off with
scmReviewed.warnOnStagingUnreviewed.
So a staged-but-unreviewed file stays visibly un-ticked (and warned about), which survives the push: pull on another machine and the same files are still un-reviewed.
Running locally with F5 (development)
npm install- Open this folder in VS Code.
- Press F5 — launches the Extension Development Host (a second VS Code window with the extension loaded), with a background watch task compiling on save.
- Open a local Git repository with some changed files in that window.
- Right-click a changed file → Mark as Reviewed (or Review & Stage). Edit and save it → the tick turns amber. Stage an unreviewed file with the native button → you get the warning.
Logs: Output panel → File Reviewed Tracker channel.
Installing as a normal extension (local .vsix)
You do not need a publisher account, and after this you never need F5 again — it installs permanently like any extension.
npm install -g @vscode/vsce # one-time, run anywhere
npm run compile
vsce package # produces file-reviewed-tracker-<version>.vsix
code --install-extension file-reviewed-tracker-<version>.vsix
…or from the Extensions view → ... menu → Install from VSIX…. Re-run these
steps only when you change the code.
Tests
Pure helpers (path normalization, lookup-key casing, Git blob hashing) are unit-tested with the built-in Node test runner — no VS Code host required:
npm run test:pure
VS Code API limitations worked around
-
The native Stage buttons cannot be intercepted. The built-in Git extension owns the stage commands, and VS Code exposes no pre-stage hook or veto. So we cannot put a modal "in the way" of the Stage / Stage All buttons. The workaround is twofold: a Review & Stage menu action for the gated flow, and a reactive warning — the extension watches each repository's index via the Git API (
repository.state.onDidChange) and warns right after unreviewed files enter the staging area. -
No direct "SCM row" decoration API. VS Code does not expose an API to push a custom badge onto a specific row of another extension's SCM pane. The reliable cross-pane approach is a
FileDecorationProvider: it decorates a URI, and VS Code renders that decoration everywhere the URI appears — Explorer, SCM pane, and editor tabs. That is how a single tick shows up in both panes. -
Per-file menu visibility via the
inoperator. Awhenclause cannot read an arbitrary per-resource value owned by this extension, and we cannot setcontextValueon the Git extension's resource states. The extension publishes the reviewed/tracked path sets to context keys (scmReviewed.reviewedPaths,scmReviewed.trackedPaths) and the menus test e.g.resourcePath in scmReviewed.reviewedPaths. So Mark shows on not-currently-reviewed files (including stale ones, to allow re-review) and Unmark shows on any tracked file. Caveat: with a multi-selection the clause is evaluated against the file you right-click while the command acts on the whole selection. The handlers are idempotent regardless. -
Single primary repo for state. The state file lives in the first workspace folder's
.vscode/. In a multi-root workspace spanning several repos, only that folder's file is committed; cross-repo marks are tracked but stored in one place. -
Marking does not require an active editor. Files are hashed via
workspace.fs.readFile, so marking works on files that are not open.