git submodules - ghdrako/doc_snipets GitHub Wiki


tags:

  • git
  • vcs

Git submodules

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

Problems with submodules

  • 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

First option:

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.

Submodules using

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 submodule to project

  1. 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
  1. 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

Cloning a Project with Submodules

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

pulling a Git submodule in our colleague Git repository detached the HEAD at a given commit.

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

Automatyczne pobieranie zmian dla wszyskich podmodułów

git submodule update --remote DbConnector  # domysnie aktualizujemy na podstawie gałęzi master
git config -f .gitmodules submodule.DbConnector.branch stable 
git submodule update --remote

Update a Git Submodule

$ 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.

Fetch new submodule commits

$ 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

Remove Git submodules

$ 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

Executing a command on every submodule

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'

git submodule sync

Kiedy po raz pierwszy dodajesz lub inicjalizujesz submoduł (git submodule init lub git submodule update --init), Git wykonuje kopię adresu URL:

$$\text{plik } \mathbf{.gitmodules} \xrightarrow{\text{kopiuje URL}} \text{lokalny plik konfiguracyjny } \mathbf{.git/config}$$

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):

  1. Ściągasz zmiany: git pull.
  2. Masz nowy plik .gitmodules z nowym URL-em.
  3. Git wciąż próbuje łączyć się ze starym URL-em, bo w lokalnym .git/config wciąż wisi stary adres.
  4. Wpisujesz:git submodule sync Dopiero ta komenda przepisuje nowy adres z gitmodules do lokalnego .git/config oraz 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 --recursive

przejdzie 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 sync zazwyczaj trzeba uruchomić git submodule update, aby pobrać commity z nowego adresu.

Podbicie submodułu na nowy commit SHA

Można to zrobić na dwa sposoby: standardowy (z pobraniem kodu) oraz niskopoziomowy (bez pobierania kodu).

Sposob 1:

  1. Przejdź do katalogu submodułu i pobierz commity:Bashcd sciezka/do/submodulu
cd sciezka/do/submodulu
git fetch
  1. 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
  1. 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):

  1. Pobierz najnowszy commit zdalny bez ręcznego wchodzenia do folderu: git submodule update --remote sciezka/do/submodulu
  2. 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):

  1. Wymuś wpis w indeksie Gita poleceniem update-index (tryb 160000 oznacza gitlink):
git update-index --cacheinfo 160000,<pelny_40_znakowy_SHA>,sciezka/do/submodulu
  1. 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.

⚠️ **GitHub.com Fallback** ⚠️