branch: elpa/magit
commit a64f246f71ea61f0dec5263ef65b27ac3ef29d6f
Author: Jonas Bernoulli <jo...@bernoul.li>
Commit: Jonas Bernoulli <jo...@bernoul.li>

    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 7ca944d60c6..49503312562 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 7584e89c492..9a52cc46552 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 2e6a14c5208..9ff3fbeff91 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 f4d70d10993..b002776631e 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.

Reply via email to