Search Knowledge

© 2026 LIBREUNI PROJECT

Submodules and Dependencies

The Dependency Problem

Modern software is built on libraries. Usually, you use a package manager (npm, pip, cargo) to handle this. But sometimes, you need to depend on another Git repository directly—perhaps a private library or a C++ project that needs to be compiled from source.

Git offers two main ways to embed one repository inside another: Submodules and Subtrees.

Git Submodules

A submodule is a pointer to a specific commit in another repository. It stays in a subdirectory of your main project, but Git sees it as a separate entity.

Adding a Submodule

git submodule add https://github.com/libs/mylib.git libs/mylib

This creates a .gitmodules file (which tracks the mapping between URL and path) and downloads the code into libs/mylib.

Cloning with Submodules

When you clone a project that has submodules, the directories will be empty by default. You must initialize and update them.

git clone https://github.com/my/project.git
cd project
git submodule init
git submodule update

Or, do it all at once:

git clone --recurse-submodules https://github.com/my/project.git

The Detached HEAD Trap

When you enter a submodule directory, you are in a “Detached HEAD” state pointing to the commit recorded by the parent project. If you make changes and commit them, they exist only in that submodule. To update the parent project to use your new changes:

  1. Push changes inside the submodule.
  2. Go to the parent directory.
  3. git add libs/mylib (this updates the pointer).
  4. git commit.
Code
package "Parent Repo" {
  [Main Code]
  folder "libs/mylib" as sub {
      [Submodule Code]
  }
}
cloud "Remote Lib" {
}
cloud "Remote Parent" {
}

[Main Code] --> sub : Points to Commit SHA
sub ..> "Remote Lib" : Pulls from
Parent Repolibs/mylibMain CodeSubmodule CodeRemote LibRemote ParentPoints to Commit SHAPulls from

Git Subtree

Subtree is an alternative that allows you to nest one repository inside another as a normal subdirectory. Unlike submodules, the files are actually present in the parent repository’s history.

Adding a Subtree

git subtree add --prefix=libs/mylib https://github.com/libs/mylib.git main --squash

This merges the history of the library into your project under the libs/mylib folder.

Updating

To pull in new changes from the library:

git subtree pull --prefix=libs/mylib https://github.com/libs/mylib.git main --squash

Pros vs Cons

Submodules:

  • Pros: Keeps repositories strictly separate. Good for large binary dependencies.
  • Cons: Complex workflow. Easy to forget to push the submodule. Users must remember --recurse-submodules.

Subtrees:

  • Pros: Simple for users (it’s just files). No special clone commands needed.
  • Cons: Complex for the maintainer. Mixing history can be confusing.

Best Practices

  1. Use Package Managers first: If you can use npm, Maven, or NuGet, do it. Use Git dependencies only when necessary.
  2. Automate: Use scripts to update submodules to ensure everyone is on the same version.
  3. Don’t modify submodules: Treat them as read-only build dependencies if possible.
git
1# Initialize a repo and add a submodule
2git init
3# We simulate adding a submodule (files only) as we have no network
4echo '[submodule "lib"]' > .gitmodules
5echo ' path = lib' >> .gitmodules
6echo ' url = https://example.com/lib.git' >> .gitmodules
7mkdir lib
8git add .gitmodules
9git commit -m "Add submodule"

Which file tracks the mapping of submodules to their URLs?

Cloning Recursively

# You want to clone a repo and automatically fetch all nested submodules.
git clone  https://host/repo.git
Previous Module Git Hooks