Git submodules reference
In a nutshell
Git submodules let you add a Git repository as a subdirectory of another Git repository. This lets you treat them as separate Git projects.
An example use case would be if you have a custom WordPress theme that needs to be used on two separate websites. You can create the theme as its own Git repo and then add the theme repo as a submodule to the two website repos.
The workflow can be something like this:
- Create Git repo for theme code.
- Create separate Git repos for website 1 and website 2.
- Add theme repo as a Git submodule to website 1 and website 2.
- Assuming you’re working on website 1, make changes to your theme (e.g., some CSS changes). Once happy, push the changes to the theme’s Git remote.
- When you’re working on website 2, you can pull the latest changes from theme submodule repo.
Add a submodule
cd
into the website project and add the theme repo as a Git submodule. Let’s assume the theme repo is called sajad-wp-theme
:
git submodule add https://github.com/sajadtorkamani/sajad-wp-theme wp-content/themes/sajad-wp-theme
This will create a new directory in wp-content/themes/sajad-wp-theme
.
It’ll also create .gitmodules
file with the following content:
[submodule "wp-content/themes/sajad-wp-theme"]
path = wp-content/themes/sajad-wp-theme
url = git@github.com:sajadtorkamani/sajad-wp-theme.git
The .gitmodules
file is tracked in version control so that other collaborators can easily clone the sub modules.
If you run git diff --cached wp-content-themes/sajad-wp-theme
, you’ll see that Git treats as a submodule and doesn’t track its contents. But it keeps track of the latest commit in the submodule (see last line).
diff --git a/wp-content/themes/sajad-wp-theme b/wp-content/themes/sajad-wp-theme
new file mode 160000
index 0000000..e06215d
--- /dev/null
+++ b/wp-content/themes/sajad-wp-theme
@@ -0,0 +1 @@
+Subproject commit e06215d97e9e470c29413e421b6cfc7865dcd647
Clone a submodule
By default, when you clone a project with submodules, you get the directories containing the submodules (e.g., wp-content/themes/sajad-wp-theme
), but those directories will be empty.
To fetch the submodules, first run:
git submodule init
This will initialize your local .git/config
file so that it changes from something like:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:sajadtorkamani/sajadtorkamani.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
to:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:sajadtorkamani/sajadtorkamani.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[submodule "wp-content/themes/sajad-wp-theme"]
active = true
url = git@github.com:sajadtorkamani/sajad-wp-theme.git
Notice the addition of the submodule metadata.
Next, run:
git submodule update
To fetch the fetch the data from the submodules and checkout the commit specified in your superproject.
Clone main project along with submodules
git clone --recurse-submodules https://github.com/<org>/<repo>
View submodules and their latest commits
In a project with submodules, run:
git submodule
Example output:
-e06215d97e9e470c29413e421b6cfc7865dcd647 ../wp-content/themes/sajad-wp-theme
Pull latest upstream changes from the submodule remote
Suppose new changes have been committed to a submodule remo and you want to pull in those changes. You can do this in two ways
1. Pull in changes in two steps
cd
into the submodule directory and fetch the latest data from the submodule remote:
git fetch
to fetch the latest data.
Run git status
and you should be told that your submodule branch is behind the remote branch:
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
Now, pull in the latest changes:
git pull
Now, cd
back to the main project root and run:
git diff
You should see that a submodule’s checked out commit has been updated:
diff --git a/wp-content/themes/sajad-wp-theme b/wp-content/themes/sajad-wp-theme
index e06215d..300fcfb 160000
--- a/wp-content/themes/sajad-wp-theme
+++ b/wp-content/themes/sajad-wp-theme
@@ -1 +1 @@
-Subproject commit e06215d97e9e470c29413e421b6cfc7865dcd647
+Subproject commit 300fcfb57a0b020ce0b1f5c007d382c7609f301a
If you commit these changes, other collaboraters will also be locked into using this submodule version – which is usually what you want.
2. Pull in changes in single step
Pull changes for all submodules:
git submodule update --remote
Pull changes for specific submodule:
git submodule update --remote <submodule-name>
Sources
Thanks for your comment 🙏. Once it's approved, it will appear here.
Leave a comment