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
git submodule add https://github.com/sajadtorkamani/sajad-wp-theme wp-content/themes/sajad-wp-theme
This will create a new directory in
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 = email@example.com:sajadtorkamani/sajad-wp-theme.git
.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 = firstname.lastname@example.org:sajadtorkamani/sajadtorkamani.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master
[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true [remote "origin"] url = email@example.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 = firstname.lastname@example.org:sajadtorkamani/sajad-wp-theme.git
Notice the addition of the submodule metadata.
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:
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:
to fetch the latest data.
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:
cd back to the main project root and run:
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>