emacs-patch-review

Port of Thunderbird Patch Review to mu4e.

git clone git://mccd.space/emacs-patch-review

README.html (5235B)

patch-review.el
Review git patches from email in Emacs
Synopsis
An Emacs port of the Thunderbird Patch Review add-on. Open a patch email, type review comments directly into the diff, send the review as an interleaved mailing-list reply, and apply the patch to a local repository with git-am(1).
Unlike the Thunderbird version, no privileged "host" component is needed: Emacs runs git directly, diff-mode provides the rendering, and message-mode the composition.
Installation

Clone and add to load-path:

(add-to-list 'load-path "/path/to/emacs-patch-review")
(require 'patch-review)        ; core, diff-mode derived
(require 'patch-review-mu4e)  ; optional mu4e integration

Requires Emacs 28.1+, git, and diffutils. Requires mu4e only for the mail adapter.

Usage from mu4e

In a *mu4e-view* buffer showing a patch:

(define-key mu4e-view-mode-map (kbd "R") #'patch-review-mu4e-review)
Usage from a file
Opening a .patch or .diff file activates patch-review-mode (via auto-mode-alist). M-x patch-review-open-message-file handles raw .eml messages.
Reviewing

The review buffer is an ordinary, editable diff-mode buffer holding the patch body. There is no "add comment" command: press RET anywhere and type. Text you insert is your commentary; the patch text stays untouched. Text inserted above the first hunk becomes a general remark.

When you send (C-c C-c), the buffer is diffed against the pristine original. Your insertions are extracted, anchored to the patch line above them, and formatted as an interleaved reply — quoted hunks with > prefix, comments underneath, kernel style:

Looks good overall, two nits.

> diff --git a/src/socket.c b/src/socket.c
> @@ -1,15 +1,20 @@
>  #include <stdio.h>
> +#include <errno.h>

Is errno.h needed on all platforms?

The outgoing mail is composed from the pristine text, so accidental edits to the patch itself can never corrupt the quote (they are reported before sending). The reply lands in a message-mode buffer; send it with C-c C-c again.

Applying
The header line shows the target project and whether the patch applies to it (probed by running git-am(1) in a throwaway detached worktree — your repository is never touched by the probe).
Controls
KeyAction
C-c C-cextract comments, compose review reply
C-c C-aapply patch to the project with git-am(1)
C-u C-c C-aapply with user git hooks suppressed
C-c C-pset/switch the target project
C-c C-rre-run the applicability probe

Plus all of diff-mode's navigation (M-n / M-p between hunks, C-c C-b word-level refinement, ...).

Status values: applies cleanly, already applied, worktree dirty, conflicts, am in progress, no project.

Design notes
  • Comment extraction uses an anchored diff(1) -U0 between the pristine and edited buffer; pure insertions become comments at the original line above them. Deletions/modifications of patch text are counted and confirmed before sending.
  • The applicability probe mirrors the Thunderbird add-on's patchHost: git-diff-index(1) --quiet HEAD for dirtiness, then git-am(1) in a temporary --detach worktree with core.hooksPath pointed at an empty directory (probes must not run user hooks against unreviewed patch content). git-am(1) itself gives the tri-state: "Patch already applied", exit 0, or exit 128.
  • Applying runs the user's hooks (a deliberate act); the prefix argument suppresses them. Applying refuses to run while a previous git-am(1) session is unfinished (rebase-apply/ present) instead of aborting it.
Roadmap
  • Series collection: gather [PATCH n/m] siblings of the same thread (mu find), review and apply the whole series at once (concatenated mbox, matching git-am(1) semantics).
  • Sourcehut integration: X-Sourcehut-Patchset-Update header on send.
  • Asynchronous applicability probe.
  • Optional apply via piem.
Development

Run the tests:

make test

Commits are atomic: one logical change per commit, and make test passes at every commit.

License
GPLv3. See the Thunderbird project for the original implementation.
Author
Marc Coquand