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

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

```shell
$ 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, the `clone` command doesn’t do
anything for the submodules:

```shell
$ git submodule update --init
```

## Clone and pull in submodules on one go

The `git submodule update --init` step can be skipped by using the `--recursive`
flag when cloning:

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

## Delete submodule

Deleting one is much harder than adding one. I’ll use the WP submodule 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](https://stackoverflow.com/a/1260982/976972)

### Delete submodule the "porcelain way"

`git submodule deinit` was introduced in v.1.8.0.

From [git docs](http://git-scm.com/docs/git-submodule):

> Unregister the given submodules, i.e. remove the whole `submodule.$name`
> section from `.git/config` together 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:

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

```shell
$ cd submodule
$ git pull origin master
$ cd ..
$ git commit ./submodule -m "Updated submodule reference"
```

### Edit and commit files in your submodule

```shell
$ 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

```shell
$ cd submodule
$ git push origin master
```

### Update WordPress submodule in a project

Let's upgrade WP to version `4.1`:

```shell
$ 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](https://github.com/tj/git-extras) has a `git delete-submodule`
command. See [here](https://github.com/tj/git-extras/wiki/Installation) how to
install git-extras. And here's the authors screen cast on it also.

[vimeo slug_hash=45506445]

Hope this helps, bye.
