Git - Kapitola 8. Submoduly

Problémy se submoduly

Obsah

Problémy se submoduly

Velké projekty se často skládají z menších, soběstačných modulů. Například, zdrojové kódy embedded Linuxových distribucí by zahrnoval veškeré kousky software v distribuci s určitými lokálními změnami; přehrávač filmů by k sestavení mohl potřebovat specifickou, funkční verzi dekompresní knihovny; několik nezávislých programů by mohli sdílet stejné buildovací skripty.

S centralizovaným systémem správy revizí je tohoto často dosahováno zahrnutím všech modulů do jediného repositáře. Vývojáři si mohou načíst všechny moduly nebo pouze moduly se kterými potřebují pracovat. Dokonce mohou modifikovat soubory v několika modulech v rámci jediného commitu přičemž přesouvají části zdrojových kódů nebo mění API a překlady.

Git neumožňuje částečné checkouty, takže aplikace tohoto přístupu v Gitu by nutila vývojáře k udržování lokální kopie modulů o které nemají zájem. Commity v enormním checkoutu by byly pomalejší než byste čekali protože Git by musel kontrolovat všechny adresáře a hledat změny. Pokud mají moduly mají dlouhou lokální historii, klonování by trvalo věčnost.

Výhodou je že distribuované verzovací systémy dokáží daleko lépe integrovat externí zdroje. V centralizovaném modelu je z verzovacího systému externího projektu vyexportován jediný snapshot, který je následně naimportován do lokálního verzovacího systému (do tzv. "vendor branch" větve). Veškerá historie je skryta. S distribuovaným verzovacímisystémem můžete naklonovat celou externí historii a daleko jednodušeji sledovat vývoj a začleňovat lokální změny.

Podpora pro submoduly v Gitu umožňuje aby repositář obsahoval, jako podadresář, checkout externího projektu. Submoduly si udržují vlastní identitu; podpora pro submoduly pouze uloží umístění repositáře submodulu a ID commitu, takže ostatní vývojáři kteří si naklonují hlavní projekt ("superproject") si mohou jednoduše naklonovat všechny submoduly ve stejné revizi. Částečné checkouty superprojektu jsou možné: můžete Gitu říci že nemá klonovat žádné, jen některé nebo všechny submoduly.

Příkaz git-submodule(1) v Gitu existuje od 1.5.3. Uživatelé s Gitem ve verzi 1.5.2 mohou v repositáři ručně vyhledat commity submodulů a manuálně je načíst (check out); dřívější verze submoduly vůbec nedokáží submoduly rozeznat.

Pro znázornění fungování submodulů, vytvořte (například) čtyři ukázkové repositáře ktaré budou později použity jako submoduly:

$ mkdir ~/git
$ cd ~/git
$ for i in a b c d
do
        mkdir $i
        cd $i
        git init
        echo "module $i" > $i.txt
        git add $i.txt
        git commit -m "Initial commit, submodule $i"
        cd ..
done

Nyní vytvořte superprojekt a přidejte všechny submoduly:

$ mkdir super
$ cd super
$ git init
$ for i in a b c d
do
        git submodule add ~/git/$i $i
done

Poznámka

Nepoužívejte lokální URL pokud plánujete superprojekt publikovat!

Podívejte se jaké soubory příkaz git submodule vytvořil:

$ ls -a
.  ..  .git  .gitmodules  a  b  c  d

Příkaz git submodule add <repo> <path> provádí několik věcí:

  • Naklonuje submodul z repositáře <repo> na danou cestu <path> v rámci aktuálního adresáře a standardně načítá master větev.
  • Přidá "clone path" submodulu do souboru gitmodules(5) přidá tento soubor do indexu, připravený ke commitu.
  • Zařadí commit ID submodulu do indexu, připravený ke commitu.

Commitněte superprojekt:

$ git commit -m "Add submodules a, b, c and d."

Nyní naklonujte superprojekt:

$ cd ..
$ git clone super cloned
$ cd cloned

Adresáře submodulů jsou tam, ale jsou prázdné:

$ ls -a a
.  ..
$ git submodule status
-d266b9873ad50488163457f025db7cdd9683d88b a
-e81d457da15309b4fef4249aba9b50187999670d b
-c1536a972b9affea0f16e0680ba87332dc059146 c
-d96249ff5d57de5de093e6baff9e0aafa5276a74 d

Poznámka

Objektová jména commitů vypsaná výše by ve vašem případě byla jiná, ale měla by odpovídat objektovým jménům commitů v HEAD vašich repositářů. To můžete zkontrolovat spuštěním příkazu git ls-remote ../a.

Načtení submodulů je dvoukrokový proces. Nejdříve spusťte příkaz git submodule init čímž URL repositářů zadáte do souboru .git/config:

$ git submodule init

Nyní použijte příkaz git submodule update pro naklonování repositářů a načtěte commity specifikované v superprojektu:

$ git submodule update
$ cd a
$ ls -a
.  ..  .git  a.txt

Velký rozdíl mezi příkazy git submodule update a git submodule add spočívá v tom že  git submodule update načítá konkrétní commit, namísto vrcholu větve. Je to jako načítání tagu: vrchol je odpojený, takže nepracujete na větvi.

$ git branch
* (no branch)
  master

Pokud v submodulu chcete provést změnu a máte odpojený vrchol, měli byste si vytvořit nebo načíst (check out) větev, provést změny, publikovat změny v submodulu, a poté aktualizovat superprojekt tak aby odkazoval na nový commit:

$ git checkout master

nebo

$ git checkout -b fix-up

a potom

$ echo "adding a line again" >> a.txt
$ git commit -a -m "Updated the submodule from within the superproject."
$ git push
$ cd ..
$ git diff
diff --git a/a b/a
index d266b98..261dfac 160000
--- a/a
+++ b/a
@@ -1 +1 @@
-Subproject commit d266b9873ad50488163457f025db7cdd9683d88b
+Subproject commit 261dfac35cb99d380eb966e102c1197139f7fa24
$ git add a
$ git commit -m "Updated submodule a."
$ git push

Pokud chcete aktualizovat i submoduly, musíte po příkazu git pull spustit také příkaz git submodule update.

Problémy se submoduly

Změnu v submodulu vždy publikujte před publikováním změny v superprojektu který submodul odkazuje. Pokud na změnu v submodulu zapomenete, ostatní nebudou schopni repositář naklonovat:

$ cd ~/git/super/a
$ echo i added another line to this file >> a.txt
$ git commit -a -m "doing it wrong this time"
$ cd ..
$ git add a
$ git commit -m "Updated submodule a again."
$ git push
$ cd ~/git/cloned
$ git pull
$ git submodule update
error: pathspec '261dfac35cb99d380eb966e102c1197139f7fa24' did not
match any file(s) known to git.
Did you forget to 'git add'?
Unable to checkout '261dfac35cb99d380eb966e102c1197139f7fa24' in
submodule path 'a'

Také byste neměli "převíjet" větve v submodulu před commity které někdy byly zaznamenány v některém superprojektu.

Není bezpečné spouštět git submodule update pokud jste provedli a commitnuli změny v submodulu bez předchozího načtení větve. Ty budou v tichosti přepsány:

$ cat a.txt
module a
$ echo line added from private2 >> a.txt
$ git commit -a -m "line added inside private2"
$ cd ..
$ git submodule update
Submodule path 'a': checked out 'd266b9873ad50488163457f025db7cdd9683d88b'
$ cd a
$ cat a.txt
module a

Poznámka

Změny jsou stále viditelné v reflogu submodulu.

Tento případ neplatí pokud jste své změny necommitnuli.

Komentáře

K tomuto článku zatím žádné komentáře neexistují (nebo čekají na schválení).

Nový komentář

Všechny komentáře podléhají schválení - mezi odesláním komentáře a jeho zobrazením na této stránce tedy může být prodleva. Vyplníte-li e-mailovou adresu, budete o schválení či neschválení komentáře informováni.

V titulku ani v textu nejsou povoleny HTML tagy - budou automaticky odstraněny. Odstavec ukončíte prázdným řádkem.

(nepovinné)