How to sync submodules in Git
Keeping Git submodules synchronized with their remote repositories is essential when working on projects with external dependencies.
As the creator of CoreUI with over 25 years of version control experience since 2000, I’ve managed complex projects where submodules need frequent updates from upstream changes.
The standard approach uses git submodule update --remote to fetch the latest changes from submodule remotes and update local references.
This ensures all team members work with the same submodule versions.
Use git submodule update --remote to sync submodules with their remote repositories.
git submodule update --remote
The --remote flag fetches the latest commits from each submodule’s remote repository. Without this flag, submodules update to the commit referenced in the parent repository. This command synchronizes all submodules to their latest remote versions.
Syncing Specific Submodules
Update only selected submodules instead of all of them.
# Sync specific submodule
git submodule update --remote libs/library1
# Sync multiple specific submodules
git submodule update --remote libs/library1 libs/library2
Specify submodule paths to update only those submodules. This is useful for large projects where you only need specific dependencies updated. Multiple paths can be specified in a single command.
Syncing and Committing Submodule Updates
After syncing submodules, commit the new references.
# Update all submodules to latest
git submodule update --remote
# Check what changed
git status
# Stage submodule updates
git add .
# Commit the new submodule references
git commit -m "Update submodules to latest versions"
# Push changes
git push
The git status shows which submodules have new commits. The parent repository tracks specific submodule commits, so changes must be committed. This records which submodule versions the project uses. Team members pulling these changes get the updated submodule references.
Syncing Submodules After Pulling
Update submodules when pulling changes from the main repository.
# Pull changes from remote
git pull
# Update submodules to match new references
git submodule update --init --recursive
# Or combine both operations
git pull --recurse-submodules
The git pull updates the parent repository including submodule references. The git submodule update moves submodules to the referenced commits. The --init flag initializes any new submodules. The --recursive flag handles nested submodules. Using git pull --recurse-submodules automates this process.
Syncing Submodules to Specific Branches
Configure submodules to track specific branches.
# Configure submodule to track develop branch
git config -f .gitmodules submodule.libs/library1.branch develop
# Update submodule to latest on tracked branch
git submodule update --remote libs/library1
# Commit the configuration change
git add .gitmodules
git commit -m "Configure library1 to track develop branch"
The .gitmodules file stores branch configuration. The submodule update --remote fetches the latest commit from the configured branch. This is useful when submodules use different release branches. Without branch configuration, submodules default to the remote’s default branch.
Checking Submodule Status
Verify submodule synchronization status before and after updates.
# Show submodule status
git submodule status
# Show detailed status for each submodule
git submodule foreach 'git status'
# Check which commit each submodule is on
git submodule foreach 'git log -1 --oneline'
# Show diff between current and remote
git submodule foreach 'git fetch && git log --oneline HEAD..origin/main'
The git submodule status displays current commit hashes. A + prefix indicates the submodule is on a different commit than referenced. The foreach command runs Git commands in each submodule directory. This helps verify synchronization before committing updates.
Automating Submodule Sync
Configure Git to automatically sync submodules on pull.
# Enable automatic submodule updates globally
git config --global submodule.recurse true
# Enable for specific repository
git config submodule.recurse true
# Enable automatic fetching of submodule changes
git config --global fetch.recurseSubmodules true
These configurations make submodule handling automatic. The submodule.recurse setting applies to most Git commands. The fetch.recurseSubmodules setting fetches submodule changes during git fetch. This reduces manual submodule management.
Handling Submodule Conflicts
Resolve conflicts when submodule updates conflict with local changes.
# If submodule has local changes
cd libs/library1
git stash
cd ../..
# Update submodule
git submodule update --remote libs/library1
# Restore local changes if needed
cd libs/library1
git stash pop
cd ../..
Local changes in submodules can prevent updates. The git stash temporarily saves local changes. After updating, git stash pop restores them. For committed changes, use git rebase or git merge to integrate upstream updates.
Best Practice Note
This is the same submodule synchronization workflow we follow in CoreUI projects to keep external dependencies current. Always commit submodule updates separately from other changes to make history clear. Before syncing, ensure local changes in submodules are committed or stashed. Configure branch tracking in .gitmodules for submodules that don’t use the default branch. For teams, document the sync workflow in the README to ensure consistent practices. Consider setting submodule.recurse true in team coding standards to automate submodule handling. For more about working with submodules, see our guide on how to clone repository with submodules.



