Function: projectile--git-submodules
projectile--git-submodules is a byte-compiled function defined in
projectile.el.
Signature
(projectile--git-submodules PATH)
Documentation
Return the raw submodule listing for the Git repo containing PATH.
The result is a list of submodule paths relative to PATH.
With projectile-git-submodule-command at its default value the
listing is produced without a shell by projectile--git-submodule-paths
(see issue #1600); when the variable is customized it is honored as a
shell command, and when nil submodules are disabled.
For Git projects without a .gitmodules file there are no submodules
to find, so the listing is skipped altogether. PATH may be inside a
Git repo without being its toplevel (e.g. a subproject of an outer
repo) so .gitmodules is looked up at the toplevel of the repo
containing PATH - the nearest parent with a .git entry - which is
where git itself resolves it. Stopping at the repo boundary also
means a populated submodule doesn't pick up its superproject's
.gitmodules.
Alien/hybrid indexing calls this on every file listing, so the result
is cached in projectile--git-submodules-cache and recomputed only
when .gitmodules changes on disk - a stat is far cheaper than the
listing (see issue #1953). projectile-invalidate-cache also
drops the cached listing.
Source Code
;; Defined in ~/.emacs.d/elpa/projectile-20260820.1509/projectile.el
(defun projectile--git-submodules (path)
"Return the raw submodule listing for the Git repo containing PATH.
The result is a list of submodule paths relative to PATH.
With `projectile-git-submodule-command' at its default value the
listing is produced without a shell by `projectile--git-submodule-paths'
\(see issue #1600); when the variable is customized it is honored as a
shell command, and when nil submodules are disabled.
For Git projects without a `.gitmodules' file there are no submodules
to find, so the listing is skipped altogether. PATH may be inside a
Git repo without being its toplevel \(e.g. a subproject of an outer
repo) so `.gitmodules' is looked up at the toplevel of the repo
containing PATH - the nearest parent with a `.git' entry - which is
where git itself resolves it. Stopping at the repo boundary also
means a populated submodule doesn't pick up its superproject's
`.gitmodules'.
Alien/hybrid indexing calls this on every file listing, so the result
is cached in `projectile--git-submodules-cache' and recomputed only
when `.gitmodules' changes on disk - a stat is far cheaper than the
listing (see issue #1953). `projectile-invalidate-cache' also
drops the cached listing."
(when-let* ((gitmodules-dir (locate-dominating-file path ".git"))
(gitmodules (expand-file-name ".gitmodules" gitmodules-dir))
;; A plain `_' binding trips "variable `_' not left unused"
;; in the Emacs 28/29 byte-compilers.
(gitmodules-exists (file-exists-p gitmodules)))
(let* ((mtime (file-attribute-modification-time
(file-attributes gitmodules)))
(command (projectile-get-sub-projects-command 'git))
(cached (gethash path projectile--git-submodules-cache)))
(pcase-let ((`(,cached-gitmodules ,cached-mtime ,cached-command ,cached-result)
cached))
(if (and cached
(equal cached-gitmodules gitmodules)
(equal cached-mtime mtime)
(equal cached-command command))
cached-result
(let ((submodules
(cond
;; nil disables submodule listing altogether.
((null command) nil)
;; The stock command is never actually run: list the
;; submodules shell-free instead (issue #1600).
((equal command projectile--default-git-submodule-command)
(let ((dir (file-name-as-directory
(expand-file-name gitmodules-dir)))
(paths (projectile--git-submodule-paths gitmodules-dir)))
(if (equal dir (file-name-as-directory (expand-file-name path)))
paths
;; PATH is below the `.gitmodules' dir: rebase the
;; listing so it stays relative to PATH.
(mapcar (lambda (submodule)
(file-relative-name
(expand-file-name submodule dir) path))
paths))))
;; A customized command is still run through the shell.
(t (projectile-files-via-ext-command path command)))))
(puthash path (list gitmodules mtime command submodules)
projectile--git-submodules-cache)
submodules))))))