Review a pull request by editing and running it, not just reading it. The whole PR lands in your working tree as one staged diff; your fixes are then extracted onto a clean branch automatically. Re-review only what changed.
And when an AI agent wrote the change, it can write the reading order too — a walkthrough committed next to the code saying which file to read first and why.
git review startpicks it up on its own and walks you through the diff in that order, instead of alphabetically.
Clients: VS Code extension · IntelliJ IDEA plugin
Reviewing in a web UI is fine for leaving comments, but poor for actually
running and editing the code. git review start puts the entire PR in your
working tree as staged, uncommitted changes: it creates a review/<branch>
branch whose working tree holds the PR tip, but whose HEAD sits at the
merge-base with your base branch. Because it is just your working tree, you open
the whole PR in any editor — read the diff, edit inline, run the tests — and when
you are done, git review finish pulls your edits back out onto a separate
review-fixes/<branch> branch (or onto the PR branch itself), keeping them
cleanly apart from the author's work. Re-review only the new commits after an
update with --delta.
All commands live under
git review <verb>—git review start,git review finish,git review status, and so on, the waygit bisectandgit stashgroup their verbs.
You asked an agent for a feature. It came back with fourteen changed files and a diff sorted alphabetically — the one order guaranteed to say nothing about the change. Reviewing that means reconstructing, file by file, reasoning you never saw in the first place.
The agent that made the change is the one party that does know that reasoning,
and git review walkthrough gives it somewhere to put
it. As part of the same task, right after writing the code, the agent runs:
git review walkthrough init # skeleton listing every changed file
# ...fills in the reading order and a why for each entry...
git review walkthrough build # validate, order, renumber
git add .review/walkthrough.md && git commit # ships with the PRThen you review it — nothing to enable, nothing to configure on your side:
git review start feature/rate-limitgit review start finds the walkthrough by itself: it prints the agent's
heads-up on what is delicate in this PR, then drops you on the first file with
the note on why it matters — the entries the agent flagged as essential are
labelled (key); git review next moves through
the rest of the order. The whole PR stays staged and editable the entire time, so
you fix what you find inline and git review finish hands your corrections back
on a separate branch.
To make it automatic, put the instruction where your agent will read it — its
CLAUDE.md, AGENTS.md, or your prompt template:
After making the change and committing it, run
git review walkthrough init, fill in the reading order and a one-line why for every entry, the## Heads-upsection with what is delicate in this PR, and a> keymarker on the few entries a reviewer must not skim, then rungit review walkthrough buildand commit.review/walkthrough.md.
The result is a plain committed Markdown file, so it also just reads on GitHub for anyone who never installs this. And you get the same benefit without the author on board: on a PR that carries no walkthrough, point your own agent at the diff and have it generate one just for your review — see Typical workflow.
Reviewing agent-written PRs is where the rest of the workflow pays off too: pull the whole change into your working tree, actually run it, and fix the code smells and subtle mistakes inline instead of writing comments about them.
Most tools let you see a PR. Two gaps this fills: acting on one — editing and running it like ordinary working-tree changes, then handing your fixes back without manual stashing or cherry-picking — and giving it a guided reading order, something neither git nor GitHub offers natively.
| View the PR | Curated order + why, per file | Edit & run as working tree | Auto-extract your fixes | Incremental re-review (--delta) |
Editor-agnostic | |
|---|---|---|---|---|---|---|
| git-review-workflow | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
gh pr checkout / glab |
❌ | ✅ | ❌ | ❌ | ✅ | |
| JetBrains Review Pull Request | ✅ | ❌ | ❌ | ❌ | ❌ | |
| VS Code GitHub PR extension | ✅ | ❌ | ❌ | ❌ | ❌ | |
| GitHub / GitLab web UI | ✅ | ❌ | ❌ | ❌ | ✅ |
None of the alternatives above give you an author-curated reading order —
which file to read first, and why — instead of an alphabetical file list or a
bare diff. The author (often an AI coding agent) writes it once, with
git review walkthrough init/build, and commits it alongside the PR; a
reviewer needs to do nothing special — git review start picks it up on its
own and drops them straight into that order, moving through it with
git review next/prev. See git review walkthrough
for the full author-and-reviewer flow. You don't even need the author or your
team on board to benefit from it — see Typical workflow
for how to generate your own, just for one review.
Because the PR is just staged changes, anything that reads a Git diff sees all of it — including AI coding agents like Claude Code or Codex that have no PR-review feature of their own. Point one at the staged diff and it can review or fix the whole PR in place.
And for the small stuff — a rename, a typo, a clearer variable name — fixing it yourself is faster and less bureaucratic than leaving a comment and waiting for a round-trip, especially when you are already looking at the PR in your editor. Because your edits are extracted automatically, the fix costs about the same as the comment would have. Or hand the staged diff to an agent and have it make the change for you.
If you mostly comment, your IDE's native PR panel is enough. If you review by editing and running the code — in any editor or agent — this is the gap it fills.
# 1. Install (needs Node.js; see Installation for Homebrew and a no-Node option)
npm install -g git-review-workflow
# 2. Tell it where PRs are integrated, once per repo
git config reviewworkflow.base develop
# 3. Stage a PR branch as a single diff, then open the repo in your IDE
git review start feature/login
# ...read and edit the staged diff in your editor, run tests...
git review finish # extract your edits onto review-fixes/feature/loginPrefer Homebrew, a native Windows (PowerShell) installer, or an install that does not need Node? See Installation. For the full flow — re-reviewing updates, walking a PR via a curated walkthrough or commit by commit, cleanup — see Typical workflow.
These commands plug into git as a single subcommand — you run them as
git review start, git review finish, and so on. The Quick start
above already covers the npm install; expand below for Homebrew, the native
Windows installer, or a no-Node option.
Installation methods (npm, Homebrew, Windows, one-line, PATH, tab completion)
Pick whichever method matches your setup. The package-manager options are the
easiest and set up your PATH for you.
If you have Node.js, this is the one-command install. It
puts git review on your PATH for you and works on Linux, macOS and Windows
(on Windows the commands still run under Git Bash):
npm install -g git-review-workflowUpdate with npm install -g git-review-workflow@latest; uninstall with
npm uninstall -g git-review-workflow. Tab completion is set up the same way as
the other non-Homebrew installs — see the note below.
brew tap EzeVillo/git-review-workflow https://github.com/EzeVillo/git-review-workflow
brew install EzeVillo/git-review-workflow/git-review-workflowTab completion is configured automatically. To update to the latest release:
brew upgrade git-review-workflow.
You still need Git for Windows, which provides the shell these commands run in. Open PowerShell and run:
irm https://raw.githubusercontent.com/EzeVillo/git-review-workflow/main/web-install.ps1 | iexThis installs the command into ~\.local\bin and adds that folder to your user
PATH automatically. Open a new terminal after it finishes. Re-run to update; to
uninstall:
irm https://raw.githubusercontent.com/EzeVillo/git-review-workflow/main/web-uninstall.ps1 | iex(If you have Node, npm install -g git-review-workflow works on Windows too —
the commands still run under Git Bash either way.)
No package manager? This downloads the command and installs it into
~/.local/bin — you don't need to clone the project first:
curl -fsSL https://raw.githubusercontent.com/EzeVillo/git-review-workflow/main/web-install.sh | shRe-run to update (always installs the latest release). To uninstall (pass the
same PREFIX if you overrode it):
curl -fsSL https://raw.githubusercontent.com/EzeVillo/git-review-workflow/main/web-uninstall.sh | shFrom a downloaded copy
If you cloned or downloaded the project, open its folder in a terminal and run:
./install.shThis installs the git review dispatcher into ~/.local/bin (change the
location with PREFIX=/usr/local/bin ./install.sh). The verbs travel beside it
as private helpers, not as separate commands on your PATH. Undo it any time
with ./uninstall.sh. To update, just git pull inside the repo — the symlink
picks up changes automatically.
"command not found" — adding ~/.local/bin to your PATH
Your PATH is the list of folders your terminal searches when you type a
command. Homebrew, npm and the PowerShell installer add their folder for you. The
one-line and manual installs use ~/.local/bin, which is already on the PATH
on most systems. If it isn't, the installer prints a note — add it once by
pasting one line into your shell's config file:
| If your terminal uses… | Add this line to the file… | The line to add |
|---|---|---|
| bash | ~/.bashrc |
export PATH="$HOME/.local/bin:$PATH" |
| zsh (default on recent macOS) | ~/.zshrc |
export PATH="$HOME/.local/bin:$PATH" |
| fish | (no file — just run this once) | fish_add_path ~/.local/bin |
Not sure which one you use? Run echo $0. After editing the file, open a new
terminal (or source the file). Run git review -h to confirm.
Tab completion (manual installs)
Homebrew sets this up for you. Otherwise, tell your shell to load the matching
file on start. Replace /path/to/git-review-workflow with where you downloaded
the project.
# bash — in ~/.bashrc
source /path/to/git-review-workflow/completions/git-review-workflow.bash
# zsh — in ~/.zshrc
source /path/to/git-review-workflow/completions/git-review-workflow.zsh
# fish — copy into fish's completions folder (no config line needed)
cp /path/to/git-review-workflow/completions/git-review-workflow.fish \
~/.config/fish/completions/Then open a new terminal. Typing git review and pressing Tab now offers
the verbs; git review start offers your branch names.
Git Bash on Windows — SSL error during install?
If you see schannel: next InitializeSecurityContext failed or a
revocation check message, your Git for Windows is using the Windows SSL
backend. Fix it once, then re-run the installer:
git config --global http.sslBackend opensslHow to read the syntax:
<x>is required,[x]is optional, anda | bmeans pick one, not both.
Every command is a verb under git review. Run git review -h for the list, or
git review <verb> -h for one verb's details.
| Command | What it does |
|---|---|
git review [-h | --version] |
List all verbs or print the installed version. |
git review start [<branch>] [<base> | --base <base> | --delta | --from <commit>] [--step | --no-walk | --keys] [--local | --offline] |
Fetch origin, then stage the PR diff on a new review/<branch> branch (omit <branch> to review the current branch; enters walk mode if the PR carries a walkthrough; --keys restricts walk to entries marked > key; --local reviews your local branch but still diffs against origin's base; --offline also skips fetching and uses your local base). |
git review compare <a> <b> [--step | --no-walk | --keys] |
Stage the diff between two commit-ish (tags, commits, branches) read-only, to read or walk it. git review finish refuses — there is nothing to write back. |
git review walkthrough (init [--base <base>] [--force] | build [--check]) |
Author a reading walkthrough for the current branch's PR — a curated order of the changed files with a note on each, committed as .review/walkthrough.md. |
git review next / git review prev |
Move a --step or walkthrough review to the next / previous entry. |
git review status [--porcelain | --why <path>] |
Show the state of the review on the current branch (--porcelain for machine-readable output, including a finish record when a closure is mid-conflict; --why <path> for a walkthrough entry's explanation). |
git review list [--porcelain] |
List every review in progress and every saved one (current branch marked *; --porcelain also reports unresolved finishes as pending or conflict). |
git review save |
Pause the current review as review-saved/<branch> and return to where you started. |
git review continue [branch] |
Resume a review saved with git review save. |
git review finish [--onto-source] [--resume | --abort [--force]] |
From a review/* branch, extract your edits onto review-fixes/<branch> (or the PR branch); --abort undoes the last finish. |
git review preview [--stat] |
Show the edits you have made so far — the diff finish would extract — without committing or switching branch. |
git review abort |
Cancel the current review and return to where you started. |
git review clean [--keep-fixes] [branch] |
Delete the review/* (and by default review-fixes/*) branches for <branch>, or all of them; --keep-fixes leaves review-fixes/* alone. |
git review forget --delta (<branch> | --all | --stale [--dry-run]) |
Discard the --delta marker for one branch, all of them, or only stale ones. |
git review forget --saved (<branch> | --all) [--dry-run] |
Discard a review saved with git review save. |
git review config [<key> [<value>]] [--unset <key>] [--porcelain [<branch>]] |
Read or write the product's config (base, remote); --porcelain also lists candidate branches to review. |
git review start
Has two independent axes — range (where the review starts) and layout
(--step or not), which compose freely.
<branch>— the branch to review. Omit it to review the branch you currently have checked out — git's own default (likepush,status,log). It only resolves the name; the mode is still chosen by flags, so pair the omitted branch with--localto review your local work. Without--localit reviewsorigin/<branch>— if that differs from your checked-out branch you get a note, since you would be reviewing a different snapshot than you have. With no branch, fails on a detached HEAD or while on areview/*branch.base— commit-ish to diff against: a branch, a tag, or a commit. Taken fromreviewworkflow.base(see below); a positional argument overrides it. Required for a full review — there is no built-in default, so a full review with no base set fails and asks you to configure one. Not used with--deltaor--from, which carry their own starting point — passing an explicit base alongside them is an error (a base from config is simply ignored).--base <base>— the base to diff against, as a flag. Use it to pass a base while letting<branch>default to the current branch — e.g.git review start --base developreviews the branch you are on againstdevelop(the lone positional is always taken as<branch>, so the flag is how you reach the base without naming the branch). Cannot be combined with a positional base.--delta— review only the commits added since your last review of this branch, instead of the whole PR. Perfect for re-reviewing an updated PR. A completed review keeps its recorded tip throughgit review clean; an abandoned start (cleaned or aborted without finishing) rolls the marker back so--deltanever skips commits you never reviewed. Discard the marker explicitly withgit review forget --delta.--from <commit>— review only the commits after<commit>. Handy when there is no recorded review to delta from, or to pick an exact starting point. Mutually exclusive with--delta.--step— review the range one commit at a time (combine with--deltaor--fromto walk just those commits). You start on the first commit after the merge-base; the command prints its author message. Edit files, then rungit review nextto bank your edits and move to the next commit with a clean tree. When the commits run out, rungit review finishand all your banked edits are replayed onto the PR tip — exactly as in a whole-PR review.- Walk mode (automatic). If the PR carries a walkthrough
(
.review/walkthrough.md, written by the author withgit review walkthrough),git review startenters walk mode: the very same staged, editable whole-PR review, plus a curated reading cursor over it. It prints the author's heads-up — what is delicate in this PR, read once before the first file — then the first entry: a file and the author's note on why it matters, labelled(key)when it is one of the few the author flagged as essential. You move through the reading order withgit review next/git review prev. The cursor is only a reading position: it never stages, resets or hides anything, so you edit andgit review finishexactly as in a whole review. The entries are filtered to the review's actual range, so a walkthrough that no longer matches (e.g. an old one under--delta) simply degrades — a broken or stale walkthrough never fails a review; at worst it falls back to a plain whole review with a note. A file that changes in the range but has no entry of its own — a stale walkthrough is the common case — is not left out either: it is appended to the end of the reading order, marked(uncovered)instead of(key), so a review never reachesgit review finishwith PR files you never saw — including the committed walkthrough itself, which joins that same uncovered tail: a walkthrough can never annotate itself, but it is content the PR adds like any other file, so it is never the one file no review shows you. --no-walk— ignore any walkthrough and review the whole diff plainly.--stepalso takes precedence over walk (they are two spellings of the same layout axis), so--stepwins with no error — it just prints a note that the PR's walkthrough is being ignored (silenced by also passing--no-walk).--keys— walk mode restricted to entries marked> key. The reading cursor,next/prev, and status list only those essential files (in walkthrough order). Requires a walkthrough with at least one key in range; cannot be combined with--stepor--no-walk. The full PR is still staged — only the guided path is shorter. A focused first pass, not a claim that the rest of the PR does not matter.--local— review your local<branch>, including unpushed commits, instead oforigin's copy. The base is a different concern — it's the shared merge target — so it is still fetched and diffed fromorigin's copy even under--local; only your local branch changes. Lets you review your own work before pushing. It keeps its own--deltamarker, separate from the remote one, so local and remote reviews of the same branch name never overwrite each other's progress.--offline— like--local, but also skips fetching entirely and resolves the base from your local branches too, for the rare case where you have no network access at all. Implies--local.- Always updates from
originfirst and fails if it cannot (unless--offline). Without--local/--offlinethe review is built fromorigin/<branch>, never a stale local copy. If a local branch of the same name points somewhere else, it prints a note: the review reflects the remote, not your checkout, and a latergit review finish --onto-sourcewould refuse until your local branch matches. - Refuses to run if you have local changes (tracked or untracked, non-ignored) — start from a clean branch.
- Merges of the base branch are excluded. If the author merged the base
(e.g.
develop) into the PR, that merged-in content is left out of the review in every mode, so you only see the author's own changes. --ends option parsing, the usual git convention: everything after it is treated as a positional argument, so a branch whose name starts with-can still be reviewed (e.g.git review start -- --weird develop).
git review compare
Stage the diff between two commit-ish — two tags, two commits, two branches — as
one read-only review, so you can read it inline or walk it commit by commit with
the same UX as a real review, without git diff | less.
git review compare v1.0 v2.0 # stage the diff between two releases
git review compare v1.0 v2.0 --step # ...and walk it commit by commit- It diffs
<a>..<b>:<a>is the lower bound (where the review starts),<b>the tip whose content fills the working tree. Both are resolved to commits, so tags and raw SHAs work, not only branch names. - It is read-only by design. The whole edit→finish half of the workflow needs
a writable branch to write back to, and a tag or a commit is not one — so
git review finishon a compare refuses explicitly ("this review is read-only, there is nothing to write back"). Usegit review abortto end it. --stepwalks it one commit at a time, exactly likegit review start --step, withgit review next/git review prev.- If
<b>'s tree carries a walkthrough,compareenters walk mode too, just likegit review start, and stays read-only.--no-walkopts out.
git review walkthrough
The one thing neither git nor GitHub offers: an author-written reading order
over a PR. As the author (often an AI coding agent), you curate the order in which
the changed files should be read and annotate each with why it matters; a
reviewer who runs git review start on the PR is then dropped into
walk mode and reads it in that order.
The walkthrough is a committed sidecar, .review/walkthrough.md — plain Markdown,
readable on GitHub, that merges with the PR. There are two subcommands:
git review walkthrough init # write a skeleton listing every changed file
# ...fill in the order and the whys...
git review walkthrough build # validate, order by your numbers, renumber 1..Ninitwrites a deterministic skeleton with every file changed vs the base (the same range a reviewer will see), each as## ?. <path>plus a<!-- why: -->placeholder, headed by a## Heads-upsection with its own placeholder. Refuses to overwrite an existing walkthrough without--force.--base <base>overridesreviewworkflow.base.- You (the author) do only the non-mechanical part: replace each
?with an order number and each placeholder with a short note. ## Heads-upis the one thing a reviewer reads before opening a file: the invariants this PR can break, the subtle or risky parts, what to be suspicious of.git review startprints it on entry. Delete the whole section if nothing in the PR is delicate — an empty section is worse than none.> keymarks the essential entries. Write it on a line of its own as the first line of the why on the few files that carry the change — the ones a reviewer must not skim — and leave every other entry unmarked; generated files, lockfiles and mechanical renames are exactly what stays unmarked. It takes no value: the why says the rest. Walk mode labels those entries(key)and counts them on entry. Reviewers can start withgit review start --keysto walk only those entries. The marker only works while it stays selective, sobuildnotes it when every entry is marked (or when a long walkthrough marks none).buildvalidates the file, orders the entries by your numbers, renumbers them1..Nand rewrites it, preserving the heads-up.--checkvalidates without writing and exits non-zero on any problem — meant for CI. It fails if any?.,<!-- whyor<!-- heads-upplaceholder is left, if> keywas given a value, if a path appears twice, if an entry heading is not in the exact## <N>. <path>form, or on drift: the set of paths must match the PR's changed files exactly (excluding.review/).
Filling in the order and the whys is a great fit for an AI coding agent — point one at the diff and let it write the placeholders. That works on either side: the PR's author can have an agent draft the walkthrough alongside the change, and it may be even more useful on the reviewer's side — a human reviewer would need to already understand the PR to hand-curate a reading order for it, which defeats the purpose, whereas an agent that reads the whole diff can write that order before you've read a single file (see the solo-review case in Typical workflow).
The walkthrough is built from committed history (base..HEAD), not your
working tree: commit the PR changes before authoring it. init and build never
see uncommitted work — they refuse with a hint when nothing is committed, and warn
when you have uncommitted changes on the side.
The file format build produces and start reads:
# Walkthrough
## Heads-up
Sessions now expire; anything that cached a token is suspect.
## 1. src/auth/session.c
> key
Read this first: it defines the token shape everything else depends on.
## 2. src/auth/login.c
Then the login flow that consumes it — note the new error path.Each entry is a ## <N>. <path> line (the path exactly as git reports it, written
plainly — a name with non-ASCII characters goes in as-is, never C-escaped)
followed by its free-text why, up to the next entry, optionally led by the
reserved > key marker. Everything above the first entry is the preamble
(the ## Heads-up section); the parser ignores it and build preserves it
verbatim, minus HTML comments. Granularity is per file in v1.
git review next / git review prev
Move a --step or walkthrough review forward or backward. In --step mode each
move banks the current commit's edits and restores any edits banked on the commit
you move to, so you can walk back and forth without losing work. In walk mode they
just move the reading cursor — your edits live in the working tree the whole time
and are never touched.
git review status
Shows the current review: source PR, mode, and — in --step mode — which commit
you are on ([k/N]) and which steps have banked edits. In walk mode it shows the
reading cursor: walk [k/N] on <path>. In whole mode (no walkthrough — the
default) it lists the files the range touches, numbered, with no cursor; an
empty range says so explicitly instead of printing nothing.
--porcelain— machine-readable output for scripts and editor integrations: stable, tab-separated lines (see below). Read-only, exactly like the human output — it never mutates config, refs or the working tree.--why <path>— print only the walkthrough's explanatory text for<path>, nothing else on the stream: no label, no other data. Walk mode only.
Exit codes — not just under --porcelain: the same codes come from every
verb that detects the situation (status, list, abort, finish, preview,
save, and next/prev for 3), so a script never has to special-case which
command it ran:
| Code | Meaning |
|---|---|
0 |
success |
1 |
error — missing or corrupt review metadata, invalid usage, not a git repository |
2 |
HEAD is not on a review branch (the common, unremarkable case) |
3 |
the walkthrough cursor is out of range because HEAD moved off the review's base — recover with git reset --soft |
--porcelain format — one line per record, fields separated by a tab, the
record's type first and a path or id (when it has one) immediately after that —
never last, so new fields are always appended at the end of the line. A consumer
should ignore any trailing field it does not recognize on a line type it knows,
and any line whose type it does not recognize: the format only ever grows.
state <branch> <source> <tip> <mode> <walkthrough>[ <position> <total> <recorded> <current>[ <essential>]]
finish conflict <onto>
entry <position> <id>[ <essential> <annotated>|<banked>]
subject <position> <subject>
author <position> <author>
base <base>
state— exactly one line, always first.modeiswhole|step|walk.walkthroughisnone|applied|degraded(alwaysnonein step mode, since the field is positional there).position/total/recorded/currentappear only with a cursor (step/walkmode);currentis a short commit SHA in step mode, a path in walk mode.totalis the live count, derived right now;recordedis what was recorded when the review started — they differ once the base has drifted, even while the cursor is still in range.essential(1/0) appears only in walk mode.finish— only while agit review finishis stopped mid-conflict on this review branch (stateis alwaysconflicthere; a completed finish already movedHEADoffreview/*, sostatusnever sees it — uselistfor that).ontois1if the finish used--onto-source,0otherwise. The whole record is omitted when no closure is in progress. Consumers must not offer sequence navigation while this record is present.entry— zero or more. Instep/walk, one per position in the reading order (walk paths or step commits, the same ordernext/prevmove through), including a walk entry the walkthrough does not annotate — appended to the end of the order rather than omitted. In whole mode, one per file the range touches — a listing, not a sequence:statestill carries noposition/total/recorded/currentin whole. In walk mode the trailing fields areessential(1/0) andannotated(1/0,0for a file the walkthrough has no entry for — the committed walkthrough itself is always in this group, since it can never annotate itself); in step mode it is justbanked(1/0, has a banked edit underrefs/review-edits/); in whole mode neither group is present, so the record ends at the path. An empty range produces zeroentryrecords and still exits0.subjectandauthor— step mode only, one of each per position, carrying the commit's subject line and its author asName <email>. Pair them withentrybyposition, never by order of appearance. A subject can be empty (a commit whose message has no first line); the record is still emitted, with an empty field, so "no subject" stays distinguishable from "this git-review does not report subjects".file— step mode only: zero or more lines for the current commit (the one under the cursor /state.current), not every commit in the range. Each line isfile<TAB>position<TAB>pathwith a 1-based position within that commit and a path under the same byte rules as other path fields. Clients use this list to draw the file inventory for the step; opening a single-file diff stays on the host (git / the editor), not in porcelain. A commit that touches no files emits zerofilelines. Walk and whole emit none (entryalready lists paths in whole).state.totalstill counts onlyentrylines (commits).base— whole mode only, and only when the review has a base recorded: the ref its range was built against. A single record with no position — the base belongs to the review, not to an entry. With no base recorded the line is omitted entirely, never emitted blank.
Free-text fields. subject, author and base carry text a person wrote,
not text git produced, and unlike a path it can contain a literal tab. So the
rule for these records — and for any future record with free text — is: the free
text is always the last field of its record, and there is at most one per
record. It is emitted byte for byte, unescaped and unquoted. Read it as
"everything after the Nth tab, to end of line", not as "the Nth field" — a
split on tab would silently truncate a subject that contains one. These records
accept no new trailing fields for that same reason; anything new goes in a record
of its own. A newline can never appear in them.
A path is always emitted exactly as git diff --name-only (with
core.quotePath=false) renders it: literal, unescaped bytes for spaces and
non-ASCII characters; git's own quoting, left untouched, for the rare path
holding a " or a \. Field boundaries are always the tab, never whitespace —
a git path never contains a literal tab.
git review list
Shows every review/* branch in progress at once (with its source PR, mode and
[k/N] position for --step and walk reviews). Reviews paused with
git review save are listed too, under saved. The branch you are currently on
is marked with a *.
-
--porcelain— machine-readable inventory, the same tab-separated format asstatus --porcelain:branch <name> <saved> <current> <orphan>[ <mode>[ <position> <total>]] finish <branch> pending|conflict <onto>saved,currentandorphanare1/0(orphanmeans the branch has no review metadata — hand-made, or left by a command that died early). Whenorphanis1there is nomode/position/totalto report.positionandtotalare the values recorded when the review started, not re-derived — for the live, derived numbers of one particular review, runstatus --porcelainfrom it. Either field is omitted, never filled with the?the human output uses, if its config key happens to be missing. Exit0even on an empty inventory (no reviews is not an error);1only if run outside a git repository.A
finishline is emitted for eachreview/<x>with an unresolved closure:pendingafter a completed finish still waiting for confirm/abort (edits onreview-fixes/<x>or the PR branch;HEADmay already have leftreview/*), andconflictwhen a finish stopped mid-replay.ontois1if that finish used--onto-source,0otherwise. Pair it with the matchingbranchrow by name. Reviews with no open closure emit nofinishrecord.
git review save / git review continue
git review save lets you put a review aside and pick it up later. It turns the
current review/<branch> into review-saved/<branch> and returns you to the
branch you started from, carrying everything needed to resume exactly where you
left off:
- In whole-PR mode, the staged PR diff and your uncommitted edits.
- In walk mode, the same, plus the reading cursor —
git review continuedrops you back on the exact entry you were on. - In
--stepmode, the commit you are on, its edits, and every edit you have banked on the other commits. The banked-edit refs are moved out ofrefs/review-edits/(whichgit review cleanprunes) intorefs/review-saved-edits/, so agit review cleannever touches a saved review.
git review continue turns review-saved/<branch> back into the active
review/<branch> and restores that exact state — in --step mode it drops you
back on the same commit, with git review next / git review prev working as
before. With no argument it resumes the only saved review, or lists them if there
is more than one; name a branch to pick a specific one.
Starting a fresh git review start on a branch that already has a saved review
is refused, so you do not silently lose the paused one — resume it or discard it
with git review forget --saved first.
git review config
Read or write git-review-workflow's own configuration — the base a full review
compares against, and the remote a review is fetched from. Mirrors git config
on purpose: a key alone reads, a key plus a value writes. Valid in any git
repository, with or without an active review (there is no exit 2).
git review config # effective config, human-readable
git review config <key> # one key (base | remote)
git review config <key> <value> # set <key>
git review config --unset <key> # remove <key>
git review config --porcelain [<branch>] # machine-readable + candidate branches
-
base— the commit-ish a full review diffs against. No product default: a full review without it fails and asks you to set one. Same value asgit config reviewworkflow.base(the raw key stays an implementation detail). -
remote— where reviews are fetched from (defaultorigin). -
--porcelain— tab-separated records for scripts and the editor panel:config <key> <value> candidate <name> remote|local <current> delta <branch> <tip> remote|localA key with no effective value omits its
configline entirely (sobaseis absent until set;remotealways appears).candidatelists every branch eligible to start a review;currentis1/0. Pass an optional<branch>to also emitdeltarows when that branch has a prior--deltamarker — zero, one or two: remote and local reviews keep separate markers, so each present axis gets its own row (originisremoteorlocal). -
--ends option parsing, so a value that starts with-(a legal branch name) is not taken as a flag:git review config base -- -foo.
git review finish
- Default — create
review-fixes/<branch>on top of the PR tip with your edits staged, so you can review and commit them yourself. If you made no edits, the branch is still created (at the tip, nothing staged) so the session closes the same way —git review finish --abortundoes it, orgit review cleandrops the leftover. --onto-source— stage your edits on the PR branch itself instead, so you can review and commit them yourself there. With no edits, you still land on the PR branch at the tip (and the same undo point is kept).- Either way the result stays local — review it and push it yourself when ready.
--resume— in--stepmode, if banked edits overlap the PR tip, the replay leaves conflict markers and stops. Resolve them in the working tree, then rungit review finish --resume(with the same flags) to continue.--abort— undo the last finish and drop you back onreview/<branch>exactly where you were editing, the same waygit merge --abortbacks out a merge. It refuses if you have changed the finish branch since, so you do not lose work; add--forceto discard those changes and abort anyway.- Refuses on a read-only
git review compare— there is no writable branch to write your edits back to.
git review preview
Shows the edits you have made so far — the same diff git review finish would
extract, your review edits on top of the PR tip — but it never commits, never
switches branch and never touches your working tree or index, so you go straight
back to editing where you left off. Think of it as "what would finish give me
right now?".
--stat— show a diffstat summary instead of the full diff.- In
--stepmode it replays the current commit's edits plus every banked edit onto the tip, exactly likefinish. An edit that genuinely conflicts with the tip is the one case that differs: a read-only preview cannot leave you conflict markers, so it omits that edit and prints a note pointing you atfinish.
git review abort
Cancels the current review in one step: it returns you to the branch you started
from, then deletes the review/<branch> branch and its banked edits. Because the
review was cancelled (not completed), it rolls the --delta marker back to your
last actual review, so a later --delta does not skip commits you never
reviewed.
git review clean
- With no
<branch>, deletes every matching leftover (review/*and, by default,review-fixes/*). --keep-fixes— delete onlyreview/*(the finish undo / active session leftover) and leavereview-fixes/*alone. Useful after a successfulfinishwhen you want to drop the undo point but keep your staged edits.- Never deletes the branch you are currently on.
- Also drops any banked commit-by-commit edit refs and finish undo records
(including a mid-conflict
reviewresumeflag), even when no review branches remain. - Rolls back the
--deltamarker when deleting an incompletereview/*(same asgit review abort). A finish that completed keeps the marker. Clear markers explicitly withgit review forget --delta. - Leaves saved reviews (
review-saved/*) untouched — discard one withgit review forget --saved.
git review forget --delta
Discards the recorded last-reviewed tip that --delta relies on. Completed
reviews keep that marker through git review clean; use this when you want to
forget it yourself.
<branch>— forget the marker(s) for one source branch, both the remote one and the--localone if present.--all— forget every recorded marker (leavesreviewworkflow.basealone).--stale— fetch and pruneorigin, then forget only the markers whose branch no longer exists: remote markers whoseorigin/<branch>is gone (e.g. PRs that were merged and deleted), and--localmarkers whose local<branch>is gone. Aborts without removing anything if the fetch fails.--dry-run— with--stale, list what would be forgotten without doing it. Rejected with the other modes, where the target is already explicit.
git review forget --saved
Discards a review put aside with git review save: deletes
review-saved/<branch>, its banked edits and its metadata. Because a saved review
was paused (not completed), it also rolls the --delta marker back to your last
actual review, the same way git review abort does.
<branch>— discard the saved review for one source branch.--all— discard every saved review.--dry-run— list what would be discarded without discarding it.
The base branch is where PRs are integrated (develop, main, master, …) and
varies per team, so there is no default — set it once per repository, as shown
in Quick start:
git config reviewworkflow.base developResolution order, and configuring the remote
Resolution order: positional base argument (or --base <base>) →
reviewworkflow.base. If neither is set, a full review fails and asks you to
configure one. The base is any commit-ish — a branch, a tag (v1.0) or a
commit — not only a branch name.
By default the commands fetch and push against origin. If you review a
repository you do not own (an upstream, with your origin as a fork, say),
point the workflow at that remote:
git config reviewworkflow.remote upstreamIt affects git review start and git review forget --delta --stale. An
--offline review ignores the remote entirely; --local still uses it to
resolve the base.
Both reviewworkflow.base and reviewworkflow.remote are plain git config
keys, so they are stored per repository (in each repo's .git/config). You
don't manage profiles or a shared config file — every repository you work in
keeps its own base and remote independently, and they never leak into one
another:
# repo A: PRs land on main, fetched from origin (the default)
cd ~/project-a && git config reviewworkflow.base main
# repo B: PRs land on develop, reviewed from an upstream you don't own
cd ~/project-b
git config reviewworkflow.base develop
git config reviewworkflow.remote upstreamThe same applies to the --delta markers — they live in each repo's config too.
If you want a fallback that applies to all your repos, set it globally
(git config --global reviewworkflow.base main); a per-repo value overrides it,
and a positional base argument overrides both.
git config reviewworkflow.base develop # once per repo
# Author side: ship a reading walkthrough with the PR (typically written by
# an AI agent as the author), curating the order the files should be read in
# and a why for each:
git review walkthrough init # skeleton of every changed file
# ...fill in the order, a why for each, the heads-up and the > key markers...
git review walkthrough build # order, renumber and validate
git add .review/walkthrough.md && git commit # ships with the PR
# Reviewer side: nothing special to run — a PR that carries a walkthrough is
# picked up automatically:
git review start feature/login # heads-up + entry 1; walk mode kicks in
# ...read the first entry and its why, edit inline if you want, run tests...
git review next # move to the next entry
git review next # ...through the rest of the order...
git review finish # extract your edits to review-fixes/feature/login
git diff --cached && git commit -m "address review comments"
git review clean feature/login # tidy up
# Re-review after the author pushes more commits:
git review start feature/login --delta # only the new commits
git review start feature/login --delta --step # ...and walk them one by one
# Or walk the PR commit by commit from the start:
git review start feature/login --step # start on the first commit
# ...edit, then...
git review next # bank edits, move to the next commit
git review next # ...until "no more commits"
git review finish # replay all your edits onto the tip
# Pick an explicit starting commit:
git review start feature/login --from a1b2c3d
# Review the branch you are already on (omit the name):
git switch feature/login && git review start # vs the configured base
git review start --base develop # ...or against an explicit base
# Compare against a tag instead of a branch:
git review start feature/login v1.0
# Compare two releases read-only:
git review compare v1.0 v2.0
# Review your own local branch before pushing, still against origin's base:
git review start feature/login --local
# Same, but with no network access at all:
git review start feature/login --offlineNo walkthrough on the PR? Generate your own, just for this review
This is a good place to hand the "fill in the order and the whys" step to an AI coding agent rather than doing it by hand: you have not read the PR yet, so manually curating a reading order for it is circular — an agent that reads the whole diff can write that order for you before you look at a single file.
# No team buy-in needed: generate your own walkthrough on any PR you're
# reviewing, use it, then throw it away:
git fetch origin feature/login:pr-scratch # grab the PR under a scratch name
git switch pr-scratch
git review walkthrough init && git review walkthrough build
# ...fill in the order and a why for each (or point an agent at the diff)...
git add .review/walkthrough.md && git commit # local only — never push it
git review start pr-scratch --local # walks it, same as above
# ...read, edit, finish or abort as usual...
git branch -D pr-scratch # drop it, walkthrough included- Git 2.23+ (uses
git switch). Git 2.38+ is recommended: excluding base content that was merged into the PR usesgit merge-tree --write-tree, and on older git that one step is skipped (the merged base content would then show in--delta/--from). - A remote named
origin(or whatever you set withreviewworkflow.remote). - A POSIX shell. On Linux and macOS this is the default. On Windows the commands
run under Git Bash or WSL, not in
cmd.exeor PowerShell.
Bug reports, fixes and ideas are welcome. See CONTRIBUTING.md for how to run the tests and the release process.
MIT © EzeVillo
