diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index 709cb0910e6..b7d6b6f9f7b 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi @@ -1682,6 +1682,21 @@ reverse of the hunk, which changes the ``new'' version into the ``old'' version. If @code{diff-jump-to-old-file} is non-@code{nil}, apply the hunk to the ``old'' version of the file instead. +@findex diff-revert-and-kill-hunk +@item C-c M-r +Reverse-apply this hunk to the target file, and then kill it +(@code{diff-revert-and-kill-hunk}). Save the buffer visiting the target +file. + +This command is useful in buffers generated by @w{@kbd{C-x v =}} and +@w{@kbd{C-x v D}} (@pxref{Old Revisions}). These buffers present you +with a view of the changes you've made, and then you can use this +command to drop changes you didn't intend, or no longer want. + +This is a destructive operation, so by default, this command asks you to +confirm you really want to reverse-apply and kill the hunk. You can +customize @code{diff-ask-before-revert-and-kill-hunk} to change that. + @findex diff-apply-buffer @item C-c @key{RET} a Apply all the hunks in the buffer (@code{diff-apply-buffer}). If the diff --git a/etc/NEWS b/etc/NEWS index 2241f0f9a4a..feadc54c17a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -363,6 +363,11 @@ according to diffs in the current buffer, but without applying the diffs to the original text. If the selected range extends a hunk, the command attempts to look up and copy the text in-between the hunks. ++++ +*** New command 'diff-revert-and-kill-hunk' bound to C-c M-r. +This command reverse-applies the hunk at point, and then kills it. +This is useful in buffers generated by C-x v = and C-x v D. + ** php-ts-mode --- diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index b8a9484627c..c59c0954ae1 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -218,6 +218,7 @@ The default \"-b\" means to ignore whitespace-only changes, "C-x 4 A" #'diff-add-change-log-entries-other-window ;; Misc operations. "C-c C-a" #'diff-apply-hunk + "C-c M-r" #'diff-revert-and-kill-hunk "C-c C-m a" #'diff-apply-buffer "C-c C-e" #'diff-ediff-patch "C-c C-n" #'diff-restrict-view @@ -242,6 +243,8 @@ The default \"-b\" means to ignore whitespace-only changes, :help "Apply the current hunk to the source file and go to the next"] ["Test applying hunk" diff-test-hunk :help "See whether it's possible to apply the current hunk"] + ["Revert and kill hunk" diff-revert-and-kill-hunk + :help "Reverse-apply and then kill the current hunk."] ["Apply all hunks" diff-apply-buffer :help "Apply all hunks in the current diff buffer"] ["Apply diff with Ediff" diff-ediff-patch @@ -2050,24 +2053,52 @@ With a prefix argument, try to REVERSE the hunk." (diff-hunk-kill) (diff-hunk-next))))) -(defun diff-apply-buffer () +(defcustom diff-ask-before-revert-and-kill-hunk t + "If non-nil, `diff-revert-and-kill-hunk' will ask for confirmation." + :type 'boolean) + +(defun diff-revert-and-kill-hunk () + "Reverse-apply and then kill the hunk at point. Save changed buffer. + +This command is useful in buffers generated by \\[vc-diff] and \\[vc-root-diff], +especially when preparing to commit the patch with \\[vc-next-action]. +You can use \\\\[diff-hunk-kill] to temporarily remove changes that you intend to +include in a separate commit or commits, and you can use this command +to permanently drop changes you didn't intend, or no longer want. + +This is a destructive operation, so by default, this command asks you to +confirm you really want to reverse-apply and kill the hunk. You can +customize `diff-ask-before-revert-and-kill-hunk' to change that." + (interactive) + (when (or (not diff-ask-before-revert-and-kill-hunk) + (yes-or-no-p "Really reverse-apply and kill this hunk?")) + (cl-destructuring-bind (beg end) (diff-bounds-of-hunk) + (when (null (diff-apply-buffer beg end t)) + (diff-hunk-kill))))) + +(defun diff-apply-buffer (&optional beg end reverse) "Apply the diff in the entire diff buffer. -When applying all hunks was successful, then save the changed buffers." +When applying all hunks was successful, then save the changed buffers. +When called from Lisp with optional arguments, restrict the application +to hunks lying between BEG and END, and reverse-apply when REVERSE is +non-nil. Returns nil if buffers were saved, or the number of failed +applications." (interactive) (let ((buffer-edits nil) (failures 0) (diff-refine nil)) (save-excursion - (goto-char (point-min)) + (goto-char (or beg (point-min))) (diff-beginning-of-hunk t) (while (pcase-let ((`(,buf ,line-offset ,pos ,_src ,dst ,switched) - (diff-find-source-location nil nil))) + (diff-find-source-location nil reverse))) (cond ((and line-offset (not switched)) (push (cons pos dst) (alist-get buf buffer-edits))) (t (setq failures (1+ failures)))) (and (not (eq (prog1 (point) (ignore-errors (diff-hunk-next))) (point))) + (or (not end) (< (point) end)) (looking-at-p diff-hunk-header-re))))) (cond ((zerop failures) (dolist (buf-edits (reverse buffer-edits)) @@ -2080,11 +2111,13 @@ When applying all hunks was successful, then save the changed buffers." (delete-region (car pos) (cdr pos)) (insert (car dst)))) (save-buffer))) - (message "Saved %d buffers" (length buffer-edits))) + (message "Saved %d buffers" (length buffer-edits)) + nil) (t (message (ngettext "%d hunk failed; no buffers changed" "%d hunks failed; no buffers changed" - failures)))))) + failures)) + failures)))) (defalias 'diff-mouse-goto-source #'diff-goto-source)