Skip to main content

Command Palette

Search for a command to run...

🧩 Git Submodules Explained — Complete Guide with Best Practices, Tips & Tricks

Published
•5 min read•View as Markdown
🧩 Git Submodules Explained — Complete Guide with Best Practices, Tips & Tricks

Have you ever worked on a large project where multiple repositories needed to stay in sync — like a shared API, Terraform module, or a reusable microservice?

If yes, then Git submodules might just become your new best friend. 💡

In this post, we’ll dive deep into:

  • What Git submodules are

  • How they work internally

  • Best practices and common pitfalls

  • Useful commands, tips, and tricks


🚀 What Are Git Submodules?

A Git submodule allows you to include one Git repository inside another as a subdirectory.
Each submodule keeps its own commit history, branches, and identity — but still links to the parent project.

Think of it like this 👇

“A submodule is a Git repo inside another Git repo — linked at a specific commit.”

This is useful when you have shared components across multiple projects, like:

  • A shared library used in multiple apps

  • A common DevOps configuration (Jenkinsfile, Dockerfiles, etc.)

  • A reusable Terraform module

  • A frontend design system used by multiple teams


🧠 How Git Submodules Work Internally

When you add a submodule, Git doesn’t copy all its files into your repo.
Instead, it:

  • Clones the external repository at a specific commit

  • Stores the reference (commit hash and path) inside a .gitmodules file

That .gitmodules file acts like a map between the parent repo and its submodules.

Example:

git submodule add https://github.com/example/library.git libs/library

This creates:

.libs/
 └── library/
.gitmodules

And your .gitmodules might look like this:

[submodule "libs/library"]
  path = libs/library
  url = https://github.com/example/library.git

⚙️ Common Git Submodule Commands

Here are the most important commands to master:

CommandDescription
git submodule add <repo-url> <path>Add a new submodule
git clone --recurse-submodules <repo>Clone repo with submodules
git submodule initInitialize submodules
git submodule updateFetch the submodule content
git submodule update --init --recursiveInitialize and update all nested submodules
git submodule foreach git pull origin mainPull latest code for all submodules
git submodule deinit <path>Remove a submodule

🧩 Example Workflow: Adding and Updating a Submodule

Let’s see it in action 👇

Step 1: Add the submodule

git submodule add https://github.com/example/library.git libs/library

Step 2: Initialize & update

git submodule update --init --recursive

Step 3: Commit the configuration

git add .gitmodules libs/library
git commit -m "Added library as submodule"

Step 4: Update the submodule to latest version

cd libs/library
git checkout main
git pull origin main
cd ../..
git add libs/library
git commit -m "Updated library submodule"

✅ Best Practices for Working with Git Submodules

Submodules can be tricky if used incorrectly. Here’s how to use them the right way 👇

1️⃣ Keep Submodules Read-Only

Treat submodules as dependencies, not active development folders.
If you need to modify them, do it in their own repo — then pull the updated commit in your parent project.


2️⃣ Always Commit Submodule Updates

When you update the submodule’s code, Git only changes its pointer (the commit hash).
So remember to commit that change in the parent repo:

git add libs/library
git commit -m "Update submodule to latest commit"

3️⃣ Use Specific Commits or Tags

Avoid tracking branches like main directly.
Use fixed commits or version tags for stable, predictable builds.

git submodule update --remote --merge

This ensures your parent repo always points to a known, stable version.


4️⃣ Keep Paths Clean and Consistent

Store all submodules in a common folder like /libs or /modules.
This makes your repo structure predictable and readable for others.


5️⃣ Use .gitmodules Wisely

Ensure .gitmodules uses relative URLs if your repos are hosted in the same organization.
This makes cloning easier, especially in private or on-prem environments.

Example:

url = ../shared-library.git

⚡ Pro Tips & Tricks

💡 Tip 1: Clone Everything in One Go
When cloning a repo with submodules, always use:

git clone --recurse-submodules <repo-url>

Otherwise, submodules will be empty until you initialize them manually.


💡 Tip 2: Automate Submodule Updates in CI/CD
Add this in your pipeline to ensure submodules are updated before build:

git submodule update --init --recursive

💡 Tip 3: Use Git Aliases for Convenience
Set up handy aliases in your ~/.gitconfig:

[alias]
  smu = submodule update --init --recursive
  smp = submodule foreach git pull origin main

Now you can just run git smu or git smp.


💡 Tip 4: Prefer Git Subtree for Heavy Collaboration
If your team frequently edits both parent and submodule repos together, consider using Git subtree instead — it simplifies merges and version tracking.


⚖️ When to Use (and When Not to)

✅ Use Git Submodules When:

  • You have shared codebases or versioned dependencies

  • You want to keep histories separate

  • You need reproducible builds (specific versions locked)

🚫 Avoid When:

  • The submodule changes frequently alongside the parent repo

  • Multiple teams edit both repos often

  • You need complex merge workflows

In such cases, monorepos or Git subtrees might be better options.


🧭 Final Thoughts

Git submodules are powerful, but they require a disciplined approach.
Used wisely, they help you:

  • Keep dependencies versioned

  • Maintain modularity

  • Avoid duplication across projects

But used carelessly, they can lead to detached commits, broken builds, and headaches 😅

So remember:

“Submodules are great for sharing stable, reusable code — not for daily-changing dependencies.”


💬 Conclusion

Mastering submodules can make your Git workflow modular, reusable, and scalable — especially in DevOps and microservice environments.

Start small: try adding a shared script repo or library as a submodule and explore how it integrates smoothly with your parent project.


✍️ Written by Tathagat Gaikwad
🔖 #Git #DevOps #VersionControl #GitTips #SoftwareEngineering

DevOps

Part 38 of 50

🚀 Kicking off my DevOps Series on Hashnode! I’ll share notes, best practices, tips, demos & interview prep on AWS, Docker, K8s, CI/CD, Terraform & more. Follow along to learn & grow together! #DevOps #Hashnode #LearningInPublic

Up next

🧩 Mastering git blame: The Secret Weapon for Debugging and Code History

Have you ever stumbled upon a mysterious bug and wondered — “Who changed this line… and why on earth?” 😅 That’s where git blame comes to the rescue. In this post, we’ll uncover everything about git blame — from how it works to real-world debugging...

More from this blog

Cloud Enthusiast

116 posts