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

From: Dmitry Gutov <[email-masked]>
Date: Thu, 17 Oct 2024 02:53:25 +0300

On 16/10/2024 23:11, Spencer Baugh wrote:

> Right.  But note that the Hg revset in my original patch finds what is
> effectively the mergebase with upstream, without doing any network IO.

Yep. So this is the implementation we can use for now.

>> As a result, the core feature will work (the "outgoing" diff), whereas
>> the "incoming" diff would only be accessible for Git
>> repositories. Also, with Git, one might need to use vc-log-mergebase
>> when the remote has diverged.
> 
> Right, that makes sense to me.
> 
> Just to be clear, you're suggesting the incoming diff would be
> accessible for a Git repository via vc-diff-mergebase, right?

Right, something like

   C-x v B M HEAD RET @{upstream} RET

Actually trying that out brings up the problem that @{upstream} is not 
in completions for rev2. We could add it as the next default:

diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index a30ba06aec3..2409b4e88a0 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -2068,7 +2073,10 @@ vc-diff-build-argument-list-internal
           (backend (car vc-fileset))
           (first (car files))
           (rev1-default nil)
+         (upstream-revision (vc-call-backend backend 'upstream-revision 
first))
           ) ;; (rev2-default nil)
+    (when upstream-revision
+      (push upstream-revision rev1-default))
      (cond
       ;; someday we may be able to do revision completion on non-singleton
       ;; filesets, but not yet.
@@ -2087,7 +2095,8 @@ vc-diff-build-argument-list-internal
                                         ;; (or rev2-default
                                         "current source"))
             (rev1 (vc-read-revision rev1-prompt files backend 
rev1-default))
-           (rev2 (vc-read-revision rev2-prompt files backend nil))) ;; 
rev2-default
+           (rev2 (vc-read-revision rev2-prompt files backend (list ""
+ 
upstream-revision)))) ;; rev2-default
        (when (string= rev1 "") (setq rev1 nil))
        (when (string= rev2 "") (setq rev2 nil))
        (list files rev1 rev2))))

Or alternatively, we could move both "upstream revision" identifiers to 
the revision-completion-table implementations. The result might be a bit 
less convenient, but "last ..." and "@{upstream}" will show up in 
completions, and after being selected once, will be in the input history 
as well. Depending on the frequency of use, that might be okay.

That diffs looks like this:

diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 5a7ffeffc9d..019abfa475c 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -1771,7 +1771,7 @@ vc-git-diff
  (defun vc-git-revision-table (_files)
    ;; What about `files'?!?  --Stef
    (let (process-file-side-effects
-	(table (list "HEAD")))
+	(table (list "HEAD" "@{upstream}")))
      (with-temp-buffer
        (vc-git-command t nil nil "for-each-ref" "--format=%(refname)")
        (goto-char (point-min))
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el
index 856bea66a6f..90ab47fa6cd 100644
--- a/lisp/vc/vc-hg.el
+++ b/lisp/vc/vc-hg.el
@@ -545,13 +545,15 @@ vc-hg-expanded-log-entry
        (buffer-string))))

  (defun vc-hg-revision-table (files)
-  (let ((default-directory (file-name-directory (car files))))
+  (let ((default-directory (file-name-directory (car files)))
+        (upstream-rev "last(. and not outgoing())"))
      (with-temp-buffer
        (vc-hg-command t nil nil "branches" "-q")
        (vc-hg-command t nil nil "bookmarks" "-q")
        (vc-hg-command t nil nil "tags" "-q")
-      (split-string
-       (buffer-substring-no-properties (point-min) (point-max))))))
+      (cons upstream-rev
+            (split-string
+             (buffer-substring-no-properties (point-min) (point-max)))))))

  ;; Modeled after the similar function in vc-cvs.el
  (defun vc-hg-revision-completion-table (files)