Merge branch 'master' of git://repo.or.cz/git-gui
[gitweb.git] / contrib / emacs / git.el
index 24629eb3e211505728c77db820618021203241ae..db87a37895f952a4e9b90de4b426e5c2ca7c0c0d 100644 (file)
@@ -75,10 +75,11 @@ then to `add-log-mailing-address' and then to `user-mail-address'."
   :type '(choice (const :tag "Default" nil)
                  (string :tag "Email")))
 
-(defcustom git-commits-coding-system 'utf-8
+(defcustom git-commits-coding-system nil
   "Default coding system for the log message of git commits."
   :group 'git
-  :type 'coding-system)
+  :type '(choice (const :tag "From repository config" nil)
+                 (coding-system)))
 
 (defcustom git-append-signed-off-by nil
   "Whether to append a Signed-off-by line to the commit message before editing."
@@ -236,6 +237,15 @@ and returns the process output as a string."
       (and (fboundp 'user-mail-address) (user-mail-address))
       (and (boundp 'user-mail-address) user-mail-address)))
 
+(defun git-get-commits-coding-system ()
+  "Return the coding system to use for commits."
+  (let ((repo-config (git-config "i18n.commitencoding")))
+    (or git-commits-coding-system
+        (and repo-config
+             (fboundp 'locale-charset-to-coding-system)
+             (locale-charset-to-coding-system repo-config))
+      'utf-8)))
+
 (defun git-escape-file-name (name)
   "Escape a file name if necessary."
   (if (string-match "[\n\t\"\\]" name)
@@ -327,7 +337,7 @@ and returns the process output as a string."
   "Call git-commit-tree with buffer as input and return the resulting commit SHA1."
   (let ((author-name (git-get-committer-name))
         (author-email (git-get-committer-email))
-        author-date log-start log-end args)
+        author-date log-start log-end args coding-system-for-write)
     (when head
       (push "-p" args)
       (push head args))
@@ -350,12 +360,12 @@ and returns the process output as a string."
                 (push "-p" args)
                 (push (match-string 1) args))))
         (setq log-start (point-min)))
-      (setq log-end (point-max)))
+      (setq log-end (point-max))
+      (setq coding-system-for-write buffer-file-coding-system))
     (git-get-string-sha1
      (with-output-to-string
        (with-current-buffer standard-output
-         (let ((coding-system-for-write git-commits-coding-system)
-               (env `(("GIT_AUTHOR_NAME" . ,author-name)
+         (let ((env `(("GIT_AUTHOR_NAME" . ,author-name)
                       ("GIT_AUTHOR_EMAIL" . ,author-email)
                       ("GIT_COMMITTER_NAME" . ,(git-get-committer-name))
                       ("GIT_COMMITTER_EMAIL" . ,(git-get-committer-email)))))
@@ -881,37 +891,80 @@ and returns the process output as a string."
   (with-current-buffer log-edit-parent-buffer
     (git-get-filenames (git-marked-files-state 'added 'deleted 'modified))))
 
+(defun git-append-sign-off (name email)
+  "Append a Signed-off-by entry to the current buffer, avoiding duplicates."
+  (let ((sign-off (format "Signed-off-by: %s <%s>" name email))
+        (case-fold-search t))
+    (goto-char (point-min))
+    (unless (re-search-forward (concat "^" (regexp-quote sign-off)) nil t)
+      (goto-char (point-min))
+      (unless (re-search-forward "^Signed-off-by: " nil t)
+        (setq sign-off (concat "\n" sign-off)))
+      (goto-char (point-max))
+      (insert sign-off "\n"))))
+
+(defun git-setup-log-buffer (buffer &optional author-name author-email subject date msg)
+  "Setup the log buffer for a commit."
+  (unless git-status (error "Not in git-status buffer."))
+  (let ((merge-heads (git-get-merge-heads))
+        (dir default-directory)
+        (committer-name (git-get-committer-name))
+        (committer-email (git-get-committer-email))
+        (sign-off git-append-signed-off-by))
+    (with-current-buffer buffer
+      (cd dir)
+      (erase-buffer)
+      (insert
+       (propertize
+        (format "Author: %s <%s>\n%s%s"
+                (or author-name committer-name)
+                (or author-email committer-email)
+                (if date (format "Date: %s\n" date) "")
+                (if merge-heads
+                    (format "Parent: %s\n%s\n"
+                            (git-rev-parse "HEAD")
+                            (mapconcat (lambda (str) (concat "Parent: " str)) merge-heads "\n"))
+                  ""))
+        'face 'git-header-face)
+       (propertize git-log-msg-separator 'face 'git-separator-face)
+       "\n")
+      (when subject (insert subject "\n\n"))
+      (cond (msg (insert msg "\n"))
+            ((file-readable-p ".dotest/msg")
+             (insert-file-contents ".dotest/msg"))
+            ((file-readable-p ".git/MERGE_MSG")
+             (insert-file-contents ".git/MERGE_MSG")))
+      ; delete empty lines at end
+      (goto-char (point-min))
+      (when (re-search-forward "\n+\\'" nil t)
+        (replace-match "\n" t t))
+      (when sign-off (git-append-sign-off committer-name committer-email)))))
+
 (defun git-commit-file ()
   "Commit the marked file(s), asking for a commit message."
   (interactive)
   (unless git-status (error "Not in git-status buffer."))
   (let ((buffer (get-buffer-create "*git-commit*"))
-        (merge-heads (git-get-merge-heads))
-        (dir default-directory)
-        (sign-off git-append-signed-off-by))
-    (with-current-buffer buffer
-      (when (eq 0 (buffer-size))
-        (cd dir)
-        (erase-buffer)
-        (insert
-         (propertize
-          (format "Author: %s <%s>\n%s"
-                  (git-get-committer-name) (git-get-committer-email)
-                  (if merge-heads
-                      (format "Parent: %s\n%s\n"
-                              (git-rev-parse "HEAD")
-                              (mapconcat (lambda (str) (concat "Parent: " str)) merge-heads "\n"))
-                    ""))
-          'face 'git-header-face)
-         (propertize git-log-msg-separator 'face 'git-separator-face)
-         "\n")
-        (cond ((file-readable-p ".git/MERGE_MSG")
-               (insert-file-contents ".git/MERGE_MSG"))
-              (sign-off
-               (insert (format "\n\nSigned-off-by: %s <%s>\n"
-                               (git-get-committer-name) (git-get-committer-email)))))))
+        (coding-system (git-get-commits-coding-system))
+        author-name author-email subject date)
+    (when (eq 0 (buffer-size buffer))
+      (when (file-readable-p ".dotest/info")
+        (with-temp-buffer
+          (insert-file-contents ".dotest/info")
+          (goto-char (point-min))
+          (when (re-search-forward "^Author: \\(.*\\)\nEmail: \\(.*\\)$" nil t)
+            (setq author-name (match-string 1))
+            (setq author-email (match-string 2)))
+          (goto-char (point-min))
+          (when (re-search-forward "^Subject: \\(.*\\)$" nil t)
+            (setq subject (match-string 1)))
+          (goto-char (point-min))
+          (when (re-search-forward "^Date: \\(.*\\)$" nil t)
+            (setq date (match-string 1)))))
+      (git-setup-log-buffer buffer author-name author-email subject date))
     (log-edit #'git-do-commit nil #'git-log-edit-files buffer)
     (setq font-lock-keywords (font-lock-compile-keywords git-log-edit-font-lock-keywords))
+    (setq buffer-file-coding-system coding-system)
     (re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t)))
 
 (defun git-find-file ()