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.
๐ 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
| Command | Purpose |
|---|---|
git submodule status | Show each submodule’s pinned commit |
git submodule foreach 'git pull' | Run a command in every submodule |
git submodule sync | Update submodule URLs after they changed in .gitmodules |
git diff --submodule | Show 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
| Option | Best when | Drawback |
|---|---|---|
| Submodule | You need another repo’s source at an exact commit | Extra commands; easy to forget updates |
| Package (npm, PyPI, Maven) | Sharing versioned code between projects | Requires publishing releases |
| Monorepo | Many related projects evolving together | One big repository to manage |
| git subtree | Copying another repo’s history into a folder | Harder to push changes back |
๐ Assignment
- Create two repositories on GitHub:
shared-test-data(with ausers.json) andqa-platform. - Add
shared-test-dataas a submodule ofqa-platformand push. - Clone
qa-platforminto a new folder without--recurse-submodules, observe the empty folder, then fix it. - Change
users.jsoninshared-test-data, push it, and update the pointer inqa-platform. - 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
- ๐ฌ Git Internals: Objects, Refs and HEAD
- ๐ Personal Access Tokens and Authentication
- ๐ Git and GitHub Tutorial: full course
๐ฌ Learn Git and GitHub step by step: watch the series on YouTube!
Subscribe to SqaToolsByDY • Practice on sqatools.in