MySQL Dump git hook-ból

Készítettem egy kis futtatható git hook-ot, ami a MySQL adatbázisom tartalmát teszi be egy sql fájlba. Azt ajánlják, hogy az adatbázis szerkezete és a tartalma külön fájlokban legyen, de én ezzel annyira most nem törődtem... Igazából ha a séma változik, akkor a tartalom is, ha a tartalom változik, akkor már mondjuk nem igaz ugyanez. Azért nem tartom fontosnak külön fájlba szedni ezeket, mert úgyis leírom a szerkezetváltozásokat a commit szövegébe...

#!/bin/sh
cd "$(git rev-parse --show-toplevel)"
rm -f "backup.sql"
exec "absolute/path/to/mysqldump.exe" --skip-comments -u myuser --password=mypass mydb |sed 's$),($),\n($g' > "backup.sql"
exit
(Sajnos a google syntax highlighter nincs a helyzet magaslatán, az & gt; helyett képzeljetek oda nagyobb jelet.)

A hook-ban az első sor a shell-t tölti be. Erre azt hiszem nincs szükség, mert a bash ezt alapból megteszi nekünk. Nem tudom, hogy van e lehetőség az ilyen futtatott fájloknál környezet betöltésre, ezt még ki kell tapasztalnom a későbbiekben.

A második sorban a git rev-parse --show-toplevel az aktuális repo root-ját adja. Ehhez előtte egy olyan útvonalat kell beállítanunk a cd-vel, ami benne van az aktuális repo-ban. A kezdő útvonal valószínűeg a git bash alapértelmezett útvonala, tehát a felhasználói könyvtár, ahol megoszott képek meg dokumentumok vannak, szóval az előző blog bejegyzésben leírt bat fájlt majd ki kell egészíteni az útvonal beállítással is, amennyiben ez lehetséges.

A harmadik sorban töröljük a régi sql fájlt. Erre azt hiszem nincs szükség, ahogy kitapasztaltam a .bat fájlokban a > azt jelenti, hogy felülírjuk a régi fájlt, a >> pedig azt, hogy hozzáfűzzük a tartalmat a régi fájl végéhez. Az eredeti kódban, amit átalakítottam erre a formára, benne volt az rm, ezért hagytam meg ebben is.

A negyedik sorban az új sql fájlt hozzuk létre az adatbázis aktuális állása alapján. A --skip-comments -re azért volt szükség, mert a commentek között szerepel többek között a készítés dátuma, ez pedig azt eredményezné, hogy minden egyes dump híváskor megváltozna a fájl függetlenül attól, hogy az adatbázis változott e. A user, password, database részek, illetve a dump fájl megadása evidensek, a sed-es rész pedig azt csinálja, hogy az egy sorba betömörített multi insert-et szépbontja több sorba, így minden egyes rekord-nál külön sorban jelenik meg az esetleges változás. Ennek hasznosságát azt hiszem nem kell hangsúlyoznom...

Nem sokára megpróbálkozom még extrémebb dolgokkal, mint például wsh-ban írt deploy kód futtatásával, és hasonlókkal, egyelőre azonban elég ennyi a parancssorból. :-)

Git hook - fájlok társítása és futtatása

A git hook-ok a .git/hooks/ könyvtár alatt található állományok. A tartalmuk a git shell által értelmezhető parancsokból áll, és esemény kezelőként szolgálnak. Nem valami fejlett az esemény kezelési modell, viszont attól még működik. Például a pre-commit hook a commit előtt fut le, mint azt a neve is mutatja, és képes megakadályozni a commit lefutását. Ez körülbelül a HTML 10 évvel ezelőtti esemény moddeljének felel meg, ahol szintén a visszatérési értékkel lehetett az eseményt semmissé tenni...

A git hook-ok egyébként nagyon hasznosak tudnak lenni pusztán ettől a funkciótól is, hiszen a deploy kódot lehet hívogatni velük... Például a pre-commit-ban elhelyezhetünk unit test-eket, vagy osztályokból nagyobb fájlok összeállítását, esetleg fájlméret optimalizálást, de akár a commit után is elvégezhetőek ugyanezek, sőt a committál fájlok teszt majd éles szerverre történő másolása, és még sok dolog ugyanígy megoldható velük. Gyakorlatilag egy egész build rendszert lehet erre építeni, ahogy már meg is tették mások a maven és az ant esetében. Ennek a hook-os megoldásnak az előbbiekkel szemben annyi az előnye, hogy nincs feleslegesen túlbonyolítva...

A git hook-ok egy nem túl standard felhasználási módja a parancsfájlként történő futtatás. Nekem erre azért volt szükségem, mert windows alatt szerettem volna unix-os parancsokat használni, és ezek bent vannak a shell-ben. Persze ugyanezt cygwinnel is megoldhattam volna, dehát minek tegyek fel egy új rendszert, amikor már van egy használható?!

Az alap problémám az volt, hogy volt egy pre-commit-om, amit szerettem volna parancsfájlba áttenni. Próbálkoztam bat fájllal, wsh-js fájllal, de egyik sem volt igazán nyerő, mindegyik elbukott, vagy a szóközös fájlnevek, vagy a unix függvények miatt. Végül úgy döntöttem, hogy megpróbálom a git-tel lefuttatni az eredeti kódot valahogyan. Persze először itt is wsh-val próbálkoztam, de nem jött össze a sok egymásba rakott idézőjel miatt megzavarodott az egész.

Végül úgy döntöttem, hogy jobb hagyni a wsh-t, és a windows-os cli-t a lehető legkisebb mértékben érintő kódot írni. Ez gyakorlatilag azt jelenti, hogy meghagyom a hook fájlt, és megpróbálom a tartalmát lefuttatni valahogyan a git shell-ben. Keresgéltem elég sokat, de nem találtam szinte semmit. Ezután megpróbáltam a hook fájlt társítani valamelyik git exe-hez, de ez sem vezetett eredményre. Végül felfedeztem, hogy a git bash-ben akár txt fájlokat is le lehet futtatni pusztán a fájlnév beírásával, és a bennük lévő parancsok ugyanúgy végrehajtásra kerülnek, mint az automatikusan hívott hook-oknál. Ebből kiindulva csináltam egy kis bat fájlt, ami a megadott fájlt a git bash-ben végrehajtja.

if not exist %1 exit
set bash=C:\Program Files (x86)\Git\bin\bash.exe
"%bash%" --login -i -c "exec "%1""

Ezek után a .hook kiterjesztésű fájlokat ehhez társítottam, és így megszületett a git shell parancsfájl. Elég vicces a munkatempóm ennél a kódnál, minden sorra pontosan egy nap jut. Három nap keresgéléssel, és windows script hosttal történő szenvedéssel jutottam el eddig, de azt hiszem megérte... :-)