Committing a partial changeset in Emacs
One of the frequent questions for the built-in Version Control support in Emacs has been the ability to commit only a part of the changes in a file or several.
In the command-line, it’s simple (though not always easy): you call git add -p and iterate through the whole repository diff with y/n/etc. Magit also has an interface for staging and committing from the staging area, but that only works for Git and requires you to switch to its UI first.
Using VC
One of the less noticed additions in Emacs 29 is the ability to
create a commit from a diff buffer.
And since diff-mode
provides functionality for editing the diff, you
can drop the unwanted pieces first (they stay saved on disk) and
commit the amended changeset.
Here’s how it works: you press C-x v = or C-x v
D to show the diff for the current file, or the whole
repository, edit the diff using commands such as diff-hunk-kill
(M-k), diff-split-hunk
(C-c C-s), and then
type C-x v v in the same buffer to proceed to the familiar
step “Edit commit message”.
I also recommend customizing diff-default-read-only
to t
so that
the short key combinations work right away in diff-mode
, including
n and p for hunk navigation and k for
removing hunks. Otherwise those only work after switching to
read-only-mode (C-x C-q)
Anyway, you enter the commit message and press C-c C-c to
create the commit. This works not only with Git, but also with
Mercurial repositories, and the fallback implementation endeavors to
support other VC systems as well (such as Bazaar and SVN), though
using a slower method. The latter is not as well-tested (the latest
bug report was regarding an incompatible command-line flags in
OpenBSD’s patch
), so more feedback welcome.
Using Diff-HL
The workflow described above doesn’t use the staging area, and if you are using Magit, you might prefer a simply faster way to stage hunks.
By popular demand, the new additions to the
diff-hl package are the commands
diff-hl-stage-current-hunk
and, more recently, diff-hl-stage-dwim
.
Either type C-x v S to stage the hunk at or above point, or prepend it with C-u to similarly pop up a buffer where you can edit the changeset to stage. Then do the commit with Magit or the command line.