Git Submodules
A practical guide to adding, updating, moving and removing Git submodules.
A submodule is a pointer to a specific commit in another repository. The parent repository stores the URL and the commit, never the files themselves.
Add a submodule
git submodule add https://github.com/user/library.git vendor/library
git commit -m "chore: add library submodule"Two things are committed: the .gitmodules file and a special entry for
vendor/library that stores the commit SHA.
Clone a repository that has submodules
# Everything in one step
git clone --recurse-submodules https://github.com/user/project.git
# Or, after a plain clone
git submodule update --init --recursiveSet git config --global submodule.recurse true and pulls, checkouts and
clones will handle submodules for you.
Update a submodule
# Move a submodule to the latest commit on its default branch
git submodule update --remote vendor/library
# The parent repository must record the new commit
git add vendor/library
git commit -m "chore: bump library submodule"Work inside a submodule
A fresh submodule checkout is in a detached HEAD state, so commit on a branch:
cd vendor/library
git switch main
git pull
# make changes, commit, push
cd ../..
git add vendor/library
git commit -m "chore: update library submodule"Remove a submodule
git submodule deinit -f vendor/library
git rm -f vendor/library
rm -rf .git/modules/vendor/library
git commit -m "chore: remove library submodule"rm -rf .git/modules/... deletes the submodule's local history. Make sure
anything you care about has been pushed first.
Useful commands
| Command | What it does |
|---|---|
git submodule status | Lists submodules with their recorded commits |
git submodule summary | Shows commits added or removed since the last record |
git submodule foreach 'git status' | Runs a command in every submodule |
git submodule sync | Applies changed URLs from .gitmodules |
git diff --submodule | Shows submodule changes as commit lists |
Troubleshooting
The submodule directory is empty
The pointer was cloned but the contents were not:
git submodule update --init --recursive"modified: vendor/library (new commits)"
The submodule is on a different commit than the one recorded. Either record the new commit, or go back to the recorded one:
git add vendor/library # accept the new commit
git submodule update --checkout vendor/library # discard itThe URL changed
git config --file=.gitmodules submodule.vendor/library.url https://new/url.git
git submodule sync
git submodule update --init --recursiveIf a submodule is only there to pin a dependency, a package manager or
git subtree is often easier for the rest of the team to live with.
Related articles
- GitGit CommandTo list all references
- GitGit Delete BranchSee which side introduced the current differences
- GitGit LogTo show short commit id, date and commit title To view the code changed by commit id To show graph with last 5 lines To show all branchs
- GitGit PullBreakdown Updating 1accfd5..b22e649 Your local branch was at commit 1accfd5. After pulling, it moved to commit b22e649. Fast-forward Git did not create a merge commit. Your local…