branch: elpa/projectile
commit 4dbcda27d6870990421e217c8379b14037d9239f
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>

    Filter deleted-but-unstaged files from git ls-files output (#1897)
    
    When fd is unavailable or disabled, `git ls-files -zco --exclude-standard`
    returns files still tracked in the index even if deleted from disk.  This
    causes projectile-dir-files-alien to list ghost files.  Fix by running
    `git ls-files -zd` and removing those entries from the result.
---
 CHANGELOG.md            |  1 +
 projectile.el           | 15 +++++++++++++--
 test/projectile-test.el | 24 ++++++++++++++++++++++++
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 014544af90..8832897589 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@
 
 ### Bugs fixed
 
+* [#1897](https://github.com/bbatsov/projectile/issues/1897): Filter 
deleted-but-unstaged files from `git ls-files` output in alien/hybrid indexing 
(when `fd` is not used).
 * [#1873](https://github.com/bbatsov/projectile/issues/1873): Skip unreadable 
directories during native indexing instead of aborting with a permission error.
 * [#1961](https://github.com/bbatsov/projectile/issues/1961): Prevent 
directories from matching file-type project root markers (e.g., a `workspace` 
directory no longer matches the `WORKSPACE` Bazel marker on case-insensitive 
filesystems).
 * [#1749](https://github.com/bbatsov/projectile/issues/1749): Strip `./` 
prefix from `fd` output in `projectile-files-via-ext-command`, fixing 
compatibility with older `fd` versions that don't support `--strip-cwd-prefix`.
diff --git a/projectile.el b/projectile.el
index 0acc7f40b3..574c5bd9b8 100644
--- a/projectile.el
+++ b/projectile.el
@@ -1539,10 +1539,21 @@ IGNORED-DIRECTORIES may optionally be provided."
   (let ((vcs (projectile-project-vcs directory)))
     (cond
      ((eq vcs 'git)
-      (nconc (projectile-files-via-ext-command directory 
(projectile-get-ext-command vcs))
-             (projectile-get-sub-projects-files directory vcs)))
+      (let* ((files (nconc (projectile-files-via-ext-command directory 
(projectile-get-ext-command vcs))
+                           (projectile-get-sub-projects-files directory vcs)))
+             ;; When using git ls-files (not fd), deleted but unstaged
+             ;; files are still reported.  Remove them.
+             (deleted (unless (and projectile-git-use-fd 
projectile-fd-executable)
+                        (projectile-git-deleted-files directory))))
+        (if deleted
+            (seq-remove (lambda (f) (member f deleted)) files)
+          files)))
      (t (projectile-files-via-ext-command directory 
(projectile-get-ext-command vcs))))))
 
+(defun projectile-git-deleted-files (directory)
+  "Get a list of deleted but unstaged files in DIRECTORY."
+  (projectile-files-via-ext-command directory "git ls-files -zd"))
+
 (defun projectile-get-ext-command (vcs)
   "Determine which external command to invoke based on the project's VCS.
 Fallback to a generic command when not in a VCS-controlled project."
diff --git a/test/projectile-test.el b/test/projectile-test.el
index c658dcd10a..25c96f1b97 100644
--- a/test/projectile-test.el
+++ b/test/projectile-test.el
@@ -532,6 +532,30 @@ Just delegates OPERATION and ARGS for all operations 
except for`shell-command`'.
     (let ((projectile-indexing-method 'hybrid))
       (expect (projectile-dir-files "/my/root/") :to-equal '("a/b/c" 
"a/d/e")))))
 
+(describe "projectile-dir-files-alien"
+  (it "excludes deleted-but-unstaged files when not using fd"
+    (projectile-test-with-sandbox
+     (projectile-test-with-files
+      ("project/"
+       "project/.git/"
+       "project/existing.txt")
+      (let ((default-directory (file-truename (expand-file-name "project/")))
+            (projectile-git-use-fd nil)
+            (projectile-fd-executable nil)
+            (projectile-indexing-method 'alien))
+        ;; Initialize a real git repo, commit a file, then delete it without 
staging
+        (call-process "git" nil nil nil "init")
+        (call-process "git" nil nil nil "config" "user.email" "[email protected]")
+        (call-process "git" nil nil nil "config" "user.name" "Test")
+        (call-process "git" nil nil nil "add" "existing.txt")
+        (write-region "content" nil "deleted.txt")
+        (call-process "git" nil nil nil "add" "deleted.txt")
+        (call-process "git" nil nil nil "commit" "-m" "init")
+        (delete-file "deleted.txt")
+        (let ((files (projectile-dir-files-alien default-directory)))
+          (expect files :to-contain "existing.txt")
+          (expect files :not :to-contain "deleted.txt")))))))
+
 (describe "projectile-index-directory"
   (it "skips unreadable directories"
     (unless (eq system-type 'windows-nt)

Reply via email to