Setup & configAlways fixable

Fix empty submodule folders after cloning

I cloned a repo and the submodule folders are empty — how do I fix it?

Short answer

Cloning records submodules but doesn't populate them. Run git submodule update --init --recursive, or clone with --recurse-submodules next time so it happens automatically.

quick fix
git submodule update --init --recursive

Fetches and checks out every submodule, including nested ones

Does this match your situation?

  • A directory listed in .gitmodules exists but is empty.
  • The build fails with missing files from a dependency folder.
  • git status reports submodules as 'not initialized'.
  • A submodule shows as modified with '(new commits)' you didn't make.

Step-by-step fix

  1. Initialise and fetch every submodule

    This registers each submodule from .gitmodules and checks out the exact commit your repository pins. --recursive handles submodules that themselves contain submodules.

    step 1
    git submodule update --init --recursive
    git submodule status
    
  2. Clone correctly next time

    One flag does the whole thing at clone time and avoids the problem entirely.

    step 2
    git clone --recurse-submodules https://github.com/user/repo.git
    
    # make it the default forever:
    git config --global submodule.recurse true
    
  3. Fix a submodule showing unexpected '(new commits)'

    This means the submodule is checked out at a different commit than the parent records — usually because you built inside it, or updated it without committing the new pointer. Reset it back to the pinned commit.

    step 3
    git submodule update --init --recursive --force
    
    # or intentionally record the new commit:
    git add path/to/submodule
    git commit -m "Update submodule to latest"
    
  4. Update a submodule to its latest upstream commit

    Submodules are pinned deliberately, so moving one forward is an explicit action that produces a commit in the parent repository.

    step 4
    git submodule update --remote path/to/submodule
    git add path/to/submodule
    git commit -m "Bump submodule to latest upstream"
    
  5. Remove a submodule properly

    Removal touches four places. Missing any one leaves the repository in a confusing half-state.

    step 5
    git submodule deinit -f path/to/submodule
    git rm -f path/to/submodule
    rm -rf .git/modules/path/to/submodule
    git commit -m "Remove submodule"
    

Why this works

A submodule isn't a copy of another project — it's a single line in the parent's tree recording a repository URL and one commit hash. Cloning fetches that pointer, but the pointed-to repository is a separate download that Git won't perform unless asked, which is why the folder is created and left empty. `--init` reads .gitmodules into your local config and `update` clones and checks out the pinned commit, which is also why a submodule always lands on a specific commit rather than a branch.

How to stop it happening again

  • Set submodule.recurse true globally so clone, pull and checkout handle submodules automatically.
  • Document the init command in your README for anyone who hasn't.
  • Consider whether a package manager or git subtree would serve you better - submodules add real friction.

Commands used in this guide

git submodule

Embed another Git repository inside yours at a pinned commit.

git clone

Copy a remote repository, its full history and its branches, onto your machine.

git subtree

Vendor another repository into a subdirectory - without submodules' friction.

git config

Read and write Git settings for one repo, your user, or the whole machine.

Still stuck?

Search the full command reference and every other rescue guide — there are 56 of them, covering everything from detached HEAD to force-push disasters.

Browse all guides →

Frequently asked questions

Why are my submodule folders empty after cloning?

A clone records the submodule pointer but doesn't download the referenced repository. Run git submodule update --init --recursive to fetch and check out each one at the commit your repository pins.

How do I clone a repository with all its submodules at once?

git clone --recurse-submodules <url>. To make it automatic for every future command, set git config --global submodule.recurse true, which also applies to pull and checkout.

Why does my submodule show as modified when I didn't change it?

The submodule is checked out at a different commit than the parent repository records - often after building inside it or pulling within it. Either reset it with git submodule update --init --force, or commit the new pointer deliberately if the update was intended.

Related rescue guides

← All Git Rescue guides