]> code.delx.au - gnu-emacs/blobdiff - lisp/vc/vc-git.el
* lisp/vc/vc-cvs.el (cvs-append-to-ignore): Fix arg spec.
[gnu-emacs] / lisp / vc / vc-git.el
index 29f7aaa5480e720249f70595479de8971304af1c..a4ce3a2c46c373ea2e75f0353bade918cf5d384d 100644 (file)
 ;; - 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))))