From a64f246f71ea61f0dec5263ef65b27ac3ef29d6f Mon Sep 17 00:00:00 2001 From: Jonas Bernoulli Date: Wed, 2 Jul 2025 12:17:12 +0200 Subject: magit-discard: On "Untracked files" delete exactly the listed files Use the same code to generate a list of untracked fils, when `magit-discard' is invoked on the "Untracked files" section as was used to populate the list of files displayed in that section. We should do that even if it weren't for the following issue, but that is how we noticed something had to be done. Contrary to what the documentation claims, "git ls-files --other --directory --exclude-standard" does not honor ".gitignore" from sub-directories. Closes #5405. --- CHANGELOG | 6 ++++++ lisp/magit-apply.el | 3 +-- lisp/magit-git.el | 35 +++++++++++++++++++++++++++++++++++ lisp/magit-status.el | 21 ++------------------- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7ca944d..4950331 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,12 @@ Bugfixes: - Refreshing was skipped after discarding all untracked files. +- When sub-directories contain ".gitignore" files, then invoking + ~magit-discard~ on the "Untracked files" section did not necessarily + remove the same set of files as listed in that section. (At least + it did show the files, which would be removed, in the confirmation + prompt.) #5405 + * v4.3.7 2025-07-01 - Refreshing a buffer causes its content to be recreated, which can diff --git a/lisp/magit-apply.el b/lisp/magit-apply.el index 7584e89..9a52cc4 100644 --- a/lisp/magit-apply.el +++ b/lisp/magit-apply.el @@ -500,8 +500,7 @@ of a side, then keep that side without prompting." (defun magit-discard-untracked () (magit-discard-files--delete - (magit-with-toplevel - (magit-untracked-files nil nil "--directory")) + (magit-with-toplevel (magit-list-untracked-files)) nil) (magit-refresh)) diff --git a/lisp/magit-git.el b/lisp/magit-git.el index 2e6a14c..9ff3fbe 100644 --- a/lisp/magit-git.el +++ b/lisp/magit-git.el @@ -63,6 +63,9 @@ (defvar magit-this-error) (defvar magit-process-error-message-regexps) +;; From `magit-status'. +(defvar magit-status-show-untracked-files) + (eval-when-compile (cl-pushnew 'orig-rev eieio--known-slot-names) (cl-pushnew 'number eieio--known-slot-names)) @@ -1069,10 +1072,42 @@ tracked file." (magit-list-files "--cached" args)) (defun magit-untracked-files (&optional all files &rest args) + "Return a list of untracked files. + +Note that when using \"--directory\", the rules from \".gitignore\" +files from sub-directories are ignore, which is probably a Git bug. +See also `magit-list-untracked-files', which does not have this +issue." (magit-list-files "--other" args (and (not all) "--exclude-standard") "--" files)) +(defun magit-list-untracked-files (&optional files) + "Return a list of untracked files. + +List files if `magit-status-show-untracked-files' is non-nil, but also +take the local value of Git variable `status.showUntrackedFiles' into +account. The local value of the Lisp variable takes precedence over the +local value of the Git variable. The global value of the Git variable +is always ignored. + +See also `magit-untracked-files'." + (and-let* + ((value (or (and (local-variable-p 'magit-status-show-untracked-files) + magit-status-show-untracked-files) + (pcase (magit-get "--local" "status.showUntrackedFiles") + ((or "no" "off" "false" "0") 'no) + ((or "yes" "on" "true" "1") t) + ("all" 'all)) + magit-status-show-untracked-files)) + ((not (eq value 'no)))) + (mapcan (##and (eq (aref % 0) ??) + (list (substring % 3))) + (apply #'magit-git-items "status" "-z" "--porcelain" + (format "--untracked-files=%s" + (if (eq value 'all) "all" "normal")) + "--" files)))) + (defun magit-ignored-files (&rest args) (magit-list-files "--others" "--ignored" "--exclude-standard" args)) diff --git a/lisp/magit-status.el b/lisp/magit-status.el index f4d70d1..b002776 100644 --- a/lisp/magit-status.el +++ b/lisp/magit-status.el @@ -752,31 +752,14 @@ remote in alphabetic order." magit-insert-assume-unchanged-files) (defun magit-insert-untracked-files () - "Maybe insert list of untracked files. + "Maybe insert a list of untracked files. List files if `magit-status-show-untracked-files' is non-nil, but also take the local value of Git variable `status.showUntrackedFiles' into account. The local value of the Lisp variable takes precedence over the local value of the Git variable. The global value of the Git variable is always ignored." - (when-let* - ((value (or (and (local-variable-p 'magit-status-show-untracked-files) - magit-status-show-untracked-files) - (pcase (magit-get "--local" "status.showUntrackedFiles") - ((or "no" "off" "false" "0") 'no) - ((or "yes" "on" "true" "1") t) - ("all" 'all)) - magit-status-show-untracked-files)) - ((not (eq value 'no)))) - (magit-insert-files - 'untracked - (lambda (files) - (mapcan (##and (eq (aref % 0) ??) - (list (substring % 3))) - (apply #'magit-git-items "status" "-z" "--porcelain" - (format "--untracked-files=%s" - (if (eq value 'all) "all" "normal")) - "--" files)))))) + (magit-insert-files 'untracked #'magit-list-untracked-files)) (defun magit-insert-tracked-files () "Insert a list of tracked files. -- cgit v1.0