Git Submodules Guide
Git submodules allow you to include one Git repository within another. They are useful for handling shared libraries, vendor code, or reusable components across different projects without copying files. Each submodule is tied to a specific commit of an external repository, keeping its history and setup distinct from the main project.
This tutorial covers how to add, clone, update, and manage Git submodules properly, including commands and strategies to avoid common mistakes.
The Short Answer Version
Add a submodule to your repository
$ git submodule add https://github.com/user/repo.git path/to/submodule
Initialize submodules in a cloned repository
$ git submodule init
Update submodules to fetch content
$ git submodule update
Clone repository and its submodules in one step
$ git clone --recurse-submodules https://github.com/user/project.git
Pull latest commits from submodule’s remote
$ git submodule update --remote
Remove a submodule completely
$ git submodule deinit -f path/to/submodule
$ rm -rf path/to/submodule
$ git rm path/to/submodule
$ rm .gitmodules
Add a Git Submodule
Submodules enable you to connect another Git repository to your project while keeping its version history and configuration independent. This section demonstrates the steps for adding a submodule to an already initialized Git project.
Command Syntax
To include a submodule, use:
git submodule add <submodule-url> <path>
<submodule-url>
: The remote Git repository’s URL to link.<path>
: The directory path inside your project where the submodule will be placed.
Git saves this reference in a .gitmodules
file and treats the submodule as a pointer to a specific commit.
Command Demonstration
Create a project directory.
$ mkdir my-project && cd my-project
Initialize the directory as a Git repository.
$ git init
Add a submodule.
$ git submodule add https://github.com/example/repo.git vendor/example-lib
This command clones the external repository into the vendor/example-lib
folder and creates a .gitmodules
file.
Check the .gitmodules
file.
$ cat .gitmodules
Output:
[submodule "vendor/example-lib"]
path = vendor/example-lib
url = https://github.com/example/repo.git
Stage the .gitmodules
file and the submodule folder.
$ git add .gitmodules vendor/example-lib
Commit the addition of the submodule.
$ git commit -m "Add example-lib as submodule"
Push your committed changes to the remote repository.
$ git push origin main
Clone a Repository with a Git Submodule
When cloning a repository that contains submodules, Git will not automatically retrieve the submodule content unless specifically instructed. This section details how to properly initialize and update submodules.
Command Syntax
To initialize and update submodules manually after cloning:
git clone <repo-url>
cd <repo-name>
git submodule init
git submodule update
To clone the repository and submodules in a single step:
git clone --recurse-submodules <repo-url>
--recurse-submodules
: Automatically clones and initializes all submodules during the initial clone.git submodule init
: Registers submodules defined in.gitmodules
.git submodule update
: Downloads the contents of the submodules.
To refresh submodules to the most recent remote-tracked commits:
git submodule update --remote
--remote
: Pulls the latest commit from the tracked branch of the submodule.
Command Demonstration
Clone the primary repository:
$ git clone https://github.com/example/project.git
Move into the repository folder:
$ cd project
Initialize the submodules defined in .gitmodules
:
$ git submodule init
Fetch the submodule contents:
$ git submodule update
Alternative: Clone the repository and submodules in one step.
$ git clone --recurse-submodules https://github.com/example/project.git
Optional: Update submodules to the most recent commit from the remote branch.
$ git submodule update --remote
By default, submodules point to a fixed commit. Use --remote
only if you want to sync to the latest upstream commit from the tracked branch.
Precautions for Adding a Git Submodule
- Submodules point to commits, not branches.
By default, submodules are tied to a fixed commit. They do not follow the latest changes of the remote repository automatically. You must update them manually usinggit submodule update --remote
. - Submodule updates must be committed.
If you move a submodule to a different commit, the parent repository registers this as a change. You must stage and commit the updated pointer. - Cloning requires additional steps.
Users must either rungit submodule init
andgit submodule update
or clone with--recurse-submodules
. - Workflows become more complex.
If branches reference different submodule commits, merges and rebases can be complicated. Ensure coordination when working in teams. - CI/CD pipelines require submodule handling.
Automated build or deployment processes must include logic to fetch and update submodules. A common issue is forgetting to include--recurse-submodules
.
Submodules should be used only when independent versioning of external repositories is truly required. Otherwise, solutions like package managers or monorepo structures may be simpler to maintain.
Remove a Git Submodule
If you no longer need a Git submodule, follow these steps to remove it completely:
Deinitialize the submodule:
$ git submodule deinit -f vendor/example-lib
Delete the submodule directory:
$ rm -rf vendor/example-lib
Remove the submodule entry from .gitmodules
:
$ git config -f .gitmodules --remove-section submodule.vendor/example-lib
Stage the modified .gitmodules
file:
$ git add .gitmodules
Remove the submodule configuration from Git:
$ git config --remove-section submodule.vendor/example-lib
Remove the submodule from the Git index:
$ git rm --cached vendor/example-lib
Commit the cleanup:
$ git commit -m "Remove vendor/example-lib submodule"
Push the changes to the remote repository:
$ git push origin main
These steps ensure that all references to the submodule are completely removed from your Git project.
Conclusion
In this tutorial, you learned how to use Git submodules to organize reusable code across multiple projects. You added submodules to a repository, cloned projects with submodules, updated them to pull remote changes, and removed them when no longer necessary. By leveraging submodules correctly, you can keep project structures modular, avoid code duplication, and ensure consistency in versioning dependencies.