Set up: This allows the repository to be local a file directory:
1 2 3 |
ROOT=/tmp echo $ROOT git config --global protocol.file.allow always |
Create remote
:
1 2 3 |
cd $ROOT mkdir remote git init --bare remote |
Creating repos1
1 2 3 4 5 6 7 8 9 10 |
mkdir repos1 cd $ROOT/repos1 git init touch main.cpp git add . git commit -m 'main.cpp added' git remote add origin ../remote/ git push --set-upstream origin master git push origin master |
Creating lib1
1 2 3 4 5 6 7 8 9 10 |
cd $ROOT mkdir lib1 cd $ROOT/lib1 git init . touch vision.hpp git add . git commit -m 'vision.hpp added' # this alows to push into this repository, as it is a non-bare repository git config --local receive.denyCurrentBranch updateInstead |
Adding lib1
as submodule to repos1
1 2 3 4 5 6 7 8 9 10 11 12 13 |
cd $ROOT/repos1 git submodule add ../lib1/ git diff --cached lib1/ # This command lists the submodules recorded in the .gitmodules file along with their current checked out commit. git submodule # Gives you the commit from repose lib1 that has been added git ls-tree master git add . git commit -m 'lib1 as submodule added' git push origin master |
Cloning a Project with Submodules to repos2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
cd $ROOT mkdir $ROOT/repos2 cd $ROOT/repos2 git clone $ROOT/remote/ . git submodule init git submodule update # Simpler way: # git clone --recurse-submodules ../remote/ . #If you already cloned the project and forgot --recurse-submodules, you can combine the git submodule init and git submodule update # We are in Detached HEAD State cd $ROOT/repos2/lib1/ git checkout master git branch -vv |
Working on Submodule lib1
in repos2
:
1 2 3 4 5 6 7 8 |
cd $ROOT/repos2/lib1/ touch reader.hpp git add . git commit -m 'reader added from repos2' cd ../ git add . git commit -m 'submodule lib1 updated' git push |
Pulling in Upstream Changes from the Submodule Remote in repos1
:
1 2 3 4 5 6 7 8 9 |
cd $ROOT/repos1/lib1 git fetch git merge now cd ../ git diff --submodule # There is an easier way to do this git submodule update --remote |
Working on Submodule lib1 in repos1
1 2 3 4 5 6 7 8 9 10 |
cd $ROOT/repos1/lib1 touch codec.hpp git add . git commit -m "codec added from repose1" git push cd ../ git add . git commit -m "changes regarding lib1 from repose1" git push |
Cloning repos3
1 2 3 4 |
cd $ROOT/ mkdir $ROOT/repos3 cd repos3 git clone --recurse-submodules ../remote/ . |
Let’s break down these Git commands related to submodules and their effects:
git submodule update
:- Effect: This command is used to update the submodules to the commit specified in the superproject. When you have a project with submodules, these submodules are usually fixed to specific commits. Running
git submodule update
will ensure your submodules are set to those specific commits. - Example: Suppose your main project (superproject) has a submodule at commit
abc123
. If someone else updates the submodule and you pull the latest changes in the superproject,git submodule update
will set the submodule to commitabc123
. - Difference: Unlike
git submodule update --remote
, it does not update the submodule to the latest commit in its own branch; it updates to the commit specified in the superproject.
- Effect: This command is used to update the submodules to the commit specified in the superproject. When you have a project with submodules, these submodules are usually fixed to specific commits. Running
git submodule sync
:- Effect: This command is used to update the URL of the submodule. If the submodule’s repository URL changes in the superproject configuration, running
git submodule sync
will update your local submodule configuration to the new URL. - Example: If the URL of a submodule repository was changed in the
.gitmodules
file,git submodule sync
will update your local configuration to match this new URL. - Difference: This command does not change any submodule content, unlike
git submodule update
, which updates the submodule to a specific commit.
- Effect: This command is used to update the URL of the submodule. If the submodule’s repository URL changes in the superproject configuration, running
git submodule update --remote
:- Effect: This updates the submodules to the latest commit available on their respective branches as specified in
.gitmodules
, rather than the commit specified in the superproject. - Example: If a submodule is set to track the
master
branch,git submodule update --remote
will update the submodule to the latest commit on themaster
branch. - Difference: Unlike the basic
git submodule update
, this command does not adhere to the commit specified in the superproject but fetches the latest from the tracked branch.
- Effect: This updates the submodules to the latest commit available on their respective branches as specified in
git pull --recurse-submodules
:- Effect: This command updates both the superproject and the submodules. It fetches and merges changes from the remote for the superproject and the submodules.
- Example: When you have changes in both your superproject and submodules in the remote repository,
git pull --recurse-submodules
will update all of them to their latest commits. - Difference: It not only updates the superproject (like a regular
git pull
) but also ensures that all submodules are updated.
git push --recurse-submodules=check
:- Effect: This command, when pushing, checks if any commits in submodules need to be pushed to their respective remotes. If there are such commits, the push is aborted.
- Example: Before pushing changes in your superproject, this command ensures that all submodule changes are also pushed. If not, it prevents the push to the superproject.
- Difference: It provides a safety check before pushing, unlike a regular
git push
, which does not consider submodule statuses.
git push --recurse-submodules=on-demand
:- Effect: Similar to the above, but instead of just checking, it attempts to push the changes of the submodules to their respective remotes automatically if needed.
- Example: If submodule changes haven’t been pushed, using this command will push both the superproject and the necessary submodule changes.
- Difference: It actively pushes submodule changes if needed, as opposed to
git push --recurse-submodules=check
, which only checks and aborts if needed.
To list all the submodules:
1 |
git submodule |
If you want more detailed information about each submodule
1 |
git submodule status |
Removing a Submodule
In modern git:
1 |
git rm <path-to-submodule> |
Refs: [1]
In older git versions:
- Delete the Submodule Reference:
Remove the submodule entry from the index and delete the relevant section from .gitmodules and .git/config:
1 2 |
git submodule deinit -f path-to-submodule git rm --cached path-to-submodule |
- Remove Submodule Files:
Manually delete the submodule’s files from your working directory:
1 2 |
rm -rf path-to-submodule rm -rf .git/modules/path-to-submodule |
- Commit the Changes:
Commit these changes to the repository:
1 |
git commit -m "Removed submodule SomeLibrary" |
Adding a Submodule
- Add the Submodule:
To add a new submodule, you use the git submodule add command followed by the repository URL and the path where you want to place it in your project:
1 |
git submodule add repository-url path-to-submodule |
For example:
1 |
git submodule add https://github.com/example/SomeLibrary.git lib/SomeLibrary |
- Initialize and Fetch the Submodule Contents:
If the submodule has nested submodules, initialize and update them:
1 |
git submodule update --init --recursive |