Subject: bug#62940: 29.0.60; vc: no easy way to get diff of all outgoing changes

From: Spencer Baugh <[email-masked]>
Date: Fri, 13 Sep 2024 16:54:29 -0400

Dmitry Gutov <[email-masked]> writes:
> On 18/04/2023 23:36, Filipp Gunbin wrote:
>> Usually I just do C-x v L, select commits that interest me (via region),
>> and do M-x log-view-diff.
>
> Just in case: 'log-view-diff' is bound to '='.
>
> That's what I wanted to suggest, too. Or use 'vc-log-outgoing':
>
>   C-x v O C-x h =
>
> Which would be D. in the original message. It doesn't support
> uncommitted changes, but I would be surprised if it did.
>
> But one can also try this:
>
>   C-u C-x v D origin/master ^J
>
> Where origin/master is the name of the upstream branch ref. This
> should include uncommitted changes.

This works great, but is a bit tricky to use because you need to type
the upstream branch ref.  I think it would be good to provide that as an
additional default in the prompt for the old revision.  The attached
patch does that.  (and probably is enough to close this bug)

>From 0a48d2973363361211c2e91c4f6c7bb75f16a853 Mon Sep 17 00:00:00 2001
From: Spencer Baugh <[email-masked]>
Date: Fri, 13 Sep 2024 16:35:19 -0400
Subject: [PATCH] Add a "last pushed revision" default in the vc-diff prompt

C-u M-x vc-root-diff will prompt for the old revision to use for the
diff.  It includes the current working revision as a default.

Now it also includes the last pushed revision as a default, through a
new pushed-revision vc backend function.

* lisp/vc/vc-git.el (vc-git-pushed-revision): Add.
(vc-git-log-outgoing): Use vc-git-pushed-revision.
* lisp/vc/vc-hg.el (vc-hg-pushed-revision): Add.
* lisp/vc/vc.el (vc-default-pushed-revision): Add new backend function
with default implementation returning nil.
(vc-diff-build-argument-list-internal): Add the last pushed revision
as a default. (bug#62940)
---
 lisp/vc/vc-git.el | 10 +++++++---
 lisp/vc/vc-hg.el  |  6 ++++++
 lisp/vc/vc.el     |  7 +++++++
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 2a7c8ae5fc4..4afbb978a3f 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -1512,6 +1512,12 @@ vc-git-print-log
                   (list "-p"))
 		'("--")))))))
 
+(defun vc-git-pushed-revision (_file &optional remote-location)
+  "Return the ref for REMOTE-LOCATION."
+  (if (and remote-location (not (string-empty-p remote-location)))
+      remote-location
+    "@{upstream}"))
+
 (defun vc-git-log-outgoing (buffer remote-location)
   (vc-setup-buffer buffer)
   (apply #'vc-git-command buffer 'async nil
@@ -1520,9 +1526,7 @@ vc-git-log-outgoing
            ,(format "--pretty=tformat:%s" (car vc-git-root-log-format))
            "--abbrev-commit"
            ,@(ensure-list vc-git-shortlog-switches)
-           ,(concat (if (string= remote-location "")
-	                "@{upstream}"
-	              remote-location)
+           ,(concat (vc-git-pushed-revision nil remote-location)
 	            "..HEAD"))))
 
 (defun vc-git-log-incoming (buffer remote-location)
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el
index 876d86dc24f..c0afb225871 100644
--- a/lisp/vc/vc-hg.el
+++ b/lisp/vc/vc-hg.el
@@ -1422,6 +1422,12 @@ vc-hg-log-incoming
   (vc-hg-command buffer 1 nil "incoming" "-n" (unless (string= remote-location "")
 						remote-location)))
 
+(defun vc-hg-pushed-revision (_file &optional remote-location)
+  "Return a revspec for the last commit not outgoing to REMOTE-LOCATION."
+  (unless remote-location
+    (setq remote-location ""))
+  (format "last(. and not outgoing(%s))" remote-location))
+
 (defun vc-hg-log-outgoing (buffer remote-location)
   (vc-setup-buffer buffer)
   (vc-hg-command buffer 1 nil "outgoing" "-n" (unless (string= remote-location "")
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index 597a1622f5a..0125924cc51 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -2061,6 +2061,11 @@ vc-read-multiple-revisions
 INITIAL-INPUT are passed on to `vc-read-revision' directly."
   (vc-read-revision prompt files backend default initial-input t))
 
+(defun vc-default-pushed-revision (_file &optional _remote-location)
+  "Return the last pushed revision of FILE.
+The default is to return nil always."
+  nil)
+
 (defun vc-diff-build-argument-list-internal (&optional fileset)
   "Build argument list for calling internal diff functions."
   (let* ((vc-fileset (or fileset (vc-deduce-fileset t))) ;FIXME: why t?  --Stef
@@ -2069,6 +2074,8 @@ vc-diff-build-argument-list-internal
          (first (car files))
          (rev1-default nil)
          ) ;; (rev2-default nil)
+    (when-let ((pushed-revision (vc-call-backend backend 'pushed-revision first)))
+      (push pushed-revision rev1-default))
     (cond
      ;; someday we may be able to do revision completion on non-singleton
      ;; filesets, but not yet.
-- 
2.39.3