The Hook (The "Byte-Sized" Intro)
Submodules don't update themselves. When a teammate commits a new submodule pointer, your local copy still shows the old version until you explicitly update. And "update" means two different things: syncing to what the parent pinned vs. pulling the latest from the submodule's remote. Getting these confused is a classic mistake.
📖 What is Updating Submodules?
There are two kinds of submodule updates: (1) checking out the commit the parent repo points to, and (2) advancing the submodule to a newer commit from its remote.
Conceptual Clarity
Two types of update:
| Goal | Command | What It Does |
|---|---|---|
| Sync to parent | git submodule update | Checks out the commit the parent pinned |
| Pull latest | cd sub && git pull | Fetches the latest from the submodule's remote |
The update workflow (pulling latest):
| Step | Command |
|---|---|
| 1. Enter submodule | cd libs/shared-utils |
| 2. Pull latest | git pull origin main |
| 3. Return to parent | cd .. |
| 4. Stage new pointer | git add libs/shared-utils |
| 5. Commit | git commit -m "chore: update shared-utils" |
Shortcut:
git submodule update --remote
This fetches the latest from each submodule's tracked branch and updates in one step.
Real-Life Analogy
git submodule update is like telling your e-reader "go back to the bookmark" (the pinned commit). git submodule update --remote is like saying "jump to the newest chapter" (the latest on the remote branch).
Visual Architecture
Why It Matters
- Predictability:
updatewithout--remotegives you exactly what the parent expects. - Intentional changes: Updating the submodule pointer is a deliberate commit.
- Team sync:
git pull && git submodule updatekeeps everyone aligned. - CI reliability: Builds always use the pinned commit, not "whatever's latest."
Code
# ─── Sync submodule to what the parent expects ───
git submodule update
# Checks out the commit SHA stored in the parent repo
# ─── After pulling parent changes that moved the pointer ───
git pull
git submodule update --init --recursive
# ─── Update submodule to the latest from remote ───
git submodule update --remote libs/shared-utils
# Fetches latest from the tracked branch
# ─── Manual approach (same result) ───
cd libs/shared-utils
git pull origin main
cd ..
git add libs/shared-utils
git commit -m "chore: update shared-utils to latest"
# ─── Update ALL submodules to latest ───
git submodule update --remote
# ─── Check submodule status ───
git submodule status
# Shows current commit and whether it matches the parent's pointerKey Takeaways
git submodule update= sync to the parent's pinned commit.git submodule update --remote= pull the latest from the submodule's remote.- After updating to latest, commit the new pointer in the parent repo.
- Always
git submodule updateaftergit pullto stay in sync.
Interview Prep
-
Q: What is the difference between
git submodule updateandgit submodule update --remote? A: Without--remote, it checks out the commit the parent repo has pinned. With--remote, it fetches the latest from the submodule's tracked remote branch — this may advance the pointer to a newer commit. -
Q: After updating a submodule to the latest version, what else must you do? A: You must stage the submodule directory (
git add <submodule-path>) and commit in the parent repo. This updates the pointer so teammates and CI get the new version. -
Q: Why don't submodules update automatically on
git pull? A: By design — submodule updates are explicit to prevent unexpected changes. You can enable automatic updates withgit config submodule.recurse true.