1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-30 12:21:25 -08:00

VC prepare-patch: New :patch-start & :patch-end plist entries

* lisp/vc/vc.el (prepare-patch): Specify :patch-start and
:patch-end plist entries.
* lisp/vc/vc-git.el (vc-git-prepare-patch): Use -n1 to avoid
passing a revision range to git-format-patch, which is a bit
simpler.  Catch search-failed errors and signal an error with a
more helpful message.  Properly handle Subject: header by
looking for continuation lines.  Return :patch-start and
:patch-end entries in the plist.
* lisp/vc/vc-hg.el (vc-hg-prepare-patch): Always pass --git to
'hg export' for consistency.  Catch search-failed errors and
signal an error with a more helpful message.  Return a
:patch-start entry in the plist.
This commit is contained in:
Sean Whitton 2025-09-27 21:36:51 +01:00
parent 1d03eb590c
commit 4e7cb37b84
3 changed files with 57 additions and 38 deletions

View file

@ -2311,26 +2311,39 @@ Rebase may --autosquash your other squash!/fixup!/amend!; proceed?")))
(defun vc-git-prepare-patch (rev)
(with-current-buffer (generate-new-buffer " *vc-git-prepare-patch*")
(vc-git-command
t 0 '() "format-patch"
"--no-numbered" "--stdout"
;; From gitrevisions(7): ^<n> means the <n>th parent
;; (i.e. <rev>^ is equivalent to <rev>^1). As a
;; special rule, <rev>^0 means the commit itself and
;; is used when <rev> is the object name of a tag
;; object that refers to a commit object.
(concat rev "^.." rev))
(let (subject)
;; Extract the subject line
(goto-char (point-min))
(search-forward-regexp "^Subject: \\(.+\\)")
(setq subject (match-string 1))
;; Jump to the beginning for the patch
(search-forward-regexp "\n\n")
;; Return the extracted data
(list :subject subject
:buffer (current-buffer)
:body-start (point)))))
(vc-git-command t 0 nil "format-patch"
"--no-numbered" "--stdout" "-n1" rev)
(condition-case _
(let (subject body-start patch-start patch-end)
(goto-char (point-min))
(re-search-forward "^Subject: \\(.*\\)")
(setq subject (match-string 1))
(while (progn (forward-line 1)
(looking-at "[\s\t]\\(.*\\)"))
(setq subject (format "%s %s" subject (match-string 1))))
(goto-char (point-min))
(re-search-forward "\n\n")
(setq body-start (point))
(if ;; If the user has added any of these to
;; `vc-git-diff-switches' then they expect to see the
;; diffstat in *vc-diff* buffers.
(cl-intersection '("--stat"
"--patch-with-stat"
"--compact-summary")
(vc-switches 'git 'diff)
:test #'equal)
(progn (re-search-forward "^---$")
(setq patch-start (pos-bol 2)))
(re-search-forward "^diff --git a/")
(setq patch-start (pos-bol)))
(re-search-forward "^-- $")
(setq patch-end (pos-bol))
(list :subject subject
:body-start body-start
:patch-start patch-start
:patch-end patch-end
:buffer (current-buffer)))
(search-failed (error "git-format-patch output parse failure")))))
;; grep-compute-defaults autoloads grep.
(declare-function grep-read-regexp "grep" ())

View file

@ -1673,14 +1673,18 @@ This runs the command \"hg merge\"."
(defun vc-hg-prepare-patch (rev)
(with-current-buffer (generate-new-buffer " *vc-hg-prepare-patch*")
(vc-hg-command t 0 '() "export" "--rev" rev)
(let (subject)
;; Extract the subject line
(goto-char (point-min))
(search-forward-regexp "^[^#].*")
(setq subject (match-string 0))
;; Return the extracted data
(list :subject subject :buffer (current-buffer)))))
(vc-hg-command t 0 nil "export" "--git" "--rev" rev)
(condition-case _
(let (subject patch-start)
(goto-char (point-min))
(re-search-forward "^[^#].*")
(setq subject (match-string 0))
(re-search-forward "\n\ndiff --git a/")
(setq patch-start (pos-bol))
(list :subject subject
:patch-start patch-start
:buffer (current-buffer)))
(search-failed (error "'hg export' output parse failure")))))
;;; Internal functions

View file

@ -670,15 +670,17 @@
;;
;; - prepare-patch (rev)
;;
;; Prepare a patch and return a property list with the keys
;; `:subject' indicating the patch message as a string, `:buffer'
;; with a buffer object that contains the entire patch message and
;; `:body-start' and `:body-end' demarcating what part of said
;; buffer should be inserted into an inline patch. If the two last
;; properties are omitted, `point-min' and `point-max' will
;; respectively be used instead. If supported by the backend, the
;; patch should contain authorship identity and date information, and
;; REV's log message.
;; Prepare a patch and return a property list with the keys `:subject'
;; with the summary line (first line) of the patch message as a
;; string; `:buffer' with a buffer object that contains the entire
;; patch message; `:body-start' and `:body-end' demarcating the part
;; of that buffer which should be inserted inline into a mail message
;; body; and `:patch-start' and `:patch-end' demarcating the part of
;; the buffer that is purely the patch, excluding any log message.
;; If any of these *-start and *-end properties are omitted, they
;; default to (point-min) and (point-max), respectively.
;; If supported by the backend, the patch should contain authorship
;; identity and date information, and REV's log message.
;;
;; - clone (remote directory rev)
;;
@ -4210,7 +4212,7 @@ If nil, no default will be used. This option may be set locally."
:buffer (current-buffer)))))
(defun vc-prepare-patch-prompt-revisions ()
"Prompt the user for a list revisions.
"Prompt the user for a list of revisions.
Prepare a default value, depending on the current context. With
a numerical prefix argument, use the last N revisions as the
default value. If the current buffer is a log-view buffer, use