X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/743fa5cbdd42a820c4320599a14aab925dcdbc8b..d3506ca5a0a4deca042d9cf91e5cbba083675220:/lisp/vc/vc-git.el diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 08b48fa7b4..a4ce3a2c46 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -1,6 +1,6 @@ ;;; vc-git.el --- VC backend for the git version control system -*- lexical-binding: t -*- -;; Copyright (C) 2006-2012 Free Software Foundation, Inc. +;; Copyright (C) 2006-2013 Free Software Foundation, Inc. ;; Author: Alexandre Julliard ;; Keywords: vc tools @@ -103,6 +103,8 @@ ;; - rename-file (old new) OK ;; - find-file-hook () NOT NEEDED +;;; Code: + (eval-when-compile (require 'cl-lib) (require 'vc) @@ -168,7 +170,7 @@ matching the resulting Git log output, and KEYWORDS is a list of ;;;###autoload "Return non-nil if FILE is registered with git." ;;;###autoload (if (vc-find-root file ".git") ; Short cut. ;;;###autoload (progn -;;;###autoload (load "vc-git") +;;;###autoload (load "vc-git" nil t) ;;;###autoload (vc-git-registered file)))) (defun vc-git-registered (file) @@ -234,30 +236,30 @@ matching the resulting Git log output, and KEYWORDS is a list of (vc-git--state-code diff-letter))) (if (vc-git--empty-db-p) 'added 'up-to-date)))) -(defun vc-git-working-revision (_file) +(defun vc-git-working-revision (file) "Git-specific version of `vc-working-revision'." (let* (process-file-side-effects - (str (with-output-to-string - (with-current-buffer standard-output - (vc-git--out-ok "symbolic-ref" "HEAD"))))) - (if (string-match "^\\(refs/heads/\\)?\\(.+\\)$" str) - (match-string 2 str) - str))) + (str (vc-git--run-command-string nil "symbolic-ref" "HEAD"))) + (vc-file-setprop file 'vc-git-detached (null str)) + (if str + (if (string-match "^\\(refs/heads/\\)?\\(.+\\)$" str) + (match-string 2 str) + str) + (vc-git--rev-parse "HEAD")))) (defun vc-git-workfile-unchanged-p (file) (eq 'up-to-date (vc-git-state file))) (defun vc-git-mode-line-string (file) "Return a string for `vc-mode-line' to put in the mode line for FILE." - (let* ((branch (vc-working-revision file)) + (let* ((rev (vc-working-revision file)) + (detached (vc-file-getprop file 'vc-git-detached)) (def-ml (vc-default-mode-line-string 'Git file)) (help-echo (get-text-property 0 'help-echo def-ml))) - (if (zerop (length branch)) - (propertize - (concat def-ml "!") - 'help-echo (concat help-echo "\nNo current branch (detached HEAD)")) - (propertize def-ml - 'help-echo (concat help-echo "\nCurrent branch: " branch))))) + (propertize (if detached + (substring def-ml 0 (- 7 (length rev))) + def-ml) + 'help-echo (concat help-echo "\nCurrent revision: " rev)))) (cl-defstruct (vc-git-extra-fileinfo (:copier nil) @@ -443,6 +445,12 @@ or an empty string if none." (when next-stage (vc-git-dir-status-goto-stage next-stage files update-function)))) +;; Follows vc-git-command (or vc-do-async-command), which uses vc-do-command +;; from vc-dispatcher. +(declare-function vc-exec-after "vc-dispatcher" (code)) +;; Follows vc-exec-after. +(declare-function vc-set-async-update "vc-dispatcher" (process-buffer)) + (defun vc-git-dir-status-goto-stage (stage files update-function) (erase-buffer) (pcase stage @@ -469,8 +477,8 @@ or an empty string if none." (`diff-index (vc-git-command (current-buffer) 'async files "diff-index" "--relative" "-z" "-M" "HEAD" "--"))) - (vc-exec-after - `(vc-git-after-dir-status-stage ',stage ',files ',update-function))) + (vc-run-delayed + (vc-git-after-dir-status-stage stage files update-function))) (defun vc-git-dir-status (_dir update-function) "Return a list of (FILE STATE EXTRA) entries for DIR." @@ -641,11 +649,18 @@ If toggling on, also insert its message into the buffer." It is based on `log-edit-mode', and has Git-specific extensions.") (defun vc-git-checkin (files _rev comment) - (let ((coding-system-for-write vc-git-commits-coding-system)) + (let* ((file1 (or (car files) default-directory)) + (root (vc-git-root file1)) + (default-directory (expand-file-name root)) + (only (or (cdr files) + (not (equal root (abbreviate-file-name file1))))) + (coding-system-for-write vc-git-commits-coding-system)) (cl-flet ((boolean-arg-fn (argument) (lambda (value) (when (equal value "yes") (list argument))))) - (apply 'vc-git-command nil 0 files + ;; When operating on the whole tree, better pass nil than ".", since "." + ;; fails when we're committing a merge. + (apply 'vc-git-command nil 0 (if only files) (nconc (list "commit" "-m") (log-edit-extract-headers `(("Author" . "--author") @@ -653,7 +668,7 @@ It is based on `log-edit-mode', and has Git-specific extensions.") ("Amend" . ,(boolean-arg-fn "--amend")) ("Sign-Off" . ,(boolean-arg-fn "--signoff"))) comment) - (list "--only" "--")))))) + (if only (list "--only" "--"))))))) (defun vc-git-find-revision (file rev buffer) (let* (process-file-side-effects @@ -672,6 +687,11 @@ It is based on `log-edit-mode', and has Git-specific extensions.") nil "cat-file" "blob" (concat (if rev rev "HEAD") ":" fullname)))) +(defun vc-git-find-ignore-file (file) + "Return the root directory of the repository of FILE." + (expand-file-name ".gitignore" + (vc-git-root file))) + (defun vc-git-checkout (file &optional _editable rev) (vc-git-command nil 0 file "checkout" (or rev "HEAD"))) @@ -706,7 +726,7 @@ for the Git command to run." command (cadr args) args (cddr args))) (apply 'vc-do-async-command buffer root git-program command args) - (with-current-buffer buffer (vc-exec-after '(vc-compilation-mode 'git))) + (with-current-buffer buffer (vc-run-delayed (vc-compilation-mode 'git))) (vc-set-async-update buffer))) (defun vc-git-merge-branch () @@ -726,15 +746,19 @@ This prompts for a branch to merge from." nil t))) (apply 'vc-do-async-command buffer root vc-git-program "merge" (list merge-source)) - (with-current-buffer buffer (vc-exec-after '(vc-compilation-mode 'git))) + (with-current-buffer buffer (vc-run-delayed (vc-compilation-mode 'git))) (vc-set-async-update buffer))) ;;; HISTORY FUNCTIONS +(autoload 'vc-setup-buffer "vc-dispatcher") + (defun vc-git-print-log (files buffer &optional shortlog start-revision limit) - "Get change log associated with FILES. -Note that using SHORTLOG requires at least Git version 1.5.6, -for the --graph option." + "Print commit log associated with FILES into specified BUFFER. +If SHORTLOG is non-nil, use a short format based on `vc-git-root-log-format'. +\(This requires at least Git version 1.5.6, for the --graph option.) +If START-REVISION is non-nil, it is the newest revision to show. +If LIMIT is non-nil, show no more than this many entries." (let ((coding-system-for-read vc-git-commits-coding-system)) ;; `vc-do-command' creates the buffer, but we need it before running ;; the command. @@ -855,6 +879,8 @@ or BRANCH^ (where \"^\" can be repeated)." (indent-region (point-min) (point-max) 2) (buffer-string)))) +(autoload 'vc-switches "vc") + (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) @@ -941,10 +967,13 @@ or BRANCH^ (where \"^\" can be repeated)." (point) (1- (point-max))))))) (or (vc-git-symbolic-commit prev-rev) prev-rev)) - (with-temp-buffer - (and - (vc-git--out-ok "rev-parse" (concat rev "^")) - (buffer-substring-no-properties (point-min) (+ (point-min) 40)))))) + (vc-git--rev-parse (concat rev "^")))) + +(defun vc-git--rev-parse (rev) + (with-temp-buffer + (and + (vc-git--out-ok "rev-parse" rev) + (buffer-substring-no-properties (point-min) (+ (point-min) 40))))) (defun vc-git-next-revision (file rev) "Git-specific version of `vc-next-revision'." @@ -1005,6 +1034,12 @@ or BRANCH^ (where \"^\" can be repeated)." (or (vc-file-getprop file 'git-root) (vc-file-setprop file 'git-root (vc-find-root file ".git")))) +;; grep-compute-defaults autoloads grep. +(declare-function grep-read-regexp "grep" ()) +(declare-function grep-read-files "grep" (regexp)) +(declare-function grep-expand-template "grep" + (template &optional regexp files dir excl)) + ;; Derived from `lgrep'. (defun vc-git-grep (regexp &optional files dir) "Run git grep, searching for REGEXP in FILES in directory DIR. @@ -1060,6 +1095,10 @@ This command shares argument histories with \\[rgrep] and \\[grep]." (if (eq next-error-last-buffer (current-buffer)) (setq default-directory dir)))))) +;; Everywhere but here, follows vc-git-command, which uses vc-do-command +;; from vc-dispatcher. +(autoload 'vc-resynch-buffer "vc-dispatcher") + (defun vc-git-stash (name) "Create a stash." (interactive "sStash name: ") @@ -1117,6 +1156,9 @@ This command shares argument histories with \\[rgrep] and \\[grep]." (match-string 1) (error "Cannot find stash at point")))) +;; vc-git-stash-delete-at-point must be called from a vc-dir buffer. +(declare-function vc-dir-refresh "vc-dir" ()) + (defun vc-git-stash-delete-at-point () (interactive) (let ((stash (vc-git-stash-get-at-point (point))))