KhueApps
Home/DevOps/Fix 'pathspec … is in submodule …' when editing nested paths

Fix 'pathspec … is in submodule …' when editing nested paths

Last updated: October 07, 2025

What this error means

You ran a Git command on a path nested under a directory that is a submodule. The superproject tracks the submodule as a single gitlink (a commit pointer), not as individual files, so commands like git add, git checkout, git restore, or git rm against files inside that folder fail with:

  • error: pathspec 'path/inside/submodule' is in submodule 'path/to/submodule'

Quickstart: choose the right fix

IntentWhere to runCommand pattern
Modify files inside the submoduleInside the submodule repocd path/to/submodule; git add/commit; cd ..; git add path/to/submodule; git commit
Remove the submodule and track files directlyIn superprojectUse deinit + rm, or the keep-files variant shown below
Run the same command in many submodulesSuperprojectgit submodule foreach --recursive '<cmd>'
Update/init nested submodulesSuperprojectgit submodule update --init --recursive

Minimal working example (reproduce and fix)

# Superproject
mkdir demo && cd demo
git init
printf 'root\n' > main.txt
git add main.txt && git commit -m 'init superproject'

# Create the submodule repo next to it
mkdir ../lib && pushd ../lib >/dev/null
git init
printf 'v1\n' > README.md
git add README.md && git commit -m 'init lib'
popd >/dev/null

# Add submodule
git submodule add ../lib vendor/lib
git commit -m 'add submodule lib'

# Change a file inside the submodule
printf 'change\n' >> vendor/lib/README.md

# This fails in the superproject:
# error: pathspec 'vendor/lib/README.md' is in submodule 'vendor/lib'
if git add vendor/lib/README.md 2>/dev/null; then :; fi

# Correct approach: commit inside the submodule, then update the pointer
git -C vendor/lib add README.md
git -C vendor/lib commit -m 'update lib readme'

git add vendor/lib
git commit -m 'bump lib pointer'

Why it happens (brief)

  • In the superproject, a submodule directory is a special entry (mode 160000) pointing to a specific commit in the submodule repository. The superproject does not track the contents of files inside that directory.
  • Therefore, pathspecs that refer to nested files are not valid from the superproject. You must operate inside the submodule’s repository.

Step-by-step fixes

1) You intended to edit files inside the submodule

  1. Enter the submodule repository and make your change.
  2. Commit in the submodule.
  3. Stage the submodule path in the superproject (updates the gitlink to the new commit).
  4. Commit the superproject.
cd path/to/submodule
# make changes here
git add <files>
git commit -m 'your change'

cd -
git add path/to/submodule
git commit -m 'update submodule pointer'

# Push both repos (order matters: push submodule first)
git -C path/to/submodule push
git push

Tips:

  • If the submodule has its own remote/branch, ensure you push it; otherwise collaborators will see a pointer to a commit they cannot fetch.
  • For automation, use: git -C path/to/submodule <cmd> instead of cd.

2) You did not want a submodule; convert it to tracked files

Two common approaches.

A) Remove submodule completely (clean slate):

git submodule deinit -f path/to/submodule
rm -rf .git/modules/path/to/submodule
# Removes the gitlink and the working tree
git rm -f path/to/submodule
# Edit .gitmodules if Git didn't do it automatically
# Commit the removal
git commit -m 'remove submodule'

B) Keep the files, stop treating it as a submodule (convert in place):

# Unstage from index but keep working files
git rm --cached -r path/to/submodule

# Remove the submodule's repo metadata so it becomes normal files
rm -rf path/to/submodule/.git

# Clean up Git metadata
git config -f .gitmodules --remove-section submodule.path/to/submodule || true
git config --remove-section submodule.path/to/submodule || true
rm -rf .git/modules/path/to/submodule

git add .gitmodules path/to/submodule
git commit -m 'convert submodule to regular directory'

After conversion, you can git add nested files normally.

3) You need to run a command in many submodules

Use foreach (and recurse if submodules have their own submodules):

git submodule foreach --recursive 'git status -s'
# Example: commit the same file if present in each submodule
# git submodule foreach --recursive 'if [ -f README.md ]; then git add README.md && git commit -m "touch" || true; fi'

4) Reset/checkout/restore files inside a submodule

Run the command inside the submodule:

# Reset a file to HEAD of the submodule
git -C path/to/submodule restore --staged --worktree -- path/inside

# Or checkout a branch inside the submodule
git -C path/to/submodule checkout main

5) Initialize or update nested submodules

If the error appears because the working tree is empty/uninitialized:

git submodule update --init --recursive

Diagnostics

  • Is this a submodule? Check the mode 160000 gitlink:
git ls-files -s | grep ' path/to/submodule$'
  • List submodules and their commits:
git submodule status --recursive
  • See where the submodule stores its Git dir:
cat path/to/submodule/.git  # often points into .git/modules/...

Pitfalls

  • Forgetting to push the submodule: teammates will see a detached pointer they cannot fetch. Always push the submodule repo first, then the superproject.
  • Committing only in the superproject: git add path/to/submodule updates the pointer but does not create commits in the submodule. You must commit inside the submodule for content changes.
  • Nested submodules: use --recursive for init/update and foreach operations.
  • Converting submodule to files: ensure path/to/submodule/.git is removed, or you will have a nested Git repo that Git ignores.

Performance notes

  • Cloning large submodules: initialize shallowly when history is not needed.
git submodule update --init --depth 1 --recommend-shallow
  • Parallel updates for many submodules:
git submodule update --init --recursive --jobs 8
  • Avoid unnecessary recursion: only use --recursive when needed to reduce network and disk I/O.

  • Use git -C path instead of repeated cd for scripts; it is faster and simpler.

Tiny FAQ

  • Q: Why can’t I add a file inside a submodule from the parent? A: The parent tracks a single gitlink entry, not individual files. Operate inside the submodule and then update the pointer in the parent.

  • Q: How do I make the submodule content part of the main repo? A: Convert it: git rm --cached -r submodule && rm -rf submodule/.git, clean .gitmodules, then commit and add files normally.

  • Q: How do I reset a file inside a submodule to its last committed state? A: Run git restore (or checkout) inside the submodule or with git -C submodule.

  • Q: Can I avoid submodules altogether? A: Consider git subtree to vendor dependencies while keeping them in your history, at the cost of heavier commits in the main repo.

Series: Git

DevOps