By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
You’re working on a microservices project where service-A depends on a shared auth-library. The library is in its own repo, and you need to: - Keep it updated (bug fixes, security patches).- Avoid copy-pasting code (DRY principle).- Allow independent development (the library team works separately).- Not break CI/CD when the library changes.
service-A
auth-library
If you ignore this, you’ll end up with: ❌ Version drift – Different services use different versions of the same library.❌ Merge hell – Manually copying code leads to conflicts.❌ Broken builds – CI fails because dependencies aren’t where they should be.
Submodules and subtrees are Git’s two main tools for handling dependencies. They let you embed one repo inside another while keeping history, updates, and version control intact.
Real-world scenario:You’re a DevOps engineer maintaining a monorepo with 10 microservices. Each service depends on a shared logging-library. Instead of duplicating the library in each service, you: - Use a submodule if the library is developed separately (e.g., by another team).- Use a subtree if the library is tightly coupled to your project and you want to modify it directly.
logging-library
git submodule update --init
.gitmodules
git submodule update
--remote
git subtree add
--prefix
git subtree pull
--squash
git subtree merge
git subtree push
git submodule foreach
git pull
git submodule foreach 'git checkout main && git pull'
Prerequisites:- Git installed (git --version).- Two repos: - my-project (your main repo). - shared-library (a dependency, e.g., a utility repo).
git --version
my-project
shared-library
cd my-project git submodule add https://github.com/your-org/shared-library.git libs/shared-library
libs/shared-library
git commit -m "Add shared-library as a submodule"
If someone else clones my-project, they must:
git clone https://github.com/your-org/my-project.git cd my-project git submodule update --init --recursive
--init
--recursive
cd libs/shared-library git checkout main git pull origin main cd ../..git add libs/shared-library git commit -m "Update shared-library to latest main"
git config -f .gitmodules submodule.libs/shared-library.branch main git submodule update --remote
cd my-project git remote add shared-library https://github.com/your-org/shared-library.git git subtree add --prefix=libs/shared-library shared-library main --squash
git subtree pull --prefix=libs/shared-library shared-library main --squash
git subtree push --prefix=libs/shared-library shared-library my-feature-branch
✅ Use SSH for submodules (not HTTPS) to avoid token leaks:
git submodule add [email protected]:your-org/shared-library.git libs/shared-library
✅ Pin submodules to a commit hash (not a branch) in production to avoid unexpected updates.✅ Audit .gitmodules – Ensure no private repos are exposed.
✅ Subtrees increase repo size – Use --squash to minimize bloat.✅ Submodules require extra CI steps – Cache them to speed up builds.
✅ Document dependencies in a README.md:
README.md
## Dependencies - `libs/shared-library` (submodule, pinned to commit `abc123`)
✅ Use git submodule foreach in CI to update all submodules:
✅ Avoid nested submodules – They complicate CI/CD and cloning.
✅ Monitor submodule updates – Set up GitHub Actions to alert on changes:
name: Check Submodule Updates on: [push] jobs: check-submodules: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: git submodule update --init --recursive - run: git submodule status
✅ Log subtree merges – Use git log --grep="subtree" to track changes.
git log --grep="subtree"
fatal: not a git repository
git submodule update --init --recursive
git status
git add <submodule-path>
submodule.<name>.branch = main
Permission denied
Trap: Subtrees are better for internal libraries you modify.
"A teammate clones your repo but the submodule is empty. What’s missing?"
Trap: git clone --recurse-submodules is the one-liner alternative.
git clone --recurse-submodules
"How do you update a submodule to the latest commit?"
bash cd <submodule-path> git pull origin main cd .. git add <submodule-path> git commit -m "Update submodule"
Trap: --remote updates to the branch, not the latest commit.
"You want to contribute changes back to a subtree’s original repo. Which command do you use?"
git subtree push --prefix=<path> <remote> <branch>
You have a repo my-app that depends on utils-lib. The utils-lib team just released a critical bug fix. Update your submodule to the latest commit and verify it works.
my-app
utils-lib
cd my-app/libs/utils-lib git checkout main git pull origin main cd ../..git add libs/utils-lib git commit -m "Update utils-lib to latest main" git push
Why it works:- git pull origin main fetches the latest changes.- git add updates the parent repo’s pointer to the new commit.
git pull origin main
git add
git submodule add <url> <path>
--branch <name>
git submodule foreach '<command>'
git subtree add --prefix=<path> <remote> <branch>
git subtree pull --prefix=<path> <remote> <branch>
git config -f .gitmodules submodule.<name>.branch <branch>
Now go update those dependencies—without breaking CI/CD! ?
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.