How to Have Git Repositories Nested Inside Each Other (The Submodules Solution)
Use Git submodules to properly nest repositories while maintaining independent version control

I was working on a project where I needed to include another Git repository inside my main repository. Sounds simple, right? But when I tried to initialize a new Git repo inside an existing one, Git immediately complained. You can't just have "Git inside Git" without proper setup.
After wrestling with .gitignore workarounds that never quite worked, I discovered the clean solution: Git submodules. This is exactly what they're designed for, and once you understand the workflow, it's incredibly powerful.
The Problem with Nested Git Repositories
When you try to create a Git repository inside another Git repository, you run into immediate issues. The parent repository wants to track everything in its directory tree, but the nested repository needs its own independent version control. Without proper setup, you get conflicts, ignored changes, and a mess of version control chaos.
The breakthrough insight is that Git submodules solve this elegantly by creating a proper parent-child relationship between repositories while keeping their histories completely separate.
Setting Up Git Submodules
Let's say you have a main project and want to include another repository inside it. Here's the step-by-step process:
# In your main project directory
cd /path/to/your-main-project
# Add the submodule
git submodule add https://github.com/username/child-repo.git path/to/nested-folder
# This creates the submodule and clones the repository
git add .gitmodules path/to/nested-folder
git commit -m "Add child repository as submodule"
This command does several important things. It clones the child repository into your specified folder, creates a .gitmodules
file that tracks the submodule configuration, and sets up the proper Git relationship between parent and child.
The .gitmodules
file looks like this:
# File: .gitmodules
[submodule "path/to/nested-folder"]
path = path/to/nested-folder
url = https://github.com/username/child-repo.git
This configuration file tells Git how to handle the nested repository, including where it lives and where to fetch updates from.
Working with Nested Repositories
Once your submodule is set up, you have two completely independent Git repositories sharing the same workspace. Here's how to work with them:
# Work on the child repository
cd path/to/nested-folder
# Make changes to files
echo "console.log('Hello from nested repo');" > index.js
# Commit changes to the child repository
git add .
git commit -m "Add new feature to nested repo"
git push origin main
# Go back to parent repository
cd ../..
# The parent repo sees the submodule has new commits
git status
# Shows: modified: path/to/nested-folder (new commits)
# Update parent to point to latest child commits
git add path/to/nested-folder
git commit -m "Update nested repo to latest version"
The key concept here is that the parent repository doesn't track the individual files in the child repository. Instead, it tracks which specific commit of the child repository it should point to. This gives you complete separation while maintaining a clear relationship.
Cloning Projects with Submodules
When someone else wants to clone your project with its submodules, they need to use special commands:
# Option 1: Clone with submodules in one command
git clone --recurse-submodules https://github.com/username/main-project.git
# Option 2: Clone first, then initialize submodules
git clone https://github.com/username/main-project.git
cd main-project
git submodule update --init --recursive
Without these commands, the submodule folder would exist but be empty. The --recurse-submodules
flag tells Git to also clone all nested repositories and check out the correct commits.
Updating Submodules
As the child repository evolves, you'll want to update your main project to use newer versions:
# Update submodule to latest remote version
git submodule update --remote path/to/nested-folder
# Or update all submodules at once
git submodule update --remote
# Commit the update to parent repository
git add .
git commit -m "Update submodules to latest versions"
This workflow lets you control exactly which version of the child repository your main project uses, giving you stability and control over dependencies.
Why This Works So Well
Git submodules solve the "Git inside Git" problem by creating a proper parent-child relationship rather than trying to merge two repositories into one. The parent repository tracks a specific commit hash from the child repository, not the files themselves. This means both repositories maintain completely independent histories while sharing the same workspace.
You get the benefits of having everything in one place for development, while maintaining clean separation for version control. No .gitignore hacks, no workarounds - just proper Git architecture.
By following this approach, you can have as many nested repositories as you need, each maintaining its own independent development cycle while being easily accessible from your main project workspace.
Let me know in the comments if you have questions about setting up submodules, and subscribe for more practical Git guides.
Thanks, Matija