{"id":45696474,"url":"https://github.com/thutt/diff-review","last_synced_at":"2026-02-24T20:48:00.427Z","repository":{"id":312806991,"uuid":"1047209258","full_name":"thutt/diff-review","owner":"thutt","description":"Side-by-side review of a Git repo's untracked, unstaged, staged \u0026 commited code using various tools.","archived":false,"fork":false,"pushed_at":"2026-02-02T05:16:02.000Z","size":1263,"stargazers_count":0,"open_issues_count":3,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-02T09:53:34.320Z","etag":null,"topics":["code-review","diff-view","diff-viewer","meld","multi-scm","side-by-side","tkdiff"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thutt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-29T23:42:38.000Z","updated_at":"2026-01-24T04:24:17.000Z","dependencies_parsed_at":"2026-02-02T02:02:43.106Z","dependency_job_id":null,"html_url":"https://github.com/thutt/diff-review","commit_stats":null,"previous_names":["thutt/diff-review"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/thutt/diff-review","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thutt%2Fdiff-review","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thutt%2Fdiff-review/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thutt%2Fdiff-review/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thutt%2Fdiff-review/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thutt","download_url":"https://codeload.github.com/thutt/diff-review/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thutt%2Fdiff-review/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29799356,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-24T19:56:48.334Z","status":"ssl_error","status_checked_at":"2026-02-24T19:55:43.372Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-review","diff-view","diff-viewer","meld","multi-scm","side-by-side","tkdiff"],"created_at":"2026-02-24T20:47:59.809Z","updated_at":"2026-02-24T20:48:00.410Z","avatar_url":"https://github.com/thutt.png","language":"Python","readme":"# diff-review\n\n**diff-review** is an open-source **pre-commit, SCM-agnostic, code\nreview tool**. Unlike traditional pre-merge review systems (Gerrit,\nGitHub, Review Board) that require changes to be committed and pushed\nto a central server, diff-review lets you review **uncommitted, local\nchanges** side-by-side before they ever leave your machine. It also\nsupports reviewing committed changes, when needed, giving you a\ncomplete local review workflow.\n\n---\n\n## Why diff-review exists\n\nTraditional pre-merge review tools only operate after changes have\nbeen committed and pushed to a central repository. This leaves a\n**blind spot** in the development workflow: the code you are actively\nwriting, experimenting with, or iterating on cannot be reviewed until\nit is committed.\n\n**diff-review fills this pre-commit chasm** by enabling developers to:\n\n- Self-review code during development, catching mistakes before commits.\n\n- Share reviews with colleagues **without pushing code**, via URL,\n  shared filesystem, or other mechanisms.\n\n- Conduct proof-of-concept (POC) reviews and feedback sessions without\n  cluttering the central repository with intermediate commits.\n\nBy supporting both uncommitted and committed changes, diff-review\nfunctions as a **local solo review tool**, a **collaborative\npre-commit review platform**, and a bridge between experimentation and\nformal pre-merge reviews.\n\nMoreover, generating diffs for historical changes requires search\ncapabilities (content-based history search, offline traversal) that\nonline review systems do not provide.  With diff-review, once the SHA\nis discovered, generate the diffs and view them using this tool; no\nneed to fumble around with a Web-based UI to construct the URL to view\nthe diff.\n\n\n## Key Features\n\n| Feature                         | Pre-commit (diff-review) | Pre-merge (Gerrit, GitHub, Review Board)    |\n|---------------------------------|--------------------------|---------------------------------------------|\n| Review uncommitted changes      | Yes                      | No                                          |\n| Review committed changes        | Yes                      | Only pre-merge, or already in review system |\n| Review whole-file history       | Yes                      | No                                          |\n| Share review without committing | Yes                      | Via patches                                 |\n| Solo / self-review              | Yes                      | Via uploaded, unpublished, commits          |\n| Take note on commit message     | Yes                      | No                                          |\n| Over-length line marker         | Yes                      | No                                          |\n| Requires central server?        | No                       | Yes                                         |\n| Supported comment editors       | PyQt, emacs, vim         | Web editor                                  |\n\n**Terminology**:\n\n- **Pre-commit**: Review of changes that have not been pushed to any server (diff-review).\n\n- **Pre-merge**: Review of changes that have been committed to a topic\n    branch and pushed to a central server (traditional tools).\n\n---\n\n# Software Prerequisites\n\n## \u003ccode\u003epython3\u003c/code\u003e\n\n  An executable named \u003ccode\u003epython3\u003c/code\u003e must be installed and on ${PATH}.\n\n## \u003ccode\u003epyqt6\u003c/code\u003e\n\nThis Python module must be installed to be able to generate the\nTcl/Tk-based menu used for viewing the generated diffs:\n\nIf this module is not installed, the \u003ccode\u003eview-review\u003c/code\u003e will stop\nwith an error indicating such.\n\nOn Ubuntu, this can be satisfied with:\n\n    sudo apt install python3-pyqt6\n\n## \u003ccode\u003erequests\u003c/code\u003e\n\nTo use the '--url' option of \u003ccode\u003evrt\u003c/code\u003e and fetch diffs from a\nURL, you must have the \u003ccode\u003erequests\u003c/code\u003e module installed.\n\nOn MacOS, and Windows \u003ccode\u003ecmd.exe\u003c/code\u003e, this can be satisfied with:\n\n    pip3 install requests\n\n\n## \u003ccode\u003ekeyring\u003c/code\u003e\n\nThe Python keyring module is an interface to the host OS key ring, and\nits use facilitates only having to enter your credentials for\nURL-based diff viewing once.\n\nIt can be installed with pip, on MacOS and Windows, and some Linux\ndistributions:\n\n    pip3 install keyring\n\nOn Ubuntu, it must be installed with:\n\n    sudo apt install python3-keyring\n\nIf it is installed, and you prefer to not use this, you can add\n'--no-keyring' to the 'vrt' invocation.  However, if keyring cannot be\nimported, the software will also transparently not use it.\n\n## \u003ccode\u003epyte\u003c/code\u003e\n\nThe \u003ccode\u003epyte\u003c/code\u003e module is a terminal emulator that is compatible\nwith PyQt6, and it is well-written enough to support running both\n\u003ccode\u003eemacs\u003c/code\u003e and \u003ccode\u003evim\u003c/code\u003e.\n\nIf \u003ccode\u003epyte\u003c/code\u003e is not installed, you cannot use\n\u003ccode\u003eemacs\u003c/code\u003e or \u003ccode\u003evim\u003c/code\u003e, but note taking is still\npossible with the built-in PyQt6 editor.\n\nIf you are a user of either one of these editors, you can now use it\nas the editor for writing review notes from within vrt, but you must\nfirst have pyte installed.\n\nOn Ubuntu, it must be installed with:\n\n    sudo apt install python3-pyte\n\nOn MacOS, the following is sufficient:\n\n    pip3 install pyte\n\nTo use emacs:\n\n    vrt --note-editor emacs --note-editor-theme light\n\nEmacs must be installed and on ${PATH}.\n\n\nTo use vim:\n\n    vrt --note-editor vim --note-editor-theme light\n\nVim must be installed and on ${PATH}.\n\nThe \u003ccode\u003e--help\u003c/code\u003e documentation will show the valid values for\n\u003ccode\u003e--note-editor-theme\u003c/code\u003e.\n\n\n# Supported Operating Systems\n\n - Linux\n - MacOS\n - Windows\n\n# Tools\n\n##  \u003ccode\u003eview-review-tabs\u003c/code\u003e (\u003ccode\u003evrt\u003c/code\u003e)\n\nThis tool shows a single window, with the list of files contained in\nthe change -- including the commit message, if one is present -- in\nthe sidebar.  Clicking on an element in the sidebar loads it into a\ntab in the view area.\n\nThis tool only provides viewing diffs with the built-in diff engine,\nbut the entire UI surrounding the diffs exposes many capabilities that\ngive a better holistic approach to reviewing code.\n\n\n## \u003ccode\u003eview-review\u003c/code\u003e (\u003ccode\u003evr\u003c/code\u003e)\n\nThis, older, tool shows a menu of all the files in the change.\nClicking on an element in the list will open the base and modified\nfiles in a separate window using the selected diff viewer.\n\nUltimately, the Claude-QT engine will be removed from this diff\nmanager, as all of its functionality is now subsumed by\n\u003ccode\u003eview-review-tabs\u003c/code\u003e.\n\n### Supported Viewers\n\nThis system currently supports the following side-by-side diff viewers,\nselectable from the \u003ccode\u003eViewer\u003c/code\u003e menu.\n\n- Claude-QT (Claude-generated, experimental, pyqt6)\n- Emacs\n- Meld\n- TkDiff\n- Vim\n\nIf any of Emacs, Meld, TkDiff or Vim cannot be found in commonly-used\ninstall paths for that program, it will not be included in the\n\u003ccode\u003eViewer\u003c/code\u003e menu.\n\n\n# Description / Terminology\n\n\nChange is omnipresent in the software industry.  To help you manage\nchanges to source, this tool enables viewing of uncommitted and\ncommitted changes in a Git repository.\n\nBefore going further, let us take a moment to understand the\nterminology used herein to describe the constituent parts of a change.\nEach file contained in a change always has two components:\n\n\n1. **Base file**\n\n    The base file refers to the original file, before modifications\n    have been made.  In most cases, the base file comes from the SCM,\n    but in some cases, such as an \u003ccode\u003eadd\u003c/code\u003e, the base file does\n    not exist in the SCM.  When the base file does not exist in the\n    SCM, and empty file is used in its stead.\n\n\n2. **Modified file**\n\n   The modified file, obviously, refers to the after-change file.\n\n   For uncommitted changes, it usually refers to the change-containing\n   on-disk file.  But, for modification such as \u003ccode\u003edelete\u003c/code\u003e,\n   an empty file will be used.\n\n   For committed changes, the modified file usually comes from the\n   SCM, but case where the modified file no longer exists, such as\n   \u003ccode\u003edelete\u003c/code\u003e, an empty file will be used in its place.\n\nThere are two modes in which this tool can operate: \u003cem\u003euncommitted\nchanges\u003c/em\u003e, and \u003cem\u003ecommitted changes\u003c/em\u003e.\n\n\n- **Uncommitted Changes**\n\n  If no revision information (-c) is provided,\n  \u003ccode\u003ediff-review\u003c/code\u003e will produce a review for for all\n  \u003ccode\u003euntracked\u003c/code\u003e, \u003ccode\u003eunstaged\u003c/code\u003e and\n  \u003ccode\u003estaged\u003c/code\u003e files.\n\n  An uncommitted change includes all modified files, as well as\n  \u003ccode\u003euntracked\u003c/code\u003e files, that are in the repository.  By\n  default, they will all be included in the generated review, but a\n  command line option can disable reviewing of untracked files.\n\n  For purposes of generating viewable diffs, there is no difference\n  between \u003ccode\u003eunstaged\u003c/code\u003e and \u003ccode\u003estaged\u003c/code\u003e; the tool uses\n  the current, on-disk, uncommitted content.\n\n- **Committed Changes**\n\n  If revision information (-c) is provided, \u003ccode\u003ediff-review\u003c/code\u003e\n  will produce a review for all the files changed in the specified\n  revision.\n\n# Usage\n\n1. Clone this repository to any location on the computer.  For\n   purposes of this text, we shall assume it has been placed at\n   \u003ccode\u003e~/diff-review\u003c/code\u003e.\n\n\n2. On POSIX-like systems, load the \u003ccode\u003ealiases\u003c/code\u003e file.\n\n   This alias file is for Bash users.  Those using some other\n   incompatible shell will have to provide their own translation.  Any\n   submissions will be gladly accepted.\n\n   \u003ccode\u003esource ~/diff-review/scripts.d/aliases\u003c/code\u003e\n\n   This will provide three aliases in your current shell environment:\n   \u003ccode\u003edr\u003c/code\u003e, \u003ccode\u003evr\u003c/code\u003e and \u003ccode\u003evrt\u003c/code\u003e.  These\n   directly reference the \u003ccode\u003ediff-review\u003c/code\u003e,\n   \u003ccode\u003eview-review\u003c/code\u003e, and \u003ccode\u003eview-review-tabs\u003c/code\u003e\n   programs respectively, bypassing the need to update\n   \u003ccode\u003e${PATH}\u003c/code\u003e.\n\n   The examples below will use these aliases.\n\n   On Windows cmd.exe, replace 'dr' with a a full path to\n   'diff-review.cmd', and 'view-review-tabs.cmd', which both reside in\n   the root directory of the repository.\n\n# Review Whole-File History\n\nUnlike traditional review tools that are limited to a single pull\nrequest or change, diff-review can assemble an arbitrary set of\ncommits into a single reviewable dossier. This enables reviewing the\ncomplete history of a file across multiple commits.\n\n## Workflow\n\n1. Find all commits that modified the file:\n\n   ```\n   git log --oneline -- src/parser.c\n   ```\n\n   This produces output like:\n\n   ```\n   a1b2c3d Fix null pointer dereference in parse_expr\n   e4f5g6h Add support for ternary operator\n   i7j8k9l Refactor token handling\n   m0n1o2p Initial parser implementation\n   ```\n\n2. Generate a dossier containing these commits:\n\n   ```\n   dr -c m0n1o2p\n   dr --ca i7j8k9l\n   dr --ca e4f5g6h\n   dr --ca a1b2c3d\n   ```\n\n   Each `--ca` (change append) adds the commit to the existing dossier.\n\n3. View the dossier:\n\n   ```\n   vrt\n   ```\n\n4. Use the revision range slider in the Commits panel to select which\ncommits to compare. Drag the top handle to set the base revision and\nthe bottom handle to set the modified revision. The file list and\ndiffs update to show changes within the selected range.\n\nThis workflow lets you trace how a file evolved over time, compare any\ntwo points in its history, and review changes in context -\ncapabilities not available in pull-request-based review systems.\n\n## Reviewing Pull Request Updates\n\nA common specialization of whole-file history review is comparing\nsuccessive updates to a pull request. When a PR author pushes new\ncommits in response to review feedback, you often want to see only\nwhat changed since your last review, not the entire PR diff again.\n\nAssemble a dossier with each PR update as a separate commit, then use\nthe range slider to compare any two updates - for example, comparing\nrounds 1 and 2 of feedback to see only what changed in response to the\nlatest review comments.\n\n\n# Examples\n\nThese examples with use \u003ccode\u003eemacs\u003c/code\u003e as the source of changes to review.\nTake the time now to go get a basic \u003ccode\u003eemacs\u003c/code\u003e source tree:\n\n    git clone https://github.com/emacs-mirror/emacs.git\n\n\nIf you prefer to use the official site, it is here, but it is\nextremely slow:\n\n\n    git clone https://git.savannah.gnu.org/git/emacs.git\n\n\n## Set aliases in your shell environment\n\n  As shown above in the \u003cem\u003eUsage\u003c/em\u003e section, load the aliases into\n  your shell.\n\n## View a single committed change\n\n  The following command will generate diffs for a 25-year-old\n  \u003ccode\u003eemacs\u003c/code\u003e change.\n\n```\ndr -c a3ba27daef3\n```\n\nThat command will produce the following output on the console:\n\n```\ndiff-review:  /home/thutt/review/default\n\n  modify   src/ChangeLog\n  modify   src/gmalloc.c\n\nChanges:  committed [2 files, 249 lines]\nViewer :  vrt --diff-dir '/home/thutt/review/default'\nViewer :  vrt --diff-url https://\u003cfqdn\u003e:443/home/thutt/review/default\nViewer :  vr -R '/home/thutt/review' -r 'default'\nElapsed:  0:00:00.094165\n```\n\nThe lines beginning with \u003ccode\u003eViewer\u003c/code\u003e are commands that can be\nexecuted to view the diffs.\n\n```\nvr\n```\n\nPressing \u003ccode\u003eEsc\u003c/code\u003e from \u003ccode\u003evr\u003c/code\u003e and \u003ccode\u003eCtrl-Q\u003c/code\u003e\nfrom \u003ccode\u003evrt\u003c/code\u003e will quit.\n\n\n## Combine and view multiple changes\n\n  The following command will generate diffs for a sequential range of\n  emacs commits.\n\n```\ndr -c 4418a37c5df^..cb17a8bbf39\n```\n\nThat command will produce the following output on the console, which\ncan be directly viewed by executing \u003ccode\u003evrt\u003c/code\u003e or  \u003ccode\u003evr\u003c/code\u003e:\n\n```\ndiff-review:  /home/thutt/review/default\n\n  modify   admin/notes/unicode\n  modify   doc/lispref/modes.texi\n  modify   doc/lispref/parsing.texi\n  modify   doc/lispref/positions.texi\n  modify   lisp/comint.el\n  modify   lisp/dired-x.el\n  modify   lisp/emacs-lisp/easy-mmode.el\n  modify   lisp/emacs-lisp/ring.el\n  modify   lisp/international/mule-cmds.el\n  modify   lisp/international/ucs-normalize.el\n  modify   lisp/net/eww.el\n  modify   lisp/net/rcirc.el\n  modify   lisp/progmodes/gdb-mi.el\n  modify   lisp/progmodes/php-ts-mode.el\n  modify   lisp/subr.el\n  modify   lisp/time.el\n  modify   lisp/vc/log-edit.el\n  modify   lisp/vc/vc.el\n  modify   src/doc.c\n  modify   src/editfns.c\n  modify   test/lisp/comint-tests.el\n  modify   test/lisp/dom-tests.el\n  modify   test/lisp/international/mule-tests.el\n  modify   test/lisp/international/ucs-normalize-tests.el\n  modify   test/lisp/net/tramp-tests.el\n  modify   test/lisp/textmodes/ispell-resources/fake-aspell-new.bash\n  modify   test/lisp/textmodes/ispell-tests/ispell-aspell-tests.el\n  modify   test/lisp/textmodes/ispell-tests/ispell-hunspell-tests.el\n  modify   test/lisp/textmodes/ispell-tests/ispell-international-ispell-tests.el\n  modify   test/lisp/textmodes/ispell-tests/ispell-tests.el\n\nChanges:  committed [30 files, 378 lines]\nViewer :  vrt --diff-dir '/home/thutt/review/default'\nViewer :  vrt --diff-url https://\u003cfqdn\u003e:443/home/thutt/review/default\nViewer :  vr -R '/home/thutt/review' -r 'default'\nElapsed:  0:00:00.397989\n```\n\n## View uncommitted changes\n\nThis example will show how untracked, unstaged and staged changes are\nprocessed.\n\nExecute the following:\n\n```\ntouch untracked;\ncat README README \u003ereadme;\nmv readme README;\ngit rm config.bat;\n```\n\nNow, run \u003ccode\u003edr\u003c/code\u003e, which will produce the console output:\n\n```\ndiff-review:  /home/thutt/review/default\n\n   unstaged   README\n     delete   config.bat\n  untracked   untracked\n\nChanges:  unstaged [1 files, 130 lines]  staged [1 files  385 lines]\nViewer :  vrt --diff-dir '/home/thutt/review/default'\nViewer :  vrt --diff-url https://\u003cfqdn\u003e:443/home/thutt/review/default\nViewer :  vr -R '/home/thutt/review' -r 'default'\nElapsed:  0:00:00.190448\n```\n\nAs ever, both \u003ccode\u003evrt\u003c/code\u003e and \u003ccode\u003evr\u003c/code\u003e can be used to view\nthe changes.\n\nNext, stage the \u003ccode\u003eREADME\u003c/code\u003e file and re-generate the diffs\nwith \u003ccode\u003edr\u003c/code\u003e.\n\n```\ngit add README\n\n```\n\nThe console output will appear like this:\n\n```\ndiff-review:  /home/thutt/review/default\n\n     staged   README\n     delete   config.bat\n  untracked   untracked\n\nChanges:  unstaged [0 files, 0 lines]  staged [2 files  515 lines]\nViewer :  vrt --diff-dir '/home/thutt/review/default'\nViewer :  vrt --diff-url https://\u003cfqdn\u003e:443/home/thutt/review/default\nViewer :  vr -R '/home/thutt/review' -r 'default'\nElapsed:  0:00:00.191670\n```\n\nFinally, make another modification to \u003ccode\u003eREADME\u003c/code\u003e to show how\nits state returns to \u003ccode\u003eunstaged\u003c/code\u003e after executing\n\u003ccode\u003edr\u003c/code\u003e.\n\n```\ncp BUGS README\n```\n\nThe console output will look like this:\n\n```\ndiff-review:  /home/thutt/review/default\n\n   unstaged   README\n     delete   config.bat\n  untracked   untracked\n\nChanges:  unstaged [1 files, 274 lines]  staged [2 files  515 lines]\nViewer :  vrt --diff-dir '/home/thutt/review/default'\nViewer :  vrt --diff-url https://\u003cfqdn\u003e:443/home/thutt/review/default\nViewer :  vr -R '/home/thutt/review' -r 'default'\nElapsed:  0:00:00.190435\n```\n\n## Clean up repository\n\nNow that the examples are finished, you can delete the\n\u003ccode\u003eemacs\u003c/code\u003e clone.\n\n# Advanced Usage\n\nInvoking either \u003ccode\u003edr\u003c/code\u003e, \u003ccode\u003evr\u003c/code\u003e or \u003ccode\u003evrt\u003c/code\u003e\nwith \u003ccode\u003e--help\u003c/code\u003e will show the current set options that the\nprogram takes.  Using these options will allow more complex\ninvocations -- such as naming the output, or putting it into a\ndifferent directory location.\n\n- Claude-QT (pyqt6)\n\n  This viewer program was entirely generated through conversations\n  with Claude.ai.  When it is deemed to be working well-enough, it\n  will likely become the default viewer, replacing TkDiff.\n\n  The Help menu describes how to use the features of the program.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthutt%2Fdiff-review","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthutt%2Fdiff-review","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthutt%2Fdiff-review/lists"}