Articles

Mastering Git submodules (Magyar)

Submodules, step by step

most felfedezzük az almodulusok használatának minden lépését egy együttműködési projektben, ügyelve arra, hogy kiemeljük az alapértelmezett viselkedést, csapdákat és a rendelkezésre álló fejlesztéseket.

annak érdekében, hogy megkönnyítse a következő mentén, már össze néhány példa repos azok “Távirányítók” (valójában csak könyvtárak)., Akkor csomagolja ki az archívum, ahol akarsz, akkor nyissa meg a shell (vagy Git Bash, ha Windows) a git-subs könyvtárat hoz létre:

Töltse le a példa repó ügyletek

találsz három könyvtárak ott:

  • fő viselkedik, mint a tartály repo, helyi, hogy az első kollaboráns,
  • plugin működik, mint a központi karbantartás repo a modul, meg
  • távirányítót tartalmaz a fájlrendszer a távirányítók a két előző repó ügyletek.

az alábbi példabeszédekben a prompt mindig megjeleníti, hogy melyik repo-ba kerülünk.,

submodule hozzáadása

kezdjük azzal, hogy bővítményünket submodulként adjuk hozzá a tárolónkban (ami fő). Maga a plugin egyszerű szerkezettel rendelkezik:

.
├── README.md
├── lib
│ └── index.js
└── plugin-config.json

tehát menjünk be a főbe, és használjuk a git almodul hozzáadása parancsot. Ehhez a távvezérlő URL-je és egy alkönyvtár szükséges, amelyben az almodul “példányosítható”. Mert az általunk használt utak helyett Url-itt a távirányítót, volt egy furcsa, bár jól ismert, gubanc: relatív elérési utak távirányítók értelmezett relatív, hogy a fő távoli, nem a repo gyökérkönyvtárában., Ez nagyon furcsa, nem leírt sehol, de láttam, hogy ez történik minden alkalommal. Tehát ahelyett, hogy azt mondaná ../ Távirányítók / plugin, csak azt mondjuk ../ plugin.

main (master u=) $ git submodule add ../plugin vendor/plugins/demo
Cloning into 'vendor/plugins/demo'…
done.
main (master + u=) $

Ez hozzáadott néhány beállítást a helyi konfigurációban:

main (master + u=) $ cat .git/config


url = ../remotes/plugin

és ez két fájlt is rendezett:

Huh?! Mi ez?gitmodules fájl? Nézzük meg:

main (master + u=) $ cat .gitmodules

path = vendor/plugins/demo
url = ../plugin

Ez dühösen hasonlít a helyi konfigurációnkra … miért a duplikáció? Nos, pontosan azért, mert a helyi konfigurációnk… helyi., Munkatársaink nem fogják látni (ami teljesen normális), ezért szükségük van egy mechanizmusra, hogy megszerezzék az összes almodul meghatározását, amelyeket saját repójukban kell létrehozniuk. Ez az, amit .a gitmodules for; később a git submodule init parancs fogja olvasni, amint azt egy pillanat alatt látni fogjuk.

amíg státuszban vagyunk, vegye figyelembe, milyen minimalista ez a submodule esetében: csak egy túlságosan általános Új fájlhoz megy, ahelyett, hogy többet mondaná nekünk arról, hogy mi folyik benne., A submodule-t valóban az alkönyvtárba injektáltuk:


└── vendor
└── plugins
└── demo
├── .git
├── README.md
├── lib
│ └── index.js
└── plugin-config.json

állapot, mint a naplók és diffs, az aktív repo-ra (jelenleg a tartályra) korlátozódik, nem pedig az almodulokra, amelyek beágyazott repók. Ez gyakran problematikus (szuper könnyű kihagyni a regressziót, ha erre a nézetre korlátozódik), ezért azt javaslom, hogy állítson be egy almodul-tudatos állapotot egyszer s mindenkorra:

git config --global status.submoduleSummary true

és most:

aaah, ez sokkal jobb., Az állapot kiterjeszti alapinformáció hozzá, hogy a submodule jelen vendor / plugins / demo kapott 3 hírek elkötelezi magát (ahogy csak létre, ez azt jelenti, a távoli ág csak három követ), az utolsó egy kívül (megjegyzés a jobbra mutató szög konzol >) egy első elkövetni üzenet sor, amely így szól: “Fix repo neve…”.

annak érdekében, hogy valóban hazavigyük, hogy itt két különálló repóval foglalkozunk, menjünk be az almodul könyvtárába:

az aktív repo megváltozott, mert egy új .,git átveszi: az aktuális könyvtárban (demo, az almodul könyvtár), a .a git valóban létezik, egyetlen fájl is, nem Könyvtár. Nézzünk bele:

demo (master u=) $ cat .git
gitdir: ../../../.git/modules/vendor/plugins/demo

ismét, mivel a Git 1.7.8, a Git nem hagyja a repo könyvtárakat a tároló könyvtárában, hanem központosítja ezeket a tárolóban .git könyvtár (belül .git / modulok), és gitdir hivatkozást használ az almodulokban.,

A magyarázata egyszerű: lehetővé teszi, hogy a tartály repo, hogy részmodult-kevesebb ágak, anélkül, hogy megszerezzék a részmodult van repo-ból a könyvtárban, illetve helyreállítása később.

természetesen az almodul hozzáadásakor dönthet úgy, hogy egy adott ágat, vagy akár egy konkrét elkötelezettséget használ a-b CLI opcióval (a szokásos módon az alapértelmezett mester). Vegye figyelembe, hogy jelenleg nem egy leválasztott fején vagyunk, ellentétben azzal, ami később fog történni: ez azért van, mert a Git ellenőrizte a mestert, nem pedig egy adott SHA1-et. Meg kellett volna adnunk egy SHA1 to-b – t, hogy leválasszuk a fejét az indulástól., Szóval, vissza a tartály aktív repó, hogy véglegesítsék a részmodult van felül, majd nyomja, hogy a távoli:

demo (master u=) $ cd -
main (master + u=) $ git commit -m "Ajout submodule plugin demo"
main (master u+1) $ git push

Megragadta a repo, amely submodules

annak érdekében, hogy bemutassa a kérdéseket együttműködési egy repo, amely submodules, majd osztott személyiség úgy, mint a kollégám, aki klónok a konténer távoli dolgozni velünk. Ezt klónozzuk egy kolléga könyvtárba, így azonnal meg tudjuk mondani, hogy melyik személyiség sapkánk van bármikor.,

az első dolog, amit észre kell venni, hogy az almodulunk hiányzik a munkakönyvtárból; csak az alapkönyvtára van itt:

vendor
└── plugins
└── demo

hogyan történt ez? Ez egyszerűen annak a ténynek köszönhető, hogy eddig az új repo (kollégánk) még nem ismeri a submodulunkat: az ehhez szükséges információ sehol nincs a helyi konfigurációban (ellenőrizze annak .git / config, ha nem hiszel nekem). Mi alapján kell ezt kitöltenünk .gitmodules kell mondani, ami pontosan mit Git submodule init csinál:

mi .a git / config most már tisztában van a submodulunkkal., Azonban még mindig nem hoztuk le a távirányítójáról, hogy ne mondjunk semmit arról, hogy jelen van-e a munkakönyvtárunkban. És mégis, az állapotunk tiszta!

lásd, meg kell ragadnunk a vonatkozó kötelezettségvállalásokat manuálisan. Ez nem olyasmi, amit a kezdeti klón tett, meg kell csinálni minden húzás. Majd jön vissza, hogy egy perc alatt, mivel ez egy viselkedés klón valóban automatizálni, ha megfelelően hívják.,

a gyakorlatban, amikor a submodule-val foglalkozunk repos, általában a két parancsot (init és update) egybe csoportosítjuk:

colleague (master u=) $ git submodule update --init

még mindig szégyen, hogy a Git mindent megtesz magának. Képzeljük csak el, a nagyobb fogselyem projektek, amikor submodules saját submodules, és így tovább … ez gyorsan lesz egy rémálom.

előfordul, hogy a Git CLI opciót biztosít a klón számára, hogy automatikusan git submodule update — init rekurzív módon közvetlenül a klónozás után: a meglehetősen találóan elnevezett-rekurzív opció.,

tehát próbáljuk meg újra az egészet:

most ez jobb! Vegye figyelembe, hogy most egy leválasztott fejen vagyunk az almodul belsejében (ahogy mostantól leszünk):

git-subs $ cd colleague/vendor/plugins/demo
demo ((master)) $

lásd a kettős zárójelkészletet a promptomban, egyetlen készlet helyett?, Ha a prompt nincs beállítva, mint az enyém, hogy megjelenjen leszakadt a feje, mint ismerteti (a Git beépített azonnali forgatókönyv, akkor meg kell határozni, hogy a GIT_PS1_DESCRIBE_STYLE=ág környezeti változó), akkor inkább valami ilyesmi:

demo ((fe64799...)) $

mindenesetre állapota megerősíti, hol vagyunk:

demo ((master)) $ git status
HEAD detached at fe64799
nothing to commit, working directory clean

, Hogy egy frissítés a részmodult távoli

OK, most, hogy megvan a saját repo (fő), valamint a “kolléga” (kolléga) minden beállítva, hogy együttműködjenek, lépjen be a cipő egy harmadik személy: az, aki fenntartja a plugin., Itt lépjünk rá:

most adjunk hozzá két pszeudo-kötelezettséget, és tegyük közzé ezeket a távvezérlőnek:

végül tegyük újra az” első Fejlesztő ” sapkát:

plugin (master u=) $ cd ../main
main (master u=) $

tegyük fel, hogy most ezt a két kötelezettséget szeretnénk megkapni az almodulunkban. Ennek elérése érdekében frissítenünk kell a helyi repo-t, kezdve a munkakönyvtárába való áthelyezéssel, így aktív repo lesz.

egy oldalsó megjegyzésen nem javasolnám a pull használatát az ilyen frissítéshez., Ahhoz, hogy megfelelően kap a frissítéseket a munkakönyvtárban, ez a parancs megköveteli, hogy te vagy a megfelelő aktív ág, amely általában nem (te egy levált fej a legtöbb időt). A fióktelep pénztárával kellene kezdened. De ami még fontosabb, a távoli ág is nagyon jól mozgott tovább, mivel a elkövetni szeretne beállítani, majd egy húzza azt adja be vállalja, lehet, hogy nem akarom, hogy a helyi codebase.,

Ezért azt javasoljuk, felosztása a folyamat kézzel: első git hozza, hogy minden új adatokat a távoli helyi cache, majd jelentkezzen, hogy ellenőrizze, mi van a pénztár a kívánt SHA1. A finomabb szemcsés vezérlés mellett ez a megközelítés további előnye, hogy a jelenlegi állapotától (aktív ág vagy leválasztott fej) függetlenül működik.

OK, tehát jók vagyunk, Nem Idegen elkövetni., Bárhogy is legyen, kifejezetten állítsuk be az érdeklődőt (nyilvánvalóan van egy másik SHA1):

demo (master u-2) $ git checkout -q 0e90143

(A-q csak azért van, hogy megkíméljen minket arról,hogy hogyan végzünk egy leválasztott fejre. Általában ez egy egészséges emlékeztető lenne, de ezen tudjuk, mit csinálunk.)

most, hogy a submodule frissül, láthatjuk az eredményt a tároló repo állapota:

a” klasszikus ” része az állapot, látunk egy új commit változás típusa, ami azt jelenti, a hivatkozott elkövetni megváltozott., Egy másik lehetőség (amely ezt kiegészítheti) az új tartalom, ami azt jelenti, hogy helyi változtatásokat hajtottunk végre az almodul munkakönyvtárában.

az alsó rész, amelyet az állapotunk engedélyez.submoduleSummary = true beállítás korábban, kifejezetten kimondja a bevezetett kötelezi (mivel azok egy jobbra mutató szög konzol >), mivel az utolsó konténer elkövetni, hogy megérintette a submodule.

a “szörnyű alapértelmezett viselkedés” családban a git diff sok kívánnivalót hagy maga után:

mi a — ?, Van egy CLI opció, amely lehetővé teszi számunkra, hogy valami hasznosabb:

main (master * u=) $ git diff --submodule=log
Submodule vendor/plugins/demo fe64799..0e90143:
> Pseudo-commit #2
> Pseudo-commit #1

jelenleg nincs más helyi változás az almodul hivatkozott commit … figyeljük meg, hogy ez majdnem pontosan megegyezik a továbbfejlesztett git állapot kijelzőjének alsó részével.

az, hogy minden alkalommal be kell írnia ezt a fajta CLI opciót (amely egyébként nem jelenik meg a Git jelenlegi befejezési ajánlataiban), meglehetősen nehézkes. Szerencsére van egy megfelelő konfigurációs beállítás:

most már csak el kell végeznünk a konténer elkövetését, amely véglegesíti az almodul frissítését., Ha meg kellett érintenie a tartály kódját, hogy működjön ezzel a frissítéssel, természetesen kövesse el. Másrészt, ne keverjen össze részmodult kapcsolatos változások, valamint a másik dolog, hogy csak vonatkoznak a tároló kódja: a szépen, hogy elválasztja a két, később vándorlások egyéb kód-újrafelhasználás megközelítések könnyebb (is, mint mindig, atomi vállalja FTW).

mivel hamarosan megragadjuk ezt a submodule frissítést kollégánk repo-jában, rögtön elkövetés után nyomunk (ami nem általános jó gyakorlat).

main (master * u=) $ git commit -am "Setting submodule on PC2"
main (master u+1) $ git push

almodul húzása-repo

kattintással!, “Kolléga” sapka!

tehát a container repo távoli…

frissítéseit húzzuk ki (lehet, hogy nem rendelkezik a “sikeresen újraindított és frissített…” verzióval, hanem a “rekurzív” stratégia által végrehajtott egyesítést ” látjuk. Ha igen, a szívem kialszik neked, és azonnal meg kell tanulni, miért húzza kell rebase).

vegye figyelembe a kijelző második felét: az almodulról van szó, kezdve a “Lekérés almodulával…”.

Ez a viselkedés lett az alapértelmezett Git 1.7.5, a Konfigurációs beállítás fetch.,recurseSubmodules most a mulasztó on-demand: ha egy tartály projekt kap frissítéseket hivatkozott részmodult követ el, ezek submodules kap automatikusan letöltésre. (Ne feledje, hogy a Lekérés a húzás első része.)

mégis, és ez kritikus: a Git automatikus lekérése, de nem automatikus frissítés. A helyi gyorsítótár naprakész az almodul távvezérlőjével, de az almodul munkakönyvtára a korábbi tartalmához ragadt. Legalább becsukhatod azt a laptopot, felszállhatsz egy gépre, és még mindig haladhatsz előre egyszer offline állapotban., Bár ez az automatikus Lekérés a már ismert almodulokra korlátozódik: minden új, még nem másolt helyi konfigurációba, nem automatikus letöltésre kerül.

Git automatikus letöltések, de nem automatikus frissítés.

az aktuális prompt csillaggal ( * ) utal a helyi módosításokra, mivel WD-nk nincs szinkronban az indexgel, az utóbbi tudatában van az újonnan hivatkozott submodule elkötelezi magát. Nézze meg az állapotot:

vegye figyelembe, hogy a szögletes zárójelek hogyan mutatnak balra (<)?, A Git úgy látja, hogy a jelenlegi WD-nek nincs ez a két kötelezettségvállalása, ellentétben a konténerprojekt elvárásaival.

Ez a hatalmas veszély: ha nem frissíti kifejezetten az almodul munkakönyvtárát, akkor a következő container commit regresszálja az almodulot. Ez egy elsőrendű csapda.

Ez tehát kötelező, hogy véglegesítsék a update:

amíg próbálunk formában generikus jó szokások, a kívánt parancs itt lenne egy git részmodult update — init — rekurzív, annak érdekében, hogy az auto-init új részmodult, hogy rekurzívan frissítés ezeket, ha szükséges.,

van egy másik él esetben: ha a submodule távoli URL megváltozott, mivel az utolsó használt (talán az egyik együttműködő megváltoztatta a .gitmodules), manuálisan kell frissítenie a helyi konfigurációt, hogy megfeleljen ennek. Ilyen helyzetben a git almodul frissítése előtt Git almodul szinkronizálást kell futtatnia.

a teljesség kedvéért meg kell említenem, hogy még akkor is, ha a git submodule update alapértelmezés szerint ellenőrzi a hivatkozott SHA1-et, ezt megváltoztathatja például bármely helyi almodul munka újraindítására (erről hamarosan beszélünk)., Ezt úgy teheti meg, hogy beállítja az almodul frissítési konfigurációs beállítását a tároló helyi konfigurációjában.

és sajnálom, de nem, nincs helyi konfigurációs beállítás, vagy akár CLI opció is, amely automatikusan frissíthető a pull-on. Az ilyen dolgok automatizálásához álneveket, egyéni szkripteket vagy gondosan kialakított helyi horgokat kell használnia., Itt van egy példa sirály alias (egysoros, osztott itt kijelző):

git config --global alias.spull '!git pull && git submodule sync --recursive && git submodule update --init --recursive'

Ha meg szeretné tartani a képességét, hogy adja át az egyéni argumentumokat Git pull, akkor sem határozza meg a funkciót on-the-fly és hívja, vagy menjen egy egyéni script. Az első megközelítés így néz ki (ismét egysoros):

nem nagyon olvasható, Mi? Inkább az egyéni script megközelítés., Tegyük fel, hogy egy git-spull script fájlt valahol az ÚT (van egy ~/engem keres/bin könyvtárat, az UTAT, csak az ilyen dolgok):

#! /bin/bash
git pull "$@" &&
git submodule sync --recursive &&
git submodule update --init --recursive

ezután add végrehajtási jogok:

chmod +x git-spull

most tudjuk használni, mint használt volna az alias.

egy almodul frissítése a

tartályban ez a legnehezebb felhasználási eset, ezért a lehető legnagyobb mértékben távol kell maradnia tőle, előnyben részesítve a karbantartást a központi, dedikált repo-n keresztül.,

előfordulhat azonban, hogy a submodule kódot nem lehet tesztelni, vagy akár összeállítani a konténerkódon kívül. Sok téma, plugin van ilyen korlátok.

az első dolog, amit meg kell érteni, mert elkötelezi magát, megfelelő alapból kell indulnia, amely ágcsúcs lesz. Ezért ellenőriznie kell, hogy a fióktelep legutóbbi kötelezettségvállalásai nem “törik” meg a konténerprojektet. Ha igen, nos, a saját konténerspecifikus ág létrehozása az almodulban csábítónak hangzik, de ez az út az almodul és a tartály közötti erős kapcsoláshoz vezet, ami nem ajánlott., Lehet, hogy abba “submoduling”, hogy a kód ebben a konkrét projekt, csak beágyazni, mint bármely rendszeres tartalom helyett.

valljuk be, hogy jó lelkiismerettel hozzá lehet adni az almodul jelenlegi mesterágához. Kezdjük azzal, hogy a szinkronizálás a helyi állam, a távoli van:

egy Másik módja, hogy ezt az lenne, hogy a tartályból repo, hogy kifejezetten fordította a részmodult helyi ág, mint a lánctalpas távoli ág (single line tetején, az utolsó követ whitespace):

most már szerkesztés a kódot, hogy ez a munka, vizsga, stb., Ha már minden kész, akkor végre a két elkötelezi magát, és a két szükséges tolja (ez szuper könnyű, és a gyakorlatban túl gyakori, hogy felejtsük el, hogy néhány, hogy).

nézzük, egyszerűen hozzá hamis dolgozni, hogy a két kapcsolódó követ el, a részmodult, valamint tartály szint:

ezen A ponton, a fő veszély az, elfelejti, hogy nyomja meg a részmodult. Visszamész a konténerprojekthez, elkötelezed, és csak megnyomod a konténert. Ez egy egyszerű hiba, különösen egy IDE vagy GUI belsejében. Amikor a kollégái megpróbálnak frissítéseket kapni, minden pokol elszabadul., Nézze meg az első lépést:

egyáltalán nincs jele annak, hogy a GIT nem tudta letölteni a hivatkozott elkövetést az almodul távirányítójáról. Ennek első jele az állapot:

figyeljük meg a figyelmeztetést: úgy tűnik, az újonnan hivatkozott commit a submodule sehol nem található. Valóban, ha megpróbáljuk frissítése a részmodult működik könyvtár, kapunk:

main (master * u=) $ git submodule update
fatal: reference is not a tree: 12e3a529698c519b2fab790630f71bd531c45727
Unable to checkout '12e3a529698c519b2fab790630f71bd531c45727' in submodule path 'vendor/plugins/demo'

világosan láthatja, milyen fontos, hogy emlékezzen nyomja a részmodult is ideális előtt nyomja a tartály., Tegyük ezt kolléga és próbálja meg újra a frissítést:

meg kell jegyeznem, hogy van egy CLI opció, amely ellenőrzi, hogy a jelenleg hivatkozott almodulokat is meg kell — e nyomni, és ha igen, akkor nyomja őket: ez git push-recurse-submodules=on-demand (elég egy falat, igaz). Szüksége van valami konténerszintre a munkához, bár: csak a submodules nem vágja le.

mi több, (ehhez nincs konfigurációs beállítás, ezért szabványosítani kell az eljárásokat egy álnév körül, például spush:) — a Git 2.7.0-tól kezdve, most van egy push.,recurseSubmodules konfigurációk beállítás megadhatja (on-demand vagy check).

git config --global alias.spush 'push --recurse-submodules=on-demand'

egy almodul eltávolítása

két olyan helyzet van, amikor egy almodulot “eltávolítani” szeretne:

  • csak törölni szeretné a munkakönyvtárat (talán a tároló WD archiválása előtt), de meg akarja őrizni a későbbi visszaállítás lehetőségét (tehát benne kell maradnia .gitmodules és .git / modulok);
  • véglegesen el szeretné távolítani a jelenlegi ágból.

lássuk az egyes eseteket egymás után.,

egy

almodul ideiglenes eltávolítása az első helyzetet a git submodule deinit könnyen kezeli. Lásd magad:

Ez nem befolyásolja a tartály állapotát. A submodule nem lokálisan ismert többé (ez elment .git / config), így a munkakönyvtárból való hiánya észrevétlen marad. Még mindig van a szállító / plugins / demo könyvtár, de ez üres; tudtuk szalag nélkül következménye.

az almodul nem tartalmazhat helyi módosításokat, ha ezt megteszi, különben kényszeríteni kell a hívást.,

bármely későbbi subcommand git submodule boldogan figyelmen kívül hagyja ezt submodule amíg init újra, mint a submodule nem is lesz a helyi config. Ilyen parancsok közé tartozik a frissítés, a foreach és a sync.

másrészt, a submodule marad definiálva .gitmodules: egy init, majd egy update (vagy egyetlen update — init) visszaállítja, mint az új:

Véglegesen eltávolítja egy részmodult

Ez azt jelenti, hogy meg akar szabadulni a részmodult jó: rendszeres git rm lesz, mint bármely más része a könyvtárban., Ez csak akkor működik, ha az almodul egy gitfile (a .git, amely egy fájl, nem könyvtár), ami a GIT 1.7.8-val kezdődik. Ellenkező esetben ezt kézzel kell kezelnie(elmondom, hogyan kell a végén).

amellett, hogy eltávolítja az almodulot a munkakönyvtárból, a parancs frissíti a .gitmodules fájlt, így nem hivatkozhat a submodule többé. Itt megy:

természetesen, advanced status info utazás át magukat itt, mert a gitfile a submodule eltűnt (valójában a teljes demo könyvtár eltűnt).,

ami azonban furcsa, az, hogy a helyi konfigurációs megőrzi az almodul információkat, ellentétben azzal, ami történik, amikor deinit. Tehát egy átfogó eltávolításhoz azt javaslom, hogy mindkettőt egymás után végezze el, hogy megfelelően megtisztuljon (az előző parancsunk után nem fog működni, mert törlődik .gitmodules már):

git submodule deinit path/to/module # ensure local config cleanup
git rm path/to/module # clean WD and .gitmodules

megközelítésétől függetlenül a submodule repo továbbra is jelen van .git / modulok / szállító / plugins / demo, de szabadon megölheti, amikor csak akarja.

Ha valaha is el kell távolítania a GIT 1.7 előtt létrehozott almodulot.,8, és ezért beágyazza annak .git könyvtár egyenesen a konténer munkakönyvtár (ahelyett, hogy egy gitfile), akkor van, hogy kitörjön a buldózer: az előző két parancsot kell megelőznie kézi mappa eltávolítása, pl. rm-fr eladó/plugins/demo, mert azt mondta, parancsok mindig hajlandó törölni tényleges adattár.