Subject: Re: bug#38044: 27.0.50; There should be an easier way to look at a specific vc commit

From: Juri Linkov <[email-masked]>
Date: Wed, 20 Nov 2019 23:50:00 +0200

>> > Stepping a notch back, wasn't the original request to have a command
>> > that would display a specific commit?  If so, that's not a "log"
>> > command, that's closer to a "diff" command.  And don't we already have
>> > a "diff" command which shows diffs for a specific revision?
>>
>> Then we could use something like the existing backend 'region-history'
>> that for vc-git uses 'git log', but displays both the log and diff
>> in one output buffer.
>
> region-history is slow, so I'm not sure it is a good starting point
> for this feature.  A diff command is usually very fats with every VCS.

It doesn't use 'region-history'.  I meant using 'region-history-mode'
on the output buffer.  Everything works perfectly with this patch
that also implements defaulting to the revision under point and
prompting for the directory like Lars asked to do:

diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index 0d29c80d02..fedc30e932 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -359,6 +359,10 @@
 ;;   and make sure it is displayed in the buffer's window.  The default
 ;;   implementation of this function works for RCS-style logs.
 ;;
+;; - print-revision (revision)
+;;
+;;   Show details of REVISION.
+;;
 ;; - comment-history (file)
 ;;
 ;;   Return a string containing all log entries that were made for FILE.
@@ -2516,6 +2520,31 @@ vc-print-branch-log
                          (list default-directory) branch t
                          (when (> vc-log-show-limit 0) vc-log-show-limit)))
 
+;;;###autoload
+(defun vc-print-revision (revision)
+  "Show the details of the revision REVISION."
+  (interactive (list (unless current-prefix-arg
+                       (let ((default (thing-at-point 'word)))
+                         (vc-read-revision
+                          (if default
+                              (format "Revision to show (default %s): " default)
+                            "Revision to show: ")
+                          nil nil default)))))
+  (when (equal revision "")
+    (error "No revision specified"))
+  (let ((backend (vc-deduce-backend))
+        rootdir)
+    (if backend
+        (setq rootdir (vc-call-backend backend 'root default-directory))
+      (setq rootdir (read-directory-name "Directory for VC print-revision: "))
+      (setq backend (vc-responsible-backend rootdir))
+      (unless backend
+        (error "Directory is not version controlled")))
+    (setq default-directory rootdir)
+    (vc-incoming-outgoing-internal backend revision
+                                   "*vc-revision*" 'print-revision)
+    (vc-call-backend backend 'region-history-mode)))
+
 ;;;###autoload
 (defun vc-log-incoming (&optional remote-location)
   "Show a log of changes that will be received with a pull operation from REMOTE-LOCATION.
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 5ab8e7ec53..a330adaa52 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -80,6 +80,7 @@
 ;; - log-search (buffer pattern)                   OK
 ;; - log-view-mode ()                              OK
 ;; - show-log-entry (revision)                     OK
+;; - print-revision (revision)                     OK
 ;; - comment-history (file)                        ??
 ;; - update-changelog (files)                      COULD BE SUPPORTED
 ;; * diff (file &optional rev1 rev2 buffer async)  OK
@@ -1163,6 +1164,22 @@ vc-git-print-log
                     (list start-revision)))
 		'("--")))))))
 
+(defun vc-git-print-revision (buffer revision)
+  "Show the details of REVISION with output in BUFFER.
+With a prefix argument, ask for a command to run that will output
+the revision information."
+  (let ((args `("show" "--no-color" ,(or revision ""))))
+    (when current-prefix-arg
+      (setq args (cdr (split-string
+		       (read-shell-command
+                        "Show revision with command: "
+                        (format "%s %s" vc-git-program
+                                (mapconcat 'identity args " "))
+                        'vc-git-history)
+		       " " t))))
+    (vc-setup-buffer buffer)
+    (apply 'vc-git-command buffer 'async nil args)))
+
 (defun vc-git-log-outgoing (buffer remote-location)
   (vc-setup-buffer buffer)
   (vc-git-command
@@ -1226,7 +1243,7 @@ vc-git-log-view-mode
   (set (make-local-variable 'log-view-file-re) regexp-unmatchable)
   (set (make-local-variable 'log-view-per-file-logs) nil)
   (set (make-local-variable 'log-view-message-re)
-       (if (not (memq vc-log-view-type '(long log-search)))
+       (if (not (memq vc-log-view-type '(long log-search print-revision)))
 	   (cadr vc-git-root-log-format)
 	 "^commit *\\([0-9a-z]+\\)"))
   ;; Allow expanding short log entries.
@@ -1235,7 +1252,7 @@ vc-git-log-view-mode
     (set (make-local-variable 'log-view-expanded-log-entry-function)
 	 'vc-git-expanded-log-entry))
   (set (make-local-variable 'log-view-font-lock-keywords)
-       (if (not (memq vc-log-view-type '(long log-search)))
+       (if (not (memq vc-log-view-type '(long log-search print-revision)))
 	   (list (cons (nth 1 vc-git-root-log-format)
 		       (nth 2 vc-git-root-log-format)))
 	 (append