Hi,
the Emacs support for git is incomplete, making it bomb out, for
example, when doing
C-u C-x v =
In order to have it work better, I need to fill in the following
functions:
(vc-git-previous-version FILE REV)
Return the version number immediately preceding REV for FILE,
or nil if there is no previous version.
(vc-git-next-version FILE REV)
Return the version number immediately following REV for FILE,
or nil if there is no previous version.
REV will tend to be a symbolic reference like "master" or possibly
"master{2}" (I am fuzzy about the details, but at least repeated
invocations of vc-git-previous-version should work with the previous
output). The corresponding next and previous versions should be
changes that actually changed the file in question.
There is likely going to be some magic shell invocation of
git-rev-list, git-symbolic-ref and/or similar things to achieve this
task. I don't have enough of a clue to fill in the necessary details,
but I'd be able to convert them into Elisp.
Anybody with good suggestions? It would be beneficial if this would
not require the newest git version in order to work. If that means
that the output needs to be somewhat more massaged, that's ok.
Thanks,
--
David Kastrup
I don't know lisp very well, and elisp not at all, but I can help you
with what command lines would give you the results you might want.
On Jul 11, 2007, at 7:39 AM, David Kastrup wrote:
(vc-git-previous-version FILE REV)
Return the version number immediately preceding REV for FILE,
or nil if there is no previous version.
If you want the last revision where the file was altered, you could
easily use
git rev-list -2 $current_rev -- $file | tail -1
The result would be a SHA-1 of the next commit where the file was
altered.
(vc-git-next-version FILE REV)
Return the version number immediately following REV for FILE,
or nil if there is no previous version.
This is a little more problematic as git doesn't have forward links
in it's history. If you have a ref to start with (HEAD is a good one
to use, if you don't have anything else) you could use a similar
command to the above
git rev-list $ref -- $file | grep -C1 -m1 $current_rev | head -1
If you don't have a ref to start from, you could use --all, but that
may not be what the user expects.
If you want a human readable name for either you could use name-rev.
(Add "| git name-rev --stdin" to the end of the above.) It places a
human readable name after the SHA-1 in parentheses. (example:
"54dadbdb29668fbd51effefd0a0c65d915f5422b (master~3)")
~~ Brian
This is necessary to make several editing functions work, like
C-u C-x v =
Signed-off-by: David Kastrup <redacted>
---
contrib/emacs/vc-git.el | 65 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/contrib/emacs/vc-git.el b/contrib/emacs/vc-git.el
index e456ab9..b8f6be5 100644
--- a/contrib/emacs/vc-git.el
+++ b/contrib/emacs/vc-git.el
@@ -81,6 +81,71 @@
(match-string 2 str)
str)))
+(defun vc-git-symbolic-commit (commit)
+ "Translate COMMIT string into symbolic form.
+Returns nil if not possible."
+ (and commit
+ (with-temp-buffer
+ (and
+ (zerop
+ (call-process "git" nil '(t nil) nil "name-rev"
+ "--name-only" "--tags"
+ commit))
+ (goto-char (point-min))
+ (= (forward-line 2) 1)
+ (bolp)
+ (buffer-substring-no-properties (point-min) (1- (point-max)))))))
+
+(defun vc-git-previous-version (file rev)
+ "git-specific version of `vc-previous-version'."
+ (let ((default-directory (file-name-directory (expand-file-name file)))
+ (file (file-name-nondirectory file)))
+ (vc-git-symbolic-commit
+ (with-temp-buffer
+ (and
+ (zerop
+ (call-process "git" nil '(t nil) nil "rev-list"
+ "-2" rev "--" file))
+ (goto-char (point-max))
+ (bolp)
+ (zerop (forward-line -1))
+ (not (bobp))
+ (buffer-substring-no-properties
+ (point)
+ (1- (point-max))))))))
+
+(defun vc-git-next-version (file rev)
+ "git-specific version of `vc-next-version'."
+ (let* ((default-directory (file-name-directory
+ (expand-file-name file)))
+ (file (file-name-nondirectory file))
+ (current-rev
+ (with-temp-buffer
+ (and
+ (zerop
+ (call-process "git" nil '(t nil) nil "rev-list"
+ "-1" rev "--" file))
+ (goto-char (point-max))
+ (bolp)
+ (zerop (forward-line -1))
+ (bobp)
+ (buffer-substring-no-properties
+ (point)
+ (1- (point-max)))))))
+ (and current-rev
+ (vc-git-symbolic-commit
+ (with-temp-buffer
+ (and
+ (zerop
+ (call-process "git" nil '(t nil) nil "rev-list"
+ "HEAD" "--" file))
+ (goto-char (point-min))
+ (search-forward current-rev nil t)
+ (zerop (forward-line -1))
+ (buffer-substring-no-properties
+ (point)
+ (progn (forward-line 1) (1- (point))))))))))
+
(defun vc-git-revert (file &optional contents-done)
"Revert FILE to the version stored in the git repository."
(if contents-done--
1.5.3.rc0.51.gb0b1f
--
David Kastrup