diff options
| author | Bozhidar Batsov <bozhidar@toptal.com> | 2026-04-26 12:29:52 +0100 |
|---|---|---|
| committer | Bozhidar Batsov <bozhidar@toptal.com> | 2026-04-26 12:29:52 +0100 |
| commit | ccd8052beb84a889565ffd08a58cf643e2e439f3 (patch) | |
| tree | 7b45e149914261c4c3591a7fdd97cf1207382a72 | |
| parent | fa890caa2b21af3895b302e22e1d74df8ee55453 (diff) | |
Skip git submodule scan when there is no .gitmodules
`projectile-get-immediate-sub-projects' was unconditionally shelling
out to `git submodule --quiet foreach ...' on every indexing call for
git projects, even when the project had no submodules at all. For
monorepos that re-index the project root often this is pure overhead.
Use `locate-dominating-file' to look for `.gitmodules' along the
parent chain (PATH may be inside a git repo without being its
toplevel) and skip the shell-out when none is found.
Also tighten `projectile-discover-projects-in-directory' to filter
`.' / `..' via `directory-files-no-dot-files-regexp' instead of a
post-filter `member' check, matching the indexing walker's style.
| -rw-r--r-- | projectile.el | 50 |
1 files changed, 29 insertions, 21 deletions
diff --git a/projectile.el b/projectile.el index 0f8c480..c4c0154 100644 --- a/projectile.el +++ b/projectile.el @@ -1330,9 +1330,10 @@ discover projects there." (format "Projectile is discovering projects in %s..." (propertize directory 'face 'font-lock-keyword-face))))) (progress-reporter-update progress-reporter) - (dolist (dir (ignore-errors (directory-files directory t))) - (when (and (file-directory-p dir) - (not (member (file-name-nondirectory dir) '(".." ".")))) + (dolist (dir (ignore-errors + (directory-files directory t + directory-files-no-dot-files-regexp))) + (when (file-directory-p dir) (projectile-discover-projects-in-directory dir (1- depth)))) (progress-reporter-done progress-reporter)) (when (projectile-project-p directory) @@ -1856,24 +1857,31 @@ searching, and should end with an appropriate path delimiter, such as If the vcs get-sub-projects query returns results outside of path, they are excluded from the results of this function." - (let* ((vcs (projectile-project-vcs path)) - ;; search for sub-projects under current project `project' - (submodules (mapcar - (lambda (s) - (file-name-as-directory (expand-file-name s path))) - (projectile-files-via-ext-command path (projectile-get-sub-projects-command vcs)))) - (project-child-folder-regex - (concat "\\`" - (regexp-quote path)))) - - ;; If project root is inside of an VCS folder, but not actually an - ;; VCS root itself, submodules external to the project will be - ;; included in the VCS get sub-projects result. Let's remove them. - (seq-filter - (lambda (submodule) - (string-match-p project-child-folder-regex - submodule)) - submodules))) + (let ((vcs (projectile-project-vcs path))) + ;; For Git projects without a `.gitmodules' file there is nothing + ;; for `git submodule foreach' to find, so we can skip the + ;; shell-out altogether. PATH may be inside a Git repo without + ;; being its toplevel (e.g. a subproject of an outer repo) so look + ;; for `.gitmodules' along the parent chain rather than just at + ;; PATH itself. This is hot for monorepos that index the project + ;; root often. + (unless (and (eq vcs 'git) + (not (locate-dominating-file path ".gitmodules"))) + (let* ((submodules (mapcar + (lambda (s) + (file-name-as-directory (expand-file-name s path))) + (projectile-files-via-ext-command + path (projectile-get-sub-projects-command vcs)))) + (project-child-folder-regex + (concat "\\`" (regexp-quote path)))) + ;; If project root is inside of an VCS folder, but not + ;; actually an VCS root itself, submodules external to the + ;; project will be included in the VCS get sub-projects + ;; result. Let's remove them. + (seq-filter + (lambda (submodule) + (string-match-p project-child-folder-regex submodule)) + submodules))))) (defun projectile-get-sub-projects-files (project-root vcs) "Get files from sub-projects for PROJECT-ROOT recursively. |
