From: Dmitry Dzhus <dima@dzhus.org>
To: 8756@debbugs.gnu.org
Subject: bug#8756: vc-git.el doesn't use --follow argument in vc-git-print-log
Date: Thu, 31 Jul 2014 00:35:32 +0400 [thread overview]
Message-ID: <3258071406752532@web22g.yandex.ru> (raw)
In-Reply-To: <87sjrxl0r1.fsf@dod.no>
[-- Attachment #1: Type: text/plain, Size: 1164 bytes --]
How are you gentlemen,
Following renames is nice no matter what Git upstream thinks,
so I gave this bug a try. I'd like to share some progress.
Diffing (`d`), paging (`f`) and annotating a file (`a`) revision works.
I've tested it with Git version 1.8.5.4 and 2.0.2.
Parallel git log with hash/file information is run when
a log is queried. (vc-git-file-shalist) provides access to
a list of SHA1's/historical file names for the file open
in the *vc-change-log* buffer.
The bad part is that whole-changeset (`D`) diffing is broken
(wrong revisions are selected for diff).
The culprit is `vc-git-previous-revision`.
Using HASH^ to obtain the parent of HASH revision produces
unexpected results when file renames are involved. However,
for whole-changeset diffing HASH^ seems to be exactly what
we need. However, `vc-git-previous-revision` doesn't seem
to enable any inspection of the context in which we use it
(in other words, if we hit `d` or `D` in the log buffer.)
Any ideas?
I also have not tackled revision navigation in the annotation
mode, but this can likely be solved by plugging calls to
`(vc-git-rev-to-filename)` somewhere in the annotation mode.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: vc-git-follow-renames.patch --]
[-- Type: text/x-diff; name="vc-git-follow-renames.patch", Size: 6450 bytes --]
=== modified file 'lisp/vc/vc-git.el'
--- lisp/vc/vc-git.el 2014-06-29 20:48:55 +0000
+++ lisp/vc/vc-git.el 2014-07-30 20:32:01 +0000
@@ -691,13 +691,7 @@
(coding-system-for-read 'binary)
(coding-system-for-write 'binary)
(fullname
- (let ((fn (vc-git--run-command-string
- file "ls-files" "-z" "--full-name" "--")))
- ;; ls-files does not return anything when looking for a
- ;; revision of a file that has been renamed or removed.
- (if (string= fn "")
- (file-relative-name file (vc-git-root default-directory))
- (substring fn 0 -1)))))
+ (vc-git-rev-to-filename rev)))
(vc-git-command
buffer 0
nil
@@ -786,20 +780,53 @@
;; If the buffer exists from a previous invocation it might be
;; read-only.
(let ((inhibit-read-only t))
+ ;; Clean SHA1 list caches whenever we query a new change log
(with-current-buffer
buffer
- (apply 'vc-git-command buffer
- 'async files
- (append
- '("log" "--no-color")
- (when shortlog
- `("--graph" "--decorate" "--date=short"
+ (if (boundp 'vc-git-file-shalist-raw)
+ (setq vc-git-file-shalist-raw nil)
+ (set (make-local-variable 'vc-git-file-shalist-raw) nil))
+ (if (boundp 'vc-git-file-shalist)
+ (setq vc-git-file-shalist nil))
+ (when (vc-git-single-file files)
+ ;; Store newline-separated list of revision hashes and file
+ ;; names in vc-git-file-shalist-raw buffer-local variable
+ (with-temp-buffer
+ (set-process-filter
+ (apply 'vc-git-command nil
+ 'async files
+ (append
+ '("log"
+ "--follow"
+ "--name-only"
+ "--pretty=tformat:%H"
+ "--no-color")
+ ;; Tail revision must now its parent
+ (when limit (list "-n" (format "%s" (1+ limit))))
+ (when start-revision (lsit start-revision))
+ '("--")))
+ (lambda (p s)
+ (with-current-buffer buffer
+ (setq
+ vc-git-file-shalist-raw
+ (replace-regexp-in-string
+ "\n\n" "\n"
+ (concat (if (boundp 'vc-git-file-shalist-raw)
+ vc-git-file-shalist-raw "") s))))))))
+ (apply 'vc-git-command buffer
+ 'async files
+ (append
+ (if (vc-git-single-file files)
+ '("log" "--follow" "--no-color")
+ '("log" "--no-color"))
+ (when shortlog
+ `("--graph" "--decorate" "--date=short"
,(format "--pretty=tformat:%s"
- (car vc-git-root-log-format))
- "--abbrev-commit"))
- (when limit (list "-n" (format "%s" limit)))
- (when start-revision (list start-revision))
- '("--")))))))
+ (car vc-git-root-log-format))
+ "--abbrev-commit"))
+ (when limit (list "-n" (format "%s" limit)))
+ (when start-revision (list start-revision))
+ '("--")))))))
(defun vc-git-log-outgoing (buffer remote-location)
(interactive)
@@ -904,11 +931,21 @@
(defun vc-git-diff (files &optional rev1 rev2 buffer)
"Get a difference report using Git between two revisions of FILES."
(let (process-file-side-effects)
- (apply #'vc-git-command (or buffer "*vc-diff*") 1 files
- (if (and rev1 rev2) "diff-tree" "diff-index")
- "--exit-code"
- (append (vc-switches 'git 'diff)
- (list "-p" (or rev1 "HEAD") rev2 "--")))))
+ (with-current-buffer (or buffer "*vc-diff*")
+ ;; Run diff from the repository root because our file names are
+ ;; relative to it
+ (setq default-directory (vc-git-root default-directory))
+ (apply #'vc-git-command (or buffer "*vc-diff*") 1
+ (if (vc-git-single-file files)
+ (list
+ (vc-git-rev-to-filename rev1)
+ (vc-git-rev-to-filename rev2))
+ files)
+ (if (and rev1 rev2) "diff-tree" "diff-index")
+ "--exit-code"
+ "-M"
+ (append (vc-switches 'git 'diff)
+ (list "-p" (or rev1 "HEAD") rev2 "--"))))))
(defun vc-git-revision-table (_files)
;; What about `files'?!? --Stef
@@ -928,7 +965,8 @@
table))
(defun vc-git-annotate-command (file buf &optional rev)
- (let ((name (file-relative-name file)))
+ (setq default-directory (vc-git-root default-directory))
+ (let ((name (vc-git-rev-to-filename rev)))
(vc-git-command buf 'async nil "blame" "--date=iso" "-C" "-C" rev "--" name)))
(declare-function vc-annotate-convert-time "vc-annotate" (time))
@@ -987,7 +1025,11 @@
(point)
(1- (point-max)))))))
(or (vc-git-symbolic-commit prev-rev) prev-rev))
- (vc-git--rev-parse (concat rev "^"))))
+ ;; Use historical data for the file if possible.
+ ;; FIXME: This breaks whole-changeset diffing.
+ (if (vc-git-file-shalist)
+ (car (cddr (member rev (vc-git-file-shalist))))
+ (vc-git--rev-parse (concat rev "^")))))
(defun vc-git--rev-parse (rev)
(with-temp-buffer
@@ -995,6 +1037,26 @@
(vc-git--out-ok "rev-parse" rev)
(buffer-substring-no-properties (point-min) (+ (point-min) 40)))))
+(defun vc-git-single-file (files)
+ "Return t if FILES contains a single non-directory file."
+ (and (eq (length files) 1)
+ (not (file-directory-p (car files)))))
+
+(defun vc-git-file-shalist ()
+ "Return alternating list of SHA1 hashes and file names.
+The list contains commit hashes and historical names for a file
+in the current change log buffer."
+ (cond
+ ((and (boundp 'vc-git-file-shalist) vc-git-file-shalist)
+ vc-git-file-shalist)
+ ((and (boundp 'vc-git-file-shalist-raw) vc-git-file-shalist-raw)
+ (set (make-local-variable 'vc-git-file-shalist)
+ (split-string vc-git-file-shalist-raw "\n")))))
+
+(defun vc-git-rev-to-filename (rev)
+ "Return a historical file name for the file in REV."
+ (cadr (member rev (vc-git-file-shalist))))
+
(defun vc-git-next-revision (file rev)
"Git-specific version of `vc-next-revision'."
(let* ((default-directory (file-name-directory
next prev parent reply other threads:[~2014-07-30 20:35 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-05-29 20:17 bug#8756: 23.3; vc-git.el doesn't use --follow argument in vc-git-print-log Steinar Bang
2011-05-31 5:25 ` Dan Nicolaescu
2011-11-28 20:21 ` Steinar Bang
2011-11-28 21:08 ` Dan Nicolaescu
2011-11-29 17:29 ` Steinar Bang
2011-12-01 18:15 ` Dan Nicolaescu
2011-12-01 21:44 ` Steinar Bang
2011-12-01 21:57 ` Steinar Bang
2014-01-09 19:21 ` Glenn Morris
2014-01-11 1:40 ` Dan Nicolaescu
2014-01-11 14:15 ` Steinar Bang
2014-01-11 23:32 ` Steinar Bang
2014-01-12 1:46 ` Dan Nicolaescu
2014-01-12 3:57 ` Eli Zaretskii
2014-01-12 10:15 ` Steinar Bang
2014-01-12 10:45 ` Steinar Bang
2014-07-30 20:35 ` Dmitry Dzhus [this message]
2019-11-03 14:32 ` bug#8756: " Lars Ingebrigtsen
2019-11-03 18:48 ` Dmitry Gutov
2019-11-08 20:44 ` Lars Ingebrigtsen
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=3258071406752532@web22g.yandex.ru \
--to=dima@dzhus.org \
--cc=8756@debbugs.gnu.org \
/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).