]> code.delx.au - gnu-emacs/blobdiff - lisp/vc/vc-git.el
Merge from origin/emacs-25
[gnu-emacs] / lisp / vc / vc-git.el
index 8a0f5547c4d6094d038855dedebd52a6e4172a51..2fd84f102f8fdbfb4c67b10ddfd89caab0ddda5a 100644 (file)
@@ -1,6 +1,6 @@
 ;;; vc-git.el --- VC backend for the git version control system -*- lexical-binding: t -*-
 
-;; Copyright (C) 2006-2015 Free Software Foundation, Inc.
+;; Copyright (C) 2006-2016 Free Software Foundation, Inc.
 
 ;; Author: Alexandre Julliard <julliard@winehq.org>
 ;; Keywords: vc tools
@@ -165,8 +165,20 @@ matching the resulting Git log output, and KEYWORDS is a list of
   :type '(list string string (repeat sexp))
   :version "24.1")
 
-(defvar vc-git-commits-coding-system 'utf-8
-  "Default coding system for git commits.")
+(defcustom vc-git-commits-coding-system 'utf-8
+  "Default coding system for sending commit log messages to Git.
+
+Should be consistent with the Git config value i18n.commitEncoding,
+and should also be consistent with `locale-coding-system'."
+  :type '(coding-system :tag "Coding system to encode Git commit logs")
+  :version "25.1")
+
+(defcustom vc-git-log-output-coding-system 'utf-8
+  "Default coding system for receiving log output from Git.
+
+Should be consistent with the Git config value i18n.logOutputEncoding."
+  :type '(coding-system :tag "Coding system to decode Git log output")
+  :version "25.1")
 
 ;; History of Git commands.
 (defvar vc-git-history nil)
@@ -674,27 +686,49 @@ If toggling on, also insert its message into the buffer."
   "Major mode for editing Git log messages.
 It is based on `log-edit-mode', and has Git-specific extensions.")
 
-(defun vc-git-checkin (files comment)
+(defun vc-git-checkin (files comment &optional _rev)
   (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))
+         (pcsw coding-system-for-write)
+         (coding-system-for-write
+          ;; On MS-Windows, we must encode command-line arguments in
+          ;; the system codepage.
+          (if (eq system-type 'windows-nt)
+              locale-coding-system
+            (or coding-system-for-write vc-git-commits-coding-system)))
+         (msg-file
+          ;; On MS-Windows, pass the commit log message through a
+          ;; file, to work around the limitation that command-line
+          ;; arguments must be in the system codepage, and therefore
+          ;; might not support the non-ASCII characters in the log
+          ;; message.
+          (if (eq system-type 'windows-nt) (make-temp-file "git-msg"))))
     (cl-flet ((boolean-arg-fn
                (argument)
                (lambda (value) (when (equal value "yes") (list argument)))))
       ;; When operating on the whole tree, better pass "-a" 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")
-                       ("Date" . "--date")
-                       ("Amend" . ,(boolean-arg-fn "--amend"))
-                       ("Sign-Off" . ,(boolean-arg-fn "--signoff")))
-                     comment)
-                   (if only (list "--only" "--") '("-a")))))))
+             (nconc (if msg-file (list "commit" "-F" msg-file)
+                      (list "commit" "-m"))
+                    (let ((args
+                           (log-edit-extract-headers
+                            `(("Author" . "--author")
+                              ("Date" . "--date")
+                              ("Amend" . ,(boolean-arg-fn "--amend"))
+                              ("Sign-Off" . ,(boolean-arg-fn "--signoff")))
+                            comment)))
+                      (when msg-file
+                        (let ((coding-system-for-write
+                               (or pcsw vc-git-commits-coding-system)))
+                          (write-region (car args) nil msg-file))
+                        (setq args (cdr args)))
+                      args)
+                   (if only (list "--only" "--") '("-a")))))
+    (if (and msg-file (file-exists-p msg-file)) (delete-file msg-file))))
 
 (defun vc-git-find-revision (file rev buffer)
   (let* (process-file-side-effects
@@ -714,7 +748,7 @@ It is based on `log-edit-mode', and has Git-specific extensions.")
      "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."
+  "Return the git ignore file that controls FILE."
   (expand-file-name ".gitignore"
                    (vc-git-root file)))
 
@@ -841,7 +875,7 @@ This prompts for a branch to merge from."
     (smerge-start-session)
     (when vc-git-resolve-conflicts
       (add-hook 'after-save-hook 'vc-git-resolve-when-done nil 'local))
-    (message "There are unresolved conflicts in this file")))
+    (vc-message-unresolved-conflicts buffer-file-name)))
 
 ;;; HISTORY FUNCTIONS
 
@@ -853,7 +887,8 @@ 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))
+  (let ((coding-system-for-read
+         (or coding-system-for-read vc-git-log-output-coding-system)))
     ;; `vc-do-command' creates the buffer, but we need it before running
     ;; the command.
     (vc-setup-buffer buffer)
@@ -970,10 +1005,40 @@ or BRANCH^ (where \"^\" can be repeated)."
     (goto-char (point-min))
     (unless (eobp)
       ;; Indent the expanded log entry.
-      (indent-region (point-min) (point-max) 2)
+      (while (re-search-forward "^  " nil t)
+        (replace-match "")
+        (forward-line))
       (buffer-string))))
 
 (defun vc-git-region-history (file buffer lfrom lto)
+  ;; The "git log" command below interprets the line numbers as applying
+  ;; to the HEAD version of the file, not to the current state of the file.
+  ;; So we need to look at all the local changes and adjust lfrom/lto
+  ;; accordingly.
+  ;; FIXME: Maybe this should be done in vc.el (i.e. for all backends), but
+  ;; since Git is the only backend to support this operation so far, it's hard
+  ;; to tell.
+  (with-temp-buffer
+    (vc-call-backend 'git 'diff file "HEAD" nil (current-buffer))
+    (goto-char (point-min))
+    (let ((last-offset 0)
+          (from-offset nil)
+          (to-offset nil))
+      (while (re-search-forward
+              "^@@ -\\([0-9]+\\),\\([0-9]+\\) \\+\\([0-9]+\\),\\([0-9]+\\) @@" nil t)
+        (let ((headno (string-to-number (match-string 1)))
+              (headcnt (string-to-number (match-string 2)))
+              (curno (string-to-number (match-string 3)))
+              (curcnt (string-to-number (match-string 4))))
+          (cl-assert (equal (- curno headno) last-offset))
+          (and (null from-offset) (> curno lfrom)
+               (setq from-offset last-offset))
+          (and (null to-offset) (> curno lto)
+               (setq to-offset last-offset))
+          (setq last-offset
+                (- (+ curno curcnt) (+ headno headcnt)))))
+      (setq lto (- lto (or to-offset last-offset)))
+      (setq lfrom (- lfrom (or to-offset last-offset)))))
   (vc-git-command buffer 'async nil "log" "-p" ;"--follow" ;FIXME: not supported?
                   (format "-L%d,%d:%s" lfrom lto (file-relative-name file))))
 
@@ -1022,7 +1087,7 @@ or BRANCH^ (where \"^\" can be repeated)."
 
 (autoload 'vc-switches "vc")
 
-(defun vc-git-diff (files &optional rev1 rev2 buffer async)
+(defun vc-git-diff (files &optional rev1 rev2 buffer _async)
   "Get a difference report using Git between two revisions of FILES."
   (let (process-file-side-effects
         (command "diff-tree"))
@@ -1033,7 +1098,7 @@ or BRANCH^ (where \"^\" can be repeated)."
       (unless rev1 (setq rev1 "HEAD")))
     (if vc-git-diff-switches
         (apply #'vc-git-command (or buffer "*vc-diff*")
-              (if async 'async 1)
+              1 ; bug#21969
               files
                command
                "--exit-code"
@@ -1336,11 +1401,15 @@ This command shares argument histories with \\[rgrep] and \\[grep]."
 
 (defun vc-git-stash-apply-at-point ()
   (interactive)
-  (vc-git-stash-apply (format "stash@%s" (vc-git-stash-get-at-point (point)))))
+  (let (vc-dir-buffers) ; Small optimization.
+    (vc-git-stash-apply (format "stash@%s" (vc-git-stash-get-at-point (point)))))
+  (vc-dir-refresh))
 
 (defun vc-git-stash-pop-at-point ()
   (interactive)
-  (vc-git-stash-pop (format "stash@%s" (vc-git-stash-get-at-point (point)))))
+  (let (vc-dir-buffers) ; Likewise.
+    (vc-git-stash-pop (format "stash@%s" (vc-git-stash-get-at-point (point)))))
+  (vc-dir-refresh))
 
 (defun vc-git-stash-menu (e)
   (interactive "e")
@@ -1353,8 +1422,10 @@ This command shares argument histories with \\[rgrep] and \\[grep]."
   "A wrapper around `vc-do-command' for use in vc-git.el.
 The difference to vc-do-command is that this function always invokes
 `vc-git-program'."
-  (let ((coding-system-for-read vc-git-commits-coding-system)
-       (coding-system-for-write vc-git-commits-coding-system))
+  (let ((coding-system-for-read
+         (or coding-system-for-read vc-git-log-output-coding-system))
+       (coding-system-for-write
+         (or coding-system-for-write vc-git-commits-coding-system)))
     (apply 'vc-do-command (or buffer "*vc*") okstatus vc-git-program
           ;; http://debbugs.gnu.org/16897
           (unless (and (not (cdr-safe file-or-list))
@@ -1377,8 +1448,10 @@ The difference to vc-do-command is that this function always invokes
   ;; directories.  We enable `inhibit-null-byte-detection', otherwise
   ;; Tramp's eol conversion might be confused.
   (let ((inhibit-null-byte-detection t)
-       (coding-system-for-read vc-git-commits-coding-system)
-       (coding-system-for-write vc-git-commits-coding-system)
+       (coding-system-for-read
+         (or coding-system-for-read vc-git-log-output-coding-system))
+       (coding-system-for-write
+         (or coding-system-for-write vc-git-commits-coding-system))
        (process-environment (cons "PAGER=" process-environment)))
     (apply 'process-file vc-git-program nil buffer nil command args)))