Git pro mě/Psaní zdrojového kódu v týmu

Ne vždy na zdrojovém kódu pracuji sám. Pravda je taková, že tým toho udělá víc. Když ví, jak spolupracovat. Tohle bude trochu delší poznámka a určitě potřebuji vědět, jak na Psaní zdrojového kódu skriptu i Psaní zdrojového kódu nové funkce.

V každém novém repozitáři je první commit

git commit -m'Add license, readme'

kde README píšu pro sebe. Chci vědět, CO je pointa, protože do zítra to zapomenu. Občas to, co si napíšu zní dost divně, takže přidám PROČ zrovna to. Navíc do README přidám JAK dělat věci, které dělám pořád (třeba jak projekt zkompilovat). A v neposlední řadě KAM a KOMU napsat dotaz či bug report (komunikační kanál).

Role v týmu editovat

Ať chci nebo ne, členové vývojového týmu mají tři různé kompetence:

  • Vývojář upravuje zdrojový kód a změny posílá k review.
  • Reviewer kontroluje a komentuje změny a vrací je k přepracování, čímž s vývojářem vytvoří nejlepší možnou sadu změn, která implementuje novou funkci.
  • Maintainer má za úkol různé sady změn zkontrolovat a začlenit do projektu.

Začlenění sady změn je cíl všech členů týmu!

Teď ještě pár poznámek o tom, co by každý člen týmu měl o Gitu vědět, a jak by spolu měli komunikovat.

Git pro vývojáře editovat

Jako vývojář implementuji nějakou funkci a to v samostatné větvi. Při vytváření nové větve se na ni chci rovnou přepnout, takže spojím dva příkazy:

git checkout -b NOVA-FUNKCE

Jako vývojář mám zodpovědnost za sadu změn, nikoli za zdrojový kód. To je úkol maintainera. Abych vytvořil rozumnou historii, používám

git diff
git add -p
git diff --cached
git commit -m'52 znaků dokončujících větu'

a tu větu už znám, zní "When applied, this patch will ...".

Jo, ještě... proč že to mám, jako vývojář, zodpovědnost za sadu změn? A proč že má být rozumná? Protože jako vývojář sadu změn pošlu k review! A protože vývojář většinou funguje zároveň jako reviewer pro další členy týmu, tak posílám sadu změn, kterou bych sám chtěl kontrolovat.

Git pro Reviewera editovat

Kód se píše jednou, ale čte se hodněkrát. Úkol reviewera je tenhle poměr změnit, aby to bylo alespoň trochu fér.

Jako reviewer se podívám na každý commit v sadě změn. Jako první si přečtu commit message (stručný komentář ke změně). Zajímá mě CO změna dělá a PROČ. JAK se dovím ze zdrojového kódu a když to vývojář napíše v commit message, spíš mě to mate.

Komentuji vše, k čemu mám co říci: design, funkci, zda je vůbec potřeba, testování, složitost, pojmenování, komentáře, styl, konzistenci, dokumentaci, kontext i co se mi líbí. Prostě každou řádku. To, že sada změn, kterou dostane maintainer, je dokonalá, je zodpovědnost reviewera.

Zpátky u vývojáře editovat

Patch set, jak se taky říká sadě změn, se po review vrátí zpátky vývojáři. Ten komentáře zapracuje a pošle novou verzi (sady změn).

Z pohledu Gitu chci, jako vývojář, změnit uloženou historii. K tomu mi slouží následující kroky:

  1. Pomocí git logg a git show IDENTIFIKATOR-ULOZENE-ZMENY zjistím, kterou z uložených změn v sadě chci upravit.
  2. Upravím soubory související se změnou IDENTIFIKATOR-ULOZENE-ZMENY.
  3. Pomocí git add -p připravím relevantní řádky souborů pro uložení do historie.
  4. A změny uložím, tentokrát pomocí
git commit -m'F IDENTIFIKATOR-ULOZENE-ZMENY'.

No a když mám všechny komentáře z review zpracované a uložené, přijde na řadu to přepisování historie. To provedu příkazem

git rebase -i master

který mi otevře textový editor. V něm přesunu řádky

pick IDENTIFIKATOR-OPRAVY F IDENTIFIKATOR-ULOZENE-ZMENY

těsně pod relevantní řádky

pick IDENTIFIKATOR-ULOZENE-ZMENY 52 znaků dokončujících větu

a změním "pick" na "f" nebo "fixup":

f IDENTIFIKATOR-OPRAVY F IDENTIFIKATOR-ULOZENE-ZMENY

Když mám konečně hotovo, soubor zavřu a je to. Pokud se při rebase na příkazové řádce objeví slovo "conflict", dám

git rebase --abort

a začnu na webu hledat, jak se v Gitu řeší merge konflikty.

Git pro Maintainera editovat

Úkol maintainera je začlenit dokonalou sadu změn. To ale neznamená, že jí musí stoprocentně chápat -- stačí, když důvěřuje vývojáři a reviewerovi.

Záleží na komunikaci v týmu, jestli maintaner použije git am, git merge, nebo klikne na tlačítko na webu.

Tady si musím poznamenat pár informací o merge konfliktech. Jako maintainerovi se mi může stát, že mám za úkol začlenit více sad změn. Problém nastane, když jednotlivé sady změn k začlenění mění stejné soubory. Může se totiž stát, že se soubory mění na stejném místě, což vede k tomu, že po aplikaci první sady změn vychází ta druhá ze zastaralého kódu, který už není k dispozici.

Jsou dvě řešení. Vrátím druhou sadu změn vývojáři a reviewerovi a řeknu, že nevychází z nejnovější verze, ať sadu změn aktualizují. To udělám v případě, kdy sadě změn vůbec nerozumím a to by se nemělo stát.

Druhé řešení je, že merge conflict vyřeším. Merge conflict znamená, že jsou dvě verze změn a Git neví, kterou z nich má použít. Můj úkol je z těch dvou verzí udělat jednu, funkční, chtěnou.

Komunikace v týmu editovat

Tak si říkám, jak daleko se můžu dostat, aniž bych věděl, že Git je decentralizovaný. To znamená, že každý člen týmu má vlastní kopii historie změn -- repozitáře. Mezi členy týmu se sdílí sady změn a předpokládá se, že změnu identifikovanou IDENTIFIKATOR-ULOZENE-ZMENY, ze které sada změn vychází, má člen týmu dostupnou ve svojí kopii repozitáře.

Komunikace týmu skrz Git, tedy spolupráce na zdrojovém kódu, je asynchronní. Takže si člověk může naplánovat, kdy pošle sadu změn k review, kdy provede review sady změn, nebo kdy sadu změn začlení. Git není chat.

Vývojář má sadu změn, kterou chce sdílet, většinou v samostatné větvi NOVA-FUNKCE. Je několik způsobů, jak mezi sebou členové týmu sady změn sdílí:

  • git daemon
  • git send-email
  • pull/merge request

Git daemon editovat

Pokud chci sdílet vývojovou větev, respektive sadu změn, rychle přes lokální síť, tak v rodičovském adresáři repozitáře:

git daemon --export-all --base-path=. --enable=receive-pack

kde --enable=receive-pack povoluje ostatním na síti do repozitáře také zapisovat. Členové týmu si přidají vzdálený repozitář:

git remote add KOLEGA git://IP-ADRESA/muj-repo

aktualizují sí svojí kopii repozitáře a přepnou se na větev:

git fetch KOLEGA
git checkout NOVA-FUNKCE

nebo se přepnou na větev, pokud ji již mají, a aktualizují ji:

git checkout NOVA-FUNKCE
git pull

Git send-email editovat

Git je dělaný pro (asynchronní) komunikaci přes email. Email se sadou změn se většinou posílá do mailing listu a při správném nastavení je příkaz jen

git send-email master..NOVA-FUNKCE

Mailing list je emailová adresa, která přesměruje příchozí zprávy na předem definované adresy. Taková emailová asynchronní diskuzní skupina. Alias na emailové adresy členů týmu.

A teď se hodí přidat odkaz na etiketu emailové komunikace.

Pull/merge requests editovat

Forge, servery poskytující služby vývojářům, přinášejí centralizaci do jinak decentralizovaného Git světa. Nejdřív: mailing list je také centralizace -- skupinová zpráva se posílá na jeden server se seznamem emailových adres. Při nedostupnosti serveru nelze zprávu do skupiny odeslat a je potřeba poslat skupinovou zprávu na všechny relevantní emailové adresy. A teď: Forge je webová platforma pro spolupráci vývojářů. Typicky poskytuje online prohlížení zdrojových kódů repozitářů, správu mailing listů, CI/CD, nástroje pro code review, bug/ticket tracker, wiki, či chat.

Používání pull/merge requestů funguje tak, že si nejdřív ve webové aplikaci forknu požadovaný projekt, čímž vlastně vytvořím svojí kopii cizího repozitáře na (cizím) serveru. Potom přidám svůj forknutý repozitář jako origin remote:

git remote add origin git@muj.vysneny.forge:/tojsemja/muj-fork

Nebo jestli nemám ještě kód, tak jej naklonuji:

git clone git@muj.vysneny.forge:/tojsemja/muj-fork

Nahraji větev, ve které mám sadu změn, ze které chci vytvořit pull/merge request:

git checkout NOVA-FUNKCE
git push -u origin NOVA-FUNKCE

A nakonec ve webové aplikaci kliknu na něco jako "vytvořit pull/merge request".

Když je kód po review, opravím jej, fixnu a nahraji znovu:

git push -f

Tentokrát není potřeba -u, to stačí jen jednou. Říká to, kterou vzdálenou větev má moje lokální větev sledovat. Pokud se ale změní historie sady změn (git rebase), je potřeba -f, který říká, že se má historie sady změn na serveru přepsat, nejen přidat nové změny.

Ještě jedna věc: potřebuji držet krok s kódem, který je v hlavní větvi forknutého projektu. Přidám si jej jako upstream:

git remote add upstream git@muj.vysneny.forge:/kolega/jeho-repo

svoji hlavní větev (master, který bude brzo main) nastavím, aby sledovala hlavní větev v upstream remote:

git fetch upstream
git branch -u upstream master:master

a svoji lokální hlavní větev aktualizuji:

git checkout master
git pull --rebase

Shrnutí editovat

Git je asynchronní komunikační kanál pro spolupráci na zdrojovém kódu.

Vývojář:

git checkout -b NOVA-FUNKCE
git diff
git add -p
git diff --cached
git commit -m'52 znaků dokončujících větu'

Znovu vývojář:

git commit -m'F IDENTIFIKATOR-ULOZENE-ZMENY'.
git rebase -i master
git rebase --abort

Maintainer:

git merge --no-ff NOVA-FUNKCE
git am *.patch

Ad-hoc sdílení:

git daemon --export-all --base-path=. --enable=receive-pack
git pull git@IP-ADRESA/muj-repo

Mailing list:

git send-email master..NOVA-FUNKCE

Pull/merge request:

git remote add origin git@muj.vysneny.forge:/tojsemja/muj-repo
git clone git@muj.vysneny.forge:/tojsemja/muj-repo
git checkout NOVA-FUNKCE
git push -u origin NOVA-FUNKCE
git push -f

A ještě:

git remote add upstream git@muj.vysneny.forge:/kolega/jeho-repo
git fetch upstream
git branch -u upstream master:master
git checkout master
git pull --rebase
◄ Git pro mě/Psaní zdrojového kódu nové funkce Psaní zdrojového kódu v týmu