× Aktuálně z oboru

SHIELD Experience Upgrade 7 – méně hledání a více zábavy [ clanek/2018052902-shield-experience-upgrade-7-mene-hledani-a-vice-zabavy/ ]
Celá zprávička [ clanek/2018052902-shield-experience-upgrade-7-mene-hledani-a-vice-zabavy/ ]

GitMagic (6) – velmistrovství v Gitu

[ http://programujte.com/profil/10927-jakub-kulhan/ ]Google [ ?rel=author ]       [ http://programujte.com/profil/118-zdenek-lehocky/ ]Google [ ?rel=author ]       27. 6. 2009       12 583×

Kromě základních věcí se při práci s Gitem setkáte i s těmi složitějšími, méně často používanými. Tato kapitola se zabývá právě jimi. Sbírka různých tipů, které se vám mohou hodit.

Tato honosně pojmenovaná kapitola je moje skládka všech nezařaditelných Gitích triků.

Vydávání

V mých projektech Git udržuje informace přesně o těch souborech, které bych rád zaarchivoval a uvolnil uživatelům. K vytvoření tarballu se zdrojovými kódy:

$ git archive --format=tar --prefix=projekt-1.2.3/ HEAD

Generování changelogů

Je dobrým zvykem udržovat tzv. changelog [ http://en.wikipedia.org/wiki/Changelog ], některé projekty to dokonce vyžadují. Pokud jste ukládali změny pravidelně, což byste měli, changelog můžete vygenerovat napsáním:

$ git log > Changelog

Git skrz SSH, HTTP

Předpokládejme, že máte na web server přístup pomocí SSH, ale není tam nainstalovám Git. I když je to méně učinné než nativní protokol, Git může komunikovat přes HTTP.

Stáhněte, zkompilujte a nainstalujte Git na váš účet a vytvořte repozitář ve vašem webovém adresáři:

$ GIT_DIR=projekt.git git init

V adresáři proj.git spusťte:

$ git --bare update-server-info
$ chmod a+x hooks/post-update

Z vašeho počítače nahrajte změny skrz SSH:

$ git push web.server:/cesta/projekt.git master

a ostatní mohou získat váš projekt pomocí:

$ git clone http://web.server/projekt.git

Git skrz cokoli

Chcete synchronizovat repozitáře bez serverů, či dokonce internetového připojení? Musíte improvizovat ve stavu nouze? Již jsme viděli, že git fast-export a git fast-import mohou zkonvertovat repozitáře do jediného souboru a zase zpět. Mohli bychom takto vyexportovaný Gití repozitář přenést pomocí jakéhokoli média, ale mnohem účinějším nástrojem je git bundle.

Odesilatel vytvoří „balíček“:

$ git bundle create nejaky_soubor HEAD

potom nějak balíček nejaky_soubor přenese na druhou stranu: e-mailem, klíčenkou, disketou, vytištěním a přečtením OCR čtečkou, posíláním bitů po telefonní lince, kouřovými signály atp. Příjemce získá commity z balíčku napsáním:

$ git pull nejaky_soubor

Příjmece tohle může udělat dokonce s prázdným repozitářem. Nehledě na velikost, nejaky_soubor obsahuje celý původní repozitář.

Ve větších projektech můžete zmenšit ztráty zabalením pouze změn, které druhý repozitář nemá:

$ git bundle create nejaky_soubor HEAD ^SHA1_KTERE_MAJI_OBA

Pokud je toto děláno často, můžete jednoduše zapomenout na to, který byl poslední odeslaný commit. Stránka s nápovědou navrhuje jako řešení používat tagy. Jmenovitě poté, co odešlete balíček, napište:

$ git tag -f posledni_balicek HEAD

a tvořete nové čerstvé balíčky s

$ git bundle create novy_balicek HEAD ^posledni_balicek

Patche jako celosvětová měna

Patche jsou textové reprezentace vašich změn, které mohou být jednoduše pochopeny počítači i lidmi. Tohle jim dává jednotný vzhled. Vývojářům můžete poslat e-mailem patch bez ohledu na to, který verzovací systém používají. Když můžete e-mail přečíst, oni mohou vidět vaše změny. Podobně všechno, co potřebujete vy, je e-mailový účet: vůbec nemusíte nastavovat nějaký online Gití repozitář.

Vzpomeňme si na první kapitolu:

$ git diff COMMIT

vytiskne patch, který může být zkopírován do e-mailu k prodiskutování. V Gitím repozitáři napište:

$ git apply < PATCH

k aplikování patche.

Trochu formálněji, pokud chcete, aby byla jména autorů a možná jejich podpisy zaznamenány, vytvořte odpovídající patche po nějakém bodu napsáním:

$ git forma-patch STARTOVNI_COMMIT

Výsledný soubor může být předán git send-email, nebo odeslán ručně. Můžete také určit rozmezí commitů:

$ git format-patch STARTOVNI_COMMIT..KONECNY_COMMIT

Na straně příjemce uložte e-mail do souboru a poté napište:

$ git am < SOUBOR

což aplikuje příchozí patch a také vytvoří nový commit obsahující informace o autorovi apod.

S pokročilejším e-mailovým klientem bude možná potřeba kliknout na tlačítko, které vám před uložením patche do souboru umožní vidět e-mail v jeho originální nezformátované podobě.

Jsou zde drobné rozdíly na mboxu založených klientech, ale pokud používáte jeden z nich, pravděpodobně jste ten typ člověka, který je dokáže rozlousknout bez toho, aby četl tutoriály.

Promiňte, jsme jinde

V předchozích kapitolách jsme viděli, že po naklonování repozitáře git push i git pull automaticky nahrávají nebo stahují data do/z originálního repozitáře. Jak tohle Git dělá? Tajemství vězí v tom, jaké konfigurační volby jsou nastaveny při klonování. Omrkněme to:

$ git config --list

Volba remote.origin.url nám říká, jaká je URL zdroje; origin je přezdívka pro zdrojový repozitář. Stejně jako s větví master můžeme tuto přezdívku změnit nebo vymazat. Ale obvykle zde není žádný důvod, proč to dělat.

Jestliže se zdrojový repozitář přesune, můžeme upravit URL pomocí:

$ git config remote.origin.url NOVA_URL

Volba branch.master.merge specifikuje název výchozí vzdálené větve pro git pull. Při úvodním klonování je nastavena na současnou větev vzdáleného repozitáře, takže i když se HEAD původního repozitáře přesune na jinou větev, pozdější nahrání změn bude poctivě provedeno na původní větvi.

Tato volba se vztahuje pouze na repozitář, který jsme poprvé naklonovali, který je zaznamenán v branch.master.remote. Pokud chceme natáhnout data z jiného repozitáře, musíme explicitně určit, kterou větev chceme:

$ git pull JINA_URL master

To vysvětluje, proč některé z našich dřívějších příkladů nahrávání a stahování změn příležitostně potřebovali argumenty.

Vzdálené větve

Když naklonujete repozitář, naklonujete tím i všechny jeho větve. Možná jste si toho nevšimli, protože Git to dobře schovává – musíte se na ně ptát výslovně. Toto zabraňuje větvím ve vzdáleném repozitáři, aby se křížili s vašimi větvemi a zároveň to dělá Git jednodušším pro začátečníky.

Vzdálené větve vypíšete s:

$ git branch -r

Měli byste vidět něco jako:

origin/HEAD
origin/master
origin/experimental

Každá z nich zastupuje jednu větev a HEAD větev vzdáleného repozitáře. A mohou být použity s normálními příkazy Gitu. Například si předtavte, že jste udělali mnoho commitů a přejete si je porovnat s poslední staženou verzí. Mohli byste se prohrabávat logy a hledat ten pravý SHA1 hash, ale je mnohem jednodušší napsat:

$ git diff origin/HEAD

Nebo se můžete podívat, co to bylo s tou experimental větví:

$ git log origin/experimental

Více vzdálených repozitářů

Řekněme, že dva další vývojáři dělají na našem projektu a my chceme sledovat, co každý z nich dělá. Můžeme sledovat více jak jeden repozitář s:

$ git remote add dalsi DALSI_URL
$ git pull dalsi nejaka_vetev

Nyní náš repozitář splynul s větví z druhého repozitáře a máme jednoduchý přístup ke všem větvím všech repozitářů:

$ git diff origin/experimental^ dalsi/nejaka_vetev~5

Ale co když chceme jenom porovnat jejich změny bez toho, aby se to jakkoli dotklo naší práce? Jinými slovy, chceme prozkoumat jejich větve bez toho, aby jejich změny byly v našem pracovním adresáři. V tomto případě, radši než git pull, spusťte:

$ git fetch        # z origin, defaultní
$ git fetch dalsi  # od dalšího programátora

Toto vezme jejich historie, ale nic víc, takže i když pracovní adresář zůstane netknutý, můžeme ukazovat na jakoukoli větev repozitáře v Gitích příkazech. Jen tak mimochodem, mimo téma, git pull je prostě jenom git fetch následovaný git merge; sloučí pozdější commity do pracovního adresáře. Obvykle používáme pull, když chceme provést sloučení po natažení data, situace výše je výjimka z pravidla.

Podívejte se na git help remote pro to, abyste věděli, jak odstranit vzdálené repozitáře, ignorovat určité větve apod.

Commit změněného

Říkat Gitu, aby přidal, odstranil a přejmenoval soubory, je u některých projektů otravné. Místo toho můžete napsat:

$ git add .
$ git add -u

Git se podívá po souborech v současném adresáři a domyslí si detaily. Pokud chcete i provést commit místo druhého příkazu, spusťte git commit -a.

Předchozí můžete též udělat jedním dechem, a to následovně:

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Přepínače -z a -0 zabraňují nehezkým vedlejším efektům, obsahují-li jména souborů divné znaky. Pozor, tento příkaz přidává ignorované soubory, podívejte se po přepínačích -x a -X.

Můj commit je ták velký!

Zapomněli jste commitnout příliš dlouho? Zběsile jste kódovali a zapomněli na verzování až do teď? Udělali jste pár nesouvisejících změn, protože to je prostě váš styl?

Žádné obavy. Spusťte:

$ git add -p

Pro každou úpravu, kterou jste udělali, vám Git ukáže kousek kódu, který byl změněn, a zeptá se, jestli by měl být součástí přístího commitu. Odpovězte y (ano) nebo n (ne). Máte i jiné možnosti jako například odložit rozhodnutí; napište ?, abyste se dozvěděli více.

Jak jste hotovi, napište:

$ git commit

k odeslání přesně těch změn, které jste vybrali (změny v indexu). Dejte si pozor, abyste nepoužili přepínač -a, jiank Git commitne všechny úpravy.

Co kdybyste pozměnili hodně souborů na hodně místech? Prohlížet každou změnu jednu za druhou se stane frustrujícně nudné. V tomto případě použijte příkaz git add -i, jehož rozhraní je méně přímočaré, ale více flexibilní. S pár údery do kláves můžete přidat nebo odebrat z indexu několik souborů najednou, nebo prohlédnout a vybrat změny pouze v určitých souborech. Případně spusťte git commit --interactive, což automaticky odešle změny, jak jste hotovi.

Index

Doposud jsme se vyhýbali Gitímu slavnému indexu. Ale nyní se mu musíme postavit čelem, abychom mohli vysvětlit předchozí věci. Index je dočasné místo pro změny. Git zřídkakdy ukládá data přímo do historie. Radši je nejdříve zapíše do indexu a poté zkopíruje data z indexu do jejich konečného umístění.

Například git commit -a je popravdě dvoufázový proces. První krok vytvoří otisk současného stavu každého sledovaného souboru do indexu. Druhý krok navždy zaznamená otisk v indexu. Provést commit bez přepínače -a udělá pouze druhý krok a má smysl jedině tehdy, když jste již nějak změnili index, jako například pomocí git add.

Obvykle můžeme index ignorovat a předstírat, že čteme a zapisujeme přímo z/do historie. Ale v případech, jako byl ten výše, chceme lepší kontrolu nad tím, co se zapíše do historie, a tak jsme přinuceni pracovat s indexem. Zapíšeme do něj otisk některých, ne všech, našich změn a pak nadobro zapíšeme tento starostlivě vybraný otisk.

Neztrácejte HLAVU (HEAD)

Tag HEAD je jako kurzor, který normálně ukazuje na poslední commit, posunuje se s každým commitem. Některé příkazy Gitu vám umožní s ním hýbat. Kupříkladu:

$ git reset HEAD~3

posune HEAD o tři commity zpátky. A tudíž se budou všechny Gití příkazy chovat, jako byste neudělali tyto tři poslední commity, i když soubory zůstanou, jak jsou. Pro některá použití se podívejte se na stránku s nápovědou.

Ale teď, můžete se dostat zpátky do budoucnosti? commity v minulosti nevědí nic o budoucnosti.

Pokud máte SHA1 hash původní HEAD, pak:

$ git reset SHA1

Ale co, jste si ho nikam nepoznamenali? Nepanikařte, pro případy jako je tenhle Git uloží původní HEAD jako tag nazvaný ORIG_HEAD a můžete se na něj bezpečně navrátit pomocí:

$ git reset ORIG_HEAD

Lov na HEAD

Možná, že ORIG_HEAD není dostatečné. Možná jste si právě uvědomili, že jste udělali kolosální chybu a potřebujete se vrátit k prastarému commitu v dlouho zapomenuté větvi.

V základu si Git udržuje commit nejméně dva týdny, i když jste rozkázali Gitu, aby smazal větev, která ho obsahuje. Problém je najít odpovídající SHA1 hash. Můžete se podívat po všech hashích v .git/objects a metodou pokus-omyl najít ten, který chcete. Ale existuje mnohem jednodušší způsob.

Git zaznamenává každý hash commitu, který vypočítá, do .git/logs. Podadresář refs obsahuje historii veškeré aktivity na všech větvích, zatímco soubor HEAD ukazuje každý hash, který byl kdy vzat. Ten druhý se dá použít pro nalezení hashů commitů na větvích, které byly náhodně okleštěny.

Příkaz reflog poskytuje přátelské rozhraní pro tyto soubory. Zkuste:

$ git reflog

Místo kopírovní a vkládání hashů z reflogu, zkuste:

$ git checkout "@{10 minutes ago}"  # před 10 minutami

Nebo checkoutněte pátý poslední commit pomocí:

$ git checkout "@{5}"

Pro více informací se podívejte na sekci „Specifying Revisions“ v git help rev-parse.

Možná si budete přát nastavit delší čas, než budou commity nadobro zatraceny. Například:

$ git config gc.pruneexpire "30 days"

znamená, že odstraněné commity budou navždy vymazány každých 30 dní nebo zavoláním git gc.

Taky byste si mohli přát, aby se git gc nespouštělo automaticky:

$ git config gc.auto 0

což zapříčiní, že commity budou nadobro smazány jen tehdy, když spustíte git gc ručně.

Stavíme na Gitu

Ve stylu UNIXu návrh Gitu dovoluje, aby byl jednoduše používán jako nízkoúrovňová komponenta jiných programů, jako například GUI a webová rozhraní, alternativní řádková rozhraní, nástroje pro správu patchů, importační a konvertovací nástroje atd. Ve skutečnosti některé Gití příkazy jsou sami o sobě skripty stojící na ramenou obrů. S trochou práce můžete poupravovat Git, aby vyhovoval vašim potřebám.

Jeden jednoduchý trik jsou vestavěné Gití aliasy ke zkrácení nejčastěji používaných příkazů:

$ git config --global alis.co checkout
$ git config --global --get-regexp alias  # zobrazit současné aliasy
alias.co checkout
$ git co foo                              # stejné jako 'git checkout foo'

Jiný je pro vytištění současné větve v promptu, nebo titulku okna. Vyvoláním:

$ git symbolic-ref HEAD

získáme současné jméno větve. V praxi nejspíše chcete, aby na začátku nebylo refs/heads/ a ignorovat chyby:

$ git symbolic-ref HEAD 2> /dev/null | cut -b 12-

Podadresář contrib je studnice pokladů z příkazů postavených na Gitu. Časem se některé z nich mohou stát oficiálními příkazy. V Debianu a Ubuntu je tento adresář v /usr/share/doc/git-core/contrib.

Jeden populární je v workdir/git-new-workdir. Skrz chytré linky tento skript vytvoří nový pracovní adresář, jehož historie je sdílená s původním repozitářem:

$ git-new-workdir existující/repo nový/adresář

O novém adresáři a souborech v něm může být přemýšleno jako o klonu s tím, že historie je sdílená, oba stromy zůstávají synchronizované. Není žádná potřeba pro merge, push, nebo pull.

Troufalé kousky

V dnešních dnech je složité, aby uživatel náhodně zničil data v Gitu. Ale pokud víte, co děláte, můžete potlačit zabezpečení pro běžné příkazy.

checkout: Necommitnuté změny způsobí, že checkout neuspěje. Ke zničení vašich změn a provedení checkoutu přesto, že jsou tu nějaké neuložené změny, použijte přepínač force:

$ git checkout -f COMMIT

Na druhou stranu, pokud specifikujete určitou cestu pro checkout, nejsou zde žádné bezpečnostní kontroly. Předané cesty jsou potichu přepsány. Dávejte si pozor, když děláte checkout takto.

reset: reset taky skončí, pokud jsou přítomny necommitnuté změny. Když chcete toto omezení obejít, spusťte:

$ git reset --hard [COMMIT]

branch: mazání větví selže, pokud by mělo způsobit ztrátu dat. Pokud chcete Git přinutit, aby větev vymazal, napište:

$ git branch -D VETEV  # -D místo -d

Podobně pokus přepsání větve pomocí přejmenování selže, pokud by z toho vyplynula ztráta dat. Aby byla i přesto větev přesunuta, napište:

$ git branch -M [ZDROJOVA] CILOVA  # -M místo -m

Narozdíl od checkoutu a resetu tyto dva příkazy odkládají zničení dat. Změny jsou stále uloženy v podadresáři .git a mohou být získány obnovením odpovídajícího hashe z .git/logs (viz „Lov na HLAVU“ výše). Standardně budou uchovány nejméně dva týdny.

clean: Některé Gití příkazy odmítají dokončit svou práci, protože se bojí, že by zašantročili nesledované soubory. Pokud jste si jisti, že všechny nesledované soubory a adresáře jsou postradatelné, pak je bezlítostně vymažte pomocí:

$ git clean -f -d

Příště ten ohavný příkaz bude fungovat!

Tento článek je překladem šesté kapitoly – Git Grandmastery [ http://www-cs-students.stanford.edu/~blynn/gitmagic/ch06.html ] – z GitMagic [ http://www-cs-students.stanford.edu/~blynn/gitmagic/ ] od Bena Lynna. Další kapitola se bude zabývat tím, jak Git vlastně funguje.


Článek stažen z webu Programujte.com [ http://programujte.com/clanek/2009062000-gitmagic-6-velmistrovstvi-v-gitu/ ].