summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--init.el9
-rw-r--r--lisp/km-magit.el78
2 files changed, 86 insertions, 1 deletions
diff --git a/init.el b/init.el
index 530efd3..3001f8f 100644
--- a/init.el
+++ b/init.el
@@ -1190,7 +1190,14 @@
'("V" "Back up current branch, v" km/magit-branch-version))
(transient-append-suffix 'magit-branch "c"
- '("m" "Checkout master" km/magit-checkout-master)))
+ '("m" "Checkout master" km/magit-checkout-master))
+
+ (after 'magit-patch
+ (transient-append-suffix 'magit-patch-create "c"
+ '("u" "@{upstream}.." km/magit-patch-create-from-upstream))
+
+ (transient-append-suffix 'magit-patch-create "u"
+ '("s" "series" km/magit-patch-create-series))))
(use-package magit-annex
:load-path "~/src/emacs/magit-annex/"
diff --git a/lisp/km-magit.el b/lisp/km-magit.el
index f0819de..8f2179a 100644
--- a/lisp/km-magit.el
+++ b/lisp/km-magit.el
@@ -26,6 +26,7 @@
(require 'km-util)
(require 'magit)
(require 'projectile)
+(require 'seq)
;;;###autoload
(defun km/magit-status (&optional default-display)
@@ -832,6 +833,83 @@ category."
(magit-run-git-async "for-each-ref" (format "--contains=%s" rev)
"--sort=v:refname" "refs/tags")))
+(defun km/magit-patch-create-from-upstream (&optional args)
+ (interactive (list (transient-args 'magit-patch-create)))
+ (if-let ((upstream (magit-get-upstream-branch)))
+ (apply #'magit-run-git "format-patch" upstream args)
+ (user-error "No upstream branch")))
+
+(defun km/magit-tweak-patch-series-summary ()
+ "Restyle \"My Name (N):\" heading.
+Drop author for single author series by `user-full-name',
+appending [M/N] to each entry."
+ (interactive)
+ (save-excursion
+ (goto-char (point-min))
+ (search-forward "*** BLURB HERE ***")
+ (let ((author-regexp (rx line-start word (zero-or-more not-newline)
+ "(" (one-or-more digit) "):" line-end)))
+ ;; Don't proceed if there looks to be more than one author.
+ (unless (and (re-search-forward author-regexp nil t)
+ (re-search-forward author-regexp nil t))
+ (let ((buffer-read-only nil))
+ (save-excursion
+ (goto-char (point-min))
+ (when-let ((total (and (re-search-forward
+ (rx line-start (eval user-full-name) " ("
+ (group (one-or-more digit))
+ "):" line-end)
+ nil t)
+ (match-string 1)))
+ (prefix (format "[%%%dd/%s] " (length total) total))
+ (idx 1))
+ (delete-region (line-beginning-position) (1+ (line-end-position)))
+ (while (and (not (eobp))
+ (not (looking-at-p "^$")))
+ (goto-char (line-beginning-position))
+ (skip-chars-forward " ")
+ (insert (format prefix idx))
+ (cl-incf idx)
+ (forward-line)))))))))
+
+(defun km/magit-patch-create-series (&optional args)
+ (interactive (list (transient-args 'magit-patch-create)))
+ (when (magit-anything-modified-p t)
+ (user-error "There are uncommitted changes"))
+ (setq args (seq-remove
+ (lambda (a) (string-match-p "\\`--base=" a))
+ args))
+ (if-let ((current (magit-get-current-branch))
+ (upstream (magit-get-upstream-branch current)))
+ (let ((patch-branch (concat "patches/" current)))
+ (if (not (magit-local-branch-p patch-branch))
+ (magit-branch-and-checkout patch-branch current)
+ (magit-update-ref (concat "refs/heads/" patch-branch)
+ (concat "reset: moving back to " current)
+ current)
+ (magit-branch-checkout patch-branch))
+ (apply #'magit-run-git "format-patch"
+ upstream (concat "--base=" upstream) args)
+ (let* ((patches (or (seq-filter
+ (lambda (f) (string-match-p "\\.patch\\'" f))
+ (magit-untracked-files))
+ (error "There should be patches")))
+ (cover (seq-find (lambda (f) (string-match-p "\\`0+-" f))
+ patches)))
+ (magit-call-git "add" patches)
+ (magit-run-git "commit" "-mpatches")
+ (when cover
+ (with-temp-buffer
+ (insert-file-contents cover)
+ (km/magit-tweak-patch-series-summary)
+ (write-region nil nil cover))
+ (magit-call-git "commit" "-mtweak cover" "--" cover))
+ (when cover
+ (find-file-other-window cover)
+ (re-search-forward (rx "Subject: [PATCH" (zero-or-more not-newline) "] "))
+ (setq buffer-read-only nil))))
+ (user-error "No upstream branch")))
+
;;; Copy functions