Adding a New Subproject

Submodule

git submodule add https://github.com/githubtraining/example-submodule

git commit -m "adding new submodule"

The submodule add command adds a new file called .gitmodules along with a subdirectory containing the files from example-submodule. Both are added to your index (staging area) and you simply need to commit them. The submodule’s history remains independent of the parent project.

Subtree

git subtree add --prefix=example-submodule https://github.com/githubtraining/example-submodule main --squash

The subtree command adds a subdirectory containing the files from example-submodule. The most common practice is to use the --squash option to combine the subproject’s history into a single commit, which is then grafted onto the existing tree of the parent project. You can omit the --squash option to maintain all of the history from the designated branch of the subproject.

Viewing a Diff of the Subproject

Submodule

To view a diff of the submodule:

# show changes to the submodule commit
git diff example-submodule
# show oneline log of new commits in the submodule
git diff --submodule example-submodule
# show changes to the files in the submodule
git diff --submodule=diff

Subtree

No special command required

Cloning a Repository with a Subproject

Submodule

To clone a repository along with its submodules:

git clone --recurse-submodules URL

If you forgot --recurse-submodules, you can clone and initialize all submodules:

git submodule update --init --recursive

Adding --recursive is only required if any submodule itself has submodules.

Subtree

No special command required

Pulling in Superproject Updates

Submodule

By default, the submodule repository is fetched, but not updated when you run git pull in the superproject. You need to use git submodule update, or add the --recurse-submodules flag to pull :

git pull
git submodule update --init --recursive
# or, in one step (Git >= 2.14)
git pull --recurse-submodules

--init is required if the superproject added new submodules, and --recursive is needed if any submodule itself has submodules.

If ever the superproject changes the URL of the submodule, a separate command is required:

# copy the new URL to your local config
git submodule sync --recursive
# update the submodule from the new URL
git submodule update --init --recursive

--recursive is only needed if any submodule itself has submodules.

Subtree

No special command required

Changing branches

Submodule

By default, the submodule working tree is not updated to match the commit recorded in the superproject when changing branches. You need to use git submodule update, or add the --recurse-submodules flag to switch :

git switch <branch>
git submodule update --recursive
# or, in one step (Git >= 2.13)
git switch --recurse-submodules <branch>

Subtree

No special command required

Pulling in Subproject Updates

Submodule

# Update the submodule repository
git submodule update --remote
# Record the changes in the superproject
git commit -am "Update submodule"

If you have more than one submodule, you can add the path to the submodule at the end of the git submodule update --remote command to specify which subproject to update.

By default, git submodule update --remote will update the submodule to the latest commit on the main branch of the submodule remote.

You can change the default branch for future calls with:

# Git >= 2.22
git submodule set-branch other-branch
# or
git config -f .gitmodules submodule.example-submodule.branch other-branch

Subtree

git subtree pull --prefix=example-submodule https://github.com/githubtraining/example-submodule main --squash

You can shorten the command by adding the subtree URL as a remote:

git remote add sub-remote https://github.com/githubtraining/example-submodule.git

You can add/pull from other refs by replacing main with the desired ref (e.g. stable, v1.0).

Making Changes to a Subproject

In most cases, it is considered best practice to make changes in a separate clone of the subproject repository and pull them in to the parent project. When this is not practical, follow these instructions:

Submodule

Access the submodule directory and create a branch:

cd example-submodule
git switch -c branch-name main

Changes require two commits, one in the subproject repository and one in the parent repository. Don’t forget to push in both the submodule and the superproject!

Subtree

No special command required, changes will be committed on the parent project branch.

It is possible to create commits mixing changes to the subproject and the parent project, but this is generally discouraged.

Pushing Changes to the Subproject Repository

Submodule

While in the submodule directory:

git push

Or while in the parent directory:

git push --recurse-submodules=on-demand

Subtree

git subtree push --prefix=example-submodule https://github.com/githubtraining/example-submodule main

Helpful Configs for Submodules

Always show the submodule log when you diff:

git config --global diff.submodule log

Show a short summary of submodule changes in your git status message:

git config --global status.submoduleSummary true

Make push default to --recurse-submodules=on-demand:

git config --global push.recurseSubmodules on-demand

Make all commands (except clone) default to --recurse-submodules if they support the flag (this works for git pull since Git 2.15):

git config --global submodule.recurse true