Git Submodules Explained: Add, Clone, Update and Remove Submodules

Submodules let one repository include another at an exact commit, for example shared test data or utilities. In this lesson you will add, clone, update, edit and remove submodules, use them in CI, and decide when an alternative is better.

Advertisement

📖 What You’ll Learn: what submodules are and when to use them, adding a submodule and .gitmodules, cloning with submodules, updating to newer commits, committing inside a submodule and detached HEAD, useful commands, removing a submodule, submodules in GitHub Actions, and alternatives.


🧩 What Is a Git Submodule?

A submodule is a Git repository nested inside another Git repository at a specific folder. The parent repository does not store the submodule’s files; it stores a pointer to one exact commit of the submodule repository.

Typical uses:

  • Sharing common test data, page objects or utilities between several test projects.
  • Including a third-party library at a fixed version.
  • Keeping a documentation or design-system repository inside an app repository.
qa-platform/                      (parent repository)
├── tests/
├── shared-test-data/   ──▶ submodule: github.com/acme/shared-test-data @ commit 9f8e7d6
└── .gitmodules

📝 Note: Submodules are powerful but add complexity. For many teams, publishing shared code as a package (npm, PyPI) or using a monorepo is simpler. Use submodules when you truly need another repository’s exact source at a fixed commit.


➕ Add a Submodule

git submodule add https://github.com/acme/shared-test-data.git shared-test-data
git status
new file:   .gitmodules
new file:   shared-test-data

.gitmodules records the mapping and is committed like any file:

[submodule "shared-test-data"]
	path = shared-test-data
	url = https://github.com/acme/shared-test-data.git
git commit -m "Add shared-test-data as a submodule"
git push

📥 Clone a Repository That Has Submodules

A normal clone leaves submodule folders empty. Use one of these:

git clone --recurse-submodules https://github.com/acme/qa-platform.git

# Already cloned without it?
git submodule update --init --recursive

💡 Tip: Set git config --global submodule.recurse true so commands such as git pull and git switch also update submodules automatically.


🔄 Update a Submodule to a Newer Commit

The parent repository pins a specific commit. To move to the latest commit of the submodule’s branch:

git submodule update --remote shared-test-data
git status                        # modified: shared-test-data (new commits)
git add shared-test-data
git commit -m "Update shared-test-data to latest"
git push

Or manually:

cd shared-test-data
git fetch
git switch main
git pull
cd ..
git add shared-test-data
git commit -m "Update shared-test-data"

After teammates pull your change, they run git submodule update --init --recursive (or have submodule.recurse enabled) to check out the new pinned commit.


✏️ Change Code Inside a Submodule

A submodule is a full repository. To change it, commit and push inside it first, then commit the new pointer in the parent:

cd shared-test-data
git switch -c feature/new-users
# edit files
git commit -am "Add premium test users"
git push -u origin feature/new-users       # then merge via PR in that repository
cd ..
git add shared-test-data
git commit -m "Point to shared-test-data with premium users"

⚠️ Common mistake: After git submodule update, the submodule is in detached HEAD state. Switch to a branch before committing inside it, or your commits may be hard to find later (see git reflog).


🧰 Useful Commands

CommandPurpose
git submodule statusShow each submodule’s pinned commit
git submodule foreach 'git pull'Run a command in every submodule
git submodule syncUpdate submodule URLs after they changed in .gitmodules
git diff --submoduleShow submodule commit changes as logs instead of hashes

🗑️ Remove a Submodule

git submodule deinit -f shared-test-data
git rm -f shared-test-data
rm -rf .git/modules/shared-test-data
git commit -m "Remove shared-test-data submodule"

🤖 Submodules in CI

In GitHub Actions, ask the checkout action to fetch submodules:

- uses: actions/checkout@v4
  with:
    submodules: recursive

Private submodules need a token or deploy key with access; see secrets and personal access tokens.


⚖️ Submodules vs Alternatives

OptionBest whenDrawback
SubmoduleYou need another repo’s source at an exact commitExtra commands; easy to forget updates
Package (npm, PyPI, Maven)Sharing versioned code between projectsRequires publishing releases
MonorepoMany related projects evolving togetherOne big repository to manage
git subtreeCopying another repo’s history into a folderHarder to push changes back

📝 Assignment

  1. Create two repositories on GitHub: shared-test-data (with a users.json) and qa-platform.
  2. Add shared-test-data as a submodule of qa-platform and push.
  3. Clone qa-platform into a new folder without --recurse-submodules, observe the empty folder, then fix it.
  4. Change users.json in shared-test-data, push it, and update the pointer in qa-platform.
  5. Remove the submodule cleanly.

❓ FAQ

🤔 What is a Git submodule?

A Git repository embedded in a folder of another repository, pinned to a specific commit.

🤔 How do I clone a repository with submodules?

git clone --recurse-submodules <url>, or after a normal clone run git submodule update --init --recursive.

🤔 How do I update a submodule to the latest commit?

git submodule update --remote <path>, then commit the changed submodule pointer in the parent repository.

🤔 Why is my submodule folder empty?

The repository was cloned without initializing submodules. Run git submodule update --init --recursive.

🤔 How do I remove a Git submodule?

git submodule deinit -f <path>, git rm -f <path>, delete .git/modules/<path>, and commit.


🎯 Next Steps

🎬 Learn Git and GitHub step by step: watch the series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

1 thought on “Git Submodules Explained: Add, Clone, Update and Remove Submodules”

Leave a Comment