"O" key-binding calls "git format-patch" from within magit.  Formatted
patches may optionally be opened in mail-mode buffers to be mailed from
within Emacs.
---
 magit-key-mode.el | 46 ++++++++++++++++++++++++++++++++++++++--
 magit.el          | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+), 2 deletions(-)

diff --git a/magit-key-mode.el b/magit-key-mode.el
index 563a395..11fd093 100644
--- a/magit-key-mode.el
+++ b/magit-key-mode.el
@@ -237,8 +237,50 @@
       ("-h" "Use histogram diff algorithm" "--histogram")
       ("-b" "Ignore whitespace changes" "--ignore-space-change")
       ("-w" "Ignore all whitespace" "--ignore-all-space")
-      ("-W" "Show surrounding functions" "--function-context"))
-     ))
+      ("-W" "Show surrounding functions" "--function-context")))
+
+    (format-patch
+     (man-page "git-format-patch")
+     (actions
+      ("f" "Format patch" magit-format-patch)
+      ("e" "Open patch(es) in mail buffers" magit-format-patch-as-message))
+     ;; The following switches and arguments are not used because they
+     ;; don't seem that commonly useful to me (maybe I'm wrong).
+     ;;
+     ;; ("-n" "use [PATCH n/m] even with a single patch" "--numbered")
+     ;; ("-N" "use [PATCH] even with multiple patches" "--no-numbered")
+     ;; ("=a" "attach the patch (Boundary)" "--attach=" read-from-minibuffer)
+     ;; ("=I" "inline the patch (Boundary)" "--inline=" read-from-minibuffer)
+     ;; ("=T" "enable message threading, styles: shallow, deep"
+     ;;  "--thread=" read-from-minibuffer)
+     (switches
+      ("-s" "print patches to standard out" "--stdout")
+      ("-S" "add Signed-off-by:" "--signoff")
+      ("-C" "generate a cover letter" "--cover-letter")
+      ("-n" "use simple number sequence for output file names"
+       "--numbered-files")
+      ("-k" "don't strip/add [PATCH]" "--keep-subject")
+      ("-B" "don't output binary diffs" "--no-binary")
+      ("-i" "don't include a patch matching a commit upstream"
+       "--ignore-if-in-upstream")
+      ("-p" "show patch format instead of default (patch + stat)" "--no-stat"))
+     (arguments
+      ("=o" "store resulting files in <dir>" "--output-directory="
+       read-directory-name)
+      ("=v" "mark the series as Nth re-roll" "--reroll-count="
+       read-number)
+      ("=P" "Use [<prefix>] instead of [PATCH]" "--subject-prefix="
+       read-from-minibuffer)
+      ("=N" "start numbering patches at <n> instead of 1" "--start-number="
+       read-number)
+      ("=S" "Signature" "--signature=" read-from-minibuffer)
+      ("=h" "add email header" "--add-header=" read-from-minibuffer)
+      ("=t" "add To: header" "--to=" read-from-minibuffer)
+      ("=c" "add Cc: header" "--cc=" read-from-minibuffer)
+      ("=f" "set From address to <ident>" "--from=" read-from-minibuffer)
+      ("=r" "make first mail a reply to <message-id>" "--in-reply-to="
+       read-from-minibuffer)))
+    )
   "Holds the key, help, function mapping for the log-mode.
 If you modify this make sure you reset `magit-key-mode-keymaps'
 to nil.")
diff --git a/magit.el b/magit.el
index 163878d..b7cf553 100644
--- a/magit.el
+++ b/magit.el
@@ -924,6 +924,7 @@ face inherit from `default' and remove all other 
attributes."
            (define-key map (kbd "t") 'magit-tag)
            (define-key map (kbd "l") 'magit-log)
            (define-key map (kbd "o") 'magit-submodule-update)
+           (define-key map (kbd "O") 'magit-format-patch)
            (define-key map (kbd "B") 'undefined))
           (t
            (define-key map (kbd "c") 'magit-key-mode-popup-committing)
@@ -938,6 +939,7 @@ face inherit from `default' and remove all other 
attributes."
            (define-key map (kbd "t") 'magit-key-mode-popup-tagging)
            (define-key map (kbd "l") 'magit-key-mode-popup-logging)
            (define-key map (kbd "o") 'magit-key-mode-popup-submodule)
+           (define-key map (kbd "O") 'magit-key-mode-popup-format-patch)
            (define-key map (kbd "B") 'magit-key-mode-popup-bisecting)))
     (define-key map (kbd "$") 'magit-display-process)
     (define-key map (kbd "E") 'magit-interactive-rebase)
@@ -2999,6 +3001,67 @@ With a prefix argument, kill the buffer instead."
              ,@(unless magit-status-verbose-untracked
                  '("--directory"))))))
 
+;;; Format Patches and Send Messages
+(defun magit-mail-from-patch (patches)
+  (require 'sendmail)
+  (let* ((headers-end (or (string-match "^$" patches)
+                          (error "missing patch delimiter")))
+         (patch-end (string-match "^From " patches headers-end))
+         (patch (substring patches 0 patch-end))
+         (marker 0)
+         headers)
+    ;; collect email fields for transfer to the mail buffer
+    (while (string-match "^\\([[:alpha:]]+\\): \\([^\n]+\\)"
+                         patch marker)
+      (setf marker (match-end 0))
+      (push (cons (intern (downcase (match-string 1 patch)))
+                  (match-string 2 patch))
+            headers))
+    ;; open the mail buffer with collected fields
+    (mail nil
+          (cdr (assoc 'to headers))
+          (cdr (assoc 'subject headers))
+          (cdr (assoc 'in-reply-to headers))
+          (cdr (assoc 'cc headers))
+          nil
+          ;; after sending send any subsequent messages
+          (when patch-end
+            `(((lambda (buf)
+                 ;; set as not modified to avoid user prompt
+                 (pop-to-buffer buf)
+                 (set-buffer-modified-p nil)) "*mail*")
+              (magit-mail-from-patch ,(substring patches patch-end)))))
+    (mail-text)
+    (save-excursion (insert (substring patch headers-end)))
+    ;; use this instead of `mail-send-and-exit' to keep this buffer on top
+    (when patch-end
+      (local-set-key (kbd "C-c C-c") 'mail-send))))
+
+(defun magit-format-patch (&optional as-message)
+  "Format Patches and write to disk or view in magit."
+  (interactive "P")
+  (let* ((since (magit-read-rev-with-default "since: "))
+         (output (apply #'magit-git-string "format-patch"
+                        (append magit-custom-options (list since)))))
+    (cond
+     (as-message (magit-mail-from-patch output))
+     ((member "--stdout" magit-custom-options)
+      (with-current-buffer (find-file-noselect (magit-git-dir "FORMAT_PATCH"))
+        (funcall (if (functionp magit-server-window-for-commit)
+                     magit-server-window-for-commit
+                   'switch-to-buffer)
+                 (current-buffer))
+        (delete-region (point-min) (point-max))
+        (insert output)
+        (goto-char (point-min))))
+     (t (message "%s" output)))))
+
+(defun magit-format-patch-as-message ()
+  "Format Patches and open the results in a message buffer."
+  (interactive)
+  (cl-pushnew "--stdout" magit-custom-options)
+  (magit-format-patch 'as-message))
+
 ;;; Diffs and Hunks
 
 (defvar magit-diff-context-lines 3)
-- 
1.8.4

-- 

--- 
You received this message because you are subscribed to the Google Groups 
"magit" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to