diff options
| author | Sean Whitton | 2025-10-02 21:48:31 +0100 |
|---|---|---|
| committer | Sean Whitton | 2025-10-04 18:18:48 +0100 |
| commit | 9ccef794a8ed55a8f96e68c0dd1e53cb07e85baa (patch) | |
| tree | 696157861965573700492168da284d8efef68de0 | |
| parent | 5ee1e205e1663409c9d0a196bd9bbec9b36cf53a (diff) | |
| download | emacs-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.texi | 9 | ||||
| -rw-r--r-- | doc/emacs/maintaining.texi | 81 | ||||
| -rw-r--r-- | etc/NEWS | 8 | ||||
| -rw-r--r-- | lisp/vc/diff-mode.el | 15 | ||||
| -rw-r--r-- | lisp/vc/log-view.el | 122 | ||||
| -rw-r--r-- | lisp/vc/vc-dispatcher.el | 10 | ||||
| -rw-r--r-- | lisp/vc/vc-hooks.el | 17 | ||||
| -rw-r--r-- | lisp/vc/vc.el | 126 |
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 | ||
| 858 | Version Control Branches | 858 | Version 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 |
| 866 | Miscellaneous Commands and Features of VC | 867 | Miscellaneous 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 |
| 1266 | Unmark all marked entries (@code{log-view-unmark-all-entries}). | 1266 | Unmark all marked entries (@code{log-view-unmark-all-entries}). |
| 1267 | |||
| 1268 | @item C | ||
| 1269 | Copy changes to a currently checked out branch; either the changes from | ||
| 1270 | the revision at point, or the changes from all marked revisions | ||
| 1271 | (@code{log-view-revision-cherry-pick}). | ||
| 1272 | |||
| 1273 | @item R | ||
| 1274 | Undo the effects of old revisions; either the revision at point, or all | ||
| 1275 | marked 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 |
| 1308 | Revert the work file(s) in the current VC fileset to the last revision | 1317 | Revert 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 | ||
| 1321 | Undo 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 |
| 1331 | change it. | 1343 | change it. |
| 1332 | 1344 | ||
| 1345 | @findex vc-revision-revert | ||
| 1346 | @cindex reverting commits | ||
| 1347 | To discard changes that have already been committed, by yourself or | ||
| 1348 | someone else, you can use @w{@kbd{M-x vc-revision-revert}}. This is | ||
| 1349 | called @dfn{reverting} a commit. The command prompts for a revision to | ||
| 1350 | revert, and then the VC backend reverts it. Most backends implement | ||
| 1351 | this by making a new commit which undoes the changes made by the | ||
| 1352 | revision. | ||
| 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 | ||
| 1356 | mode buffers (@pxref{VC Change Log}). Compared to using @w{@kbd{M-x | ||
| 1357 | vc-revision revert}} directly, this can make it easier to be sure you | ||
| 1358 | are 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 | |||
| 1642 | different branches. | 1669 | different 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. | |||
| 1857 | on that branch. To leave the branch, you must explicitly select a | 1885 | on that branch. To leave the branch, you must explicitly select a |
| 1858 | different revision with @kbd{C-u C-x v v}. | 1886 | different 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 | ||
| 1893 | Copy 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. | ||
| 1899 | This means creating a new revision with the same changes, log message | ||
| 1900 | and authorship information as an existing revision that can be found on | ||
| 1901 | another branch. This is often called @dfn{cherry-picking} the revision | ||
| 1902 | from 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 | ||
| 1906 | merged (@pxref{Merging}) into your current branch. For example, your | ||
| 1907 | project might have a feature-frozen branch that accepts only bug fixes. | ||
| 1908 | Someone (possibly you) fixes a bug on the main development branch. You | ||
| 1909 | can then cherry-pick that revision onto the feature-frozen branch in | ||
| 1910 | order to fix the bug there, too. This is called @dfn{backporting} the | ||
| 1911 | revision, 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 | ||
| 1915 | cherry-pick revisions. It prompts for a revision to cherry-pick. It | ||
| 1916 | then pops up a buffer for you to edit the log message for the new | ||
| 1917 | revision. Normally the VC backend generates a log message including a | ||
| 1918 | reference to the revision you want to copy, so that the copy can be | ||
| 1919 | traced. 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, | ||
| 1923 | i.e. @w{@kbd{C-u M-x vc-revision-cherry-pick}}. In this case the log | ||
| 1924 | message from the source revision is used unmodified, and the cherry-pick | ||
| 1925 | happens 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 | ||
| 1929 | View mode buffers (@pxref{VC Change Log}). Compared to using | ||
| 1930 | @w{@kbd{M-x vc-revision-cherry-pick}} directly, this can make it easier | ||
| 1931 | to 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 |
| @@ -2227,6 +2227,14 @@ after VCS operations, the new mode is a more reliable way to ensure that | |||
| 2227 | Emacs reverts buffers visiting tracked files when VCS operations change | 2227 | Emacs reverts buffers visiting tracked files when VCS operations change |
| 2228 | the contents of those files. | 2228 | the contents of those files. |
| 2229 | 2229 | ||
| 2230 | +++ | ||
| 2231 | *** New commands to cherry-pick and revert revisions. | ||
| 2232 | The commands 'vc-revision-cherry-pick' and 'vc-revision-revert' let you | ||
| 2233 | copy revisions between branches, and revert revisions. | ||
| 2234 | From Log View buffers, you can use 'C' to cherry-pick the revision at | ||
| 2235 | point or all marked revisions, and 'R' to revert the revision at point | ||
| 2236 | or all marked revisions. | ||
| 2237 | |||
| 2230 | *** New command 'log-edit-done-strip-cvs-lines'. | 2238 | *** New command 'log-edit-done-strip-cvs-lines'. |
| 2231 | This command strips all lines beginning with "CVS:" from the buffer. | 2239 | This command strips all lines beginning with "CVS:" from the buffer. |
| 2232 | It is intended to be added to the 'log-edit-done-hook' so that | 2240 | It 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. | ||
| 1180 | Optional 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. | ||
| 708 | DIRECTORY is the destination, the root of the target working tree. | ||
| 709 | NO-COMMENT non-nil means use the log messages of the revisions | ||
| 710 | unmodified, instead of using the backend's default cherry-pick comment | ||
| 711 | for that revision. | ||
| 712 | NO-COMMENT non-nil with zero or one revisions marked also means don't | ||
| 713 | prompt to edit the log message. | ||
| 714 | REVERSE non-nil means to make commit(s) undoing the effects of the | ||
| 715 | revisions, 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. | ||
| 760 | If there are marked revisions, use those instead of the revision at point. | ||
| 761 | |||
| 762 | When called interactively, prompts for the target working tree to which | ||
| 763 | to copy the revision(s); the current working tree is the default choice. | ||
| 764 | When called from Lisp, DIRECTORY is the root of the target working tree. | ||
| 765 | |||
| 766 | When copying a single revision, prompts for editing the log message for | ||
| 767 | the new commit, except with optional argument NO-COMMENT non-nil | ||
| 768 | (interactively, with a prefix argument). | ||
| 769 | When copying multiple revisions, never prompts to edit log messages. | ||
| 770 | |||
| 771 | Normally a log message for each new commit is generated by the backend, | ||
| 772 | including references to the source commits so that the copy can be | ||
| 773 | traced. With optional argument NO-COMMENT non-nil (interactively, with | ||
| 774 | a prefix argument), use the log messages from the source revisions | ||
| 775 | unmodified. | ||
| 776 | |||
| 777 | See 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. | ||
| 787 | When revisions are marked, undo the effects of each of them. | ||
| 788 | When called interactively, prompts for the target working tree in which | ||
| 789 | to revert; the current working tree is the default choice. | ||
| 790 | When called from Lisp, DIRECTORY is the root of the target working tree. | ||
| 791 | |||
| 792 | When reverting a single revision, prompts for editing the log message | ||
| 793 | for the new commit. | ||
| 794 | When reverting multiple revisions, never prompts to edit log messages. | ||
| 795 | |||
| 796 | See 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'. | |||
| 836 | BACKEND, if non-nil, specifies a VC backend for the Log Edit buffer. | 836 | BACKEND, if non-nil, specifies a VC backend for the Log Edit buffer. |
| 837 | PATCH-STRING is a patch to check in. | 837 | PATCH-STRING is a patch to check in. |
| 838 | DIFF-FUNCTION is `log-edit-diff-function' for the Log Edit buffer." | 838 | DIFF-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 | ||
| 2009 | COMMENT is a comment string; if omitted, a buffer is popped up to accept | 2009 | There are three calling conventions for the COMMENT and INITIAL-CONTENTS |
| 2010 | a comment. If INITIAL-CONTENTS is non-nil, then COMMENT is used as the | 2010 | optional arguments: |
| 2011 | initial 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 | ||
| 2013 | The optional argument REV may be a string specifying the new revision | 2019 | The optional argument REV may be a string specifying the new revision |
| 2014 | level (only supported for some older VCSes, like RCS and CVS). | 2020 | level (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. | ||
| 2119 | REVERSE means to undo the effects of REV, instead. | ||
| 2120 | COMMENT is a comment string; if omitted, a buffer is popped up to accept | ||
| 2121 | a comment. If INITIAL-CONTENTS is non-nil, then COMMENT is used as the | ||
| 2122 | initial contents of the log entry buffer. If COMMENT is t then use | ||
| 2123 | BACKEND's default cherry-pick comment for REV without prompting. | ||
| 2124 | BACKEND 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. | ||
| 2178 | When called interactively, prompts for REV. | ||
| 2179 | Typically REV is a revision from another branch, where that branch is | ||
| 2180 | one that will not be merged into the branch checked out in this working | ||
| 2181 | tree. | ||
| 2182 | |||
| 2183 | Normally a log message for the new commit is generated by the backend | ||
| 2184 | and includes a reference to REV so that the copy can be traced. | ||
| 2185 | When called interactively with a prefix argument, use REV's log message | ||
| 2186 | unmodified, and also skip editing it. | ||
| 2187 | |||
| 2188 | When called from Lisp, there are three calling conventions for the | ||
| 2189 | COMMENT 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 | |||
| 2198 | Optional 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. | ||
| 2212 | When called interactively, prompts for REV. | ||
| 2213 | |||
| 2214 | When called from Lisp, there are three calling conventions for the | ||
| 2215 | COMMENT 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 | |||
| 2224 | Optional 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) |