Git submodules provide a way to consider any repository as a versioned "package" that can be included in any other git repo.
clone a repo that has submodules
git clone --recurse-submodules -j8 git://github.com/foo/bar.git
Note: -j8 is an optional performance optimization that became available in version 2.8, and fetches up to 8 submodules at a time in parallel — see man git-clone
clone in repositories after cloning a repo
When you clone a repository git will not automatically clone in the contents of any submodules, but it will clone an empty directory with the name of that repository, in order to actually get the contents of those submodules you have to do the following
git submodule init
git submodule update
alternatively if you know that it recursively contains more submodules
git submodule update --init --recursive
git pulling in submodules
Suppose you're in a submodule that contains more submodules, currently git status
tells you that there are no changes at all, now you run git pull in that submodule and there are updates, namely the updates update the references to a few of the submodules, this can occur when someone has updated the versions of the submodules elsewhere and you are just getting those changes.
What usually appears is something like this:
$ git status
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
modified: build_notifier (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
This may seem confusing, but just know that even though it says that there are changes, the changes are not from you editing files, its just that when you git pulled it changed the reference to the git submodule to the new version, and since your local version still contains the old copy, there is a diff being generated. To fix this run:
git submodule update
Don't read these command as magic incantations to solve all your problems, for further understanding run man git submodule
mistakes
ssh submodules, github organizations and collaborators
When adding submodules from an organization using ssh links, then there comes a problem that people who are not part of the organization will not be able to clone in submodules as they do not have access for ssh as only collaborators can do this (even with public repositories). One fix to this is to add people as collaborators to the organization, but eventually adding everyone to an organization just so they can clone in the submodules becomes a little unwieldy. Here's a way we can fix this:
-
If you haven't added your submodule yet, add it regularly using the methods described above, eg
git submodule add git@github.com:username/repo.git path/to/submodule
-
Now edit
.gitmodules
to look like this
[submodule "path/to/submodule"]
path = path/to/submodule
url = git@github.com:username/repo.git
pushUrl = https://github.com/username/repo.git
git submodule sync --recursive
to apply the .gitmodules
configuration to your local .git/config
HEAD detached from 54b9bf8
If you see that you are on a detached head, this means that you cannot commit any changes here, if you have uncommitted changes you can switch to main with git checkout main
, if you do have committed changes then you have to do this:
git switch -c temp-work
git switch main
git merge temp-work
git branch -d temp-work
To avoid this problem in the future, we have to realize why this usually occurs, it happens when you clone a repository and initialize its submodules such as by doing git clone --recursive URL
, it makes sense that git puts every submodule at its respective commit, this is so that you can have reproducible behavior when you clone in submodules, but sometimes you know what you want the most up-to-date version of a submodule, in that case run this after the fact:
git submodule foreach --recursive git checkout main