Subject: bug#20608: 25.0.50; vc-git-log-view-mode inserts "Show 2X entries" at bob when interrupted

From: Dmitry Gutov <[email-masked]>
Date: Tue, 19 May 2015 14:43:31 +0300

Tags: patch

1. Visit lisp/vc/vc-dispatcher.el (the important part being that it's a
file with long history).

2. Press C-x v l, see the print-log buffer pop up, with [waiting ...].

3. Press g before the process finishes running.

See the window shrink and "Show 2X entries    Show unlimited entries"
appear at the top (it will also get added at the bottom when the process
finishes).

It seems like a general problem, to be fixed either in vc-do-command (by
unsetting the process sentinel before deleting the process), or in
vc--process-sentinel. Here's the patch for the second option:

diff --git a/lisp/vc/vc-dispatcher.el b/lisp/vc/vc-dispatcher.el
index a2c1cba..d6b50b7 100644
--- a/lisp/vc/vc-dispatcher.el
+++ b/lisp/vc/vc-dispatcher.el
@@ -183,35 +183,36 @@ Another is that undo information is not kept."
 (defvar vc-sentinel-movepoint)          ;Dynamically scoped.
 
 (defun vc--process-sentinel (p code)
-  (let ((buf (process-buffer p)))
+  (let ((buf (process-buffer p))
+        (status (process-status p)))
     ;; Impatient users sometime kill "slow" buffers; check liveness
     ;; to avoid "error in process sentinel: Selecting deleted buffer".
     (when (buffer-live-p buf)
       (with-current-buffer buf
         (setq mode-line-process
-              (let ((status (process-status p)))
-                ;; Leave mode-line uncluttered, normally.
-                (unless (eq 'exit status)
-                  (format " (%s)" status))))
-        (let (vc-sentinel-movepoint
-              (m (process-mark p)))
-          ;; Normally, we want async code such as sentinels to not move point.
-          (save-excursion
-            (goto-char m)
-            ;; Each sentinel may move point and the next one should be run
-            ;; at that new point.  We could get the same result by having
-            ;; each sentinel read&set process-mark, but since `cmd' needs
-            ;; to work both for async and sync processes, this would be
-            ;; difficult to achieve.
-            (vc-exec-after code)
-            (move-marker m (point)))
-          ;; But sometimes the sentinels really want to move point.
-          (when vc-sentinel-movepoint
-	    (let ((win (get-buffer-window (current-buffer) 0)))
-	      (if (not win)
-		  (goto-char vc-sentinel-movepoint)
-		(with-selected-window win
-		  (goto-char vc-sentinel-movepoint))))))))))
+              ;; Leave mode-line uncluttered, normally.
+              (unless (eq 'exit status)
+                (format " (%s)" status)))
+        (unless (eq 'signal status)
+          (let (vc-sentinel-movepoint
+                (m (process-mark p)))
+            ;; Normally, we want async code such as sentinels to not move point.
+            (save-excursion
+              (goto-char m)
+              ;; Each sentinel may move point and the next one should be run
+              ;; at that new point.  We could get the same result by having
+              ;; each sentinel read&set process-mark, but since `cmd' needs
+              ;; to work both for async and sync processes, this would be
+              ;; difficult to achieve.
+              (vc-exec-after code)
+              (move-marker m (point)))
+            ;; But sometimes the sentinels really want to move point.
+            (when vc-sentinel-movepoint
+              (let ((win (get-buffer-window (current-buffer) 0)))
+                (if (not win)
+                    (goto-char vc-sentinel-movepoint)
+                  (with-selected-window win
+                    (goto-char vc-sentinel-movepoint)))))))))))
 
 (defun vc-set-mode-line-busy-indicator ()
   (setq mode-line-process