git submodules - ghdrako/doc_snipets GitHub Wiki
tags:
- git
- vcs
| action | command | comment |
|---|---|---|
| add submodule to repo | git submodule add https://github.com/<remote_path> ./<local_path> |
git will store the commit ID and URL of submodule |
| download submodule | git submodule update --init |
cloning repository doesn't download its submodules |
| update submodule | git submodule update |
git pull and git checkout don't update submodules. Use command every single time you switch branch or pull and it puts the submodule in detached HEAD state
|
| automatic update submodule after pull/checkout | submodule.recurse true |
config option |
| show which commits were added/removed in git diff/git status |
status.submoduleSummary true diff.submodule log git config diff.submodule log
|
config option |
- if added via ssh protocol, users without ssh configured for their git account can’t clone them - so always use https-protocol to add a submodule
- submodules easily get in a “detached head” state
- at least git on windows has authentication problems with submodules (use of pageant helps)
Update the reference of the submodule in your main repository without pulling or fetching the submodule's content to your local machine
- https://stackoverflow.com/questions/68862399/is-it-possible-to-update-a-submodule-sha-without-pulling
- https://stackoverflow.com/questions/33514642/how-can-i-set-a-submodule-to-point-to-a-specific-commit-without-fetching-it
local repo that has a reference to a submodule - update the submodule's reference to a more recent SHA without pulling the submodule's contents from the remote
There's a core command to set index entries directly.
git update-index --cacheinfo 160000,<new_SHA_here>,path
- 160000 is the mode for a submodule entry in the Git index.
- <new_SHA_here> should be replaced with the desired commit SHA-1 hash.
- path/to/submodule is the path to the submodule within your main repository. sets the entry for path to that commit, exactly as if you'd git added a submodule's checkout of that commit. Note to others that you need to use the full SHA, rather than the short SHA that git commands often accept.
Make sure to commit the changes in your main repository after running the git update-index command to record the updated submodule reference.
git update-index --cacheinfo 160000,<Git hash of the submodule's tree>,<path to the submodule>
So for example if your project directory structure looks like this:
.
├── .git
└── submodule
Then to update the submodule to point to commit 2764a900748fbed7453f5839cb983503cee346d2 you would run:
git update-index --cacheinfo 160000,2764a900748fbed7453f5839cb983503cee346d1,submodule
And finally follow it up with git commit as usual.
A Git submodule is essentially a reference to another Git repository. It allows you to include a specific commit or branch of an external repository as a subdirectory within your own Git repository. This subdirectory is managed as a separate Git repository in its own right. Submodules are very static and only track specific commits. Submodules do not track git refs or branches and are not automatically updated when the host repository is updated.
Submodules allow you to keep a Git repository as a subdirectory of another Git repository. This lets you clone another repository into your project and keep your commits separate.
- Add a Git submodule to your main project. git submodule add:
git submodule add <remote_url> <destination_folder> # desctination folder is optional
$ git submodule add https://github.com/chaconinc/DbConnector
$ git status
By default, submodules will add the subproject into a directory named the same as the repository, in this case “DbConnector”. You can add a different path at the end of the command if you want it to go elsewhere.
When adding a new Git submodule into your project, multiple actions will be performed for you :
- A folder is created in your Git repository named after the submodule that you chose to add
- A hidden file named “.gitmodules” is created in your Git repository : this file contains the references to the remote repositories that you cloned as submodules;
- Your Git configuration (located at .git/config) was also modified in order to include the submodule you just added;
- The submodule you just added are marked as changes to be committed in your repository.
$ cat .gitmodules
[submodule "DbConnector"]
path = DbConnector
url = https://github.com/chaconinc/DbConnector
$git config submodule.DbConnector.url PRIVATE_URL
Example1
git submodule add https://github.com/example/repo.git path/to/submodule
- When adding a Git submodule, your submodule will be staged. As a consequence, you will need to commit your submodule by using the “git commit” command.
$ git diff --cached DbConnector
$ git diff --cached DbConnector --submodule
$ git commit -am 'Add DbConnector module'
git push origin master
Whenever you are cloning a Git repository having submodules, you need to execute an extra command in order for the submodules to be pulled.
$ git clone https://github.com/chaconinc/MainProject # powstanie DbConnector ale pusty
#$ git submodule init # initialize submodule configuration
$ git submodule update --init --recursive
W jednym kroku - clone a repository including its submodules
$ git clone --recursive https://github.com/chaconinc/MainProject
$ git clone --recurse-submodules https://github.com/chaconinc/MainProject
The submodule is always set to have its HEAD detached at a given commit by default : as the main repository is not tracking the changes of the submodule, it is only seen as a specific commit from the submodule repository.
In submodule dir:
git fetch
git submodule update --remote DbConnector # domysnie aktualizujemy na podstawie gałęzi master
git config -f .gitmodules submodule.DbConnector.branch stable
git submodule update --remote
$ git submodule update --remote --merge
Using the “–remote” command, you will be able to update your existing Git submodules without having to run “git pull” commands in each submodule of your project.
When using this command, your detached HEAD will be updated to the newest commit in the submodule repository.
$ cd repository/submodule
$ git fetch
git log --oneline origin/master -3
git checkout -q 93360a2
Your HEAD is now aligned with the newest commits from the submodule repository.
You can now go back to your main repository and commit your changes for other developers to fetch those new commits.
$ cd repository
$ git add .
$ git commit -m "Added new commits from the submodule repository"
$ git push
$ git submodule deinit <submodule>
$ git rm <submodule>
When executing the “git submodule deinit” command, you will delete the local submodule configuration stored in your repository.
As a consequence, the line referencing the submodule will be deleted from your .git/config file.
The “git rm” command is used in order to delete submodules files from the working directory and remaining .git folders.
To remove a submodule called mymodule you need to:
git submodule deinit -f — mymodule
rm -rf .git/modules/mymodule
git rm -f mymodule
git push recursive-submodules=check
# or
cd submodule
git push
# automatycznie
git push recursive-submodules=on-demand
git submodule foreach 'git reset --hard'
# including nested submodules
git submodule foreach --recursive 'git reset --hard'
git submodule foreach --recursive 'git stash'
git submodule foreach --recursive 'git checkout -B funkcjaA' # automatyczne utworzenie galezi w podmodulach i przejscie do nich
git submodule foreach 'git diff'
Kiedy po raz pierwszy dodajesz lub inicjalizujesz submoduł (git submodule init lub git submodule update --init), Git wykonuje kopię adresu URL:
Od tego momentu wszystkie operacje sieciowe (fetch, update, remote) pobierają dane z adresu zapisanego w Twoim prywatnym .git/config (oraz w pliku .git/modules/<nazwa>/config), całkowicie ignorując zmiany w pliku .gitmodules.Jeśli ktoś w zespole zmieni adres URL repozytorium w repozytorium nadrzędnym (np. przeniesiono projekt na nowy serwer, zmieniono nazwę organizacji na GitHubie lub zaktualizowano ścieżkę w .gitmodules):
- Ściągasz zmiany:
git pull. - Masz nowy plik
.gitmodulesz nowym URL-em. - Git wciąż próbuje łączyć się ze starym URL-em, bo w lokalnym
.git/configwciąż wisi stary adres. - Wpisujesz:
git submodule syncDopiero ta komenda przepisuje nowy adres zgitmodulesdo lokalnego.git/configoraz aktualizuje konfigurację zdalną w samym podkatalogu submodułu.
Co dokładnie robi git submodule sync pod maską?
- Przepisuje wartość submodule..url w pliku .git/config na wartość z .gitmodules.
- Wchodzi do katalogu submodułu (lub .git/modules//config) i aktualizuje adres dla remote.origin.url.
- Jeśli użyjesz flagi --recursive:
git submodule sync --recursiveprzejdzie w głąb przez wszystkie zagnieżdżone podmoduły i zaktualizuje ich adresy.
Czego ta komenda NIE robi?
- Nie przestawia commita – commit SHA w żaden sposób nie zależy od sync.
- Nie pobiera danych z sieci – po wykonaniu
git submodule synczazwyczaj trzeba uruchomićgit submodule update, aby pobrać commity z nowego adresu.
Można to zrobić na dwa sposoby: standardowy (z pobraniem kodu) oraz niskopoziomowy (bez pobierania kodu).
Sposob 1:
- Przejdź do katalogu submodułu i pobierz commity:Bashcd sciezka/do/submodulu
cd sciezka/do/submodulu
git fetch
- 2.Przestaw submoduł na wybrany commit SHA lub gałąź: Możesz wskazać konkretny hash albo wierzchołek gałęzi:
git checkout <nowy_SHA>
# lub: git checkout origin/main
- Wróć do głównego repozytorium i zatwierdź zmianę: Z punktu widzenia projektu głównego submoduł to pojedynczy wpis w indeksie (nowy commit SHA):
git add sciezka/do/submodulu
git commit -m "Bump submodule to <nowy_SHA>"
git push
Sposób 2: Automatyczny (do najnowszego commita na gałęzi)
Jeśli w pliku .gitmodules masz zdefiniowaną gałąź dla danego submodułu (lub ma to być domyślny branch na serwerze):
- Pobierz najnowszy commit zdalny bez ręcznego wchodzenia do folderu:
git submodule update --remote sciezka/do/submodulu - Zatwierdź zmianę w głównym repozytorium:
git add sciezka/do/submodulu
git commit -m "Update submodule to latest remote HEAD"
git push
Sposób 3: Bez pobierania kodu (tylko przestawienie SHA w indeksie)
Jeśli znasz pełny 40-znakowy hash commita i nie chcesz ściągać kodu submodułu na dysk (np. w skryptach automatyzacji czy CI):
- Wymuś wpis w indeksie Gita poleceniem update-index (tryb 160000 oznacza gitlink):
git update-index --cacheinfo 160000,<pelny_40_znakowy_SHA>,sciezka/do/submodulu
- Zatwierdź zmianę:
git commit -m "Bump submodule reference to <SHA>"
git push
Ważne przy sposobie 3: Upewnij się, że podany hash na pewno istnieje na serwerze zdalnym podmodułu. Git nie weryfikuje poprawności hasha przy update-index, więc pomyłka sprawi, że nikt inny nie będzie w stanie sklonować projektu bez błędów.