emacs-31 b6e7962700d: Fix "diff-apply-buffer applies to the wrong file"
Dmitry Gutov <[email protected]>
| Newsgroups | gmane.emacs.diffs |
|---|---|
| Message-ID | <[email protected]> |
branch: emacs-31 commit b6e7962700dd1a7ae774b9f2ae2a2c0d9e33151d Author: Dmitry Gutov <[email protected]> Commit: Dmitry Gutov <[email protected]> Fix "diff-apply-buffer applies to the wrong file" * lisp/vc/diff-mode.el (diff-find-file-name): Inhibit the "drop dir" behavior in diffs produced by Git and Hg (bug#81210). Except for the virtual subdirectories like a/b/etc, which is moved and happens for all such diffs. Tighten the check for such virtual directory names, though (characters are the chars used by the configuration option 'diff.mnemonicPrefix'). (diff-setup-buffer-type): Recognize Hg diffs where only one revision is specified, too. * test/lisp/vc/diff-mode-tests.el (diff-mode-test-setup-buffer-type) (diff-mode-test-find-file-name-create): New tests. --- lisp/vc/diff-mode.el | 15 +++++++------ test/lisp/vc/diff-mode-tests.el | 48 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index 32f34ebaa10..c1227573351 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -1176,6 +1176,10 @@ PREFIX is only used internally: don't use it." (or (ignore-errors (diff-beginning-of-file)) (re-search-forward diff-file-header-re nil t))) (let ((fs (diff-hunk-file-names old))) + (when (memq diff-buffer-type '(git hg)) + (setq fs + (mapcar (lambda (f) (replace-regexp-in-string "\\`[icoawib]/" "" f)) + fs))) (if prefix (setq fs (mapcar (lambda (f) (concat prefix f)) fs))) (or ;; use any previously used preference @@ -1186,7 +1190,10 @@ PREFIX is only used internally: don't use it." (if (and newfile (file-exists-p newfile)) (cl-return newfile)))) ;; look for each file in turn. If none found, try again but ;; ignoring the first level of directory, ... - (cl-do* ((files fs (delq nil (mapcar #'diff-filename-drop-dir files))) + (cl-do* ((files fs (and (not (and (memq diff-buffer-type '(git hg)) + (not old) + (equal null-device (cadr files)))) + (delq nil (mapcar #'diff-filename-drop-dir files)))) (file nil nil)) ((or (null files) (setq file (cl-do* ((files files (cdr files)) @@ -1212,10 +1219,6 @@ PREFIX is only used internally: don't use it." (let ((file (or (car fs) "")) (creation (equal null-device (car (diff-hunk-file-names (not old)))))) - (when (and (memq diff-buffer-type '(git hg)) - (string-match "/" file)) - ;; Strip the dst prefix (like b/) if diff is from Git/Hg. - (setq file (substring file (match-end 0)))) (setq file (expand-file-name file)) (setq file (read-file-name (format "Use file %s: " file) @@ -1822,7 +1825,7 @@ modified lines of the diff." (setq-local diff-buffer-type (if (re-search-forward "^diff --git" nil t) 'git - (if (re-search-forward "^diff -r.*-r" nil t) + (if (re-search-forward "^diff -r " nil t) 'hg nil)))) (when (eq diff-buffer-type 'git) diff --git a/test/lisp/vc/diff-mode-tests.el b/test/lisp/vc/diff-mode-tests.el index c75e7ef066b..36291fee0a5 100644 --- a/test/lisp/vc/diff-mode-tests.el +++ b/test/lisp/vc/diff-mode-tests.el @@ -744,5 +744,53 @@ plum (set-buffer-modified-p nil) (kill-buffer buf-after)))))) +(ert-deftest diff-mode-test-setup-buffer-type () + "Check that `diff-setup-buffer-type' recognizes the diff's origin." + (with-temp-buffer + (insert "diff --git a/foo b/foo\n--- a/foo\n+++ b/foo\n") + (diff-mode) + (should (eq diff-buffer-type 'git))) + (with-temp-buffer + (insert "diff -r 0123456789ab foo\n--- a/foo\n+++ b/foo\n") + (diff-mode) + (should (eq diff-buffer-type 'hg))) + (with-temp-buffer + (insert "--- foo\n+++ foo\n@@ -1 +1 @@\n-a\n+b\n") + (diff-mode) + (should (eq diff-buffer-type nil)))) + +(ert-deftest diff-mode-test-find-file-name-create () + "Check `diff-find-file-name' for a Git/Hg file creation. +It should not use existing file without subdirectory." + (ert-with-temp-directory temp-dir + (let ((default-directory temp-dir) + call-dir call-initial call-mustmatch) + ;; A decoy with the same basename as the created file, but in a + ;; different directory. + (with-temp-file (expand-file-name "created.txt" temp-dir) + (insert "decoy\n")) + (with-temp-buffer + (insert "diff --git a/sub/created.txt b/sub/created.txt +new file mode 100644 +index 0000000..3456789 +--- /dev/null ++++ b/sub/created.txt +@@ -0,0 +1 @@ ++new +") + (diff-mode) + (goto-char (point-min)) + (let ((read-file-name-function + (lambda (_p &optional dir _def mustmatch initial _pred) + (setq call-dir dir + call-initial initial + call-mustmatch mustmatch) + "magic"))) + (should (equal (diff-find-file-name) + "magic")) + (should (equal call-dir (expand-file-name "sub/" temp-dir))) + (should (equal call-initial "created.txt")) + (should (equal call-mustmatch nil))))))) + (provide 'diff-mode-tests) ;;; diff-mode-tests.el ends here