Git - Kapitola 8. Submoduly
Problémy se submoduly
Obsah
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.




