What’s a Git submodule? How to add, use and remove them? Plus some third party scripts to help deal with them in general.
2015-01-17 Added: method to update a project submodule.
Submodules are great! But at times, a bit hard to deal with. This post tries to make that easier.
What is a git submodule?
Git submodules enable a kind of nesting of Git projects, Git documentation sums it nicely:
It often happens that while working on one project, you need to use another project from within it. Perhaps it’s a library that a third party developed or that you're developing separately and using in multiple parent projects. A common issue arises in these scenarios: you want to be able to treat the two projects as separate yet still be able to use one from within the other.
Init a submodule:
WordPress in this case:
$ git submodule add [email protected]:WordPress/WordPress.git wpThat pulls in a WP, basically it does the same as git clone, pulls a project
in. But it’s also added as a submodule now.
Fetch submodules after clone
If a repository that has submodules is cloned, say, from GitHub, then the
submodules need to be initiated to pull them in, the clone command doesn’t do
anything for the submodules:
$ git submodule update --initClone and pull in submodules on one go
The git submodule update --init step can be skipped by using the --recursive
flag when cloning:
$ git clone --recursive git://github.com/user/some-project.gitDelete submodule
Deleting one is much harder than adding one. I’ll use the WP submodule added earlier as an example:
- Delete the relevant section from the
.gitmodulesfile. - Stage the
.gitmoduleschangesgit add .gitmodules - Delete the relevant section from
.git/config. - Run
git rm --cached path_to_submodule(no trailing slash). - Run
rm -rf .git/modules/path_to_submodule - Commit
git commit -m "Removed submodule <name>" - Delete the now untracked submodule files
rm -rf path_to_submodule
Delete submodule the "porcelain way"
git submodule deinit was introduced in v.1.8.0.
From git docs:
Unregister the given submodules, i.e. remove the whole
submodule.$namesection from.git/configtogether with their work tree.
It does two things:
- Clear the contents of the submodule directory, does not remove the dir.
- Removes the submodule from
.git/config.
When using deinit, the submodule removal workflow looks like this:
- Run
git submodule deinit <path_to_the_module> - Delete the relevant section from the
.gitmodulesfile. - Stage the
.gitmoduleschangesgit add .gitmodules - Run
git rm --cached path_to_submodule(no trailing slash). - Run
rm -rf .git/modules/path_to_submodule - Commit
git commit -m "Removed submodule <name>" - Delete the now untracked submodule files
rm -rf path_to_submodule
It’s not that different from the non-porcelain method to be honest.
Handy submodule workflows
Pull upstream changes to submodule
$ cd submodule
$ git pull origin master
$ cd ..
$ git commit ./submodule -m "Updated submodule reference"Edit and commit files in your submodule
$ cd submodule
$ edit some-file.js
$ git add some-file.js
$ git commit -m "Tweaked some-file.js"
$ cd ..
$ git add submodule/
$ git commit -m "Updated submodule reference"Push submodule changes to submodule upstream
$ cd submodule
$ git push origin masterUpdate WordPress submodule in a project
Let's upgrade WP to version 4.1:
$ cd wp
$ git fetch && git fetch --tags
$ git checkout 4.1
$ cd ..
# Now git status shows a dirty tree
$ git add wp
$ git commit -m "Upgrade to WP 4.1"Submodule removal script
Git-extras has a git delete-submodule
command. See here how to
install git-extras. And here's the authors screen cast on it also.
[vimeo slug_hash=45506445]
Hope this helps, bye.