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 7ca944d60c..4950331256 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 7584e89c49..9a52cc4655 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 2e6a14c520..9ff3fbeff9 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 f4d70d1099..b002776631 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