From 5e37b27ce9785b7b67506f44318fc56d3ce517e5 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Sun, 2 Oct 2022 21:50:08 +0300 Subject: [PATCH] * lisp/vc/vc-git.el (vc-git-checkin): Add more checks for vc-git-patch-string Check that vc-git-patch-string contains the same changes that already exists in the staged area when files were added/removed by vc commands (bug#52349). --- lisp/vc/vc-git.el | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 9cc1aee6747..4a2a42ad2a7 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -1015,7 +1015,31 @@ It is based on `log-edit-mode', and has Git-specific extensions." (make-nearby-temp-file "git-msg"))))) (when vc-git-patch-string (unless (zerop (vc-git-command nil t nil "diff" "--cached" "--quiet")) - (user-error "Index not empty")) + ;; Check that all staged changes also exist in the patch. + ;; This is needed to allow adding/removing files that are + ;; currently staged to the index. So remove the whole file diff + ;; from the patch because commit will take it from the index. + (with-temp-buffer + (vc-git-command (current-buffer) t nil "diff" "--cached") + (goto-char (point-min)) + (let ((pos (point)) file-diff file-beg) + (while (not (eobp)) + (forward-line 1) ; skip current "diff --git" line + (search-forward "diff --git" nil 'move) + (move-beginning-of-line 1) + (setq file-diff (buffer-substring pos (point))) + (if (and (setq file-beg (string-search + file-diff vc-git-patch-string)) + ;; Check that file diff ends with an empty string + ;; or the beginning of the next file diff. + (string-match-p "\\`\\'\\|\\`diff --git" + (substring + vc-git-patch-string + (+ file-beg (length file-diff))))) + (setq vc-git-patch-string + (string-replace file-diff "" vc-git-patch-string)) + (user-error "Index not empty")) + (setq pos (point)))))) (let ((patch-file (make-temp-file "git-patch"))) (with-temp-file patch-file (insert vc-git-patch-string)) -- 2.39.2