Git
Chapters ▾ 2nd Edition

5.3 Distribuovaný Git - Správa projektu

Správa projektu

K znalosti toho, jak lze do projektu efektivně přispívat, budete pravděpodobně muset vědět, jak ho spravovat. Spadá sem přijímání a aplikování záplat generovaných příkazem format-patch a zaslaných elektronickou poštou, nebo integrování změn ve vzdálených větvích pro repozitáře, které jste do svého projektu přidali jako vzdálené repozitáře. Ať už spravujete obecně uznávaný repozitář, nebo chcete pomáhat při ověřování či schvalování záplat, budete muset vědět, jak přijímat práci ostatních přispěvatelů způsobem, který je pro ostatní přispěvatele co nejčistší a pro vás dlouhodobě udržitelný.

Práce v tématických větvích

Pokud uvažujete o integraci nové práce do projektu, je většinou dobré vyzkoušet si to v tématické větvi, tj. v dočasné větvi, kterou vytvoříte konkrétně pro vyzkoušení této práce. Tímto způsobem můžete záplatu odděleně doladit, a pokud není funkční, můžete ji nechat být až do doby, kdy najdete čas se k ní vrátit. Pokud pro větev vytvoříte jednoduchý název spojený s tématem testované práce (například ruby_client nebo něco obdobně popisného), snadno si zase vzpomenete, pokud ji na nějakou dobu opustíte a vrátíte se k až tomu později. Správce projektu v Gitu má sklony přidělovat těmto větvím také jmenný prostor — například sc/ruby_client, kde sc je zkratka pro osobu, která práci vytvořila. Jak si vzpomínáte, můžete větev založenou na své větvi master vytvořit takto:

$ git branch sc/ruby_client master

Nebo, pokud na ni chcete rovnou přepnout, můžete použít volbu checkout -b:

$ git checkout -b sc/ruby_client master

Teď jste připraveni svůj příspěvek do této tématické větve přidat a rozhodnout se, zda ji začleníte do své větve s delší životností.

Aplikace záplat zaslaných elektronickou poštou

Pokud elektronickou poštou obdržíte záplatu, kterou potřebujete integrovat do svého projektu, budete ji chtít aplikovat do tématické větve, kde ji posoudíte. Záplatu zaslanou elektronickou poštou lze aplikovat dvěma způsoby: příkazem git apply nebo příkazem git am.

Aplikace záplaty příkazem apply

Pokud dostanete záplatu od někoho, kdo ji vygeneroval příkazem git diff nebo unixovým příkazem diff (což se nedoporučuje — viz následující část), můžete ji aplikovat příkazem git apply. Za předpokladu, že jste záplatu uložili jako /tmp/patch-ruby-client.patch, můžete záplatu aplikovat následovně:

$ git apply /tmp/patch-ruby-client.patch

Tím se soubory ve svém pracovním adresáři změní. Je to téměř stejné, jako byste k aplikaci záplaty použili příkaz patch -p1. Příkaz apply je ale víc paranoidní a přijímá méně přibližných shod než příkaz patch. Poradí si také s přidanými, odstraněnými a přejmenovanými soubory, jsou-li popsány ve formátu git diff, což by příkaz patch neudělal. A konečně příkaz git apply pracuje na principu „aplikuj vše, nebo zruš vše“. Buď jsou tedy aplikovány všechny soubory, nebo žádný. Naproti tomu příkaz patch může aplikovat soubory záplat jen částečně a tím zanechat váš pracovní adresář v podivném stavu. Příkaz git apply je celkově konzervativnější než příkaz patch. Tímto příkazem se nezapíše revize. Po jeho provedení budete muset připravit a zapsat provedené změny ručně.

Příkaz git apply můžete použít také ke kontrole, zda bude záplata aplikována čistě ještě před tím, než skutečnou aplikaci provedete. V takovém případě pro záplatu použijte příkaz git apply --check:

$ git apply --check 0001-seeing-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply

Pokud se nezobrazí žádný výstup, bude záplata aplikována čistě. Jestliže kontrola selže, vrací příkaz nenulový návratový kód, a proto ho můžete snadno používat ve skriptech.

Aplikace záplaty příkazem am

Pokud je přispěvatel uživatelem Gitu a byl natolik dobrý, že k vygenerování záplaty použil příkaz format-patch, budete mít usnadněnou práci, protože záplata obsahuje informace o autorovi a zprávu k revizi. Můžete-li, doporučte svým přispěvatelům, aby místo příkazu diff používali příkaz format-patch. K použití příkazu git apply byste měli být nuceni jen v případě použití starého typu záplat.

K aplikaci záplaty vygenerované příkazem format-patch používejte příkaz git am. Z technického hlediska je git am navržen tak, aby četl soubor ve formátu elektronické pošty (mbox), což je jednoduchý textový formát pro uložení jedné nebo více e-mailových zpráv do jednoho textového souboru. Vypadá například takto:

From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

Toto je začátek výstupu příkazu format-patch, který jste viděli v předchozí části. Zároveň je to také platný e-mailový formát mbox. Pokud vám někdo poslal záplatu příkazem git send-email a vy záplatu stáhnete do formátu mbox, můžete tento soubor mbox předat příkazu git am a ten začne aplikovat všechny záplaty, které najde. Jestliže spustíte poštovního klienta, který dokáže uložit několik e-mailů ve formátu mbox, můžete do jednoho souboru uložit celou sérii záplat a příkazem git am je pak aplikovat všechny najednou.

Pokud však někdo nahrál soubor záplaty vygenerovaný příkazem format-patch do tiketového nebo podobného systému, můžete soubor uložit lokálně a poté jej aplikovat předáním uloženého souboru příkazu git am:

$ git am 0001-limit-log-function.patch
Applying: add limit to log function

Jak vidíte, záplata byla aplikována čistě a automaticky byla vytvořena nová revize. Informace o autorovi jsou převzaty z hlavičkových polí e-mailu From a Date, zpráva k revizi je převzata z pole Subject a těla e-mailu (před samotnou záplatou). Pokud byla záplata aplikována například ze souboru mbox z předchozího příkladu, bude vygenerovaná revize vypadat zhruba takto:

$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author:     Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit:     Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700

   add limit to log function

   Limit log functionality to the first 20

Informace Commit uvádí osobu, která záplatu aplikovala, a čas, kdy se tak stalo. Informace Author uvádí jedince, který záplatu původně vytvořil, a kdy tak učinil.

Může se ale stát, že záplata nebude aplikována čistě. Vaše hlavní větev se mohla příliš odchýlit od větve, z níž byla záplata vytvořena, nebo je záplata závislá na jiné záplatě, kterou jste ještě neaplikovali. V takovém případě proces git am selže a zeptá se vás, co chcete udělat dál:

$ git am 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".

Tento příkaz vloží značky konfliktu do všech problematických souborů — podobně jako při konfliktu u operací sloučení (merge) nebo přeskládání (rebase). Problém se řešíte v podstatě stejným způsobem. Úpravou souboru konflikt odstraňte, připravte nový soubor k zapsání a spusťte příkaz git am --resolved, čímž se přesunete k následující záplatě:

$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: seeing if this helps the gem

Pokud chcete, aby se Git pokusil vyřešit konflikt inteligentněji, můžete zadat volbu -3. Git se pokusí o třícestné sloučení. Tato možnost není nastavena jako výchozí, protože ji nelze použít v situaci, kdy revize, o níž záplata říká, že je na ní založena, není obsažena ve vašem repozitáři. Pokud ale tuto revizi k dispozici máte — záplata byla založena na veřejné revizi — vede volba -3 k mnohem inteligentnější aplikaci kolidující záplaty:

$ git am -3 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.

V tomto případě už byla záplata aplikována. Bez volby -3 by to vypadalo jako konflikt.

Pokud aplikujete několik záplat z jednoho souboru mbox, můžete příkaz am spustit také v interaktivním režimu, který zastaví před každou nalezenou záplatou a zeptá se vás, zda ji chcete aplikovat:

$ git am -3 -i mbox
Commit Body is:
--------------------------
seeing if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all

To oceníte v situaci, kdy už máte uložených více záplat, protože pokud si nepamatujete, o co v záplatě jde, můžete si ji před aplikací prohlédnout a neaplikovat ji, pokud už jste tak učinili dříve.

Až budete mít všechny záplaty aplikovány a zapsány do tématické větve, můžete se rozhodnout, zda a jak je chcete integrovat do některé z trvalejších větví.

Získání vzdálených větví (checkout)

Pokud váš příspěvek pochází od uživatele Gitu, který založil vlastní repozitář, odeslal do něj sérii změn a následně vám poslal adresu repozitáře (URL) a název vzdálené větve, v níž změny najdete, můžete je přidat jako vzdálené a lokálně je začlenit.

Pokud vám například Jessica poslala dopis, že ve svém repozitáři ve větvi ruby-client vytvořila skvělou novou funkci, můžete si ji po přidání vzdáleného repozitáře a po získání obsahu zmíněné větve otestovat lokálně:

$ git remote add jessica git://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client

Pokud vám později znovu napíše, že jiná větev obsahuje další skvělou funkci, můžete tuto větev vyzvednout a získat její obsah, protože už repozitář máte nastaven jako vzdálený.

Užitečné je to zejména tehdy, když s někým spolupracujete dlouhodobě. Pokud někdo přispěje jen sem tam jednou záplatou, pak bude časově výhodnější, když vám ji pošle e-mailem, než abyste všechny přispěvatele kvůli pár záplatám nutili zprovoznit si vlastní server a abyste si stále přidávali a odstraňovali vzdálené repozitáře. Asi byste taky nechtěli spravovat stovky vzdálených repozitářů — jeden pro každého, kdo přispěje jednou či dvěma záplatami. Ale skripty a hostované služby tento přístup mohou velmi usnadnit. Do velké míry tu záleží na tom, jak vy a vaši vývojáři k vývoji přistupujete.

Další výhodou tohoto postupu je, že získáte rovněž historii revizí. I když můžete při slučování narazit na opodstatněné problémy, víte, z jakých historických základů jejich práce vychází. Řádné třícestné sloučení je vždy lepším řešením, než nutnost zadat volbu -3 a doufat, že byla záplata vygenerována z veřejné revize, kterou máte k dispozici.

Pokud s někým nespolupracujete dlouhodobě, ale přesto od něj chcete stáhnout data tímto způsobem, můžete zadat URL vzdáleného repozitáře k příkazu git pull. Provede se jednorázové stažení a URL se neuloží jako odkaz na vzdálený repozitář:

$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
 * branch            HEAD       -> FETCH_HEAD
Merge made by recursive.

Jak zjistit provedené změny

Máte tématickou větev, která obsahuje příspěvek od jiného vývojáře. V tomto okamžiku můžete určit, co byste s ním rádi udělali. V této části si zopakujeme několik příkazů, abyste viděli, jak se dají použít k přesnému zjištění toho, co se v případě sloučení (merge) dostane do vaší hlavní větve.

Často může být užitečné získat přehled o všech revizích, které jsou obsaženy v určité větvi, ale nejsou ve vaší větvi master. Revize ve větvi master lze vyloučit přidáním volby --not před název větve. Činnost je stejná jako při uvedení tvaru master..contrib, který jsme použili dříve. Pokud vám například přispěvatel pošle dvě záplaty a vy vytvoříte větev s názvem contrib, do níž tyto záplaty aplikujete, můžete spustit následující příkaz:

$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Oct 24 09:53:59 2008 -0700

    seeing if this helps the gem

commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date:   Mon Oct 22 19:38:36 2008 -0700

    updated the gemspec to hopefully work better

Chcete-li zjistit, jaké změny byly provedeny v jednotlivých revizích, můžete k příkazu git log přidat volbu -p, která ke každé revizi připojí rozdíly ve formátu diff.

Chcete-li vidět úplný výpis rozdílů, které by vznikly sloučením této tématické větve s jinou větví, budete muset pro obdržení správných výsledků použít zvláštní trik. Možná vás napadne, že byste spustili příkaz:

$ git diff master

Výstupem příkazu bude výpis rozdílů, ale může být zavádějící. Pokud se vaše větev master posunula vpřed od chvíle, kdy jste z ní vytvořili tématickou větev, dostanete zdánlivě nesmyslné výsledky. Je to tím, že Git přímo porovnává snímek poslední revize v tématické větvi, na které se nacházíte, se snímkem poslední revize ve větvi master. Pokud jste například do souboru ve větvi master přidali jeden řádek, přímé srovnání snímků bude vypadat, jako kdyby měla tématická větev tento řádek odstranit.

Pokud je větev master přímým předkem vaší tématické větve, nebude s příkazem žádný problém. Pokud se však obě historie v nějakém bodě rozdělily, bude výpis rozdílů vypadat, jako kdybyste chtěli přidat všechny nové věci v tématické větvi a odstranit vše, co je pouze ve větvi master.

To, co opravdu chcete vidět, jsou změny přidané do tématické větve — tj. práci, která se objeví v případě, že provedete začlenění této větve do větve master. Dosáhnete toho tak, že necháte Git porovnat poslední revizi z tématické větve s nejbližším společným předchůdcem sdíleným s větví master.

Šlo by to udělat tak, že explicitně najdete společného předka obou větví a spustíte pro něj příkaz diff:

$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db

Ale není to moc praktické, a proto Git nabízí pro provedení stejné činnosti jinou zkratku: trojtečkovou syntaxi. V souvislosti s příkazem diff můžete za jméno druhé větve připsat tři tečky a pak jméno aktuální větve. Zjistí se tím změny mezi poslední revizí v aktuální větvi a společným předkem s druhou větví:

$ git diff master...contrib

Tento příkaz zobrazí pouze práci, která byla ve vaší aktuální tématické větvi provedena od chvíle, kdy se oddělila od hlavní větve. Tento velmi užitečný zápis stojí za zapamatování.

Integrace příspěvků

Když už je práce v tématické větvi připravena k integraci do některé z významnějších větví, vyvstává otázka, jak to provést. Kromě toho, jaký celkový pracovní postup chcete při správě projektu používat? Můžete si vybrat z řady možností, takže se na pár z nich podíváme.

Pracovní postupy založené na slučování

Jeden z jednoduchých pracovních postupů používá začleňování vaší práce do vaší větve master. V tomto scénáři máte svou větev master, která obsahuje v podstatě stabilní kód. Pokud mátě v tématické větvi nějakou práci, kterou jste vytvořili sami, nebo kterou přispěl někdo jiný a vy jste ji ověřovali, začleníte ji do své větve master (merge), odstraníte tématickou větev a pokračujete dál. Máme-li repozitář s prací ve dvou větvích pojmenovaných ruby_client a php_client, který vypadá jako na obrázku Historie s několika tématickými větvemi., a začleníme nejprve větev ruby_client a poté php_client, bude naše historie vypadat jako na obrázku Po začlenění tématické větve..

Historie s několika tématickými větvemi.
Figure 73. Historie s několika tématickými větvemi.
Po začlenění tématické větve.
Figure 74. Po začlenění tématické větve.

Jde nejspíš o nejjednodušší pracovní postup, ale může vést k problémům v případě, že se použije pro větší nebo stabilnější projekty, u kterých chcete být při vkládání nových věcí opravdu opatrní.

U důležitějších projektů asi budete chtít použít dvoufázový cyklus slučování[18]. V tomto scénáři máte dvě větve s dlouhou životností: hlavní větev master a větev develop. Určíte, že větev master bude aktualizována, pouze když je k dispozici velmi stabilní verze. Veškerý nový kód je integrován do větve develop. Obě tyto větve pravidelně odesíláte do veřejného repozitáře. Pokaždé, když máte novou tématickou větev nachystanou k začlenění (obrázek Před začleněním tématické větve.), začleníte ji do větve develop (obrázek Po začlenění tématické větve.), označíte vydání (tag) a poté posunete větev master rychle vpřed do místa, kde je nyní větev develop stabilní (obrázek Po vydání nové verze projektu.).

Před začleněním tématické větve.
Figure 75. Před začleněním tématické větve.
Po začlenění tématické větve.
Figure 76. Po začlenění tématické větve.
Po vydání nové verze projektu.
Figure 77. Po vydání nové verze projektu.

Pokud někdo při takovém přístupu naklonuje repozitář vašeho projektu, může se buď přepnout na větev master s cílem přeložit si poslední stabilní verzi a snadno ji udržovat aktuální, nebo se může přepnout na větev develop, která obsahuje nejpokročilejší funkčnost. Tento koncept můžete dále rozšířit o integrační větev, v níž budete veškerou práci slučovat. Teprve pokud je kód v této větvi stabilní a projde testováním, začleníte ho do větve develop. A až se větev develop ukáže v některém okamžiku jako stabilní, posunete rychle vpřed i svou větev master.

Pracovní postupy se začleňováním velkého objemu dat

Váš gitový projekt má čtyři větve s dlouhou životností: master, next a pu (proposed updates, čili navrhované úpravy) pro novou práci a maint pro přenos oprav z novějších verzí do starších (maintenance backports). Pokud přispěvatelé vytvoří novou práci, je shromažďována v tématických větvích v repozitáři správce podobným způsobem, jaký jsme popsali dříve (viz obrázek Správa komplexní série paralelně zpracovávaných příspěvků v tématických větvích.). V této fázi jsou náměty vyhodnoceny a určí se, zda jsou bezpečné a zralé k použití, nebo zda potřebují dopracovat. Pokud jsou bezpečné, jsou začleněny do větve next a ta je odeslána do sdíleného repozitáře, aby si všichni mohli vyzkoušet výsledek jejich integrace.

Správa komplexní série paralelně zpracovávaných příspěvků v tématických větvích.
Figure 78. Správa komplexní série paralelně zpracovávaných příspěvků v tématických větvích.

Pokud nějaké téma ještě vyžaduje dopracování, je místo toho začleněno do větve pu. Pokud se ukáže, že jsou tyto tématické větve naprosto stabilní, budou začleněny do větve master a poté budou znovu sestaveny z tématických větví, které byly ve větvi next, ale ještě se nedostaly do větve master. To znamená, že se větev master téměř vždy posouvá vpřed, větev next je čas od času přeskládána a větev pu je přeskládávána o něco častěji:

Začlenění tématických větví s příspěvky do integračních větví s dlouhou životností.
Figure 79. Začlenění tématických větví s příspěvky do integračních větví s dlouhou životností.

Pokud se tématická větev nakonec začlení do větve master, z repozitáře se odstraní. Projekt Git má kromě toho větev maint, která byla odštěpena z posledního vydání a obsahuje záplaty přenesené z vyšších verzí (backport) pro případ, že by bylo třeba vydat opravnou verzi. Pokud tedy klonujete repozitář Git, můžete se přepnout do čtyř větví a podívat se na projekt v různých fázích vývoje — v závislosti na tom, jak čerstvou verzi chcete nebo jak chcete přispívat. A správce projektu má k dispozici strukturovaný pracovní postup k posouzení nových příspěvků.

Pracovní postupy s přeskládáním a s částečným převzetím revizí

Někteří správci dávají místo začlenění práce z příspěvků (merge) přednost přeskládání (rebase) nebo částečnému převzetí (cherry pick) do větve master, čímž udržují historii téměř lineární. Máte-li hotovou práci v tématické větvi a rozhodli jste se, že ji chcete integrovat, přejdete na tuto větev a spustíte příkaz rebase, jímž znovu sestavíte příslušné změny na vrcholu své aktuální větve master (nebo větve develop a podobně). Pokud vše funguje, můžete větev master posunout rychle vpřed a výsledkem procesu bude lineární historie projektu.

Druhým způsobem, jak přesunout práci z jedné větve do druhé, je tzv. částečné převzetí (angl. cherry picking[19]). Částečné převzetí lze v systému Git přirovnat k přeskládání jediného objektu revize. Vezme se záplata, která byla provedena v dané revizi, a zkusí se znovu aplikovat na větev, na níž se právě nacházíte. Využijete to v situaci, kdy tématická větev obsahuje několik revizí a chcete integrovat pouze jednu z nich, nebo když máte v tématické větvi jediný objekt revize a dáváte přednost použití cherry-pick před provedením rebase. Dejme tomu, že máte projekt, který vypadá nějak takto:

Příklad historie před provedením cherry-pick.
Figure 80. Příklad historie před provedením cherry-pick.

Chcete-li do hlavní větve stáhnout revizi e43a6, můžete zadat následující příkaz:

$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
 3 files changed, 17 insertions(+), 3 deletions(-)

Tím se stáhne stejná změna, která byla uvedena v revizi e43a6, ale hodnota SHA-1 obou revizí se bude lišit, protože se bude lišit datum. Vaše historie teď vypadá nějak takto:

Historie po částečném převzetí revize z tématické větve.
Figure 81. Historie po částečném převzetí revize z tématické větve.

Teď můžete tématickou větev odstranit a zahodit revize, které nehodláte vtáhnout do jiné větve.

Rerere

Pokud provádíte velké množství operací slučování a přeskládání, nebo pokud spravujete tématické větve s dlouhou životností, může vám pomoci vlastnost Gitu zvaná „rerere“.

Rerere znamená „reuse recorded resolution“, čili „znovupoužití zaznamenaného řešení“. Jde o způsob jak si zjednodušit ruční řešení konfliktu. Pokud je mechanismus rerere povolen, uchovává Git sadu obrazů před a po úspěšných sloučeních. Pokud si Git všimne, že konflikt vypadá přesně jako ten, který jste už vyřešili, použije vaše řešení z minula a nebude vás tím zatěžovat.

Uvedený rys má dvě části: konfigurační nastavení a příkaz. Konfigurační nastavení se jmenuje rerere.enabled a je dost šikovné na to, abyste je umístili do globální konfigurace:

$ git config --global rerere.enabled true

Kdykoliv teď provedete sloučení, které řeší konflikt, zaznamená se řešení do mezipaměti pro případ, že bychom ho v budoucnu potřebovali.

V případě potřeby můžete s mezipamětí pro rerere pracovat pomocí příkazu git rerere. Pokud je vyvolán bez parametru, prochází Git svou databázi řešení a pokouší se najít shodu s konflikty při aktuální operaci slučování a vyřešit je (i když při nastavení rerere.enabled na hodnotu true se to dělá automaticky). Existují i varianty příkazu pro případy, kdy chceme zobrazit, co se bude zaznamenávat, když chceme odstranit určité řešení z mezipaměti a když chceme celou mezipaměť vymazat. Příkazem rerere se budeme podrobněji zabývat v podkapitole Rerere.

Označení vydání značkou

Když jste se rozhodli vydat určitou verzi, pravděpodobně ji budete chtít označit, abyste mohli toto vydání v kterémkoli okamžiku v budoucnosti obnovit. Novou značku můžete vytvořit způsobem, který jsme probrali v kapitole Základy práce se systémem Git. Pokud se rozhodnete značku podepsat jako správce, bude označení probíhat takto:

$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09

Pokud své značky podepisujete, můžete mít problémy s distribucí veřejného klíče PGP použitého k podepsání značky. Správce projektu Git vyřešil tento problém tak, že přidal svůj veřejný klíč jako blob do repozitáře a poté vložil značku, která ukazuje přímo na tento obsah. Pomocí příkazu gpg --list-keys můžete určit, jaký klíč chcete:

$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub   1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid                  Scott Chacon <schacon@gmail.com>
sub   2048g/45D02282 2009-02-09 [expires: 2010-02-09]

Poté můžete klíč přímo importovat do gitové databáze: vyexportujte ho a výsledek předáte příkazu git hash-object, který zapíše nový blob s tímto obsahem do systému Git a vrátí vám otisk SHA-1 tohoto blobu:

$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92

Teď máte v Gitu obsah svého klíče a můžete vytvořit značku, která bude ukazovat přímo na něj s tím, že zadáte novou hodnotu SHA-1, kterou vám vrátil příkaz hash-object:

$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92

Pokud provedete příkaz git push --tags, začnete značku maintainer-pgp-pub sdílet s ostatními. Když bude chtít kdokoliv nějakou značku ověřit, může přímo importovat váš klíč PGP tak, že stáhne blob přímo z databáze a naimportuje ho do programu GPG:

$ git show maintainer-pgp-pub | gpg --import

Klíč pak může použít k ověření všech vašich podepsaných značek. Pokud navíc zadáte do zprávy značky další instrukce k jejímu ověření, může si je koncový uživatel zobrazit příkazem git show <značka>.

Vygenerování čísla sestavení

Git nepoužívá pro jednotlivé revize monotónně rostoucí čísla jako „v123“ nebo něco podobného. Pokud chcete získat čitelnou podobu jména revize, můžete pro daný objekt revize spustit příkaz git describe[20]. Git vám vrátí název nejbližší značky, který doplní počtem revizí za touto značkou a částečnou hodnotou SHA-1 popisovaného objektu revize:

$ git describe master
v1.6.2-rc1-20-g8c5b85c

Díky tomu lze pro snímek nebo sestavení (build) při exportu použít jméno, které je pro člověka trochu srozumitelné. Pokud překládáte Git ze zdrojového kódu naklonovaného z repozitáře projektu Git, získáte ve skutečnosti po spuštění příkazu git --version něco, co vypadá podobně. Pokud získáváte popis objektu revize, který jste právě opatřili značkou, vrátí příkaz název této značky.

Příkaz git describe upřednostňuje anotované značky (značky vytvořené s příznakem -a nebo -s). Pokud tedy používáte příkaz git describe, měli byste značky vytvářet právě tímto způsobem, čímž si při získávání popisu objektu revize zajistíte vhodné pojmenování. Tento řetězec můžete také použít jako cíl příkazů checkout nebo show, ačkoli ty spoléhají na část se zkrácenou hodnotou SHA-1, a proto nemusí platit navždy. Například jádro Linuxu nyní přešlo z 8 na 10 znaků SHA-1, aby byla zajištěna jedinečnost identifikace objektů. Starší výstupy příkazu git describe tím byly zneplatněny.

Příprava vydání

Nyní budete chtít sestavení vydat. Jednou z věcí, kterou budete chtít udělat, je vytvoření archivu nejnovějšího snímku vašeho kódu pro všechny nebohé duše, které Git nepoužívají. Příkaz pro vytvoření archivu zní git archive[21]:

$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz

Pokud někdo tento tarball otevře, získá nejnovější snímek vašeho projektu uvnitř adresáře projektu. V podstatě stejným způsobem můžete vytvořit také archiv zip tím, že k příkazu git archive přidáte volbu --format=zip:

$ git archive master --prefix='project/' --format=zip > `git describe master`.zip

Nyní máte vytvořen tarball a archiv zip s novou verzí projektu. Můžete je nahrát na příslušnou webovou stránku nebo rozeslat elektronickou poštou.

Příkaz „shortlog“

Nyní je na čase obeslat přes poštovní konferenci lidi, kteří chtějí vědět, co je ve vašem projektu nového. Seznam změn (changelog), které byly do projektu přidány od posledního vydání nebo e-mailu, lze rychle a elegantně získat příkazem git shortlog. Příkaz shrne popis všech revizí v zadaném rozmezí. Pokud bylo vaše poslední vydání pojmenováno v1.0.1, zobrazí následující příkaz shrnutí změn ve všech novějších revizích:

$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (8):
      Add support for annotated tags to Grit::Tag
      Add packed-refs annotated tag support.
      Add Grit::Commit#to_patch
      Update version and History.txt
      Remove stray `puts`
      Make ls_tree ignore nils

Tom Preston-Werner (4):
      fix dates in history
      dynamic version method
      Version bump to 1.0.2
      Regenerated gemspec for version 1.0.2

Výstupem příkazu je shrnutí všech revizí od v1.0.1 (seskupené podle autora), které můžete přes poštovní konferenci rozeslat.