aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Whitton2025-10-02 21:48:31 +0100
committerSean Whitton2025-10-04 18:18:48 +0100
commit9ccef794a8ed55a8f96e68c0dd1e53cb07e85baa (patch)
tree696157861965573700492168da284d8efef68de0
parent5ee1e205e1663409c9d0a196bd9bbec9b36cf53a (diff)
downloademacs-9ccef794a8ed55a8f96e68c0dd1e53cb07e85baa.tar.gz
emacs-9ccef794a8ed55a8f96e68c0dd1e53cb07e85baa.zip
VC: New commands for cherry-picking (bug#79408)
* lisp/vc/diff-mode.el (diff-buffer-file-names): New function. * lisp/vc/log-view.el (vc--pick-or-revert) (vc--prompt-other-working-tree): Autoload. (vc-parent-buffer-name, vc-log-short-style) (vc-print-log-internal): Declare. (log-view--pick-or-revert): New function. (log-view-revision-cherry-pick, log-view-revision-revert): New commands. (log-view-mode-map, log-view-mode-menu): Bind them. * lisp/vc/vc-dispatcher.el (vc-start-logentry): If get-file-buffer returns nil, use the current buffer as the parent buffer. * lisp/vc/vc.el (diff-buffer-file-names, diff-reverse-direction): Declare. (vc--pick-or-revert): New function. (vc-revision-cherry-pick, vc-revision-revert): New commands. * lisp/vc/vc-hooks.el (vc-menu-map): Bind them. * doc/emacs/maintaining.texi (VC Change Log, VC Undo) (Copying Between Branches): * etc/NEWS: Document the new commands.
-rw-r--r--doc/emacs/emacs.texi9
-rw-r--r--doc/emacs/maintaining.texi81
-rw-r--r--etc/NEWS8
-rw-r--r--lisp/vc/diff-mode.el15
-rw-r--r--lisp/vc/log-view.el122
-rw-r--r--lisp/vc/vc-dispatcher.el10
-rw-r--r--lisp/vc/vc-hooks.el17
-rw-r--r--lisp/vc/vc.el126
8 files changed, 361 insertions, 27 deletions
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index b32c704bd12..7a5107ee359 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -857,10 +857,11 @@ VC Directory Mode
857 857
858Version Control Branches 858Version Control Branches
859 859
860* Switching Branches:: How to get to another existing branch. 860* Switching Branches:: How to get to another existing branch.
861* Pulling / Pushing:: Receiving/sending changes from/to elsewhere. 861* Pulling / Pushing:: Receiving/sending changes from/to elsewhere.
862* Merging:: Transferring changes between branches. 862* Merging:: Transferring changes between branches.
863* Creating Branches:: How to start a new branch. 863* Creating Branches:: How to start a new branch.
864* Copying Between Branches:: Copying the changes made by revisions.
864 865
865@ifnottex 866@ifnottex
866Miscellaneous Commands and Features of VC 867Miscellaneous Commands and Features of VC
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index e7a05a3556b..9d768cc1a77 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -1264,6 +1264,15 @@ Unmark the entry at point (@code{log-view-unmark-entry}).
1264 1264
1265@item U 1265@item U
1266Unmark all marked entries (@code{log-view-unmark-all-entries}). 1266Unmark all marked entries (@code{log-view-unmark-all-entries}).
1267
1268@item C
1269Copy changes to a currently checked out branch; either the changes from
1270the revision at point, or the changes from all marked revisions
1271(@code{log-view-revision-cherry-pick}).
1272
1273@item R
1274Undo the effects of old revisions; either the revision at point, or all
1275marked revisions (@code{log-view-revision-revert}).
1267@end table 1276@end table
1268 1277
1269@vindex vc-log-show-limit 1278@vindex vc-log-show-limit
@@ -1307,6 +1316,9 @@ also prompt for a specific VCS shell command to run for this purpose.
1307@item C-x v u 1316@item C-x v u
1308Revert the work file(s) in the current VC fileset to the last revision 1317Revert the work file(s) in the current VC fileset to the last revision
1309(@code{vc-revert}). 1318(@code{vc-revert}).
1319
1320@item M-x vc-revision-revert
1321Undo the effects of an older commit.
1310@end table 1322@end table
1311 1323
1312@kindex C-x v u 1324@kindex C-x v u
@@ -1330,6 +1342,21 @@ unlocked; you must lock again to resume editing. You can also use
1330@kbd{C-x v u} to unlock a file if you lock it and then decide not to 1342@kbd{C-x v u} to unlock a file if you lock it and then decide not to
1331change it. 1343change it.
1332 1344
1345@findex vc-revision-revert
1346@cindex reverting commits
1347 To discard changes that have already been committed, by yourself or
1348someone else, you can use @w{@kbd{M-x vc-revision-revert}}. This is
1349called @dfn{reverting} a commit. The command prompts for a revision to
1350revert, and then the VC backend reverts it. Most backends implement
1351this by making a new commit which undoes the changes made by the
1352revision.
1353
1354 An alternative way to access this functionality is to the
1355@code{log-view-revision-revert} command, bound to @kbd{R} in Log View
1356mode buffers (@pxref{VC Change Log}). Compared to using @w{@kbd{M-x
1357vc-revision revert}} directly, this can make it easier to be sure you
1358are reverting the revision you intend.
1359
1333@node VC Ignore 1360@node VC Ignore
1334@subsection Ignore Version Control Files 1361@subsection Ignore Version Control Files
1335 1362
@@ -1642,10 +1669,11 @@ supports checking out different branches and committing into new or
1642different branches. 1669different branches.
1643 1670
1644@menu 1671@menu
1645* Switching Branches:: How to get to another existing branch. 1672* Switching Branches:: How to get to another existing branch.
1646* Pulling / Pushing:: Receiving/sending changes from/to elsewhere. 1673* Pulling / Pushing:: Receiving/sending changes from/to elsewhere.
1647* Merging:: Transferring changes between branches. 1674* Merging:: Transferring changes between branches.
1648* Creating Branches:: How to start a new branch. 1675* Creating Branches:: How to start a new branch.
1676* Copying Between Branches:: Copying the changes made by revisions.
1649@end menu 1677@end menu
1650 1678
1651@node Switching Branches 1679@node Switching Branches
@@ -1857,6 +1885,51 @@ revision.
1857on that branch. To leave the branch, you must explicitly select a 1885on that branch. To leave the branch, you must explicitly select a
1858different revision with @kbd{C-u C-x v v}. 1886different revision with @kbd{C-u C-x v v}.
1859 1887
1888@node Copying Between Branches
1889@subsubsection Copying Changes Made By Revisions Between Branches
1890
1891@table @kbd
1892@item M-x vc-revision-cherry-pick
1893Copy a single revision to branch checked out in this working tree.
1894@end table
1895
1896@cindex cherry-pick
1897@cindex revision, cherry-picks of
1898 Sometimes it is useful to copy a revision from one branch to another.
1899This means creating a new revision with the same changes, log message
1900and authorship information as an existing revision that can be found on
1901another branch. This is often called @dfn{cherry-picking} the revision
1902from one branch to another.
1903
1904@cindex revisions, backporting
1905 The most common case is copying a revision from a branch that won't be
1906merged (@pxref{Merging}) into your current branch. For example, your
1907project might have a feature-frozen branch that accepts only bug fixes.
1908Someone (possibly you) fixes a bug on the main development branch. You
1909can then cherry-pick that revision onto the feature-frozen branch in
1910order to fix the bug there, too. This is called @dfn{backporting} the
1911revision, or backporting the fix.
1912
1913@findex vc-revision-cherry-pick
1914 You can use the command @kbd{M-x vc-revision-cherry-pick} to
1915cherry-pick revisions. It prompts for a revision to cherry-pick. It
1916then pops up a buffer for you to edit the log message for the new
1917revision. Normally the VC backend generates a log message including a
1918reference to the revision you want to copy, so that the copy can be
1919traced. If you wish, you can delete this reference before typing
1920@kbd{C-c C-c} to conclude the cherry-pick.
1921
1922 Alternatively you can invoke the command with a prefix argument,
1923i.e. @w{@kbd{C-u M-x vc-revision-cherry-pick}}. In this case the log
1924message from the source revision is used unmodified, and the cherry-pick
1925happens immediately, without popping up a buffer for log message edits.
1926
1927 An alternative way to access this functionality is the
1928@code{log-view-revision-cherry-pick} command, bound to @kbd{C} in Log
1929View mode buffers (@pxref{VC Change Log}). Compared to using
1930@w{@kbd{M-x vc-revision-cherry-pick}} directly, this can make it easier
1931to be sure you are cherry-picking the revision you intend.
1932
1860@ifnottex 1933@ifnottex
1861@include vc1-xtra.texi 1934@include vc1-xtra.texi
1862@end ifnottex 1935@end ifnottex
diff --git a/etc/NEWS b/etc/NEWS
index 8cabafd57cf..09497e499ab 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2227,6 +2227,14 @@ after VCS operations, the new mode is a more reliable way to ensure that
2227Emacs reverts buffers visiting tracked files when VCS operations change 2227Emacs reverts buffers visiting tracked files when VCS operations change
2228the contents of those files. 2228the contents of those files.
2229 2229
2230+++
2231*** New commands to cherry-pick and revert revisions.
2232The commands 'vc-revision-cherry-pick' and 'vc-revision-revert' let you
2233copy revisions between branches, and revert revisions.
2234From Log View buffers, you can use 'C' to cherry-pick the revision at
2235point or all marked revisions, and 'R' to revert the revision at point
2236or all marked revisions.
2237
2230*** New command 'log-edit-done-strip-cvs-lines'. 2238*** New command 'log-edit-done-strip-cvs-lines'.
2231This command strips all lines beginning with "CVS:" from the buffer. 2239This command strips all lines beginning with "CVS:" from the buffer.
2232It is intended to be added to the 'log-edit-done-hook' so that 2240It is intended to be added to the 'log-edit-done-hook' so that
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index f207f87811c..2fb552597fd 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -1175,6 +1175,21 @@ PREFIX is only used internally: don't use it."
1175 (cons (cons fs file) diff-remembered-files-alist))) 1175 (cons (cons fs file) diff-remembered-files-alist)))
1176 file))))))) 1176 file)))))))
1177 1177
1178(defun diff-buffer-file-names (&optional old noprompt)
1179 "Return file names corresponding to all of this buffer's hunks.
1180Optional arguments OLD and NOPROMPT are passed on to
1181`diff-find-file-name', which see."
1182 (save-excursion
1183 (cl-loop initially
1184 (goto-char (point-min))
1185 (ignore-errors (diff-file-next))
1186 when (and (looking-at diff-file-header-re)
1187 (diff-find-file-name old noprompt))
1188 collect it
1189 until (eq (prog1 (point)
1190 (ignore-errors (diff-file-next)))
1191 (point)))))
1192
1178 1193
1179(defun diff-ediff-patch () 1194(defun diff-ediff-patch ()
1180 "Call `ediff-patch-file' on the current buffer." 1195 "Call `ediff-patch-file' on the current buffer."
diff --git a/lisp/vc/log-view.el b/lisp/vc/log-view.el
index 68ce4f1baa5..0e2d506a23a 100644
--- a/lisp/vc/log-view.el
+++ b/lisp/vc/log-view.el
@@ -114,6 +114,8 @@
114(require 'log-edit) 114(require 'log-edit)
115(autoload 'vc-find-revision "vc") 115(autoload 'vc-find-revision "vc")
116(autoload 'vc-diff-internal "vc") 116(autoload 'vc-diff-internal "vc")
117(autoload 'vc--pick-or-revert "vc")
118(autoload 'vc--prompt-other-working-tree "vc")
117 119
118(defvar cvs-minor-wrap-function) 120(defvar cvs-minor-wrap-function)
119(defvar cvs-force-command) 121(defvar cvs-force-command)
@@ -138,7 +140,9 @@
138 "p" #'log-view-msg-prev 140 "p" #'log-view-msg-prev
139 "w" #'log-view-copy-revision-as-kill 141 "w" #'log-view-copy-revision-as-kill
140 "TAB" #'log-view-msg-next 142 "TAB" #'log-view-msg-next
141 "<backtab>" #'log-view-msg-prev) 143 "<backtab>" #'log-view-msg-prev
144 "C" #'log-view-revision-cherry-pick
145 "R" #'log-view-revision-revert)
142 146
143(easy-menu-define log-view-mode-menu log-view-mode-map 147(easy-menu-define log-view-mode-menu log-view-mode-map
144 "Log-View Display Menu." 148 "Log-View Display Menu."
@@ -161,6 +165,11 @@
161 ["Toggle Details at Point" log-view-toggle-entry-display 165 ["Toggle Details at Point" log-view-toggle-entry-display
162 :active log-view-expanded-log-entry-function] 166 :active log-view-expanded-log-entry-function]
163 "-----" 167 "-----"
168 ["Cherry-Pick Revision(s)" log-view-revision-cherry-pick
169 :help "Copy changes from revision(s) to a branch"]
170 ["Revert Revision(s)" log-view-revision-revert
171 :help "Undo the effects of old revision(s)"]
172 "-----"
164 ["Next Log Entry" log-view-msg-next 173 ["Next Log Entry" log-view-msg-next
165 :help "Go to the next count'th log message"] 174 :help "Go to the next count'th log message"]
166 ["Previous Log Entry" log-view-msg-prev 175 ["Previous Log Entry" log-view-msg-prev
@@ -686,9 +695,114 @@ If called interactively, annotate the version at point."
686 (log-view-current-tag) 695 (log-view-current-tag)
687 nil nil nil log-view-vc-backend))) 696 nil nil nil log-view-vc-backend)))
688 697
689;; 698;;;;
690;; diff 699;;;; Cherry-picks and reverts
691;; 700;;;;
701
702(defvar vc-parent-buffer-name)
703(defvar vc-log-short-style)
704(declare-function vc-print-log-internal "vc")
705
706(defun log-view--pick-or-revert (directory no-comment reverse)
707 "Copy changes from revision at point or all marked revisions.
708DIRECTORY is the destination, the root of the target working tree.
709NO-COMMENT non-nil means use the log messages of the revisions
710unmodified, instead of using the backend's default cherry-pick comment
711for that revision.
712NO-COMMENT non-nil with zero or one revisions marked also means don't
713prompt to edit the log message.
714REVERSE non-nil means to make commit(s) undoing the effects of the
715revisions, instead."
716 (let ((default-directory directory)
717 (marked (log-view-get-marked)))
718 (if (length> marked 1)
719 (progn
720 (save-excursion
721 (dolist (rev (if reverse (reverse marked) marked))
722 ;; Unmark each revision *before* copying it.
723 ;; Then if there is a conflict such that a cherry-pick
724 ;; fails, after resolving that conflict and committing the
725 ;; cherry-pick, the right revisions will be marked to
726 ;; resume the original multiple cherry-pick operation.
727 (log-view-goto-rev rev)
728 (log-view-unmark-entry 1)
729 (vc--pick-or-revert rev
730 reverse
731 (if no-comment
732 (vc-call-backend log-view-vc-backend
733 'get-change-comment
734 nil rev)
735 t)
736 nil
737 log-view-vc-backend)))
738 (when (vc-find-backend-function log-view-vc-backend
739 'modify-change-comment)
740 (let (vc-log-short-style)
741 (vc-print-log-internal log-view-vc-backend
742 (list default-directory)
743 nil nil (length marked)))
744 (setq-local vc-log-short-style nil ; For \\`g'.
745 vc-parent-buffer-name nil)
746 (message (substitute-command-keys "Use \
747\\[log-view-modify-change-comment] to modify any of these messages"))))
748 (let ((rev (or (car marked) (log-view-current-tag))))
749 (vc--pick-or-revert rev
750 reverse
751 (and no-comment
752 (vc-call-backend log-view-vc-backend
753 'get-change-comment
754 nil rev))
755 nil
756 log-view-vc-backend)))))
757
758(defun log-view-revision-cherry-pick (directory &optional no-comment)
759 "Copy changes from revision at point to current branch.
760If there are marked revisions, use those instead of the revision at point.
761
762When called interactively, prompts for the target working tree to which
763to copy the revision(s); the current working tree is the default choice.
764When called from Lisp, DIRECTORY is the root of the target working tree.
765
766When copying a single revision, prompts for editing the log message for
767the new commit, except with optional argument NO-COMMENT non-nil
768(interactively, with a prefix argument).
769When copying multiple revisions, never prompts to edit log messages.
770
771Normally a log message for each new commit is generated by the backend,
772including references to the source commits so that the copy can be
773traced. With optional argument NO-COMMENT non-nil (interactively, with
774a prefix argument), use the log messages from the source revisions
775unmodified.
776
777See also `vc-revision-cherry-pick'."
778 (interactive
779 (list (vc--prompt-other-working-tree log-view-vc-backend
780 "Cherry-pick to working tree"
781 'allow-empty)
782 current-prefix-arg))
783 (log-view--pick-or-revert directory no-comment nil))
784
785(defun log-view-revision-revert (directory)
786 "Undo the effects of the revision at point.
787When revisions are marked, undo the effects of each of them.
788When called interactively, prompts for the target working tree in which
789to revert; the current working tree is the default choice.
790When called from Lisp, DIRECTORY is the root of the target working tree.
791
792When reverting a single revision, prompts for editing the log message
793for the new commit.
794When reverting multiple revisions, never prompts to edit log messages.
795
796See also `vc-revision-revert'."
797 (interactive (list (vc--prompt-other-working-tree
798 (vc-responsible-backend default-directory)
799 "Revert in working tree"
800 'allow-empty)))
801 (log-view--pick-or-revert directory nil t))
802
803;;;;
804;;;; diff
805;;;;
692 806
693(defun log-view-diff (beg end) 807(defun log-view-diff (beg end)
694 "Get the diff between two revisions. 808 "Get the diff between two revisions.
diff --git a/lisp/vc/vc-dispatcher.el b/lisp/vc/vc-dispatcher.el
index c4ad148bdf1..78173786705 100644
--- a/lisp/vc/vc-dispatcher.el
+++ b/lisp/vc/vc-dispatcher.el
@@ -836,12 +836,10 @@ AFTER-HOOK specifies the local value for `vc-log-after-operation-hook'.
836BACKEND, if non-nil, specifies a VC backend for the Log Edit buffer. 836BACKEND, if non-nil, specifies a VC backend for the Log Edit buffer.
837PATCH-STRING is a patch to check in. 837PATCH-STRING is a patch to check in.
838DIFF-FUNCTION is `log-edit-diff-function' for the Log Edit buffer." 838DIFF-FUNCTION is `log-edit-diff-function' for the Log Edit buffer."
839 (let ((parent (if (and (length= files 1) 839 (let ((parent (or (and (length= files 1)
840 (not (vc-dispatcher-browsing))) 840 (not (vc-dispatcher-browsing))
841 (get-file-buffer (car files)) 841 (get-file-buffer (car files)))
842 (current-buffer)))) 842 (current-buffer))))
843 (unless parent
844 (error "Unable to determine VC parent buffer"))
845 (if (and comment (not initial-contents)) 843 (if (and comment (not initial-contents))
846 (set-buffer (get-buffer-create logbuf)) 844 (set-buffer (get-buffer-create logbuf))
847 (pop-to-buffer (get-buffer-create logbuf))) 845 (pop-to-buffer (get-buffer-create logbuf)))
diff --git a/lisp/vc/vc-hooks.el b/lisp/vc/vc-hooks.el
index 2972f139d06..48e84d6aee1 100644
--- a/lisp/vc/vc-hooks.el
+++ b/lisp/vc/vc-hooks.el
@@ -1010,11 +1010,16 @@ other commands receive global bindings where they had none before."
1010 1010
1011(defvar vc-menu-map 1011(defvar vc-menu-map
1012 (let ((map (make-sparse-keymap "Version Control"))) 1012 (let ((map (make-sparse-keymap "Version Control")))
1013 ;;(define-key map [show-files] 1013 (define-key map [vc-revision-revert]
1014 ;; '("Show Files under VC" . (vc-directory t))) 1014 '(menu-item "Revert Revision" vc-revision-revert
1015 :help "Undo the effects of a revision"))
1016 (define-key map [vc-revision-cherry-pick]
1017 '(menu-item "Cherry-Pick Revision" vc-revision-cherry-pick
1018 :help "Copy the changes from a single revision to this branch"))
1019 (define-key map [separator1] menu-bar-separator)
1015 (define-key map [vc-retrieve-tag] 1020 (define-key map [vc-retrieve-tag]
1016 '(menu-item "Retrieve Tag" vc-retrieve-tag 1021 '(menu-item "Retrieve Tag" vc-retrieve-tag
1017 :help "Retrieve tagged version or branch")) 1022 :help "Retrieve tagged version or branch"))
1018 (define-key map [vc-create-tag] 1023 (define-key map [vc-create-tag]
1019 '(menu-item "Create Tag" vc-create-tag 1024 '(menu-item "Create Tag" vc-create-tag
1020 :help "Create version tag")) 1025 :help "Create version tag"))
@@ -1027,7 +1032,7 @@ other commands receive global bindings where they had none before."
1027 (define-key map [vc-create-branch] 1032 (define-key map [vc-create-branch]
1028 '(menu-item "Create Branch..." vc-create-branch 1033 '(menu-item "Create Branch..." vc-create-branch
1029 :help "Make a new branch")) 1034 :help "Make a new branch"))
1030 (define-key map [separator1] menu-bar-separator) 1035 (define-key map [separator2] menu-bar-separator)
1031 (define-key map [vc-annotate] 1036 (define-key map [vc-annotate]
1032 '(menu-item "Annotate" vc-annotate 1037 '(menu-item "Annotate" vc-annotate
1033 :help "Display the edit history of the current file using colors")) 1038 :help "Display the edit history of the current file using colors"))
@@ -1058,7 +1063,7 @@ other commands receive global bindings where they had none before."
1058 (define-key map [vc-print-root-log] 1063 (define-key map [vc-print-root-log]
1059 '(menu-item "Show Top of the Tree History " vc-print-root-log 1064 '(menu-item "Show Top of the Tree History " vc-print-root-log
1060 :help "List the change log for the current tree in a window")) 1065 :help "List the change log for the current tree in a window"))
1061 (define-key map [separator2] menu-bar-separator) 1066 (define-key map [separator3] menu-bar-separator)
1062 (define-key map [vc-insert-header] 1067 (define-key map [vc-insert-header]
1063 '(menu-item "Insert Header" vc-insert-headers 1068 '(menu-item "Insert Header" vc-insert-headers
1064 :help "Insert headers into a file for use with a version control system.")) 1069 :help "Insert headers into a file for use with a version control system."))
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index 55606f29bea..7c28e4092dd 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -2006,9 +2006,15 @@ Type \\[vc-next-action] to check in changes.")
2006 (files backend &optional comment initial-contents rev patch-string register) 2006 (files backend &optional comment initial-contents rev patch-string register)
2007 "Check in FILES. 2007 "Check in FILES.
2008 2008
2009COMMENT is a comment string; if omitted, a buffer is popped up to accept 2009There are three calling conventions for the COMMENT and INITIAL-CONTENTS
2010a comment. If INITIAL-CONTENTS is non-nil, then COMMENT is used as the 2010optional arguments:
2011initial contents of the log entry buffer. 2011- COMMENT a string, INITIAL-CONTENTS nil means use that comment string
2012 without prompting the user to edit it.
2013- COMMENT a string, INITIAL-CONTENTS non-nil means use that comment
2014 string as the initial contents of the log entry buffer but stop for
2015 editing.
2016- COMMENT t means check in immediately with an empty comment, and ignore
2017 INITIAL-CONTENTS.
2012 2018
2013The optional argument REV may be a string specifying the new revision 2019The optional argument REV may be a string specifying the new revision
2014level (only supported for some older VCSes, like RCS and CVS). 2020level (only supported for some older VCSes, like RCS and CVS).
@@ -2105,6 +2111,120 @@ have changed; continue with old fileset?" (current-buffer))))
2105 backend 2111 backend
2106 patch-string))) 2112 patch-string)))
2107 2113
2114(declare-function diff-buffer-file-names "diff-mode")
2115(declare-function diff-reverse-direction "diff-mode")
2116
2117(defun vc--pick-or-revert (rev reverse comment initial-contents backend)
2118 "Copy a single revision REV to branch checked out in this working tree.
2119REVERSE means to undo the effects of REV, instead.
2120COMMENT is a comment string; if omitted, a buffer is popped up to accept
2121a comment. If INITIAL-CONTENTS is non-nil, then COMMENT is used as the
2122initial contents of the log entry buffer. If COMMENT is t then use
2123BACKEND's default cherry-pick comment for REV without prompting.
2124BACKEND is the VC backend to use."
2125 (let* ((backend (or backend (vc-responsible-backend default-directory)))
2126 ;; `vc-*-prepare-patch' will always give us a patch with file
2127 ;; names relative to the VC root, so switch to there now.
2128 ;; In particular this is needed for `diff-buffer-file-names' to
2129 ;; work properly.
2130 (default-directory (vc-call-backend backend 'root default-directory))
2131 (patch (vc-call-backend backend 'prepare-patch rev))
2132 files whole-patch-string diff-patch-string)
2133 (with-current-buffer (plist-get patch :buffer)
2134 (diff-mode)
2135 (with-restriction
2136 (or (plist-get patch :patch-start) (point-min))
2137 (or (plist-get patch :patch-end) (point-max))
2138 (when reverse
2139 (diff-reverse-direction (point-min) (point-max)))
2140 (setq files (diff-buffer-file-names nil t)
2141 diff-patch-string (buffer-string)))
2142 ;; In the case of reverting we mustn't copy the original
2143 ;; authorship information. The author of the revert is the
2144 ;; current user, and its timestamp is now.
2145 (setq whole-patch-string
2146 (if reverse diff-patch-string (buffer-string))))
2147 (unless (stringp comment)
2148 (cl-psetq comment (vc-call-backend backend 'cherry-pick-comment
2149 files rev reverse)
2150 initial-contents (not (eq comment t))))
2151 (vc-start-logentry files comment initial-contents
2152 (format "Edit log message for %s revision."
2153 (if reverse
2154 "new"
2155 ;; ^ "reverted revision" would mean
2156 ;; REV, not the revision we are about
2157 ;; to create. We could use
2158 ;; "reverting revision" but it reads
2159 ;; oddly.
2160 "copied"))
2161 "*vc-cherry-pick*"
2162 (lambda ()
2163 (vc-call-backend backend 'log-edit-mode))
2164 (lambda (_files comment)
2165 (vc-call-backend backend 'checkin-patch
2166 whole-patch-string comment))
2167 nil
2168 backend
2169 diff-patch-string)))
2170
2171;; No bindings in `vc-prefix-map' for the following two commands because
2172;; we expect users will usually use `log-view-revision-cherry-pick' and
2173;; `log-view-revision-revert', which do have bindings.
2174
2175;;;###autoload
2176(defun vc-revision-cherry-pick (rev &optional comment initial-contents backend)
2177 "Copy the changes from a single revision REV to the current branch.
2178When called interactively, prompts for REV.
2179Typically REV is a revision from another branch, where that branch is
2180one that will not be merged into the branch checked out in this working
2181tree.
2182
2183Normally a log message for the new commit is generated by the backend
2184and includes a reference to REV so that the copy can be traced.
2185When called interactively with a prefix argument, use REV's log message
2186unmodified, and also skip editing it.
2187
2188When called from Lisp, there are three calling conventions for the
2189COMMENT and INITIAL-CONTENTS optional arguments:
2190- COMMENT a string, INITIAL-CONTENTS nil means use that comment string
2191 without prompting the user to edit it.
2192- COMMENT a string, INITIAL-CONTENTS non-nil means use that comment
2193 string as the initial contents of the log entry buffer but stop for
2194 editing.
2195- COMMENT t means use BACKEND's default cherry-pick comment for REV
2196 without prompting for editing, and ignore INITIAL-CONTENTS.
2197
2198Optional argument BACKEND is the VC backend to use."
2199 (interactive (let ((rev (vc-read-revision "Revision to copy: "))
2200 (backend (vc-responsible-backend default-directory)))
2201 (list rev
2202 (and current-prefix-arg
2203 (vc-call-backend backend 'get-change-comment
2204 nil rev))
2205 nil
2206 backend)))
2207 (vc--pick-or-revert rev nil comment initial-contents backend))
2208
2209;;;###autoload
2210(defun vc-revision-revert (rev &optional comment initial-contents backend)
2211 "Undo the effects of revision REV.
2212When called interactively, prompts for REV.
2213
2214When called from Lisp, there are three calling conventions for the
2215COMMENT and INITIAL-CONTENTS optional arguments:
2216- COMMENT a string, INITIAL-CONTENTS nil means use that comment string
2217 without prompting the user to edit it.
2218- COMMENT a string, INITIAL-CONTENTS non-nil means use that comment
2219 string as the initial contents of the log entry buffer but stop for
2220 editing.
2221- COMMENT t means use BACKEND's default revert comment for REV without
2222 prompting for editing, and ignore INITIAL-CONTENTS.
2223
2224Optional argument BACKEND is the VC backend to use."
2225 (interactive (list (vc-read-revision "Revision to revert: ")))
2226 (vc--pick-or-revert rev t comment initial-contents backend))
2227
2108(declare-function diff-bounds-of-hunk "diff-mode") 2228(declare-function diff-bounds-of-hunk "diff-mode")
2109 2229
2110(defun vc-default-checkin-patch (_backend patch-string comment) 2230(defun vc-default-checkin-patch (_backend patch-string comment)