Code modularization with Git Submodules

Git submodules feature grants you the ability to add links to a Git repository to other repositories as dependencies. When linked, the submodules are integrated as a subdirectory to the main repository you are working on and by default the content is not downloaded, but the Git history.

Code modularization with Git Submodules
Purple background with 3 with boxes stacked together

Git submodules feature grants you the ability to add links to a Git repository to other repositories as dependencies. When linked, the submodules are integrated as a subdirectory to the main repository you are working on and by default the content is not downloaded, but the Git history. The most simple use case for using this feature is for fetching updates for the submodules from time to time.

Making changes to a submodule does not affect the main repository and vice-versa. The Git history is kept separated, only showing changes when you are in the directory of the repository you want to commit changes. A use-case for this Modularity approach is to manage multiple applications in a centralized place while keeping each code-base logically separated. Particularly, when attempting to move a massive monolithic application into a microservice type of architecture with buy-in from the team. It does not solve every issue with tracking each separate pull request or issue, but this feature can be useful for collecting repositories together and updating each one easily with one command.

Other examples of utilizing Git submodules can be when adding a Design Language System, an internal or external library, creating an Android/iOS native application from a web application, etc. Before adding a submodule, verify if an alternative like NPM or other dependency managers would be better solutions because these tools are very easy to use and have extensive configuration options.

For the following sections, we will be exploring a few commands to get you started on utilizing this feature.

Adding a submodule

To add a submodule to a Git repository is quite simple and all you will need is the URL of the remote repository. This will add a subdirectory with the name of the submodule and a configuration file named .gitmodules that stores the mapping between the URL of the submodule and the subdirectory where it is contained.

git submodule add url-for-remote-repository

If you run git status you will see the files mentioned above. Make sure to add and commit these new files to incorporate the submodule. Git won't track changes in the subdirectory as long as you aren't in the directory because it recognizes that it is a submodule.

On Git repository hosting providers like GitHub or GitLab they have a feature where they will display the submodule on the main repository after the changes have been added and If you click the submodule on the platform it navigates you to the repository's page.

Pasted-image-20211009104527
Source repository

Cloning a project that contain submodules

When you clone a repository that contain submodules, by default it won't download the submodule's content. To clone a project and also include the submodules content, you will have to use the --recurse-submodules[=<pathspec>] flag. By default, if no pathspec is provided it initializes and clones all submodules, in the repository. If a submodule has submodules this command will also get the content for that repository.

git clone  url-for-remote-repository --recurse-submodules

Updating submodules

Updating a particular submodule content, you will need to use the fetch and merge command on the submodule directory.

cd module
git fetch
git merge origin/main

With new changes merged, you can run git diff --submodule and see that the submodule was updated with a list of commits that were added.

To avoid running all the previous commands, there is an alternative to updating an individual submodule. By default, it will fetch and update the default branch in the URL specified in origin . Using the --remote flag, it integrates the changes from the remote repository into the current HEAD. If you leave this flag off, it will only fetch the commit history, but not merge it.

git submodule update --remote name-of-submodule

To change the default branch on your submodule, you utilize the git config utility. The following command changes the branch for everybody that has access to the remote repository.

git config -f .gitmodules submodule.name-of-submodule.branch new-branch-name

If you only want to change the default branch for yourself locally, leave off the -f .gitmodules, but depending on your situation it might make more sense for everybody to be tracking the same branch.

Updating all submodules, including submodules of submodules you can use the --recursive flag.

git submodule update --remote --recursive

Removing a submodule

Removing a submodule from your main repository, you remove the reference of it first.

git submodule deinit name-of-submodule

When that is completed, you will need to delete the subdirectory of the submodule and .git/modules/name-of-submodule directory.

rm -rf .git/modules/name-of-module
git rm name-of-module
rm -rf name-of-module

References