|$ curl https://forge-ai.dev/api/markdown?path=docs/git/submodules
$cat docs/git-submodules.md
updated Recently·25 min read·published

Git Submodules

GitIntermediate🎯Free Tools
Introduction

Git submodules allow you to embed one Git repository inside another. The parent repo tracks a specific commit of the submodule, not a branch — ensuring reproducible builds across environments. Submodules are useful for shared libraries, vendor code, and monorepo-like structures without the overhead.

Adding & Cloning Submodules
submodules.sh
Bash
1# Add a submodule
2git submodule add https://github.com/org/shared-lib.git libs/shared-lib
3
4# This creates:
5# .gitmodules — submodule configuration
6# libs/shared-lib/ — the submodule directory
7
8# Add with a specific branch
9git submodule add -b main https://github.com/org/shared-lib.git libs/shared-lib
10
11# Commit the submodule reference
12git add .gitmodules libs/shared-lib
13git commit -m "Add shared-lib submodule"
14
15# Clone a repo with submodules
16git clone https://github.com/org/main-project.git
17cd main-project
18git submodule init
19git submodule update
20
21# One-liner: clone with submodules
22git clone --recurse-submodules https://github.com/org/main-project.git
23
24# Update to latest commits
25cd libs/shared-lib
26git pull origin main
27cd ../..
28git add libs/shared-lib
29git commit -m "Update shared-lib to latest"

info

Always use --recurse-submodules when cloning. Without it, the submodule directories will be empty — one of the most common surprises for new Git users.
Managing Submodules
managing-submodules.sh
Bash
1# List all submodules
2git submodule status
3# abc1234 libs/shared-lib (heads/main)
4
5# Update all submodules to their tracked commits
6git submodule update --init --recursive
7
8# Update to the latest commit on the tracked branch
9git submodule update --remote --merge
10
11# Update a specific submodule
12git submodule update --remote libs/shared-lib
13
14# See what changed in a submodule
15cd libs/shared-lib
16git log --oneline HEAD..origin/main
17cd ../..
18
19# Remove a submodule
20git submodule deinit -f libs/shared-lib
21git rm -f libs/shared-lib
22rm -rf .git/modules/libs/shared-lib
23git add .gitmodules
.gitmodules
Bash
1# .gitmodules file (auto-generated)
2[submodule "libs/shared-lib"]
3 path = libs/shared-lib
4 url = https://github.com/org/shared-lib.git
5 branch = main
6
7# CI/CD: always initialize submodules
8# GitHub Actions:
9# - uses: actions/checkout@v4
10# with:
11# submodules: recursive
12
13# Docker: copy .gitmodules for multi-stage builds
14# COPY .gitmodules .
15# RUN git submodule update --init --recursive
Submodules vs Subtrees
AspectSubmodulesSubtrees
SetupSimpleModerate
TrackingPinned to a commitFull history merge
CloningRequires init/updateAutomatic (inlined)
Contributing backSeparate workflowPush to subtree remote
Repo sizeStays smallGrows with history
subtree.sh
Bash
1# Add a subtree
2git subtree add --prefix=libs/shared-lib https://github.com/org/shared-lib.git main --squash
3
4# Update subtree
5git subtree pull --prefix=libs/shared-lib https://github.com/org/shared-lib.git main --squash
6
7# Push changes back to the subtree repo
8git subtree push --prefix=libs/shared-lib https://github.com/org/shared-lib.git feature/improvement

best practice

Use submodules when you need precise version pinning and the submodule has its own development lifecycle. Use subtreeswhen you want simpler cloning and don't mind the larger repo size.
$Blueprint — Engineering Documentation·Section ID: GIT-SM-01·Revision: 1.0