diff options
| author | Sean Whitton | 2025-09-04 11:25:25 +0100 |
|---|---|---|
| committer | Sean Whitton | 2025-09-16 14:30:02 +0100 |
| commit | 208e80018a7cdc87b35c7f8a08a243600c54c9cc (patch) | |
| tree | 8905aae6b0f9976d628345e083406f4aa02fdba5 | |
| parent | 0000d9b7b1a457793deecff2cb56ec82c04545f3 (diff) | |
| download | emacs-208e80018a7cdc87b35c7f8a08a243600c54c9cc.tar.gz emacs-208e80018a7cdc87b35c7f8a08a243600c54c9cc.zip | |
New commands to apply changes to other working trees
* lisp/vc/diff-mode.el (diff-apply-buffer): New TEST argument.
* lisp/vc/vc.el (diff-apply-buffer): Declare.
(vc-no-confirm-moving-changes): New user option.
(vc-apply-to-other-working-tree)
(vc-apply-root-to-other-working-tree): New commands.
* lisp/vc/vc-hooks.el (vc-prefix-map): Bind them.
* doc/emacs/vc1-xtra.texi (Other Working Trees):
* etc/NEWS: Document them.
| -rw-r--r-- | doc/emacs/vc1-xtra.texi | 52 | ||||
| -rw-r--r-- | etc/NEWS | 2 | ||||
| -rw-r--r-- | lisp/vc/diff-mode.el | 50 | ||||
| -rw-r--r-- | lisp/vc/vc-hooks.el | 4 | ||||
| -rw-r--r-- | lisp/vc/vc.el | 151 |
5 files changed, 227 insertions, 32 deletions
diff --git a/doc/emacs/vc1-xtra.texi b/doc/emacs/vc1-xtra.texi index b5a0f0c129b..15b7a73e5d7 100644 --- a/doc/emacs/vc1-xtra.texi +++ b/doc/emacs/vc1-xtra.texi | |||
| @@ -397,15 +397,15 @@ want to disturb. So you type @kbd{C-x v w c} (see below) and create a | |||
| 397 | new working tree, following the prompts to check out the version 2 | 397 | new working tree, following the prompts to check out the version 2 |
| 398 | branch there. | 398 | branch there. |
| 399 | 399 | ||
| 400 | You apply the patch to that working tree, build and test it. Satisfied, | 400 | You apply the patch to that working tree using @w{@kbd{C-x v w a}} (see |
| 401 | you use @kbd{C-x v P} (@pxref{Pulling / Pushing}) in the other working | 401 | below), build and test it. Satisfied, you use @w{@kbd{C-x v P}} |
| 402 | tree. In the course of testing the patch, you've realised that the bug | 402 | (@pxref{Pulling / Pushing}) in the other working tree. In the course of |
| 403 | exists in version 3 of the software, too. So you switch back to your | 403 | testing the patch, you've realised that the bug exists in version 3 of |
| 404 | first working tree, and use @kbd{C-x v m} (@pxref{Merging}) to merge the | 404 | the software, too. So you switch back to your first working tree, and |
| 405 | branch you have checked out in the other working tree. Now your version | 405 | use @kbd{C-x v m} (@pxref{Merging}) to merge the branch you have checked |
| 406 | of the trunk has all of version 2's fixes merged into it, but you | 406 | out in the other working tree. Now your version of the trunk has all of |
| 407 | haven't pushed it yet because you're still refactoring. You'll use | 407 | version 2's fixes merged into it, but you haven't pushed it yet because |
| 408 | @kbd{C-x v P} later. | 408 | you're still refactoring. You'll use @kbd{C-x v P} later. |
| 409 | @end indentedblock | 409 | @end indentedblock |
| 410 | 410 | ||
| 411 | Ordinary VC commands like @kbd{C-x v v} (@pxref{Basic VC Editing}) and | 411 | Ordinary VC commands like @kbd{C-x v v} (@pxref{Basic VC Editing}) and |
| @@ -440,6 +440,12 @@ Visit this file or directory in another working tree. | |||
| 440 | Invoke @kbd{C-x p p} (@code{project-switch-project}) but limited to | 440 | Invoke @kbd{C-x p p} (@code{project-switch-project}) but limited to |
| 441 | other working trees. | 441 | other working trees. |
| 442 | 442 | ||
| 443 | @item C-x v w a | ||
| 444 | Copy or move fileset changes to another working tree. | ||
| 445 | |||
| 446 | @item C-x v w A | ||
| 447 | Copy or move all changes to another working tree. | ||
| 448 | |||
| 443 | @item C-x v w x | 449 | @item C-x v w x |
| 444 | Delete a working tree you no longer need. | 450 | Delete a working tree you no longer need. |
| 445 | 451 | ||
| @@ -500,6 +506,34 @@ to other working trees. The main difference between @kbd{C-x v w w} and | |||
| 500 | buffer in the other working tree while the latter considers the other | 506 | buffer in the other working tree while the latter considers the other |
| 501 | working tree as a whole, independent project. | 507 | working tree as a whole, independent project. |
| 502 | 508 | ||
| 509 | @kindex C-x v w a | ||
| 510 | @findex vc-apply-to-other-working-tree | ||
| 511 | The command @kbd{C-x v w a} (@code{vc-apply-to-other-working-tree}) | ||
| 512 | prompts you to select a working tree, then copies changes from the | ||
| 513 | current working tree to that other working tree. With a prefix | ||
| 514 | argument, it moves changes instead of just copying them. Usually the | ||
| 515 | command operates on local (uncommitted) changes to the current VC | ||
| 516 | fileset. When invoked in a Diff mode (@pxref{Diff Mode}) buffer, it | ||
| 517 | operates on the changes specified by the contents of that buffer. The | ||
| 518 | command stops and does nothing if any of the changes don't apply. | ||
| 519 | |||
| 520 | @kbd{C-x v w a} is useful to copy changes to a temporary working tree in | ||
| 521 | order to test them. It is also useful to copy fixes back to your main | ||
| 522 | working tree for checking in. For example, you might hack away at a bug | ||
| 523 | in a temporary working tree, and fix it. You'd then want to copy or | ||
| 524 | move the fix back to your main working tree to check it in and push it. | ||
| 525 | |||
| 526 | @kindex C-x v w A | ||
| 527 | @findex vc-apply-root-to-other-working-tree | ||
| 528 | The command @kbd{C-x v w A} works similarly, except that it always | ||
| 529 | copies or moves all local changes to the whole working tree, not just | ||
| 530 | changes to the current VC fileset or changes represented by the contents | ||
| 531 | of a Diff mode buffer. With two prefix arguments, this command shows a | ||
| 532 | preview of changes to be copied, leaving you to apply them using | ||
| 533 | standard Diff mode commands like @kbd{C-c C-a} and @w{@kbd{C-c <RET> a}} | ||
| 534 | (@pxref{Diff Mode}). (@w{@kbd{C-u C-u C-x v w A}} is roughly equivalent | ||
| 535 | to typing @w{@kbd{C-x v D}} followed by @w{@kbd{C-x v w w}}.) | ||
| 536 | |||
| 503 | @kindex C-x v w x | 537 | @kindex C-x v w x |
| 504 | @kindex C-x v w R | 538 | @kindex C-x v w R |
| 505 | @findex vc-delete-working-tree | 539 | @findex vc-delete-working-tree |
| @@ -2072,6 +2072,8 @@ other working trees: | |||
| 2072 | - 'C-x v w c': Add a new working tree. | 2072 | - 'C-x v w c': Add a new working tree. |
| 2073 | - 'C-x v w w': Visit this file in another working tree. | 2073 | - 'C-x v w w': Visit this file in another working tree. |
| 2074 | - 'C-x v w s': Like 'C-x p p' but limited to other working trees. | 2074 | - 'C-x v w s': Like 'C-x p p' but limited to other working trees. |
| 2075 | - 'C-x v w a': Copy or move fileset changes to another working tree. | ||
| 2076 | - 'C-x v w A': Copy or move all changes to another working tree. | ||
| 2075 | - 'C-x v w x': Delete a working tree you no longer need. | 2077 | - 'C-x v w x': Delete a working tree you no longer need. |
| 2076 | - 'C-x v w R': Relocate a working tree to another file name. | 2078 | - 'C-x v w R': Relocate a working tree to another file name. |
| 2077 | 2079 | ||
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index c58ad67ff52..f207f87811c 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el | |||
| @@ -2213,17 +2213,21 @@ customize `diff-ask-before-revert-and-kill-hunk' to control that." | |||
| 2213 | (when (null (diff-apply-buffer beg end t)) | 2213 | (when (null (diff-apply-buffer beg end t)) |
| 2214 | (diff-hunk-kill))))) | 2214 | (diff-hunk-kill))))) |
| 2215 | 2215 | ||
| 2216 | (defun diff-apply-buffer (&optional beg end reverse) | 2216 | (defun diff-apply-buffer (&optional beg end reverse test) |
| 2217 | "Apply the diff in the entire diff buffer. | 2217 | "Apply the diff in the entire diff buffer. |
| 2218 | Interactively, if the region is active, apply all hunks that the region | 2218 | Interactively, if the region is active, apply all hunks that the region |
| 2219 | overlaps; otherwise, apply all hunks. | 2219 | overlaps; otherwise, apply all hunks. |
| 2220 | With a prefix argument, reverse-apply the hunks. | 2220 | With a prefix argument, reverse-apply the hunks. |
| 2221 | If applying all hunks succeeds, save the changed buffers. | 2221 | If applying all hunks succeeds, save the changed buffers. |
| 2222 | 2222 | ||
| 2223 | When called from Lisp with optional arguments, restrict the application | 2223 | When called from Lisp, returns nil if buffers were successfully modified |
| 2224 | to hunks lying between BEG and END, and reverse-apply them when REVERSE | 2224 | and saved, or the number of failed hunk applications otherwise. |
| 2225 | is non-nil. Returns nil if buffers were successfully modified and | 2225 | Optional arguments BEG and END restrict the hunks to be applied to those |
| 2226 | saved, or the number of failed hunk applications otherwise." | 2226 | lying between BEG and END. |
| 2227 | Optional argument REVERSE means to reverse-apply hunks. | ||
| 2228 | Optional argument TEST means to not actually apply or reverse-apply any | ||
| 2229 | hunks, but return the same information: nil if all hunks can be applied, | ||
| 2230 | or the number of hunks that can't be applied." | ||
| 2227 | (interactive (list (use-region-beginning) | 2231 | (interactive (list (use-region-beginning) |
| 2228 | (use-region-end) | 2232 | (use-region-end) |
| 2229 | current-prefix-arg)) | 2233 | current-prefix-arg)) |
| @@ -2234,7 +2238,7 @@ saved, or the number of failed hunk applications otherwise." | |||
| 2234 | (goto-char (or beg (point-min))) | 2238 | (goto-char (or beg (point-min))) |
| 2235 | (diff-beginning-of-hunk t) | 2239 | (diff-beginning-of-hunk t) |
| 2236 | (while (pcase-let ((`(,buf ,line-offset ,pos ,_src ,dst ,switched) | 2240 | (while (pcase-let ((`(,buf ,line-offset ,pos ,_src ,dst ,switched) |
| 2237 | (diff-find-source-location nil reverse))) | 2241 | (diff-find-source-location nil reverse test))) |
| 2238 | (cond ((and line-offset (not switched)) | 2242 | (cond ((and line-offset (not switched)) |
| 2239 | (push (cons pos dst) | 2243 | (push (cons pos dst) |
| 2240 | (alist-get buf buffer-edits))) | 2244 | (alist-get buf buffer-edits))) |
| @@ -2244,23 +2248,25 @@ saved, or the number of failed hunk applications otherwise." | |||
| 2244 | (or (not end) (< (point) end)) | 2248 | (or (not end) (< (point) end)) |
| 2245 | (looking-at-p diff-hunk-header-re))))) | 2249 | (looking-at-p diff-hunk-header-re))))) |
| 2246 | (cond ((zerop failures) | 2250 | (cond ((zerop failures) |
| 2247 | (dolist (buf-edits (reverse buffer-edits)) | 2251 | (unless test |
| 2248 | (with-current-buffer (car buf-edits) | 2252 | (dolist (buf-edits (reverse buffer-edits)) |
| 2249 | (dolist (edit (cdr buf-edits)) | 2253 | (with-current-buffer (car buf-edits) |
| 2250 | (let ((pos (car edit)) | 2254 | (dolist (edit (cdr buf-edits)) |
| 2251 | (dst (cdr edit)) | 2255 | (let ((pos (car edit)) |
| 2252 | (inhibit-read-only t)) | 2256 | (dst (cdr edit)) |
| 2253 | (goto-char (car pos)) | 2257 | (inhibit-read-only t)) |
| 2254 | (delete-region (car pos) (cdr pos)) | 2258 | (goto-char (car pos)) |
| 2255 | (insert (car dst)))) | 2259 | (delete-region (car pos) (cdr pos)) |
| 2256 | (save-buffer))) | 2260 | (insert (car dst)))) |
| 2257 | (message "Saved %d buffers" (length buffer-edits)) | 2261 | (save-buffer))) |
| 2262 | (message "Saved %d buffers" (length buffer-edits))) | ||
| 2258 | nil) | 2263 | nil) |
| 2259 | (t | 2264 | (t |
| 2260 | (message (ngettext "%d hunk failed; no buffers changed" | 2265 | (unless test |
| 2261 | "%d hunks failed; no buffers changed" | 2266 | (message (ngettext "%d hunk failed; no buffers changed" |
| 2262 | failures) | 2267 | "%d hunks failed; no buffers changed" |
| 2263 | failures) | 2268 | failures) |
| 2269 | failures)) | ||
| 2264 | failures)))) | 2270 | failures)))) |
| 2265 | 2271 | ||
| 2266 | (defalias 'diff-mouse-goto-source #'diff-goto-source) | 2272 | (defalias 'diff-mouse-goto-source #'diff-goto-source) |
| @@ -2616,7 +2622,7 @@ Call FUN with two args (BEG and END) for each hunk." | |||
| 2616 | (or (ignore-errors (diff-hunk-next) (point)) | 2622 | (or (ignore-errors (diff-hunk-next) (point)) |
| 2617 | max))))))))) | 2623 | max))))))))) |
| 2618 | 2624 | ||
| 2619 | ;; This doesn't use `diff--iterate-hunks', since that assumes that | 2625 | ;; This doesn't use `diff--iterate-hunks' because that assumes that |
| 2620 | ;; hunks don't change size. | 2626 | ;; hunks don't change size. |
| 2621 | (defun diff--ignore-whitespace-all-hunks () | 2627 | (defun diff--ignore-whitespace-all-hunks () |
| 2622 | "Re-diff all the hunks, ignoring whitespace-differences." | 2628 | "Re-diff all the hunks, ignoring whitespace-differences." |
diff --git a/lisp/vc/vc-hooks.el b/lisp/vc/vc-hooks.el index ded24ada8a0..da67f7f1815 100644 --- a/lisp/vc/vc-hooks.el +++ b/lisp/vc/vc-hooks.el | |||
| @@ -970,7 +970,9 @@ In the latter case, VC mode is deactivated for this buffer." | |||
| 970 | "w w" #'vc-switch-working-tree | 970 | "w w" #'vc-switch-working-tree |
| 971 | "w s" #'vc-working-tree-switch-project | 971 | "w s" #'vc-working-tree-switch-project |
| 972 | "w x" #'vc-delete-working-tree | 972 | "w x" #'vc-delete-working-tree |
| 973 | "w R" #'vc-move-working-tree) | 973 | "w R" #'vc-move-working-tree |
| 974 | "w a" #'vc-apply-to-other-working-tree | ||
| 975 | "w A" #'vc-apply-root-to-other-working-tree) | ||
| 974 | (fset 'vc-prefix-map vc-prefix-map) | 976 | (fset 'vc-prefix-map vc-prefix-map) |
| 975 | (define-key ctl-x-map "v" 'vc-prefix-map) | 977 | (define-key ctl-x-map "v" 'vc-prefix-map) |
| 976 | 978 | ||
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index e0e9d0e2ac6..07b9ea8b951 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el | |||
| @@ -4661,6 +4661,157 @@ BACKEND is the VC backend." | |||
| 4661 | (when-let* ((p (project-current nil to))) | 4661 | (when-let* ((p (project-current nil to))) |
| 4662 | (project-remember-project p))) | 4662 | (project-remember-project p))) |
| 4663 | 4663 | ||
| 4664 | (declare-function diff-apply-buffer "diff-mode") | ||
| 4665 | |||
| 4666 | ;;;###autoload | ||
| 4667 | (defun vc-apply-to-other-working-tree (directory &optional move) | ||
| 4668 | "Apply VC fileset's local changes to working tree under DIRECTORY. | ||
| 4669 | Must be called from within an existing VC working tree. | ||
| 4670 | When called interactively, prompts for DIRECTORY. | ||
| 4671 | With a prefix argument (when called from Lisp, with optional argument | ||
| 4672 | MOVE non-nil), don't just copy the changes, but move them, from the | ||
| 4673 | current working tree to DIRECTORY. | ||
| 4674 | |||
| 4675 | When called from a `diff-mode' buffer, move or copy the changes | ||
| 4676 | specified by the contents of that buffer, only. | ||
| 4677 | |||
| 4678 | If any changes to be moved or copied can't be applied to DIRECTORY, it | ||
| 4679 | is an error, and no changes are applied. | ||
| 4680 | If any changes to be moved can't be reverse-applied to this working | ||
| 4681 | tree, it is an error, and no changes are moved." | ||
| 4682 | ;; The double prefix arg that `vc-apply-root-to-other-working-tree' | ||
| 4683 | ;; has is omitted here, for now, because it is probably less useful. | ||
| 4684 | (interactive | ||
| 4685 | (list | ||
| 4686 | (vc--prompt-other-working-tree | ||
| 4687 | (vc-responsible-backend default-directory) | ||
| 4688 | (format "%s changes to working tree" | ||
| 4689 | (if current-prefix-arg "Move" "Apply"))) | ||
| 4690 | current-prefix-arg)) | ||
| 4691 | (let* ((relative-dir (file-relative-name default-directory | ||
| 4692 | (vc-root-dir))) | ||
| 4693 | (mirror-dir (expand-file-name relative-dir directory))) | ||
| 4694 | (unless (file-directory-p mirror-dir) | ||
| 4695 | (user-error "`%s' not found in `%s'" relative-dir directory)) | ||
| 4696 | (vc--apply-to-other-working-tree directory mirror-dir | ||
| 4697 | (vc-deduce-fileset) | ||
| 4698 | (and (derived-mode-p 'diff-mode) | ||
| 4699 | (buffer-string)) | ||
| 4700 | move))) | ||
| 4701 | |||
| 4702 | ;;;###autoload | ||
| 4703 | (defun vc-apply-root-to-other-working-tree (directory &optional move preview) | ||
| 4704 | "Apply all local changes to this working tree to the one under DIRECTORY. | ||
| 4705 | Must be called from within an existing VC working tree. | ||
| 4706 | When called interactively, prompts for DIRECTORY. | ||
| 4707 | With a prefix argument (when called from Lisp, with optional argument | ||
| 4708 | MOVE non-nil), don't just copy the changes, but move them, from the | ||
| 4709 | current working tree to DIRECTORY. | ||
| 4710 | |||
| 4711 | With a double prefix argument (\\[universal-argument] \\[universal-argument]; \ | ||
| 4712 | when called from Lisp, with | ||
| 4713 | optional argument PREVIEW non-nil), don't actually apply changes to | ||
| 4714 | DIRECTORY, but instead show all those changes in a `diff-mode' buffer | ||
| 4715 | with `default-directory' set to DIRECTORY. | ||
| 4716 | You can then selectively apply changes with `diff-mode' commands like | ||
| 4717 | `diff-apply-hunk' and `diff-apply-buffer'. | ||
| 4718 | |||
| 4719 | If any changes to be moved or copied can't be applied to DIRECTORY, it | ||
| 4720 | is an error, and (except with \\[universal-argument] \\[universal-argument]) \ | ||
| 4721 | no changes are applied. | ||
| 4722 | If any changes to be moved can't be reverse-applied to this working | ||
| 4723 | tree, it is an error, and no changes are moved." | ||
| 4724 | (interactive | ||
| 4725 | (list | ||
| 4726 | (vc--prompt-other-working-tree | ||
| 4727 | (vc-responsible-backend default-directory) | ||
| 4728 | (format "%s changes to working tree" | ||
| 4729 | (if (equal current-prefix-arg '(4)) "Move" "Apply"))) | ||
| 4730 | (equal current-prefix-arg '(4)) | ||
| 4731 | (equal current-prefix-arg '(16)))) | ||
| 4732 | (cond ((and move preview) | ||
| 4733 | (error "Invalid arguments to vc-apply-root-to-other-working-tree")) | ||
| 4734 | (preview | ||
| 4735 | ;; In this mode, no need to abort if some hunks aren't | ||
| 4736 | ;; applicable. | ||
| 4737 | (vc-root-diff nil t) | ||
| 4738 | (setq default-directory directory) | ||
| 4739 | (message | ||
| 4740 | (substitute-command-keys | ||
| 4741 | "Use \\[diff-hunk-kill] to kill hunks not to be copied \ | ||
| 4742 | then \\[diff-apply-buffer] to copy changes, | ||
| 4743 | or use \\[diff-apply-hunk] to copy individual hunks. \ | ||
| 4744 | Type \\[describe-mode] for more commands"))) | ||
| 4745 | (t | ||
| 4746 | (let ((default-directory (vc-root-dir))) | ||
| 4747 | (vc--apply-to-other-working-tree directory directory | ||
| 4748 | `(,(vc-deduce-backend) | ||
| 4749 | (,default-directory)) | ||
| 4750 | nil move))))) | ||
| 4751 | |||
| 4752 | (defcustom vc-no-confirm-moving-changes nil | ||
| 4753 | "Whether VC commands prompt before moving changes between working trees. | ||
| 4754 | |||
| 4755 | Normally the commands \\[vc-apply-to-other-working-tree] \ | ||
| 4756 | and \\[vc-apply-root-to-other-working-tree] prompt for confirmation | ||
| 4757 | when asked to move changes between working trees (i.e., when invoked | ||
| 4758 | with a prefix argument). This is because it can be surprising to have | ||
| 4759 | work disappear from your current working tree. You can customize this | ||
| 4760 | option to non-nil to skip the prompting." | ||
| 4761 | :type '(choice (const :tag "Prompt before moving changes" nil) | ||
| 4762 | (const :tag "Move changes without prompting" t)) | ||
| 4763 | :group 'vc | ||
| 4764 | :version "31.1") | ||
| 4765 | |||
| 4766 | (defun vc--apply-to-other-working-tree | ||
| 4767 | (directory mirror-dir fileset patch-string move) | ||
| 4768 | "Workhorse routine for copying/moving changes to other working trees. | ||
| 4769 | DIRECTORY is the root of the target working tree | ||
| 4770 | (used only for messages). | ||
| 4771 | MIRROR-DIR is the target directory for application. | ||
| 4772 | FILESET is the VC fileset from which to copy changes. | ||
| 4773 | PATCH-STRING non-nil overrides calling `vc-diff-internal' on FILESET to | ||
| 4774 | determine the changes to copy or move. | ||
| 4775 | MOVE non-nil means to move instead of copy." | ||
| 4776 | (unless (or (not move) | ||
| 4777 | vc-no-confirm-moving-changes | ||
| 4778 | (yes-or-no-p | ||
| 4779 | (format "Really %s uncommitted work out of this working tree?" | ||
| 4780 | (propertize "move" 'face 'bold)))) | ||
| 4781 | (user-error "Aborted")) | ||
| 4782 | (vc-buffer-sync-fileset fileset nil) | ||
| 4783 | (with-temp-buffer | ||
| 4784 | (if (not patch-string) | ||
| 4785 | (let ((display-buffer-overriding-action '(display-buffer-no-window | ||
| 4786 | (allow-no-window . t)))) | ||
| 4787 | (vc-diff-internal nil fileset nil nil nil (current-buffer))) | ||
| 4788 | (diff-mode) | ||
| 4789 | (insert patch-string)) | ||
| 4790 | (let ((default-directory mirror-dir)) | ||
| 4791 | (vc-buffer-sync-fileset (diff-vc-deduce-fileset) nil)) | ||
| 4792 | (when-let* (move | ||
| 4793 | (failed (diff-apply-buffer nil nil 'reverse 'test))) | ||
| 4794 | ;; If PATCH-STRING is non-nil and this fails, the user called us | ||
| 4795 | ;; from a `diff-mode' buffer that doesn't reverse-apply; that's | ||
| 4796 | ;; a `user-error'. | ||
| 4797 | ;; If PATCH-STRING is nil and this fails, `vc-diff-internal' | ||
| 4798 | ;; generated a nonsense diff -- not the user's fault. | ||
| 4799 | (funcall (if patch-string #'user-error #'error) | ||
| 4800 | (ngettext "%d hunk does not reverse-apply to this working tree" | ||
| 4801 | "%d hunks do not reverse-apply to this working tree" | ||
| 4802 | failed) | ||
| 4803 | failed)) | ||
| 4804 | (let ((default-directory mirror-dir)) | ||
| 4805 | (when-let* ((failed (diff-apply-buffer))) | ||
| 4806 | (user-error (ngettext "%d hunk does not apply to `%s'" | ||
| 4807 | "%d hunks do not apply to `%s'" | ||
| 4808 | failed) | ||
| 4809 | failed directory))) | ||
| 4810 | (when move | ||
| 4811 | (diff-apply-buffer nil nil 'reverse)) | ||
| 4812 | (message "Changes %s to `%s'" | ||
| 4813 | (if move "moved" "applied") directory))) | ||
| 4814 | |||
| 4664 | 4815 | ||
| 4665 | 4816 | ||
| 4666 | ;; These things should probably be generally available | 4817 | ;; These things should probably be generally available |