|$ curl https://forge-ai.dev/api/markdown?path=docs/git/submodules
$cat docs/git-submodules.md
updated Recently·25 min read·published
Git Submodules
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 |
| 2 | git 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 |
| 9 | git submodule add -b main https://github.com/org/shared-lib.git libs/shared-lib |
| 10 | |
| 11 | # Commit the submodule reference |
| 12 | git add .gitmodules libs/shared-lib |
| 13 | git commit -m "Add shared-lib submodule" |
| 14 | |
| 15 | # Clone a repo with submodules |
| 16 | git clone https://github.com/org/main-project.git |
| 17 | cd main-project |
| 18 | git submodule init |
| 19 | git submodule update |
| 20 | |
| 21 | # One-liner: clone with submodules |
| 22 | git clone --recurse-submodules https://github.com/org/main-project.git |
| 23 | |
| 24 | # Update to latest commits |
| 25 | cd libs/shared-lib |
| 26 | git pull origin main |
| 27 | cd ../.. |
| 28 | git add libs/shared-lib |
| 29 | git 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 |
| 2 | git submodule status |
| 3 | # abc1234 libs/shared-lib (heads/main) |
| 4 | |
| 5 | # Update all submodules to their tracked commits |
| 6 | git submodule update --init --recursive |
| 7 | |
| 8 | # Update to the latest commit on the tracked branch |
| 9 | git submodule update --remote --merge |
| 10 | |
| 11 | # Update a specific submodule |
| 12 | git submodule update --remote libs/shared-lib |
| 13 | |
| 14 | # See what changed in a submodule |
| 15 | cd libs/shared-lib |
| 16 | git log --oneline HEAD..origin/main |
| 17 | cd ../.. |
| 18 | |
| 19 | # Remove a submodule |
| 20 | git submodule deinit -f libs/shared-lib |
| 21 | git rm -f libs/shared-lib |
| 22 | rm -rf .git/modules/libs/shared-lib |
| 23 | git 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
| Aspect | Submodules | Subtrees |
|---|---|---|
| Setup | Simple | Moderate |
| Tracking | Pinned to a commit | Full history merge |
| Cloning | Requires init/update | Automatic (inlined) |
| Contributing back | Separate workflow | Push to subtree remote |
| Repo size | Stays small | Grows with history |
subtree.sh
Bash
| 1 | # Add a subtree |
| 2 | git subtree add --prefix=libs/shared-lib https://github.com/org/shared-lib.git main --squash |
| 3 | |
| 4 | # Update subtree |
| 5 | git subtree pull --prefix=libs/shared-lib https://github.com/org/shared-lib.git main --squash |
| 6 | |
| 7 | # Push changes back to the subtree repo |
| 8 | git 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