Git: Submodules Guide
Git submodules are a way to include and manage external repositories within a parent repository. They allow you to keep a Git repository as a subdirectory of another Git repository, enabling you to track and manage dependencies or libraries separately.
Add a submodule
To add a submodule to your repository, use the following command:
git submodule add <repository-url> <path> Replace <repository-url> with the URL of the repository you want to add as a submodule, and <path> with the directory where you want to place the submodule. Submodules are typically added to a directory within your main repository like libs/ or external/ or third_party/ or 3rd_party/ etc.
Added submodules are tracked in a file named .gitmodules located at the root of your repository.
Add a submodule at a specific branch
By default, when you add a submodule, it checks out the default branch (usually main or master) of the submodule repository. If you want to add a submodule and track a specific branch, you can do so by following these steps:
git submodule add -b <branch-name> <repository-url> <path> Replace <branch-name> with the name of the branch you want to track, <repository-url> with the URL of the repository you want to add as a submodule, and <path> with the directory where you want to place the submodule.
Add a submodule at a specific commit
If you want to add a submodule and check out a specific commit, you can do so by following these steps:
git submodule add <repository-url> <path> First, add the submodule as usual. Replace <repository-url> with the URL of the repository you want to add as a submodule, and <path> with the directory where you want to place the submodule.
After adding the submodule, you can check out the specific commit by running the command:
git checkout <commit-hash> Replace <commit-hash> with the hash of the commit you want to check out.
Example:
git submodule add -b main https://github.com/user/repo.git third_party/external
cd third_party/external
git checkout a1b2c3d4 # Replace with your desired commit hash
cd ../..The state of repository after adding a submodule
After adding a submodule, your main repository will have the following changes:
- A new directory (the path you specified) containing the submodule's files.
- A new file named .gitmodules at the root of your repository, which contains metadata about the submodule (its URL and path) or a new entry in the existing .gitmodules file.
- The submodule will be in a "detached HEAD" state, meaning it is not on any branch. You can switch to a branch within the submodule if needed.
- The submodule will be pinned to a specific commit.
Pushing the submodule changes
After adding a submodule, you need to commit the changes to your main repository. This includes the new submodule directory and the updated .gitmodules file.
Example
cd my-repo
git submodule add -b branch-name https://github.com/user/lib.git lib/external
cd lib/external
git checkout a1b2c3d # Specific commit
cd ..
git add lib/external
git commit -m "Pin submodule to commit a1b2c3d"
git push
Now, when another developer clones your repository and initializes the submodules, they will get the correct state including branch and pinned commit (a1b2c3d):
git clone https://github.com/user/my-repo.git
cd my-repo
git submodule update --init --recursiveUpdate a submodule
To update a submodule to the latest commit on its tracked branch, navigate to the submodule directory and pull the latest changes:
cd <path> && git pull origin <branch-name> Replace <path> with the path to your submodule and <branch-name> with the branch you want to update from.
After updating the submodule, go back to the main repository, stage the changes, and commit them:
cd .. && git add <path> && git commit -m "Update submodule"Finally, push the changes to the remote repository:
git pushUpdate all submodules
To update all submodules to the latest commit on their tracked branches, run the following command in the root of your main repository:
git submodule update --remote --mergeThis command fetches the latest changes for all submodules and merges them into the current commit. After updating, your main repository will be "pinned" to those new commits after you stage and commit the changes.
git add . && git commit -m "Update all submodules"Finally, push the changes to the remote repository:
git pushRemove a submodule
To remove a submodule from your repository, follow these steps:
git submodule deinit -f <path> Replace <path> with the path to your submodule.
rm -rf .git/modules/<path>Remove the submodule's entry from the Git configuration.
git rm -f <path>Remove the submodule directory and stage the changes.
git commit -m "Remove submodule"Commit the changes to your main repository.
git pushPush the changes to the remote repository.