Why submodules?
In Git, you can add a submodule to a repository. This is basically a repository embedded in your master repository. This can be very helpful. A couple of advantages of using submodules:
-
You can separate code into different repositories
.
Useful if you have a code base with large components, you can convert a component into a submodule. This way, you’ll have a cleaner Git log (commits are specific to a certain component).
-
You can add the submodule to
multiple repositories.
Useful if you have multiple repositories that share the same components. With this approach, you can easily update those components in all repositories that added them as a submodule. This is much more convenient than copying and pasting the code into the repositories.
Basics
When you add a submodule in Git, you don’t add the submodule’s code to the master repository
, you just add information about the submodule that’s added to the master repository. This information describes which confirmation the submodule points to. This way, the submodule code will not be automatically updated if the submodule repository is updated. This is good, because your code may not work with the last submodule commit, it prevents unexpected behavior.
Add a submodule You can add a submodule to
a repository like
this: git submodule Add git@github.com:url_to/awesome_submodule.git path_to_awesome_submodule With the default settings, this will check out the code from the awesome_submodule.git repository to the path_to_awesome_submodule directory
and add information to the master repository about this submodule, which contains the confirmation that the submodule points to. , which will be the current commit to the default branch (typically the master branch) at the time this command is run.
After this operation, if you perform a git state, you will see two files in the Changes to commit list: the .gitmodules file and the path to the submodule. When you commit and send these files, you commit/push the submodule to the source.
Getting the submodule code
If one person creates a new submodule, the other people on the team must start this submodule. First you need to get the information about the submodule, this is retrieved by a normal git pull. If there are new submodules, you will see it in the git pull output. Then you will have to start them with:
git init submodule
This will extract all the code from the submodule and place it in the directory in which it is configured
.
If you have cloned a repository that uses submodules, you must also run this command to get the submodule code. This is not done automatically by git clone. However, if you add the -recurse-submodules flag, it does.
Pushing updates to the
submodule
The submodule is just a separate repository. If you want to make changes to it, you need to make the changes to your repository and push them as in a regular Git repository (just run the git commands in the submodule directory). However, you must also inform the master repository that you have updated the submodule repository and have it use the new submodule repository commit. Because if you make new commits within a submodule, the master repository will still point to the previous commit.
If there are changes in the submodule repository, then git status in the master repository, will display Untentized changes to commit and has the text (modified content) behind it. This means that the submodule code is extracted in a different commit than the one pointed to by the master repository. For the master repository to point to this new commit, you must create another commit to the master repository.
The following sections describe different scenarios for doing this.
Make
changes within a
submodule CD within the submodule directory. Make the desired changes. Git confirms the new changes. git
- push the new commit
- CD back to master
- status you will see that the submodule directory is modified. In
- diff you’ll see the old and new
- .
- git
- commit to the master repository, it will update the pointer.
.
repository. In git
git
commit pointers
When
Update the submodule pointer
to a different confirmation cd within the submodule directory.
- Git checks out the branch or commit you want to point to
- CD back to master
- git status you will see that the submodule directory is modified. In
- diff you’ll see the old and new commit pointers.
- When git commit to the master repository, it will update the pointer.
.
repository. In
git
If someone else updated the submodule
pointer If someone updated
a submodule, the other team members must update the code in their submodules. This is not done automatically by git pull, because with git pull it only retrieves the information that the submodule points to another commit, but it does not update the submodule code. To update the code of your submodules, you must run:
git submodule update
If a submodule has not yet started, add the -init flag. If any submodules have submodules, you can add the -recursive flag to the startup and recursive update submodules.
What happens if I don’t run this command?
If you do not run this command, the submodule code is checked out in an old commit. When you do the git state, you’ll see the submodule in the Untentative changes to commit list with the text (modified content) behind it. If you were to do a git state inside the submodule, it would say separate HEAD in <commit-hash>. This is not because the submodule code has changed, but because its code is checked out in a different commit. So Git sees this as a change, but you didn’t really just update the submodule code. So if you’re working with submodules, don’t forget to keep your submodules up to date.
Making it easier for everyone
Sometimes it’s annoying if you forget to launch and update your submodules. Luckily, there are a few tricks to make it
easier: git clone -recurse-submodules This
will clone a repository and also check and launch any possible submodules that the repository has
. git pull -recurse-submodules
This will pull the master repository and also its submodules
.
And you can make it easier with
aliases: git config -global alias.clone-all ‘clone -recurse-submodules’ git config -global alias.pull-all ‘pull -recurse-submodules’