James Thomas <jim...@gmx.net> writes: > Suhail Singh writes: > >> emacs-git-email > > This is only tangential, but... > > I'd come up with an equivalent (?) hack that I'd posted here: > > (gnus-summary-goto-article "<868qypm5c5....@gmx.net>") > > Basically: > >> M-& >> git send-email --sendmail-cmd=echo HEAD^..HEAD >> RET >>
FWIW, I've submitted patches to Guix using a version of the built-in vc.el command 'vc-prepare-patch' modified to act like 'git send-email'. Am I missing something, or would the code below do the same thing as 'emacs-git-email'? Could we submit a patch upstream to Emacs to make sending patches to projects like Guix easier? --8<---------------cut here---------------start------------->8--- (require 'vc) (require 'seq) (defun fern--git-variable (variable &optional file) "Return the value of the Git VARIABLE for the repo containing FILE. Return nil if the variable is undefined or if FILE is not version controlled by Git." (when-let* (((memq (ignore-errors (vc-responsible-backend (or file default-directory))) '(Git))) (result (string-chop-newline (shell-command-to-string (format "git config --get %s" (shell-quote-argument variable))))) ((not (string-empty-p result)))) result)) (defun fern-prepare-patch (addressee subject revisions &optional other-headers no-self-bcc) "Compose an email sending patches for REVISIONS to ADDRESSEE. Interactively, prompt for REVISIONS and prompt for ADDRESSEE if it cannot be determined automatically (see below). When invoked with a numerical prefix argument, use the last N revisions. If `vc-prepare-patches-separately' is nil, use SUBJECT as the subject, or prompt for a subject when invoked interactively. Otherwise, compose a separate message for each revision, with the subject automatically derived from each revision subject. Optional argument OTHER-HEADERS is as with `compose-mail', which see. When invoked interactively, OTHER-HEADERS is automatically populated by running the command specified by the sendemail.headerCmd. That command, if found, will be called with one argument, a patch file for the first revision in REVISIONS. Unless optional argument NO-SELF-BCC is non-nil, add a Bcc header with the user's mail address, specified by the value of `user-mail-address'. This command is like `vc-prepare-patch', but differs in that it automatically determines ADDRESSEE according to the sendemail.to Git variable, and it adds extra headers according to the sendemail.headerCmd Git variable (see above). Additionally, it ensures that no signatures are inserted at the end of the message. This makes the behavior more similar to what one would expect from `git send-email' command." ;; Modified from `vc-prepare-patch'. (interactive (let* ((revs (vc-prepare-patch-prompt-revisions)) (rev (car revs)) (patch (vc-call-backend (vc-responsible-backend default-directory) 'prepare-patch rev)) (subject (when (length= revs 1) (plist-get patch :subject))) (to (or (fern--git-variable "sendemail.to") (progn (require 'message) (completing-read (format-prompt "Addressee" vc-default-patch-addressee) (message--name-table "") nil nil nil nil vc-default-patch-addressee)))) (other (when-let* ((buf (plist-get patch :buffer)) (patch-file (make-temp-file (format "vc-patch-for-%s" rev) nil nil (with-current-buffer buf (buffer-substring-no-properties (point-min) (point-max))))) (cmd (fern--git-variable "sendemail.headerCmd")) ;; XXX: Give headerCmd a patch file argument. (cmd-1 (concat cmd " " (shell-quote-argument patch-file))) ;; XXX: Prompt before running the command ;; as a security precaution! (headers (when (yes-or-no-p (format "Run header command: %s?" cmd-1)) (shell-command-to-string cmd-1)))) (let (result) (dolist (header (string-lines headers)) ;; XXX: Is this regexp enough to parse header ;; names and values? (when (string-match "^\\([^:]+\\):[[:blank:]]*\\(.*\\)$" header) (push (cons (match-string 1 header) (match-string 2 header)) result))) (nreverse result))))) (list to (and (not vc-prepare-patches-separately) (read-string "Subect: " (or subject "[PATCH] ") nil nil t)) revs other))) (save-current-buffer (let ((patches (mapcar (lambda (rev) (vc-call-backend (vc-responsible-backend default-directory) 'prepare-patch rev)) revisions)) ;; XXX: Disable signatures (mail-signature nil) (message-signature nil)) (unless no-self-bcc (let* ((val (alist-get "bcc" other-headers nil nil #'string-equal-ignore-case)) (val-1 (if (stringp val) (string-join (seq-uniq (append (list user-mail-address) (split-string val ",[[:blank:]]*")) #'string-equal-ignore-case) ", ") user-mail-address))) (setq other-headers (copy-tree other-headers)) (setf (alist-get "bcc" other-headers nil nil #'string-equal-ignore-case) val-1))) (if vc-prepare-patches-separately (dolist (patch (reverse patches)) (compose-mail addressee (plist-get patch :subject) other-headers nil nil nil `((kill-buffer ,(plist-get patch :buffer)))) (rfc822-goto-eoh) (forward-line) (save-excursion (insert-buffer-substring (plist-get patch :buffer) (plist-get patch :body-start) (plist-get patch :body-end)))) (compose-mail addressee subject other-headers nil nil nil (mapcar (lambda (p) (list #'kill-buffer (plist-get p :buffer))) patches)) (rfc822-goto-eoh) (forward-line) (save-excursion (let ((i 0)) (dolist (patch patches) (let* ((patch-subject (plist-get patch :subject)) (file (vc--subject-to-file-name patch-subject))) (mml-attach-buffer (buffer-name (plist-get patch :buffer)) "text/x-patch" patch-subject "attachment" (format "%04d-%s" (setq i (1+ i)) file)))))) (open-line 2))))) --8<---------------cut here---------------end--------------->8--- -- Kierin Bell