Cheat Sheet for git Submodules

I use git submodules pretty often. Usually, I interact with them while maintaining my configuration files ('dotfiles'), which you can find on Github. I have 45 submodules in that repository. Pretty epic.

If you are looking for a full tutorial, I highly recommend the git-scm page on this.

So, cheat sheet time. I will break this into tasks, and organize them by general duties. For nomenclature, parent.git will be the top-level repository, and child.git will be a submodule in that repository.

You Are Using a Repository with Submodules

These are commands that you will need to use if you are using a git repository that has submodules in it, but you aren't maintaining the 'primary' git repository. That is, your clone of parent.git is not considered the upstream.

Cloning a Repository with Submodules

$ git clone --recursive <url> <destination>

This is pretty straight-forward. The recursive flag is what tells git to also clone the submodules. This is what all users of parent.git will need to use to get the full tree, including submodules.

N.B. This is the only command where the --recursive flag is effectively mandatory.

Pulling Updates to Submodules

$ git remote update -p
$ git pull <remote> <branch>
$ git submodule update [--init] [--recursive]

Let's say that maintainer updated parent.git upstream, and as part of the changes, updated the submodule child.git. Pulling changes from the upstream parent.git pulls any changes in the child.git submodule pointer. So, in order to update the submodule, you first update your parent repository, and then tell git to update the submodules based on the new data in the parent.

The --init flag: This flag tells git to not only update the submodules you already have, but if there are any new submodules in the upstream, add those as well. For example, let's say you have been using parent.git for a while, and then the maintainer adds child.git as a submodule. In order to pull the new submodule into your copy of parent.git, you would need to use this flag once. From then on, child.git will get updated without the --init flag.

N.B. Using this command, with the --init and --recursive flags, is also how you download a repo's submodules if you forgot to clone it with --recursive in the first step.

N.B.B. The -p on git remote update prunes your remotes. This isn't necessary, but is good practice.

Update Submodule URLs

$ git submodule sync

I have never had to use this. You only need to run this if the maintainer of parent.git changed the URL of an existing submodule (e.g., child.git) upstream.

You are Maintaining a Project with Submodules

If you are maintaining a project (and thus a repository) with submodules, these are commands you will need to be familiar with.

Adding a Submodule to a Repository

$ git submodule add <url> <destination>

Note that whatever destination you put here will be the location of the submodule, so it should be your target directory name.

Delete a Submodule

$ git submodule deinit <submodule location>
$ git rm -rf <submodule location>

This will deinitialize the submodule from your git tree and then delete the associated files.

Note that the process to remove a submodule has changed several times. If you aren't using a semi-recent version of git, you may not have the deinit command. Refer to this SO thread if you need help.

Update All Submodules (no local changes)

$ git submodule update --remote [--recursive]

If you do not have any local changes in your submodules, and all you want to do is consume new commits for your submodules' upstreams, you can run this command. It will go through each submodule, update remotes, and then update to the latest commit. This command assumes you want to be on the master branch. If that isn't true, you should read this section of the docs.

Update All Submodules (with local changes)

$ git submodule update --remote [--rebase | --merge] [--recursive]

If you have made local changes to your submodules, and want to pull new changes from the submodules' upstream, git makes this really simple. Make sure to specify whether you want to rebase or merge.

Prepare All Submodules for Local Work

$ git submodule foreach 'git remote update; git checkout master; git pull origin master'

This is really more of an example of how to use the foreach command. But, regardless, this command will go into each submodule, checkout the master branch, and pull the latest changes. You only really need to do this if you intend to do work in the submodule, because the next time you update your submodule with upstream using the submodule command you'll go back into a detached-HEAD state.

Additional Notes & Details

This breaks from the 'cheat sheet' idea, but I thought these were important.

About '--recursive'

Most of these commands will take the --recursive flag, so I have listed it in this post. You do not actually need the --recursive flag unless there are submodules in your submodules; Inception-style.

The one exception to this rule is in the git clone command. If you do not include the --recursive flag in your git clone, you will not pull down any submodules.

About Branches

Anytime you run a git submodule command, it is likely that your submodules will be in a detached-HEAD state. This is perfectly okay and expected, so don't freak out if you see that. This is why in that last command I explicitly check out the master branch before pulling changes.

Clarifying the 'update' Command

If you were paying close attention, you may have noticed above that git submodule update is used both for telling git to bring your submodules up to date with what the parent repo says they should be at, and for updating your submodules with changes in that specific submodule's upstream. These are two very different things, and the only distinction between them in terms of commands is the --remote option.

Reusing Directory for Different Submodule

Let's say you add a submodule and put it at parent.git/src/child.git. A while later, you delete that submodule. Then, a while after that, you want to put a new submodule in that same location. You might see an error like this:

A git directory for 'src/child.git' is found locally with remote(s):
If you want to reuse this local git directory instead of cloning again from
use the '--force' option. If the local git directory is not the correct repo
or you are unsure what this means choose another name with the '--name' option.

What's happening here is that your git tree still knows about the old submodule. Your sanity may be fleeting, but git is forever.

First, make sure you went through the 'Delete a Submodule' steps above. Secondly, you'll need to delete the config directory in the git tree that is tracking that location. So, for the above example, that would be:

$ rm -irf parent.git/.git/modules/src/child.git

Be very careful with this. I added that -i in there just for an extra little bit of protection.


I hope this is helpful to someone out there, and happy hacking. If you have any questions, feel free to ask in the comments and I'll do my best to help.

Remember, though, that this isn't meant to be a tutorial - it's just a cheat sheet!

Ben Hilburn

Ben Hilburn

bits, nibbles, bytes, and words
D.C. Metro Area