🔀 Everyone Else’s Submodule Updated – Yours Quietly Didn’t
A Git submodule doesn’t automatically track the latest commit on its remote’s default branch – it’s pinned to a specific commit recorded in the parent repository, and that pin only moves when someone explicitly runs an update command, which means a teammate can pull the latest parent repository changes and still be working against a submodule commit that’s weeks old, with no error or warning indicating anything is out of date.
🔎 The Problem
$ git pull # Pulls the parent repo'"'"'s latest changes $ git status On branch main Your branch is up to date with '"'"'origin/main'"'"'. # But the submodule directory is still checked out at whatever commit # was recorded the LAST time someone ran a submodule update - a plain # `git pull` on the parent repository does not automatically update # submodule contents, even if the parent'"'"'s tracked commit pointer for # that submodule has since changed.
✅ Fix: Update Submodules Explicitly, Every Time
- `git submodule update –init –recursive` after every pull brings every submodule to the exact commit the parent repository currently expects – this needs to run as a deliberate, separate step, since a plain `git pull` on the parent repo alone never does this automatically.
- `git config –global submodule.recurse true` makes `git pull`, `git checkout`, and several other common commands automatically recurse into submodules going forward – removing the need to remember the separate update command every single time, for anyone who sets this once.
- For a team where this trips people up repeatedly, a post-merge Git hook that automatically runs the submodule update command removes the manual step entirely, so pulling the parent repository and having an up-to-date submodule become the same action rather than two separate ones people have to remember.
⚠️ Why This Produces Confusing ‘Works for Me’ Reports
- Two developers who both ran `git pull` can be working against genuinely different submodule commits at the same time – one who happened to also run the submodule update recently, and one who didn’t – which produces exactly the kind of “it works on my machine” report that’s maddening to debug without already suspecting the submodule pin is the actual difference.
- `git submodule status` shows exactly which commit each submodule is currently checked out at, and whether it matches what the parent repository currently expects – a fast, direct way to confirm or rule out submodule staleness before looking anywhere else for the cause of an inconsistency.
A submodule isn’t a live link to ‘whatever the latest version is’ – it’s a pinned pointer that only moves when somebody deliberately moves it, and pulling the parent repo alone was never going to do that automatically.
