Function: vc--pick-or-revert
vc--pick-or-revert is a byte-compiled function defined in vc.el.gz.
Signature
(vc--pick-or-revert REV REVERSE INTERACTIVE DELETE COMMENT INITIAL-CONTENTS BACKEND)
Documentation
Copy a single revision REV to branch checked out in this working tree.
REVERSE non-nil means to undo the effects of REV, instead.
This is affected by whether the VCS is centralized or distributed and
the INTERACTIVE and DELETE arguments, as follows:
- For a centralized VCS for which Emacs knows how to do true undos, then
unless DELETE is the special value never, do a true undo of REV.
This function supports creating new commits undoing the effects of REV
for even a centralized VCS with true undos by passing never as
DELETE (as vc-revert-revision does).
For centralized VCS, INTERACTIVE is ignored.
- For a distributed VCS, when INTERACTIVE is non-nil, DELETE is nil, and
REV has not yet been pushed, offer to delete REV entirely instead of
creating a new commit undoing its EFFECTS.
If INTERACTIVE is no-confirm, don't prompt to confirm the deletion.
- For a distributed VCS, when DELETE is non-nil (but not never), only
consider deleting REV, never create a new commit, but subject to
vc-allow-rewriting-published-history.
In this case INTERACTIVE is ignored.
(This complex calling convention makes for simple usage of this
workhorse function from the frontend VC commands that provide access to
all this functionality.)
COMMENT is a comment string; if omitted, a buffer is popped up to accept a comment. If INITIAL-CONTENTS is non-nil, then COMMENT is used as the initial contents of the log entry buffer. If COMMENT is t then use BACKEND's default cherry-pick comment for REV without prompting. BACKEND is the VC backend to use.
Return deleted if we actually undid/deleted a commit.
Any other return value means we called vc-start-logentry.
Source Code
;; Defined in /usr/src/emacs/lisp/vc/vc.el.gz
(defun vc--pick-or-revert
(rev reverse interactive delete comment initial-contents backend)
"Copy a single revision REV to branch checked out in this working tree.
REVERSE non-nil means to undo the effects of REV, instead.
This is affected by whether the VCS is centralized or distributed and
the INTERACTIVE and DELETE arguments, as follows:
- For a centralized VCS for which Emacs knows how to do true undos, then
unless DELETE is the special value `never', do a true undo of REV.
This function supports creating new commits undoing the effects of REV
for even a centralized VCS with true undos by passing `never' as
DELETE (as `vc-revert-revision' does).
For centralized VCS, INTERACTIVE is ignored.
- For a distributed VCS, when INTERACTIVE is non-nil, DELETE is nil, and
REV has not yet been pushed, offer to delete REV entirely instead of
creating a new commit undoing its EFFECTS.
If INTERACTIVE is `no-confirm', don't prompt to confirm the deletion.
- For a distributed VCS, when DELETE is non-nil (but not `never'), only
consider deleting REV, never create a new commit, but subject to
`vc-allow-rewriting-published-history'.
In this case INTERACTIVE is ignored.
(This complex calling convention makes for simple usage of this
workhorse function from the frontend VC commands that provide access to
all this functionality.)
COMMENT is a comment string; if omitted, a buffer is popped up to accept
a comment. If INITIAL-CONTENTS is non-nil, then COMMENT is used as the
initial contents of the log entry buffer. If COMMENT is t then use
BACKEND's default cherry-pick comment for REV without prompting.
BACKEND is the VC backend to use.
Return `deleted' if we actually undid/deleted a commit.
Any other return value means we called `vc-start-logentry'."
(cond*
((bind* (backend (or backend
(vc-responsible-backend default-directory)))))
((and reverse (not (eq delete 'never))
(null (vc-find-backend-function backend
'revision-published-p))
(vc-find-backend-function backend 'delete-revision))
;; Centralized VCS implementing `delete-revision'.
(vc-call-backend backend 'delete-revision rev)
'deleted)
((and reverse interactive (not delete)
;; Distributed VCS for which we can do deletions.
(vc-find-backend-function backend 'revision-published-p)
(vc-find-backend-function backend 'delete-revision)
;; REV is safe to delete.
(not (vc-call-backend backend 'revision-published-p rev)))
;; Require confirmation, because the commit is unpublished, and so
;; this might be the only copy of the work in REV. Don't fall back
;; to making a new commit undoing REV's changes because we don't
;; know the user wants that just because they said "no" to our
;; question here, and we want to avoid two y/n prompts in a row,
;; which is probably a less good UI than this.
(cond ((or (eq interactive 'no-confirm)
(yes-or-no-p
(format "Permanently delete %s from the revision history?"
rev)))
(vc-call-backend backend 'delete-revision rev)
'deleted)
((derived-mode-p 'log-view-mode)
(user-error (substitute-command-keys "\
Use \\[log-view-revert-revisions] to create new commits \
undoing changes made by revision(s)")))
(t
(user-error (substitute-command-keys "\
Use \\[vc-revert-revision] to create a new commit undoing %s's changes")
rev))))
((and reverse delete (not (eq delete 'never))
;; Distributed VCS for which we can do deletions.
(vc-find-backend-function backend 'revision-published-p)
(vc-find-backend-function backend 'delete-revision))
;; Even though the user has explicitly requested deletion with a
;; prefix argument / invoking `vc-delete-revision' / invoking
;; `log-view-delete-revisions', by default we still confirm such a
;; destructive operation.
;; However, we want to avoid prompting twice in the case that the
;; user has set `vc-allow-rewriting-published-history' to `ask', and
;; we should avoid prompting at all in the case that
;; `vc-allow-rewriting-published-history' is another non-nil value.
;; These requirements lead to the nested `cond*' form here.
(cond*
((and vc-allow-rewriting-published-history
(not (eq vc-allow-rewriting-published-history 'ask)))
(vc-call-backend backend 'delete-revision rev)
'deleted)
((bind* (published (vc-call-backend backend 'revision-published-p rev))))
((and published
(eq vc-allow-rewriting-published-history 'ask)
(yes-or-no-p
(format "Revision %s appears published; allow rewriting history?"
rev)))
(vc-call-backend backend 'delete-revision rev)
'deleted)
(published
(user-error "Will not rewrite likely-public history"))
((yes-or-no-p
(format "Permanently delete %s from the revision history?"
rev))
(vc-call-backend backend 'delete-revision rev)
'deleted)
(t
(user-error "Aborted"))))
;; If we get this far we give up on `delete-revision', i.e. we fall
;; back to creating a commit undoing the effects of REV.
;;
;; `vc-*-prepare-patch' will always give us a patch with file names
;; relative to the VC root, so switch to there now. In particular
;; this is needed for `diff-buffer-file-names' to work properly.
((bind* (default-directory (vc-call-backend backend 'root
default-directory))
(patch (vc-call-backend backend 'prepare-patch rev))
files whole-patch-string diff-patch-string))
(t
(with-current-buffer (plist-get patch :buffer)
(diff-mode)
(with-restriction
(or (plist-get patch :patch-start) (point-min))
(or (plist-get patch :patch-end) (point-max))
(when reverse
(diff-reverse-direction (point-min) (point-max)))
(setq files (diff-buffer-file-names nil t)
diff-patch-string (buffer-string)))
;; In the case of reverting we mustn't copy the original
;; authorship information. The author of the revert is the
;; current user, and its timestamp is now.
(setq whole-patch-string
(if reverse diff-patch-string (buffer-string))))
(unless (stringp comment)
(cl-psetq comment (vc-call-backend backend 'cherry-pick-comment
files rev reverse)
initial-contents (not (eq comment t))))
(vc-start-logentry files comment initial-contents
(format "Edit log message for %s revision."
(if reverse
"new"
;; ^ "reverted revision" would mean
;; REV, not the revision we are about
;; to create. We could use
;; "reverting revision" but it reads
;; oddly.
"copied"))
"*vc-cherry-pick*"
(lambda ()
(vc-call-backend backend 'log-edit-mode))
(lambda (_files comment)
(vc-call-backend backend 'checkin-patch
whole-patch-string comment))
nil
backend
diff-patch-string))))