A lightweight Python script to automate committing, pushing, and updating Git submodules (including nested ones) from a single “parent” repo.
When you have a “monorepo” or a larger project that pulls in several smaller repos as submodules (even nested submodules), the manual workflow of entering each folder, committing, pushing, then updating the parent’s SHA reference can be tedious.
This script:
- Finds all submodules (recursively)
- Commits & pushes any local changes within each submodule
- Updates the submodule pointers (SHAs) in the root repo and pushes them
Run one command and everything stays in sync.
- Git (2.13+ recommended)
- Python 3.x (tested on 3.6+)
- Unix-like shell (Linux, macOS, WSL) or Git Bash on Windows
git clone --recurse-submodules <YOUR_NEW_REPO_URL>
cd <YOUR_NEW_REPO_NAME>If you forget
--recurse-submodules, you can later run:git submodule update --init --recursivegit clone --recurse-submodules ...: You use this command when you are cloning a repository that already contains submodules. It tells git to download the main repository and all its submodules at the same time. git submodule update --init --recursive: You use this if you've already cloned a repository but forgot to use --recurse-submodules. It initializes and fetches the submodule code.
To add a new submodule (public or private):
git submodule add <URL-TO-SMALL-REPO> path/to/submodule
git commit -m "feat: add submodule at path/to/submodule"
git pushRepeat for any nested submodules inside those repos as needed.
-
Make the Python script executable:
chmod +x sync_submodules_recursive.py
-
Run it from the root of this repository:
./sync_submodules_recursive.py
The script will:
- Commit & push changes in each submodule (skipping if no changes).
- Stage all submodule folder pointers in the root repo, commit & push once.
-
Detection
Usesgit submodule status --recursiveto list every submodule path. -
Inside each submodule
git add . git commit -m "chore: sync local changes in submodule" git push
Errors are caught and skipped if there’s nothing to commit.
-
Back in root repo
git add <each-submodule-path> git commit -m "chore: update submodule pointers" git push
No additional configuration is needed: the script works out-of-the-box.
- Public: Use HTTPS or SSH URL, no extra step.
- Private: Prefer SSH URLs (
git@github.com:…) and ensure your SSH key is loaded (ssh-agent).
If you prefer HTTPS, configure a credential helper or provide a personal access token.
-
“Permission denied” when running the script
- Ensure you ran
chmod +x sync_submodules_recursive.py. - Verify your shell is executing
./sync_submodules_recursive.py, not a stray file.
- Ensure you ran
-
SSH authentication failures
- Check
ssh-add -lto confirm your key is loaded. - Test with
git ls-remote <private-submodule-url>.
- Check
-
Script exits early with an error
- Read the printed stderr; the script aborts on any unexpected Git failure.
- Fix the underlying Git error in the indicated repo or path, then retry.
This project is released under the MIT License. See LICENSE for details.