;; - working with revisions other than HEAD
;;
+(eval-when-compile (require 'cl))
+
(defvar git-commits-coding-system 'utf-8
"Default coding system for git commits.")
(with-temp-buffer
(let* ((dir (file-name-directory file))
(name (file-relative-name file dir)))
- (when dir (cd dir))
- (and (ignore-errors (eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name)))
+ (and (ignore-errors
+ (when dir (cd dir))
+ (eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name)))
(let ((str (buffer-string)))
(and (> (length str) (length name))
(string= (substring str 0 (1+ (length name))) (concat name "\0"))))))))
(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
(vc-git--run-command file "commit" "-m" comment "--only" "--")))
(defun vc-git-checkout (file &optional editable rev destfile)
- (vc-git--run-command file "checkout" (or rev "HEAD")))
+ (if destfile
+ (let ((fullname (substring
+ (vc-git--run-command-string file "ls-files" "-z" "--full-name" "--")
+ 0 -1))
+ (coding-system-for-read 'no-conversion)
+ (coding-system-for-write 'no-conversion))
+ (with-temp-file destfile
+ (eq 0 (call-process "git" nil t nil "cat-file" "blob"
+ (concat (or rev "HEAD") ":" fullname)))))
+ (vc-git--run-command file "checkout" (or rev "HEAD"))))
(defun vc-git-annotate-command (file buf &optional rev)
; FIXME: rev is ignored