Git submodules
On several projects, the design system and front-end elements of the project are contained in a separate Git repository to the back-end. We do this as the front-end is normally built some weeks ahead of the backend, potentially causing work for different sprints to overlap—which is problematic if breaking changes are being introduced. Having front-end in a separate repo means that it can be independently versioned and released, and used to get client review and approval of interfaces that are still in development.
To marry front- and back-end repos together we use Git submodules. Submodules, as the name may suggest, basically allow one Git repo to be included inside of another one. In Git terminology, a project which has submodules is named a “superproject”.
By default, submodules appear in the file system as an empty directory. After updating the submodule, the directly will be populated by code from the submodule’s repo. Git, however, will treat the directory as though it is a file containing a commit ID (a “lockfile”). This is the ID for the commit that was most recent at the time the submodule was last updated, and is what allows us to choose which version of the design system repo is being deployed.
By default, cloning, fetching or pulling on the superproject will not update submodules, they must be updated with separate commands or by using flags.
Configuration for submodules is stored in the .gitmodules
file.
Adding the submodule
In the superproject, navigate your terminal to the root of the superproject (aka, where the .git
directory is located, but not inside the directory itself), and use this command:
git submodule add <url> <path>
url
is the cloning path of the Git repo you’re using as a submodule.
path
is the directory path of where you want this submodule to live in the superproject. This must be a directory that is publicly accessible when the project is deployed, usually a sub-directory of the UI/presentation directory of the project.
Getting the submodule
If you have yet to clone the superproject, you can clone it and its submodules at the same time:
git clone --recurse-submodules <url>
If you’ve already cloned the superproject without the submodules, you’ll need to run two commands instead:
git submodule init
git submodule update
The first command initialises the .gitmodules
file (which updates the configuration file in the .git
directory). The second fetches the commit specified in the submodule lockfile.
Updating the submodule
By default, submodules are “locked” to the commit that they were on when first added to the superproject. No matter who pulls the superproject, or when they do it, they will receive the submodule’s code as it existed at the time it was locked. This is to allow for dependency management; you don’t want the code to be changing under your feet, after all!
To update the submodule code and update the lockfile:
git submodule update --remote
The updated lockfile needs to be committed in the superproject.
Removing a submodule
Rarely you may need to remove a submodule, such as if it’s been misconfigured or you’re attempting a clean install in order to resolve a problem. Removing a submodule is relatively labour intensive, compared to creating one, so get your command line hats on.
In all of the below, replace path/to/submodule
to match the path defined when the submodule was added. If you’re not sure what this is, look in the .gitmodules
file.
Step 1
Before starting, make sure that you have no staged, uncommitted changes, and that your repo version is aligned with any remote versions. This will help avoid merging issues later on.
Firstly, navigate to the root of the project (where the .git
directory is, but not the directory itself) and open the .gitmodules
file in a text editor.
Find the section relevant to the submodule. This will start with [submodule "path/to/submodule"]
, and includes any indented lines under this heading. Delete the entire section and save the file.
Stage the change.
git add .gitmodules
Step 2
Open the file located at .git/config
in a text editor and delete the section for the submodule. This will be formatted in the same way as the section in the .gitmodules
file.
Step 3
Remove the submodule directory from Git.
git rm --cached path/to/submodule
Step 4
Delete the submodule configuration.
rm -rf .git/modules/path/to/submodule
Add and commit all of the changes made so far.
Step 5
Finally, delete the submodule directory.
rm -rf path/to/submodule