If you've ever wanted to reuse another Git repository inside your project without copying its code, Git Submodules are exactly what you're looking for.
At first, submodules can seem confusing. But once you understand how they work, they're actually straightforward.
In this article, we'll cover:
- What Git Submodules are
- Why you should use them
- How they work
- Common commands you'll use
- Common mistakes beginners make
- How to remove a submodule
What is a Git Submodule?
A Git Submodule lets you include one Git repository inside another Git repository.
Instead of copying files from another project, Git keeps a reference to that repository and remembers which commit should be used.
my-project/
│
├── src/
├── docs/
├── shared-library/ ← Git Submodule
├── package.json
└── .gitmodules
Here:
- my-project is the main repository (called the superproject).
- shared-library is another completely separate Git repository.
Each repository keeps its own commits, branches, and history.
Why Use Git Submodules?
Submodules are useful when you want to:
- Share common libraries between multiple projects
- Include third-party code without copying it
- Split a large project into smaller repositories
- Keep independent version history for reusable components
For example:
Suppose you have three applications that all use the same authentication library.
Instead of copying the authentication code into every project, you can keep it in its own repository and include it as a submodule.
Auth Library Repository
│
┌──────┴─────────┐
│ │
Project A Project B
Now every project references the same library.
How Git Stores a Submodule
A common misconception is that Git copies the entire repository into your project.
It doesn't.
Instead, the superproject only stores:
- the repository URL
- the folder path
- the exact commit hash
That means your main repository simply says:
"Use commit
abc123from this repository."
This allows the submodule to evolve independently.
The .gitmodules File
When you add a submodule, Git creates a file called:
.gitmodules
Example:
[submodule "shared-library"]
path = shared-library
url = https://github.com/example/shared-library.git
This file tells Git:
- where the submodule lives
- where to clone it from
Because .gitmodules is version controlled, everyone on your team gets the same configuration.
Adding a Submodule
Use:
git submodule add <repository-url> <path>
Example:
git submodule add https://github.com/example/shared-library.git shared-library
Git will:
- clone the repository
- create
.gitmodules - stage both the new folder and
.gitmodules
Then commit the changes:
git commit -m "Add shared library as submodule"
Cloning a Repository with Submodules
The easiest way is:
git clone --recurse-submodules <repository-url>
This clones:
- the main repository
- every submodule
- nested submodules as well
Forgot --recurse-submodules?
No problem.
Run:
git submodule update --init --recursive
This initializes and downloads all submodules after cloning.
Updating a Submodule
To fetch the latest commits from the remote repository:
git submodule update --remote
Git updates the submodule to the latest commit of its tracked branch.
After that, don't forget to commit the updated reference:
git add shared-library
git commit -m "Update submodule"
Otherwise your teammates won't receive the updated version.
Pushing Changes
If you've made changes inside the submodule, push them first.
A convenient command is:
git push --recurse-submodules=on-demand
This ensures Git pushes:
- the submodule commits
- then the main repository
This prevents broken references for other developers.
Detached HEAD Explained
One thing that surprises many beginners is seeing this message:
HEAD detached at abc123
This is normal.
The superproject points to a specific commit instead of a branch.
A detached HEAD simply means:
"You're viewing a particular commit."
If you want to make changes inside the submodule, switch to a branch first:
cd shared-library
git checkout main
Then make your changes, commit, push, and finally update the superproject.
Common Beginner Mistakes
1. Forgetting to clone submodules
Incorrect:
git clone <repository>
Correct:
git clone --recurse-submodules <repository>
Or run:
git submodule update --init --recursive
2. Updating the submodule but forgetting to commit
After updating:
git submodule update --remote
You still need:
git add shared-library
git commit -m "Update submodule reference"
3. Editing inside a detached HEAD
Always switch to a branch before making changes:
git checkout main
Removing a Submodule
Removing a submodule involves more than deleting the folder because Git tracks additional metadata.
The process differs slightly depending on your Git version.
A detailed step-by-step guide is available here:
https://stackoverflow.com/questions/1260748/how-do-i-remove-a-submodule
When Should You Use Git Submodules?
Use submodules when:
- multiple projects share the same codebase
- you want independent version histories
- you need to pin an exact version of another repository
- you want to include third-party repositories without copying code
Avoid submodules if your team is unfamiliar with Git or if your project requires frequent synchronized changes across repositories. In those cases, alternatives like package managers or monorepos may be simpler.
Final Thoughts
Git Submodules are often considered difficult—not because they're complicated, but because many developers don't understand that a submodule is simply another Git repository tracked by a specific commit.
Once you remember these three rules, everything becomes easier:
- A submodule has its own Git history.
- The main repository stores only a commit reference.
- Updating a submodule requires committing the new reference in the superproject.
Master these concepts, and working with shared repositories becomes much cleaner and more maintainable.
Useful Commands Cheat Sheet
# Add a submodule
git submodule add <repo-url> <path>
# Clone with submodules
git clone --recurse-submodules <repo-url>
# Initialize submodules after cloning
git submodule update --init --recursive
# Update submodule to latest remote commit
git submodule update --remote
# Push submodule and superproject together
git push --recurse-submodules=on-demand
# Switch submodule to a branch
cd submodule
git checkout main
Thaks for reading!
Top comments (0)