Function: vc-git-checkin

vc-git-checkin is a byte-compiled function defined in vc-git.el.gz.

Signature

(vc-git-checkin FILES COMMENT &optional REV)

Source Code

;; Defined in /usr/src/emacs/lisp/vc/vc-git.el.gz
(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)))))
         (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.  Handle also remote files.
          (if (eq system-type 'windows-nt)
              (let ((default-directory (or (file-name-directory file1)
                                           default-directory)))
                (make-nearby-temp-file "git-msg")))))
    (when vc-git-patch-string
      (unless (zerop (vc-git-command nil t nil "diff" "--cached" "--quiet"))
        ;; Check that all staged changes also exist in the patch.
        ;; This is needed to allow adding/removing files that are
        ;; currently staged to the index.  So remove the whole file diff
        ;; from the patch because commit will take it from the index.
        (with-temp-buffer
          ;; If the user has switches like -D, -M etc. in their
          ;; `vc-git-diff-switches', we must pass them here too, or
          ;; our string matches will fail.
          (if vc-git-diff-switches
              (apply #'vc-git-command (current-buffer) t nil
                     "diff" "--cached" (vc-switches 'git 'diff))
            ;; Following code doesn't understand plain diff(1) output.
            (user-error "Cannot commit patch with nil `vc-git-diff-switches'"))
          (goto-char (point-min))
          (let ((pos (point)) file-diff file-beg)
            (while (not (eobp))
              (forward-line 1) ; skip current "diff --git" line
              (search-forward "diff --git" nil 'move)
              (move-beginning-of-line 1)
              (setq file-diff (buffer-substring pos (point)))
              (if (and (setq file-beg (string-search
                                       file-diff vc-git-patch-string))
                       ;; Check that file diff ends with an empty string
                       ;; or the beginning of the next file diff.
                       (string-match-p "\\`\\'\\|\\`diff --git"
                                       (substring
                                        vc-git-patch-string
                                        (+ file-beg (length file-diff)))))
                  (setq vc-git-patch-string
                        (string-replace file-diff "" vc-git-patch-string))
                (user-error "Index not empty"))
              (setq pos (point))))))
      (unless (string-empty-p vc-git-patch-string)
        (let ((patch-file (make-nearby-temp-file "git-patch"))
              ;; Temporarily countermand the let-binding at the
              ;; beginning of this function.
              (coding-system-for-write
               (coding-system-change-eol-conversion
                ;; On DOS/Windows, it is important for the patch file
                ;; to have the Unix EOL format, because Git expects
                ;; that, even on Windows.
                (or pcsw vc-git-commits-coding-system) 'unix)))
          (with-temp-file patch-file
            (insert vc-git-patch-string))
          (unwind-protect
              (vc-git-command nil 0 patch-file "apply" "--cached")
            (delete-file patch-file)))))
    (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 (and only (not vc-git-patch-string)) files)
             (nconc (if msg-file (list "commit" "-F"
                                       (file-local-name msg-file))
                      (list "commit" "-m"))
                    (let ((args
                           (log-edit-extract-headers
                            `(("Author" . "--author")
                              ("Date" . "--date")
                              ("Amend" . ,(boolean-arg-fn "--amend"))
                              ("No-Verify" . ,(boolean-arg-fn "--no-verify"))
                              ("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)
                    (unless vc-git-patch-string
                      (if only (list "--only" "--") '("-a"))))))
    (if (and msg-file (file-exists-p msg-file)) (delete-file msg-file))))