unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Dmitry Gutov <dgutov@yandex.ru>
To: "Nicolás Ojeda Bär" <n.oje.bar@gmail.com>
Cc: 55871@debbugs.gnu.org
Subject: bug#55871: Acknowledgement (27.1; vc-git.el log view 'a', 'f', 'd' do not work when following renames)
Date: Fri, 15 Dec 2023 04:01:59 +0200	[thread overview]
Message-ID: <36b48587-a723-73ae-fefb-886d69d04ec8@yandex.ru> (raw)
In-Reply-To: <1b16a642-8a85-e693-66fc-41c37df24908@yandex.ru>

[-- Attachment #1: Type: text/plain, Size: 326 bytes --]

On 14/12/2023 03:23, Dmitry Gutov wrote:
> On 14/12/2023 02:52, Dmitry Gutov wrote:
>> but otherwise seems to function well (with potential for future 
>> additions)
> 
> To clarify: this version only makes 'd' work (not 'f' or 'a'), but the 
> other two are fixed more easily.

Attached is the new revision with combined fix.

[-- Attachment #2: vc-git-file-name-changes-v2.diff --]
[-- Type: text/x-patch, Size: 8153 bytes --]

diff --git a/etc/NEWS b/etc/NEWS
index 1ff2f8a149f..4dd11c99927 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -457,6 +457,14 @@ With this value only the revision number is displayed on the mode-line.
 *** Obsolete command 'vc-switch-backend' re-added as 'vc-change-backend'.
 The command was previously obsoleted and unbound in Emacs 28.
 
+*** Support for viewing file change history across renames.
+When a fileset's VC change history ends at a rename, we now print the
+old name(s) and a button which jumps to their history.  Only supported
+with Git at the moment.
+
+*** New option 'vc-git-file-name-changes-switches'.
+It allows tweaking the thresholds for rename and copy detection.
+
 ** Diff mode
 
 +++
diff --git a/lisp/vc/log-view.el b/lisp/vc/log-view.el
index af24fcfd398..6c3abd15d8d 100644
--- a/lisp/vc/log-view.el
+++ b/lisp/vc/log-view.el
@@ -516,7 +516,8 @@ log-view-find-revision
     (switch-to-buffer (vc-find-revision (if log-view-per-file-logs
 					    (log-view-current-file)
 					  (car log-view-vc-fileset))
-					(log-view-current-tag)))))
+					(log-view-current-tag)
+                                        log-view-vc-backend))))
 
 
 (defun log-view-extract-comment ()
@@ -562,7 +563,8 @@ log-view-annotate-version
     (vc-annotate (if log-view-per-file-logs
 		     (log-view-current-file)
 		   (car log-view-vc-fileset))
-		 (log-view-current-tag))))
+		 (log-view-current-tag)
+                 nil nil nil log-view-vc-backend)))
 
 ;;
 ;; diff
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 2e057ecfaa7..f1d0ffd9b44 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -89,6 +89,7 @@
 ;; - make-version-backups-p (file)                 NOT NEEDED
 ;; - previous-revision (file rev)                  OK
 ;; - next-revision (file rev)                      OK
+;; - file-name-changes (rev)                       OK
 ;; - check-headers ()                              COULD BE SUPPORTED
 ;; - delete-file (file)                            OK
 ;; - rename-file (old new)                         OK
@@ -152,6 +153,20 @@ vc-git-shortlog-switches
                  (repeat :tag "Argument List" :value ("") string))
   :version "30.1")
 
+;; XXX: (setq vc-git-log-switches '("--simplify-merges")) can also
+;; create fuller history when using this feature.  Not sure why.
+(defcustom vc-git-file-name-changes-switches '("-M" "-C")
+  "String or list of string to pass to Git when finding previous names.
+
+This option should usually at least contain '-M'.  You can adjust
+the flags to change the similarity thresholds (default 50%).  Or
+add `--find-copies-harder' (slower in large projects, since it
+uses a full scan)."
+  :type '(choice (const :tag "None" nil)
+                 (string :tag "Argument String")
+                 (repeat :tag "Argument List" :value ("") string))
+  :version "30.1")
+
 (defcustom vc-git-resolve-conflicts t
   "When non-nil, mark conflicted file as resolved upon saving.
 That is performed after all conflict markers in it have been
@@ -1239,6 +1254,30 @@ vc-git-find-revision
      nil
      "cat-file" "blob" (concat (if rev rev "HEAD") ":" fullname))))
 
+(defun vc-git-file-name-changes (rev)
+  (with-temp-buffer
+    (let ((root (vc-git-root default-directory)))
+      (apply #'vc-git-command (current-buffer) t nil
+             "diff"
+             "--name-status"
+             "--diff-filter=ADCR"
+             (concat rev "^") rev
+             (vc-switches 'git 'file-name-changes))
+      (let (res)
+        (goto-char (point-min))
+        (while (re-search-forward "^\\([ADCR]\\)[0-9]*\t\\([^\n\t]+\\)\\(?:\t\\([^\n\t]+\\)\\)?" nil t)
+          (pcase (match-string 1)
+            ("A" (push (cons nil (match-string 2)) res))
+            ("D" (push (cons (match-string 2) nil) res))
+            ((or "C" "R") (push (cons (match-string 2) (match-string 3)) res))
+            ;; ("M" (push (cons (match-string 1) (match-string 1)) res))
+            ))
+        (mapc (lambda (c)
+                (if (car c) (setcar c (expand-file-name (car c) root)))
+                (if (cdr c) (setcdr c (expand-file-name (cdr c) root))))
+                res)
+        (nreverse res)))))
+
 (defun vc-git-find-ignore-file (file)
   "Return the git ignore file that controls FILE."
   (expand-file-name ".gitignore"
@@ -1416,7 +1455,15 @@ vc-git-clone
 ;; Long explanation here:
 ;; https://stackoverflow.com/questions/46487476/git-log-follow-graph-skips-commits
 (defcustom vc-git-print-log-follow nil
-  "If true, follow renames in Git logs for a single file."
+  "If true, use the flag `--follow' when producing single file logs.
+
+It will make the printed log automatically follow the renames.
+The downsides is that the log produced this way may omit
+certain (merge) commits, and that `log-view-diff' fails on
+commits that used the previous name, in that log buffer.
+
+When this variable is nil, and the log ends with a rename, we
+print a button that shows the log for the previous name."
   :type 'boolean
   :version "26.1")
 
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index 958929fe4c6..fab454994e1 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -517,6 +517,13 @@
 ;;   Return the revision number that precedes REV for FILE, or nil if no such
 ;;   revision exists.
 ;;
+;; - file-name-changes (rev)
+;;
+;;   Return the list of pairs with changes in file names in REV.  When
+;;   a file was added, it should be a cons with nil car.  When
+;;   deleted, a cons with nil cdr.  When copied or renamed, a cons
+;;   with the source name as car and destination name as cdr.
+;;
 ;; - next-revision (file rev)
 ;;
 ;;   Return the revision number that follows REV for FILE, or nil if no such
@@ -2695,9 +2702,46 @@ vc-print-log-setup-buttons
       (goto-char (point-min))
       (while (re-search-forward log-view-message-re nil t)
         (cl-incf entries))
-      ;; If we got fewer entries than we asked for, then displaying
-      ;; the "more" buttons isn't useful.
-      (when (>= entries limit)
+      (if (< entries limit)
+          ;; The log has been printed in full.  Perhaps it started
+          ;; with a copy or rename?
+          (let* ((last-revision (log-view-current-tag (point-max)))
+                 ;; XXX: Could skip this when vc-git-print-log-follow = t.
+                 (name-changes
+                  (condition-case nil
+                      (vc-call-backend log-view-vc-backend
+                                       'file-name-changes last-revision)
+                    (vc-not-supported nil)))
+                 (matching-changes
+                  (cl-delete-if-not (lambda (f) (member f log-view-vc-fileset))
+                                    name-changes :key #'cdr))
+                 (old-names (mapcar #'car matching-changes))
+                 (relatives (mapcar #'file-relative-name old-names)))
+            (when old-names
+              (goto-char (point-max))
+              (insert "\n")
+              (insert
+               (format
+                "Renamed from %s"
+                (mapconcat (lambda (s)
+                             (propertize s 'font-lock-face
+                                         'log-view-file))
+                           relatives ", "))
+               " ")
+              ;; TODO: Also print a different button somewhere in the
+              ;; created buffer to be able to go back easily.  (There
+              ;; are different ways to do that.)
+              (insert-text-button
+               "View log"
+               'action (lambda (&rest _ignore)
+                         (let ((backend log-view-vc-backend))
+                           (with-current-buffer vc-parent-buffer
+                             ;; To set up parent buffer in the new viewer.
+                             (vc-print-log-internal backend old-names
+                                                    last-revision nil limit))))
+               'help-echo
+               "Show the log for the file name(s) before the rename")))
+        ;; Perhaps there are more entries in the log.
         (goto-char (point-max))
         (insert "\n")
         (insert-text-button

  reply	other threads:[~2023-12-15  2:01 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-09  9:54 bug#55871: 27.1; vc-git.el log view 'a', 'f', 'd' do not work when following renames Nicolás Ojeda Bär
     [not found] ` <handler.55871.B.16547851264967.ack@debbugs.gnu.org>
2022-06-10 17:31   ` bug#55871: Acknowledgement (27.1; vc-git.el log view 'a', 'f', 'd' do not work when following renames) Nicolás Ojeda Bär
2022-08-18  2:10     ` Dmitry Gutov
2022-09-06 10:56       ` bug#55871: 27.1; vc-git.el log view 'a', 'f', 'd' do not work when following renames Lars Ingebrigtsen
2022-09-06 12:12         ` Nicolás Ojeda Bär
2022-09-06 12:13           ` Lars Ingebrigtsen
2022-12-03  2:02           ` Dmitry Gutov
2022-12-11 23:02       ` bug#55871: Acknowledgement (27.1; vc-git.el log view 'a', 'f', 'd' do not work when following renames) Dmitry Gutov
2022-12-12 16:44         ` Nicolás Ojeda Bär
2022-12-13  1:23           ` Dmitry Gutov
2023-12-14  0:52             ` Dmitry Gutov
2023-12-14  1:23               ` Dmitry Gutov
2023-12-15  2:01                 ` Dmitry Gutov [this message]
2023-12-15 13:05                   ` Eli Zaretskii
2023-12-15 14:39                     ` Dmitry Gutov
2023-12-15 15:10                       ` Eli Zaretskii
2023-12-15 20:45                         ` Dmitry Gutov
2023-12-16  7:21                           ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=36b48587-a723-73ae-fefb-886d69d04ec8@yandex.ru \
    --to=dgutov@yandex.ru \
    --cc=55871@debbugs.gnu.org \
    --cc=n.oje.bar@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).