Git
Chapters ▾ 1st Edition

5.3 Rozproszony Git - Utrzymywanie projektu

Utrzymywanie projektu

Ponad to co musisz wiedzieć, aby efektywnie uczestniczyć w projekcie, powinieneś również wiedzieć jak go utrzymywać. Składa się na to akceptowanie i nakładanie łat wygenerowanych przez format-patch i wysłanych do Ciebie, lub łączenie zmian z zewnętrznych repozytoriów które dodałeś w projekcie. Nieważne czy prowadzisz zwykłe repozytorium, lub chcesz pomóc przy weryfikacji i integrowaniu łat, musisz wiedzieć w jaki sposób akceptować zmiany innych w taki sposób, który będzie przejrzysty dla innych i spójny w dłuższym okresie.

Praca z gałęziami tematycznymi

Jeżeli zamierzasz włączyć nowe zmiany, dobrym pomysłem jest stworzenie do tego nowej tymczasowej gałęzi, specjalnie przygotowanej do tego, aby przetestować te zmiany. W ten sposób najłatwiej dostosować pojedyncze zmiany, lub zostawić je jeżeli nie działają, do czasu aż będziesz mógł się tym ponownie zająć. Jeżeli stworzysz nową gałąź bazując na głównym motywie wprowadzanych zmian które chcesz przetestować, np. ruby_client lub coś podobnego, możesz łatwo zapamiętać czy musiałeś ją zostawić aby później do niej wrócić. Opiekun projektu Git często tworzy oddzielną przestrzeń nazw dla nich - np. sc/ruby_client, gdzie sc jest skrótem od osoby która udostępniła zmianę. Jak pamiętasz, możesz stworzyć nową gałąź bazując na swojej gałęzi master, w taki sposób:

$ git branch sc/ruby_client master

Lub, jeżeli chcesz się od razu na nią przełączyć, możesz użyć komendy checkout -b:

$ git checkout -b sc/ruby_client master

Teraz jesteś gotowy do tego, aby dodać do niej udostępnione zmiany i zdecydować czy chcesz je włączyć do jednej ze swoich gałęzi.

Aplikowanie łat przychodzących e-mailem

Jeżeli otrzymasz łatę poprzez wiadomość e-mail, którą musisz włączyć do swojego projektu, musisz zaaplikować ją do gałęzi tematycznej w celu przetestowania. Istnieją dwa sposoby aby włączyć takie zmiany: przy użyciu git apply lub git am.

Aplikowanie łaty za pomocą komendy apply

Jeżeli otrzymałeś łatę od kogoś kto wygenerował ją za pomocą komendy git diff lub uniksowej diff, możesz zaaplikować ją za pomocą komendy git apply. Zakładając, że zapisałeś plik w /tmp/patch-ruby-client.patch, możesz go nałożyć w taki sposób:

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

Ta komenda zmodyfikuje pliki znajdujące się w obecnym katalogu. Jest ona prawie identyczna do komendy patch -p1 w celu nałożenia łaty, ale jest bardziej restrykcyjna pod względem akceptowanych zmian. Obsługuje również dodawanie plików, usuwanie, oraz zmiany nazw jeżeli zostały zapisane w formacie git diff, czego komenda patch nie zrobi. Wreszcie, git apply ma zasadę "zaakceptuj lub odrzuć wszystko", gdzie albo wszystko jest zaakceptowane albo nic, a patch może częściowo nałożyć zmiany zostawiając projekt z niespójnym stanem. Komenda git apply jest z zasady bardziej restrykcyjna niż patch. Nie stworzy za Ciebie commita - po uruchomieniu, musisz zatwierdzić wprowadzone zmiany ręcznie.

Możesz również użyć git apply aby zobaczyć, czy łata nałoży się czysto zanim ją zaaplikujesz - jeżeli uruchomiesz git apply --check z łatą:

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

Jeżeli nie zostanie wygenerowany żaden komunikat, to łata nałoży się poprawnie. Ta komenda również kończy działanie z niezerowym statusem w przypadku błędu, możesz więc użyć jej w skryptach jeżeli tylko chcesz.

Aplikowanie łaty za pomocą am

Jeżeli otrzymałeś łatę wygenerowaną przez użytkownika używającego Gita, który stworzył go za pomocą format-patch, twoja praca będzie prostsza ponieważ łatka zawiera już informacje o autorze oraz komentarz do zmiany. Jeżeli możesz, namawiaj swoich współpracowników aby używali format-patch zamiast diff do generowania dla Ciebie łat. Powinieneś móc użyć jedynie git apply dla takich łat.

Aby zaaplikować łatę wygenerowaną przez format-patch, użyj git am. Technicznie rzecz biorąc, git am został stworzony, aby odczytywać plik w formacie mbox, który jest prostym, tekstowym formatem zawierającym jedną lub więcej wiadomości e-mail w jednym pliku. Wygląda on podobnie do:

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

To są pierwsze linie z wyniku komendy format-patch którą zobaczyłeś w poprzedniej sekcji. Jest to również poprawny plik w formacie mbox. Jeżeli ktoś poprawnie przesłał do Ciebie łatkę za pomocą git send-email, możesz ją zapisać w formacie mbox, następnie wskazać git am ten plik, a git zacznie aplikować wszystkie łatki które znajdzie. Jeżeli używasz klienta pocztowego, który potrafi zapisać kilka wiadomości e-mail w formacie mbox, możesz zapisać serię łatek do pliku i uzyć git am aby jest wszystkie nałożyć za jednym zamachem.

Również, jeżeli ktoś wgrał łatkę wygenerowaną poprzez format-patch do systemy rejestracji błędów lub czegoś podobnego, możesz zapisać lokalnie ten plik i potem przekazać go do git am aby zaaplikować go:

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

Możesz zobaczyć, że został czysto nałożony i automatycznie zatwierdzony. Informacje o autorze zostały pobrane z wiadomości e-mail z nagłówków From i Date, a treść komentarz została pobrana z tematu i treści (przed łatką) e-maila. Na przykład, jeżeli ta łatka została zaaplikowana z pliku mbox który przed chwilą pokazałem, wygenerowany commit będzie wygląda podobnie do:

$ 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

Linie zaczynające się od Commit pokazują osobę która zaaplikowała łatkę oraz czas kiedy to zrobiła. Linie rozpoczynające się od Author pokazują osobę która stworzyła łatę wraz z dokładną datę.

Jednak możliwa jest również sytuacja, w której łatka nie zostanie bez problemów nałożona. Być może twoja gałąź zbyt mocno się zmieniła, w stosunku do gałęzi na której łatka została stworzona, albo zależna jest ona od innej łatki której jeszcze nie nałożyłeś. W takiej sytuacji git am zakończy się błędem i zapyta co robić dalej:

$ 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".

Ta komenda zaznacza pliku z którymi miała problemy, podobnie do konfliktów występujących podczas komend merge lub rebase. Rozwiązujesz takie sytuacja również analogicznie - zmień plik w celu rozwiązania konfliktu, dodaj do przechowalni nowe pliki i następnie uruchom git am --resolved aby kontynuować działanie do następnej łatki:

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

Jeżeli chcesz aby Git spróbował w bardziej inteligentny sposób rozwiązać konflikty, dodaj opcję -3 do komendy, która daje Gitowi możliwość spróbowania trójstronnego łączenia. Opcja ta nie jest domyślnie włączona, ponieważ nie działa poprawnie w sytuacji gdy w twoim repozytorium nie ma commitu na którym bazuje łata. Jeżeli go masz - jeżeli łatka bazowała na publicznym commit-cie - to dodanie -3 zazwyczaj pozwala na dużo mądrzejsze zaaplikowanie konfliktującej łatki:

$ 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.

W tej sytuacji, próbowałem zaaplikować łatkę którą już wcześniej włączyłem. Bez podanej opcji -3 wyglądało to na konflikt.

Jeżeli włączasz większą liczbę łat z pliku mbox, możesz użyć komendy am w trybie interaktywnym, który zatrzymuje się na każdej łacie którą znajdzie i pyta czy chcesz ją zaaplikować:

$ 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

Jest to całkiem dobre jeżeli masz zapisaną większą liczbę łat, ponieważ możesz najpierw zobaczyć łatę jeżeli nie pamiętasz do czego była, lub nie aplikować jej jeżeli już to zrobiłeś.

Kiedy wszystkie łatki zostaną wgrane i commitnięte w Twojej gałęzi, możesz zastanowić się w jaki sposób i czy chcesz integrować je do jednej z głównych gałęzi.

Sprawdzanie zdalnych gałęzi

Jeżeli zmiana przyszła od użytkownika Gita który ma skonfigurowane własne repozytorium, wgrał do niego już jakąś liczbę zmian i następnie wysłał do Ciebie adres URL repozytorium oraz nazwę zdalnej gałęzi zawierającej zmiany, możesz ją dodać jako zdalną i połączyć zmiany lokalnie.

Na przykład, jeżeli Jessica wysyła Ci wiadomość e-mail w której pisze, że ma nową funkcjonalność w gałęzi ruby-client w swoim repozytorium, możesz je przetestować dodając zdalne repozytorium i sprawdzając tą gałąź lokalnie:

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

Jeżeli napisze do Ciebie ponownie z nową gałęzią która zawiera kolejną funkcjonalność, możesz ją pobrać i sprawdzić ponieważ masz już dodane zdalne repozytorium.

Jest to bardzo pomocne w sytuacji, w której współpracujesz z jakąś osobą na stałe. Jeżeli ktoś ma tylko pojedyncze łatki które udostępnia raz na jakiś czas, to akceptowanie ich poprzez e-mail może być szybsze, niż zmuszanie wszystkich do tego aby mieli własny serwer, jak również dodawanie i usuwanie zdalnych repozytoriów aby otrzymać jedną lub dwie łatki. Jednakże, skrypty oraz usługi udostępniane mogą uczynić to prostszym - zależy od tego w taki sposób pracujesz, oraz jak pracują Twoi współpracownicy.

Kolejną zaletą takiego podejścia jest to, że otrzymujesz również całą historię zmian. Chociaż mogą zdarzyć się uzasadnione problemy ze scalaniem zmian, wiesz na którym etapie historii ich praca bazowała; prawidłowe trójstronne scalenie jest domyślne, nie musisz więc podawać -3 i mieć nadzieję że łatka została wygenerowana z publicznie dostępnego commitu/zmiany.

Jeżeli nie współpracujesz z jakąś osobą na stałe, ale mimo wszystko chcesz pobrać od niej zmiany w ten sposób, możesz podać URL repozytorium do komendy git pull. Wykona ona jednokrotne zaciągnięcie zmian i nie zapisze URL repozytorium jako zdalnego:

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

Ustalenie co zostało wprowadzone

Teraz posiadać gałąź tematyczną która zawiera otrzymane zmiany. W tym momencie możesz zdecydować co chcesz z nimi zrobić. Ta sekcja przywołuje kilka komend, tak abyś mógł zobaczyć w jaki sposób ich użyć, aby przejrzeć dokładnie co będziesz włączał do głównej gałęzi.

Często pomocne jest przejrzenie wszystkich zmian które są w tej gałęzi, ale nie ma ich w gałęzi master. Możesz wyłączyć zmiany z gałęzi master poprzez dodanie opcji --not przed jej nazwą. Na przykład, jeżeli twój współpracownik prześle ci dwie łaty, a ty stworzysz nową gałąź contrib i włączysz te łatki tam, możesz uruchomić:

$ 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

Aby zobaczyć jakie zmiany każdy z commitów wniósł, zapamiętaj że możesz dodać opcję -p do git log, a otrzymasz również w wyniku różnice w kodzie.

Aby zobaczyć różnice tego co się stanie, jeżeli chciałbyś połączyć tą gałąź z inną, będziesz musiał użyć całkiem ciekawych sztuczek aby otrzymać poprawne wyniki. Możesz pomyśleć, aby uruchomić:

$ git diff master

Ta komenda pokaże ci różnice w kodzie, ale może to być mylące. Jeżeli twoja gałąź master zmieniła się od czasu stworzenia gałęzi tematycznej, otrzymasz dziwne wyniki. Tak dzieje się dlatego, ponieważ Git porównuje bezpośrednio ostatnią migawkę z gałęzi tematycznej, z ostatnią migawkę w gałęzi master. Na przykład, jeżeli dodasz linię w pliku w gałęzi master, bezpośrednie porównanie pokaże, że gałąź tematyczna zamierza usunąć tą linię.

Jeżeli master jest bezpośrednim przodkiem Twojej gałęzi tematycznej, nie stanowi to problemu; jeżeli jednak obie linie się rozjechały, wynik diff pokaże dodawane wszystkie zmiany z gałęzi tematycznej, a usuwane wszystkie unikalne z master.

Wynik którego naprawdę oczekujesz, to ten, pokazujący zmiany będące w gałęzi tematycznej - zmiany które wprowadzisz jeżeli scalisz tą gałąź z master. Możesz to zrobić, poprzez porównanie ostatniego commitu z gałęzi tematycznej, z pierwszym wspólnym przodkiem z gałęzi master.

Technicznie rzecz ujmując, możesz to zrobić poprzez wskazanie wspólnego przodka i uruchomienie na nim diff:

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

Jednak to nie jest wygodne rozwiązanie, dlatego Git udostępnia krótszą metodę aby to osiągnąć: składnie z potrójną kropką. W kontekście komendy diff, możesz wstawić trzy kropki po nazwie gałęzi z którą chcesz porównać, aby otrzymać różnice z ostatniej zmiany z gałęzi na której się znajdujesz a wspólnym przodkiem tej drugiej.

$ git diff master...contrib

Ta komenda pokaże zmiany wprowadzone tylko w gałęzi tematycznej, od czasu jej stworzenia. Jest to bardzo użyteczna składnia warta zapamiętania.

Integrowanie otrzymanych zmian

Kiedy zakończysz prace nad zmianami w gałęzi tematycznej i będą one gotowe do włączenia do głównej, pozostaje pytanie w jaki sposób to zrobić. Ponadto, jaki rodzaj przepływu pracy chcesz stosować w swoim projekcie? Masz różne możliwości, opiszę więc kilka z nich.

Przepływ pracy podczas scalania zmian

Jednym z prostszych przepływów pracy jest scalenie zmian z twoją gałęzią master. W tym scenariuszu, posiadasz gałąź master która zawiera stabilny kod. Kiedy masz zmiany w jednej z gałęzi tematycznych które wykonałeś, lub ktoś Ci przesłał a Ty je zweryfikowałeś, scalasz je z gałęzią master, usuwasz gałąź i kontynuujesz pracę. Jeżeli mielibyśmy repozytorium ze zmianami w dwóch gałęziach ruby_client oraz php_client (zob. rys. 5-19) i mielibyśmy scalić najpierw ruby_client, a w następnej kolejności php_client, to twoja historia zmian wyglądała by podobnie do rys. 5-20.


Rysunek 5-19. Historia zmian z kilkoma gałęziami tematycznymi.


Rysunek 5-20. Po scaleniu gałęzi.

To jest prawdopodobnie najprostszy schemat pracy, ale jest on również problematyczny jeżeli masz do czynienia z dużymi repozytoriami lub projektami.

Jeżeli masz większą ilość deweloperów lub większy projekt, będziesz chciał pewnie używał przynajmniej dwufazowego cyklu scalania. W tym scenariuszu, posiadasz dwie długodystansowe gałęzie master oraz develop, z których master jest aktualizowana tylko z bardzo stabilnymi zmianami, a cały nowy kod jest włączany do gałęzi develop. Regularnie wysyłasz ("push") obie te gałęzie do publicznego repozytorium. Za każdym razem gdy masz nową gałąź tematyczną do zintegrowania (rys. 5-21), włączasz ją do develop (rys. 5-22); a kiedy tagujesz kolejną wersję, przesuwasz master za pomocą fast-forward o punktu w którym jest gałąź develop(rys. 5-23).


Rysunek 5-21. Przed scaleniem gałęzi tematycznej.


Rysunek 5-22. Po scaleniu gałęzi tematycznej.


Rysunek 5-23. Po utworzeniu kolejnej wersji.

W ten sposób, kiedy ludzie klonują Twoje repozytorium, mogą albo pobrać master aby zbudować najnowszą stabilną wersję i utrzymywać ją uaktualnioną, lub mogą pobrać develop która zawiera mniej stabilne zmiany. Możesz rozbudować tą koncepcję, poprzez dodanie gałęzi służącej do integracji. Wtedy jeżeli kod w znajdujący się w niej jest stabilny i przechodzi wszystkie testy, scalasz ją do gałęzi develop; a jeżeli ta okaże się również stabilna, przesuwasz master za pomocą fast-forward.

Large-Merging Workflows

Projekt Gita ma cztery długodystansowe gałęzie: master, next, pu (proponowane zmiany) dla nowych funkcjonalności, oraz maint do wprowadzania zmian wstecznych. Kiedy nowe zmiany są dostarczone przez deweloperów, zbierane są do gałęzi tematycznych w repozytorium opiekuna, w sposób podobny do tego który opisałem (zob. rys. 5-24). W tym momencie, są one weryfikowane i sprawdzane czy mogą być użyte, lub czy nadal wymagają dalszych prac. Jeżeli są gotowe, są włączona do next, a ta gałąź jest wypychana dalej, tak aby każdy mógł wypróbować nowe funkcjonalności.


Rysunek 5-24. Zarządzanie złożoną serią równoczesnych zmian w gałęziach tematycznych.

Jeżeli funkcjonalność potrzebuje jeszcze kolejnych zmian, są one włączane do gałęzi pu. Kiedy okaże się, że cały kod działa już poprawnie, zmiany są włączane do master oraz przebudowywane włącznie ze zmianami z gałęzi next, które nie znalazły się jeszcze w master. Oznacza to, że master praktycznie zawsze przesuwa się do przodu, next tylko czasami ma zmienianą bazę poprzez "rebase", a pu najczęściej z nich może się przesunąć w innym kierunku (zob. rys. 5-25).


Rysunek 5-25. Włączanie gałęzi tematycznych do gałęzi długodystansowych.

Z chwilą, gdy gałąź tematycznie zostanie włączona do master, jest usuwana z repozytorium. Projekt Gita ma również gałąź maint, która jest tworzona z ostatniej wersji, w celu dostarczania zmian w sytuacji gdy trzeba wydać wersję poprawkową. Dlatego kopiując repozytorium Gita masz cztery gałęzie, w których możesz zobaczyć projekt w różnych stadiach rozwoju, w zależności od tego jak stabilny kod chcesz używać, lub nad którym pracować; a opiekun ma ułatwiony przepływ zmian pomagający panować nad nowymi zmianami.

Zmiana bazy oraz wybiórcze pobieranie zmian

Część opiekunów woli używać "rebase" lub "cherry-pick" w celu włączania zmian w gałęzi master, zamiast przy użyciu "merge", aby zachować bardziej liniową historię. Kiedy masz zmiany w gałęzi tematycznej i decydujesz się zintegrować je, przenosisz gałąź i uruchamiasz "rebase" aby nałożyć zmiany na górze swojej gałęzi master (lub develop, czy innej). Jeżeli to zadziała poprawnie, możesz przesunąć swoją gałąź master i otrzymasz praktycznie liniową historię.

Drugim sposobem na przeniesienie zmian z jednej gałęzi do drugiej jest zrobienie tego za pomocą komendy cherry-pick. Komenda ta jest podobna do rebase, ale dla pojedynczej zmiany. Pobiera ona zmianę która została wprowadzona i próbuje ją ponownie nałożyć na gałąź na której obecnie pracujesz. Jest to całkiem przydatne, w sytuacji gdy masz większą ilość zmian w gałęzi tematycznej, a chcesz zintegrować tylko jedną z nich, lub jeżeli masz tylko jedną zmianę w gałęzi i wolisz używać cherry-pick zamiast rebase. Dla przykładu, załóżmy że masz projekt który wygląda podobnie do rys. 5-26.


Rysunek 5-26. Przykładowa historia przez wybiórczym zaciąganiem zmian.

Jeżeli chcesz pobrać zmianę e43a6 do swojej gałęzi master, możesz uruchomić:

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

To pobierze tylko zmiany z commita e43a6, ale otrzyma nową sumę SHA-1, ze względu na nową datę nałożenia. Teraz Twoja historia wygląda podobnie do rysunku 5-27.


Rysunek 5-27. Historia po wybiórczym zaciągnięciu zmiany z gałęzi tematycznej.

Teraz możesz usunąć swoją gałąź tematyczną, oraz zmiany których nie chciałeś pobierać.

Tagowanie Twoich Wersji

Kiedy zdecydowałeś, że wydasz nową wersję, najprawdopodobniej będziesz chciał stworzyć taga, tak abyś mógł odtworzyć tą wersję w każdym momencie. Możesz stworzyć nowego taga, tak jak zostało to opisane w rozdziale 2. Jeżeli zdecydujesz się na utworzenie taga jako opiekun, komenda powinna wyglądać podobnie do:

$ 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

Jeżeli podpisujesz swoje tagi, możesz mieć problem z dystrybucją swojego publicznego klucza PGP, który został użyty. Można rozwiązać ten problem poprzez dodanie obiektu binarnego (ang. blob) w repozytorium, a następnie stworzenie taga kierującego dokładnie na jego zawartość. Aby to zrobić, musisz wybrać klucz za pomocą komendy gpg --list-keys:

$ 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]

Następnie, możesz bezpośrednio zaimportować wybrany klucz do Gita, poprzez eksport i przekazanie go do git hash-object, który zapisuje nowy obiekt binarny i zwraca jego sumę SHA-1:

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

Teraz, gdy masz zawartość swojego klucza w Gitcie, możesz utworzyć taga wskazującego bezpośrednio na ten klucz, poprzez podanie sumy SHA-1 zwróconej przez hash-object:

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

Po uruchomieniu git push --tags, etykieta maintainer-pgp-pub zostanie udostępniona dla wszystkich. Jeżeli ktoś chciałby zweryfikować etykietę, może bezpośrednio zaimportować twój klucz PGP poprzez pobranie zawartości z gita i import do GPG:

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

Możesz używać tego klucza do weryfikacji wszystkich podpisanych etykiet. Możesz również dodać do komentarza do etykiety dodatkowe informacje, które będą możliwe do odczytania po uruchomieniu git show <tag> i pozwolą na prostszą weryfikację.

Generowanie numeru kompilacji

Ponieważ Git nie zwiększa stale numerów, np. 'v123' lub w podobny sposób, jeżeli chcesz mieć łatwiejszą do używania nazwę dla konkretnej zmiany, możesz uruchomić git describe na commitcie. Git poda Ci nazwę najbliższej etykiety, wraz z ilością zmian, oraz skróconą sumą SHA-1:

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

W ten sposób, możesz udostępnić konkretną wersję lub kompilację pod nazwą łatwiejszą do użycia przez ludzi. W rzeczywistości, jeżeli masz Gita zbudowanego ze źródeł pobranych z jego repozytorium, komenda git --version pokaże wynik podobny do powyższego. Jeżeli zamierzasz opisać zmianę którą bezpośrednio zatagowałeś, pokaże ona nazwę taga.

Komenda git describe faworyzuje etykiety stworzone przy użyciu opcji -a lub -s, więc etykiety dotyczące konkretnych wersji powinny być tworzone w ten sposób, jeżeli używasz git describe w celu zapewnienia poprawnych nazw commitów. Możesz również używać tej nazwy do komend "checkout" lub "show", choć polegają one na skróconej wartości SHA-1, mogą więc nie być wiecznie poprawne. Na przykład, projekt jądra Linuksa przeszedł ostatnio z 8 na 10 znaków aby zapewnić unikalność sum SHA-1, więc poprzednie nazwy wygenerowane za pomocą git describe zostały unieważnione.

Przygotowywanie nowej wersji

Teraz chcesz stworzyć nową wersję. Jedną z rzeczy które będziesz musiał zrobić, jest przygotowanie spakowanego archiwum z ostatnią zawartością kodu, dla tych, którzy nie używają Gita. Komenda która to umożliwia to git archive:

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

Jeżeli ktoś otworzy spakowany plik, otrzyma ostatnią wersję kodu w podkatalogu z nazwą projektu. Możesz również stworzyć archiwum zip w podobny sposób, dodając parametr --format=zip do git archive:

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

Masz teraz spakowane pliki projektu w formatach tar i zip, które możesz łatwo wgrać na serwer lub wysłać do ludzi.

Komenda Shortlog

Nadszedł czas aby wysłać na listę dyskusyjną

$ 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

Możesz pobrać podsumowanie wszystkich zmian począwszy od wersji v1.0.1 pogrupowanych po autorze, które jest gotowe do wysłania na listę.