diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index a7119327df3..de2f9aa3848 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -2332,6 +2332,18 @@ Rebase may --autosquash your other squash!/fixup!/amend!; proceed?"))) (vc-git-command nil 0 nil "rebase" "--abort") (error "Merge conflicts while trying to delete %s; aborting" rev))) +(defun vc-git-delete-revisions-from-end (rev) + "Hard reset back to REV. +It is an error if REV is not on the current branch." + (vc-git--assert-revision-on-branch rev (vc-git--current-branch)) + (vc-git-command nil 0 nil "reset" "--hard" rev)) + +(defun vc-git-uncommit-revisions-from-end (rev) + "Soft reset back to REV. +It is an error if REV is not on the current branch." + (vc-git--assert-revision-on-branch rev (vc-git--current-branch)) + (vc-git-command nil 0 nil "reset" "--soft" rev)) + (defvar vc-git-extra-menu-map (let ((map (make-sparse-keymap))) (define-key map [git-grep] diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el index cf1653a9051..1beaf32e3d5 100644 --- a/lisp/vc/vc-hg.el +++ b/lisp/vc/vc-hg.el @@ -1906,6 +1906,35 @@ Always has to fetch, like `vc-hg-incoming-revision' does." rev))) (delete-file commands)))) +(defun vc-hg--assert-rev-on-current-branch (rev) + "Assert that REV is on the current branch." + (with-temp-buffer + (vc-hg-command t nil nil "log" "--limit=1" + (format "--rev=%s & ancestors(.)" rev) + "--template={node}") + (when (bobp) + (error "Revision %s is not on the current branch" rev)))) + +(defun vc-hg--reset-back-to (rev keep) + "Strip revisions up to but not including rev. +If KEEP is non-nil, also pass --keep to `hg strip'." + (apply #'vc-hg-command nil 0 nil "--config=extensions.strip=" + "strip" "--force" + (format "--rev=descendants(%s) & !%s" rev rev) + (and keep '("--keep")))) + +(defun vc-hg-delete-revisions-from-end (rev) + "Strip revisions up to but not including REV. +It is an error if REV is not on the current branch." + (vc-hg--assert-rev-on-current-branch rev) + (vc-hg--reset-back-to rev nil)) + +(defun vc-hg-uncommit-revisions-from-end (rev) + "Strip revisions up to but not including REV w/o modifying working tree. +It is an error if REV is not on the current branch." + (vc-hg--assert-rev-on-current-branch rev) + (vc-hg--reset-back-to rev t)) + (provide 'vc-hg) ;;; vc-hg.el ends here diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index c76511fac2f..4a505b2de19 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -408,6 +408,20 @@ ;; different; for example CVS has true undos (not yet implemented in ;; Emacs). A distributed VCS that implements this must also implement ;; revision-published-p. +;; +;; - delete-revisions-from-end (rev) +;; +;; Delete revisions from the revision history, from the end of the +;; branch up to but not including REV, including removing the changes +;; made by those revisions to the working tree. If there are +;; uncommitted changes the implementation should discard them. +;; +;; - uncommit-revisions-from-end (rev) +;; +;; Delete revisions from the revision history, from the end of the +;; branch up to but not including REV, but without removing the +;; changes made by those revisions from the working tree. +;; I.e., the working tree contents should not change. ;; HISTORY FUNCTIONS ;;