Git
Submodule
Sub-directory
Version Control
Tutorial

How do I add Git submodule to a sub-directory?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Adding a Git submodule to a sub-directory is the standard way to include another repository inside your project while keeping histories separate. This is useful for shared libraries, vendor code, or internal tools that evolve independently. The workflow is simple once you understand what Git tracks in the parent repository.

Add the Submodule at a Specific Path

Use git submodule add with both repository URL and target folder.

bash
git submodule add https://github.com/example/shared-lib.git libs/shared-lib
git status

Git creates two things:

  • A .gitmodules file containing submodule metadata.
  • A special entry in the index that stores the submodule commit pointer.

Commit both changes from the parent repository.

bash
git add .gitmodules libs/shared-lib
git commit -m "Add shared-lib as a submodule under libs/shared-lib"

The parent repo does not store the submodule file contents directly. It stores the exact commit hash that should be checked out in that directory.

Clone and Initialize Correctly

When teammates clone the parent repository, they must also initialize submodules.

bash
git clone https://github.com/example/main-app.git
cd main-app
git submodule update --init --recursive

A one-line clone option is even better for new setups.

bash
git clone --recurse-submodules https://github.com/example/main-app.git

Without this step, submodule folders appear empty or detached, which causes confusion during builds.

Update a Submodule Intentionally

Inside the submodule directory, fetch and checkout the desired revision, then commit the pointer update in the parent repository.

bash
1cd libs/shared-lib
2git fetch
3git checkout main
4git pull
5cd ../..
6git add libs/shared-lib
7git commit -m "Bump shared-lib submodule to latest main"

This explicit pointer update is a feature. It gives parent repository owners control over exactly which dependency revision is used.

Track a Branch in .gitmodules

If your workflow expects updates from a specific branch, add branch metadata and use update commands consistently.

bash
git config -f .gitmodules submodule.libs/shared-lib.branch main
git add .gitmodules
git commit -m "Track main branch for shared-lib submodule"

Then update with:

bash
git submodule update --remote --merge

Review changes before committing. Auto-following a branch can pull in surprises if upstream moves quickly.

Move or Remove a Submodule Safely

To move a submodule path, use git mv and verify .gitmodules updates.

bash
git mv libs/shared-lib vendor/shared-lib
git add .gitmodules
git commit -m "Move shared-lib submodule to vendor path"

To remove a submodule, use deinit and remove the path.

bash
1git submodule deinit -f libs/shared-lib
2git rm -f libs/shared-lib
3rm -rf .git/modules/libs/shared-lib
4git commit -m "Remove shared-lib submodule"

This cleanup avoids stale metadata that can break future clones.

CI and Build Pipeline Considerations

Submodules require explicit handling in CI. If your pipeline checks out only the parent repository, builds can fail because dependency directories are empty. Add a submodule init step to your workflow.

bash
git submodule sync --recursive
git submodule update --init --recursive

If your submodule URL uses SSH, ensure CI runners have the correct deploy key. If HTTPS with tokens is required, inject credentials through secure CI secrets. Keep these details documented so local setup and CI behavior stay aligned.

Common Pitfalls

One frequent pitfall is forgetting to commit the submodule pointer change in the parent repository after updating inside the submodule folder. Another issue is cloning without --recurse-submodules, then assuming the dependency is missing or broken. Teams also sometimes edit files inside a detached submodule head and lose track of where those commits went. Always check branch state with git -C <path> status before editing. Finally, mixing submodules with ad-hoc copy-paste vendor directories creates unclear ownership boundaries. Pick one strategy and document it in your contribution guide.

Summary

  • Add submodules with git submodule add <url> <subdir>.
  • Commit both .gitmodules and the submodule pointer entry.
  • Clone with --recurse-submodules or initialize after cloning.
  • Update submodule commits intentionally and commit pointer bumps.
  • Clean up metadata correctly when moving or removing submodules.

Course illustration
Course illustration

All Rights Reserved.