Git: submodules

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.

Sub what??

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.

Let’s get to it.

Init a submodule:

WordPress in this case:

$ git submodule add git@github.com:WordPress/WordPress.git wp

That 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:

$ git submodule update --init

Clone and pull in submodules on one go

The git submodule update --init step can be skipped if using the --recursive flag when coning:

$ git clone --recursive git://github.com/user/some-project.git

Delete submodule

Lot harder than adding one. I’ll use the WP, that I added earlier, as an example:

  1. Delete the relevant section from the .gitmodules file.
  2. Stage the .gitmodules changes git add .gitmodules
  3. Delete the relevant section from .git/config.
  4. Run git rm --cached path_to_submodule (no trailing slash).
  5. Run rm -rf .git/modules/path_to_submodule
  6. Commit git commit -m "Removed submodule <name>"
  7. Delete the now untracked submodule files
    rm -rf path_to_submodule

Source

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.$name section from .git/config together with their work tree.

It does two things:

  1. Clear the contents of the submodule directory, does not remove the dir
  2. Removes the submodule from .git/config

When using deinit, the submodule removal workflow looks like this:

  1. Run git submodule deinit <path_to_the_module>
  2. Delete the relevant section from the .gitmodules file.
  3. Stage the .gitmodules changes git add .gitmodules
  4. Run git rm --cached path_to_submodule (no trailing slash).
  5. Run rm -rf .git/modules/path_to_submodule
  6. Commit git commit -m "Removed submodule <name>"
  7. 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 master

Update WordPress submodule in a project

Lets 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.

Hope this helps, bye.

Club-Mate, the beverage → club-mate.fi