Improve handling of non-ASCII characters in Git log messages

* lisp/vc/vc-git.el (vc-git-commits-coding-system): Now a defcustom.
(vc-git-log-output-coding-system): New defcustom.
(vc-git-print-log, vc-git-command, vc-git--call): Use
'vc-git-log-output-coding-system' for reading stuff from Git.
Don't override values of 'coding-system-for-read/write' if they
are bound by caller -- this allows the user to force an encoding
via "C-x RET c".
(vc-git-checkin): On MS-Windows, pass the log message via a
temporary file, to work around the limitations on passing
non-ASCII characters via command-line arguments.  Force using the
'locale-coding-system' for Git command-line arguments.  This fixes
problems with non-ASCII commit log messages on MS-Windows.
(Bug#23076)

* etc/NEWS: Mention the new vc-git related defcustoms.
This commit is contained in:
Eli Zaretskii 2016-04-10 19:04:33 +03:00
parent b57076929f
commit 668c7bc5ba
2 changed files with 62 additions and 15 deletions

View file

@ -987,6 +987,17 @@ back-end for the buffer's file, or remove it from version control.
the color range from 'vc-annotate-color-map' is applied to the the color range from 'vc-annotate-color-map' is applied to the
background or to the foreground. background or to the foreground.
---
*** New options for customizing encoding of Git commit log messages.
The new options `vc-git-commits-coding-system' and
`vc-git-log-output-coding-system' allow to customize the encoding of
the log messages sent to Git when committing, and the decoding of the
log messages read from Git history commands. Both default to UTF-8;
if you customize them, make sure they are consistent with the Git
config variables i18n.commitEncoding and i18n.logOutputEncoding.
(`vc-git-commits-coding-system' existed previously, but was a
variable, not a user option.)
+++ +++
*** 'compare-windows' now compares text with the most recently selected window *** 'compare-windows' now compares text with the most recently selected window
instead of the next window. If you want the previous behavior of instead of the next window. If you want the previous behavior of

View file

@ -165,8 +165,20 @@ matching the resulting Git log output, and KEYWORDS is a list of
:type '(list string string (repeat sexp)) :type '(list string string (repeat sexp))
:version "24.1") :version "24.1")
(defvar vc-git-commits-coding-system 'utf-8 (defcustom vc-git-commits-coding-system 'utf-8
"Default coding system for git commits.") "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. ;; History of Git commands.
(defvar vc-git-history nil) (defvar vc-git-history nil)
@ -680,21 +692,43 @@ It is based on `log-edit-mode', and has Git-specific extensions.")
(default-directory (expand-file-name root)) (default-directory (expand-file-name root))
(only (or (cdr files) (only (or (cdr files)
(not (equal root (abbreviate-file-name file1))))) (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 (cl-flet ((boolean-arg-fn
(argument) (argument)
(lambda (value) (when (equal value "yes") (list argument))))) (lambda (value) (when (equal value "yes") (list argument)))))
;; When operating on the whole tree, better pass "-a" than ".", since "." ;; When operating on the whole tree, better pass "-a" than ".", since "."
;; fails when we're committing a merge. ;; fails when we're committing a merge.
(apply 'vc-git-command nil 0 (if only files) (apply 'vc-git-command nil 0 (if only files)
(nconc (list "commit" "-m") (nconc (if msg-file (list "commit" "-F" msg-file)
(log-edit-extract-headers (list "commit" "-m"))
`(("Author" . "--author") (let ((args
("Date" . "--date") (log-edit-extract-headers
("Amend" . ,(boolean-arg-fn "--amend")) `(("Author" . "--author")
("Sign-Off" . ,(boolean-arg-fn "--signoff"))) ("Date" . "--date")
comment) ("Amend" . ,(boolean-arg-fn "--amend"))
(if only (list "--only" "--") '("-a"))))))) ("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) (defun vc-git-find-revision (file rev buffer)
(let* (process-file-side-effects (let* (process-file-side-effects
@ -854,7 +888,7 @@ If SHORTLOG is non-nil, use a short format based on `vc-git-root-log-format'.
If START-REVISION is non-nil, it is the newest revision to show. 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." If LIMIT is non-nil, show no more than this many entries."
(let ((coding-system-for-read (let ((coding-system-for-read
(or coding-system-for-read vc-git-commits-coding-system))) (or coding-system-for-read vc-git-log-output-coding-system)))
;; `vc-do-command' creates the buffer, but we need it before running ;; `vc-do-command' creates the buffer, but we need it before running
;; the command. ;; the command.
(vc-setup-buffer buffer) (vc-setup-buffer buffer)
@ -1387,7 +1421,7 @@ This command shares argument histories with \\[rgrep] and \\[grep]."
The difference to vc-do-command is that this function always invokes The difference to vc-do-command is that this function always invokes
`vc-git-program'." `vc-git-program'."
(let ((coding-system-for-read (let ((coding-system-for-read
(or coding-system-for-read vc-git-commits-coding-system)) (or coding-system-for-read vc-git-log-output-coding-system))
(coding-system-for-write (coding-system-for-write
(or coding-system-for-write vc-git-commits-coding-system))) (or coding-system-for-write vc-git-commits-coding-system)))
(apply 'vc-do-command (or buffer "*vc*") okstatus vc-git-program (apply 'vc-do-command (or buffer "*vc*") okstatus vc-git-program
@ -1412,8 +1446,10 @@ The difference to vc-do-command is that this function always invokes
;; directories. We enable `inhibit-null-byte-detection', otherwise ;; directories. We enable `inhibit-null-byte-detection', otherwise
;; Tramp's eol conversion might be confused. ;; Tramp's eol conversion might be confused.
(let ((inhibit-null-byte-detection t) (let ((inhibit-null-byte-detection t)
(coding-system-for-read vc-git-commits-coding-system) (coding-system-for-read
(coding-system-for-write vc-git-commits-coding-system) (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))) (process-environment (cons "PAGER=" process-environment)))
(apply 'process-file vc-git-program nil buffer nil command args))) (apply 'process-file vc-git-program nil buffer nil command args)))