vc-git--checkin: Apply PATCH-STRING to working tree

* lisp/vc/vc-git.el
(vc-git--with-apply-temp-to-staging): Rename ...
(vc-git--with-apply-temp): ... to this.  New ARGS parameter.
All uses changes.
(vc-git--checkin): In POST function, apply PATCH-STRING to the
working tree with 'git apply --3way --ours'.
* lisp/vc/vc-hg.el (vc-hg--checkin): Document what the call to
'hg update' is for.
* test/lisp/vc/vc-tests/vc-tests.el (vc-test--checkin-patch):
Delete completed FIXME and workaround.
This commit is contained in:
Sean Whitton 2025-09-24 16:07:51 +01:00
parent 190450f4f0
commit 8368fcb38c
3 changed files with 53 additions and 32 deletions

View file

@ -1122,8 +1122,8 @@ It is based on `log-edit-mode', and has Git-specific extensions."
("Sign-Off" . ,(boolean-arg-fn "--signoff")))
comment)))
(defmacro vc-git--with-apply-temp-to-staging (temp &rest body)
(declare (indent 1) (debug (symbolp body)))
(cl-defmacro vc-git--with-apply-temp ((temp &rest args) &body body)
(declare (indent 1))
`(let ((,temp (make-nearby-temp-file ,(format "git-%s" temp))))
(unwind-protect (progn ,@body
;; This uses `file-local-name' to strip the
@ -1131,7 +1131,8 @@ It is based on `log-edit-mode', and has Git-specific extensions."
;; because we've had at least one problem
;; report where relativizing the file name
;; meant that Git failed to find it.
(vc-git-command nil 0 nil "apply" "--cached"
(vc-git-command nil 0 nil "apply"
,@(or args '("--cached"))
(file-local-name ,temp)))
(delete-file ,temp))))
@ -1235,7 +1236,7 @@ It is an error to supply both or neither."
;; to have the Unix EOL format, because Git expects
;; that, even on Windows.
(or pcsw vc-git-commits-coding-system) 'unix)))
(vc-git--with-apply-temp-to-staging patch
(vc-git--with-apply-temp (patch)
(with-temp-file patch
(insert patch-string)))))
(when to-stash (vc-git--stash-staged-changes to-stash)))
@ -1246,8 +1247,29 @@ It is an error to supply both or neither."
(lambda ()
(when (and msg-file (file-exists-p msg-file))
(delete-file msg-file))
;; If PATCH-STRING didn't come from C-x v = or C-x v D, we
;; now need to update the working tree to include the
;; changes from the commit we just created.
;; If there are conflicts we want to favor the working
;; tree's version and the version from the commit will just
;; show up in the diff of uncommitted changes.
;;
;; 'git apply --3way --ours' is the way Git provides to
;; achieve this. This requires that the index match the
;; working tree and also implies the --index option, which
;; means applying the changes to the index in addition to
;; the working tree. These are both okay here because
;; before doing this we know the index is empty (we just
;; committed) and so we can just make use of it and reset
;; afterwards.
(when patch-string
(vc-git-command nil 0 nil "add" "--all")
(vc-git--with-apply-temp (patch "--3way" "--ours")
(with-temp-file patch
(insert patch-string)))
(vc-git-command nil 0 nil "reset"))
(when to-stash
(vc-git--with-apply-temp-to-staging cached
(vc-git--with-apply-temp (cached)
(with-temp-file cached
(vc-git-command t 0 nil "stash" "show" "-p")))
(vc-git-command nil 0 nil "stash" "drop")))))
@ -1391,7 +1413,7 @@ REV is ignored."
(unwind-protect
(progn
(vc-git-command nil 0 nil "read-tree" "HEAD")
;; See `vc-git--with-apply-temp-to-staging'
;; See `vc-git--with-apply-temp'
;; regarding use of `file-local-name'.
(vc-git-command nil 0 nil "apply" "--cached"
(file-local-name cached))

View file

@ -1255,23 +1255,30 @@ It is an error to supply both or neither."
(cond (msg-file (cl-list* "-l" (file-local-name msg-file)
(cdr args)))
(args (cons "-m" args)))))
(post (lambda ()
(when (and msg-file (file-exists-p msg-file))
(delete-file msg-file))
(when (and patch-file (file-exists-p patch-file))
(delete-file patch-file))
;; When committing a patch we run 'hg import' and
;; then 'hg update'. We have 'hg update' here in the
;; always-synchronous `post' function because we
;; assume that 'hg import' is the one that might be
;; slow and so benefits most from `vc-async-checkin'.
;; If in fact both the 'hg import' and the 'hg
;; update' can be slow, then we need to make both of
;; them part of the async command, possibly by
;; writing out a tiny shell script (bug#79235).
(when patch-file
(vc-hg-command nil 0 nil "update" "--merge"
"--tool" "internal:local" "tip")))))
(post
(lambda ()
(when (and msg-file (file-exists-p msg-file))
(delete-file msg-file))
(when (and patch-file (file-exists-p patch-file))
(delete-file patch-file))
;; If PATCH-STRING didn't come from C-x v = or C-x v D, we
;; now need to update the working tree to include the
;; changes from the commit we just created.
;; If there are conflicts we want to favor the working
;; tree's version and the version from the commit will just
;; show up in the diff of uncommitted changes.
;;
;; When committing a patch we run two commands, 'hg import'
;; and then 'hg update'. We have 'hg update' here in the
;; always-synchronous `post' function because we assume
;; that 'hg import' is the one that might be slow and so
;; benefits most from `vc-async-checkin'. If in fact both
;; the 'hg import' and the 'hg update' can be slow, then we
;; need to make both of them part of the async command,
;; possibly by writing out a tiny shell script (bug#79235).
(when patch-file
(vc-hg-command nil 0 nil "update" "--merge"
"--tool" "internal:local" "tip")))))
(if vc-async-checkin
(let ((buffer (vc-hg--async-buffer)))
(vc-wait-for-process-before-save

View file

@ -881,15 +881,7 @@ This checks also `vc-backend' and `vc-responsible-backend'."
;; Should take the author, date but not the comment from
;; PATCH-STRING.
(let ((patch-string (get-patch-string)))
;; FIXME: We shouldn't need to branch here. Git should
;; update the working tree after making the commit.
(cl-case backend
(Git (with-current-buffer buf
(vc-checkin (list file) backend)
(insert "Revert modification, second time")
(let (vc-async-checkin)
(log-edit-done))))
(t (revert "Revert modification, second time")))
(revert "Revert modification, second time")
(vc-call-backend backend 'checkin-patch patch-string desc2))
(check author date desc2))