Skip to content

Git Submodules — Managing External Dependencies Across Repos

DodaTech 4 min read

In this tutorial, you'll learn about Git Submodules. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

What You'll Learn

Use Git submodules to embed one Repository inside another — add shared libraries, pin dependencies to specific commits, and update them across projects without copy-pasting.

Why It Matters

When multiple projects share a utility library, you can copy the files (and manually sync them) or use submodules — a reference to an external repo at a specific commit. Submodules keep the dependency linked to its source, so updates are deliberate and traceable.

Real-World Use

A Hugo website includes a theme as a submodule, a backend project pins a shared auth library at a specific version, and a Monorepo-style project breaks its codebase into submodules for independent team ownership.

What Are Submodules?

A submodule is a reference to another Git Repository at a fixed commit:

your-project/
├── src/
├── themes/hugo-theme → github.com/themes/hugo-theme (at commit a1b2c3)
├── lib/utils → github.com/org/utils (at commit d4e5f6)
└── .gitmodules         # Tracks submodule URLs and paths
graph TD
    A[Your Repository] --> B[.gitmodules]
    A --> C[themes/hugo-theme]
    A --> D[lib/shared-utils]
    B --> E[URL: github.com/themes/hugo-theme]
    B --> F[URL: github.com/org/shared-utils]
    C --> G[Pinned commit: a1b2c3]
    D --> H[Pinned commit: d4e5f6]
    G --> I[External Repo: hugo-theme]
    H --> J[External Repo: shared-utils]

Adding a Submodule

# Add a theme as a submodule
git submodule add https://github.com/themes/hugo-theme.git themes/hugo-theme
# Cloning into 'themes/hugo-theme'...
# remote: Enumerating objects: 150, done.
# Receiving objects: 100% (150/150), done.

# Add a shared library
git submodule add https://github.com/org/shared-utils.git lib/shared-utils
# Cloning into 'lib/shared-utils'...

# This creates .gitmodules and stages the submodule
git status
# new file:   .gitmodules
# new file:   themes/hugo-theme
# new file:   lib/shared-utils

git commit -m "chore: add hugo theme and shared utils as submodules"

Cloning a Repository with Submodules

# Clone the parent repo
git clone https://github.com/user/your-project.git
cd your-project

# Submodule directories exist but are empty — initialize them
git submodule init
git submodule update
# Submodule path 'themes/hugo-theme': checked out 'a1b2c3...'
# Submodule path 'lib/shared-utils': checked out 'd4e5f6...'

# One-command clone + submodule init
git clone --recurse-submodules https://github.com/user/your-project.git

Updating Submodules

# Update all submodules to their latest remote commit
git submodule update --remote
# remote: Enumerating objects: 5, done.
# Submodule path 'lib/shared-utils': checked out 'f7a8b9...'

# Update a specific submodule
git submodule update --remote lib/shared-utils

# Check what changed
cd lib/shared-utils
git log --oneline HEAD..origin/main
# f7a8b9 Add caching layer
# a1b2c3 Fix memory leak

# After updating, commit the new submodule pointer
cd ../..
git add lib/shared-utils
git commit -m "chore: update shared-utils to include caching layer"

Working Inside a Submodule

# Enter the submodule
cd lib/shared-utils

# Check out a specific branch
git checkout main

# Pull latest changes
git pull origin main

# Make changes, commit, and push
echo "new function" >> utils.py
git add utils.py
git commit -m "feat: add new utility function"
git push origin main

# Go back to parent repo — it sees the submodule changed
cd ../..
git status
# modified: lib/shared-utils (new commits)
git add lib/shared-utils
git commit -m "chore: update shared-utils with new utility"

Removing a Submodule

# Remove a submodule (Git 2.12+)
git submodule deinit -f themes/hugo-theme
# Clears the submodule's working tree

git rm themes/hugo-theme
# Removes the submodule entry and .gitmodules reference

git commit -m "chore: remove hugo-theme submodule"

# Clean up leftover .git/modules entry
rm -rf .git/modules/themes/hugo-theme

Submodule Workflows for Teams

# Developer A: Updates a submodule
cd lib/shared-utils
git checkout main
git pull origin main
cd ../..
git add lib/shared-utils
git commit -m "chore: update shared-utils to latest"

# Developer B: Pulls the update
git pull                      # Parent repo updates
git submodule update --init --recursive
# Submodule path 'lib/shared-utils': checked out 'f7a8b9...'

Common Pitfalls

Mistake Solution
Submodule at wrong commit after clone Always use git clone --recurse-submodules
Detached HEAD inside submodule Run git checkout main inside the submodule before making changes
Forgetting to push submodule changes Submodule commits must exist on remote before parent repo references them
Nested submodules Use --recursive with git submodule update

Practice Questions

  1. What file tracks submodule URLs and paths?
  2. How do you clone a Repository and initialize all submodules in one command?
  3. Why might you see a detached HEAD inside a submodule, and how do you fix it?

FAQs

What is the difference between git submodule and git subtree?

A submodule is a reference to another Repository — the parent repo stores only the pointer. git subtree copies the external repo's files into your Repository. Submodules are more flexible but require explicit init/update; subtrees are self-contained but bloat your history.

Can I use submodules with monorepos?

Yes — many teams use submodules to split a Monorepo into independently versioned components. Each team owns their submodule and the parent repo pins specific versions, similar to a package manager for Git repos.

How do I see which commit a submodule is pointing to?

Run git submodule status to see the pinned commit hash for each submodule. Add --recursive to show nested submodules. The output shows the commit hash, path, and whether the submodule is initialized.

Next Steps

After mastering submodules, learn version control strategies for monorepos, or explore Git Worktrees to work across multiple branches simultaneously.


Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro