10. Git

Git

Na přednášce jste se dozvěděli o pokročilejších funcích Gitu, které si nyní vyzkoušíte v praxi. Git už byste měli mít nastavený z minulého cvičení (pokud ne, následujte návod z minulého týdne).

Práce s větvemi

Větve umožňují paralelně pracovat na různých částech projektu, nejčastěji se hodí při spolupráci více vývojářů na jednom projektu.

  1. Otevřete si stránku https://learngitbranching.js.org/?NODEMO, kde si můžete interaktivně vyzkoušet práci s větvemi v Gitu a ihned uvidíte, jak vaše příkazy ovlivní historii repozitáře.

    1. Vytvořte několik commitů na hlavní větvi (main): git commit
    2. Vytvořte nad větví main alespoň dvě nové větve, v každé vytvořte alespoň jeden commit: git branch, git switch
      • Pozor, aby obě větve začínaly z větve main (před vytvořením druhé větve se vraťte zpět na main).
    3. Obě větve slučte do větve main pomocí příkazu git merge.
      • Nejdříve se musíte přepnout na větev main.
  2. Nyní si práci s větvemi vyzkoušejte v reálném repozitáři:

    1. Vytvořte nový adresář ls-python a inicializujte v něm nový Git repozitář: git init
    2. Stáhněte si soubor ls.py, soubor umístěte do vytvořeného repozitáře a commitněte: git add, git commit
    3. Script spusťte a ověřte, že funguje, seznamte se se strukturou kódu.
    4. Vytvořte větev reverse-order, ve které implementujete podporu pro přepínač -r, který vypíše soubory v opačném pořadí (od Z do A). Změny commitněte.
    5. Vytvořte z větve main druhou větev list-hidden, ve které implementujete přepínač -a, se kterým příkaz vypíše i skryté soubory (začínající tečkou). Změny také commitněte.
  3. Slučte obě větve do větve main:

    1. Vraťte se zpět na větev main a pomocí git merge slučte změny z větve reverse-order do hlavní větve.
    2. Slučte i druhou větev list-hidden do hlavní větve a vyřešte případné konflikty.
    3. Ověřte, že výsledný kód korektně implementuje oba přepínače.

Úpravy historie

Občas se stane, že omylem commitnete změnu, kterou jste v historii nechtěli, například omylem přidanou binárku, nebo soubor s hesly. Git nabízí několik nástrojů, jak historii opravit, které si nyní vyzkoušíte.

  1. Stáhněte si archiv pages.zip s připraveným repozitářem a rozbalte do složky pages.

  2. Seznamte se zběžně s historií repozitáře: git log --oneline

  3. Opravte překlep v posledním commitu (dvemdvěma): git commit --amend

  4. Smažte z posledního commitu omylem přidaný soubor credentials.json:

    • Nejdříve commit odstraňte pomocí git reset --soft HEAD~
    • Následně soubor smažte a zbylé změny znovu commitněte
  5. V 5. commitu (od HEADu) je překlep v commit message (modulemodules), pomocí git rebase --interactive překlep opravte.

  6. Vypadá to, že někdo omylem nahrál privátní SSH klíč do repozitáře: src/labs/08-ssh/ssh-key

    • Zjistěte, ve kterém commitu byl klíč přidaný.
    • Pomocí git rebase --interactive a git commit --amend klíč z historie odstraňte.
    • Ověřte, že už soubor v historii není, porovnejte změny pomocí git diff ORIG_HEAD.
  7. V 6. commitu (labs/08-ssh: for interested individuals) kolega upravuje stránku cvičení o SSH. Zkombinujte commit s původním commitem, který tuto stránku přidal (výsledkem tedy bude jeden commit).

  8. Přesuňte commit labs/08: More detailed SSH key setup description hned za commit labs/08: Add SSH lab page, reorder labs.

Konflikty a jejich řešení

Konflikt je událost, která nastane, když ve dvou odvětveních modifkujeme soubor na stejném místě, se kterém si algoritmy mergování nedokážou poradit. Za vyřešení konfliktu je poté zodpovědná osoba, která merge dělá (vývojář, project manager, ...).

Na konflikt Vás git upozorní tak, že konfliktní místa označí v příslušných kolidujících souborech. Úkolem zodpovědné osoby je poté konflikt vyřešit.

⚠️ Je potřeba se vždy zamyslet, jaký má být výsledek po mergi. Výsledek si představíme na tom, že mergujete větev do main a vznikne Vám konflikt.

  1. Představte si, že větev v konfliktu lépe implementuje danou funkcionalitu (např. to v main můžete považovat za zastaralé) - přijmete tedy změnu z větve.
  2. V rámci vaší větve jste experimentálně a dočasně něco změnili, např. aby Vám to lokálně fungovalo, ale víte, že se jedná o dočasnou změnu - přijmete tedy to, co je v main.
  3. Obě změny jsou správné (v průběhu práce se změnila business logika jak v main tak ve větvi či jsou oběma případy lépe pokryté okrajové případy) - vyřešení konfliktu je kombinace obou přístupů.

Ponaučení: Řešení konfliktu není jen mechanická záležitost.

Vyřešení konfliktu si ukážeme na příkladě. K tomu si stáhněte soubor conflicts.zip a rozbalte jej do nějakého lokálního adresáře. Objeví se Vám adresář conflicts.

  1. Koukněte se, co dělají oba soubory. Ve větvi main (git switch main) se koukněte na funkci sqrt_ratio a zamyslete se nad tím, kde může matematika selhat.
  2. Opravy jsou implementované ve dvou větvích, vylistujte je pomocí git branch. Obě opravy vycházejí z posledního commitu ve větvi main.
  3. Prohlédněte si jednotlivé úpravy pomocí příkazů git show <jmeno-featury>.
  4. Slučte tyto změny do main tak, že se přepnete do main a provedete git merge <feature-1> <feature-2>. Můžete také provést git merge <feature-1> a poté git merge <feature-2>.
  5. Sledujte, co se stalo. Jaké jsou důvody, proč se to stalo? Cvičící Vám ukáže způsoby, jak to vyřešit.
  6. Nyní si vyzkoušíme příkaz rebase. Stáhněte si adresář znovu a slučte POUZE jednu z větví na main. Poté se přepněte do větve, kterou jste nesloučili a proveďte git rebase main. Co nastalo?
  7. Po vyřešení konfliktů v druhé větvi se přepněte zpět do main a udělejte git merge <jmeno-vetve>. Merge by měl proběhnout bez konfliktů.

ℹ️ Dodatečná poznámka: příkaz rebase slouží obecně ke změně historie, kdy se série commitů naaplikuje na jiný startovací bod. V režimu -i toho dokáže více, viz minulé cvičení. Často se tento příkaz využívá, když:

  • Pracujete s větvemi, ale potřebujete do své větve zahrnout novější historii, kterou tam nemáte. Řešením je posunout začátek vaší větve na mladší historii.
  • (Případ v 6. a 7.): Pokud provedete také rebase vůči větvi, do které chcete mergovat, a vyřešíte během rebase konflikty, máte potom jistotu, že git merge proběhne bez problému.

ℹ️ Dodatečná poznámka: aby konflikty nenastávaly, je rozumné, aby každý vývojář pracoval pouze na svých souborech a "nelezl ostatním do zelí". To bohužel u větších projektů zajistit nelze, kdy si logicky nezávislé změny začnou mít souborové závislosti (úprava business logiky, definice rozhraní, konfigurační soubory, ...). Proto je důležité umět konflikty řešit.

Vytváření PR (pull request)

Pokud chcete kontribuovat do cizího projektu, je běžné vytvořit tzv. pull request (PR) – žádost o začlenění vašich změn do hlavní větve projektu. Nyní si vyzkoušíte vytvořit svojí kopii ("fork") repozitáře na GitLabu, v něm udělat změny a ty následně přidat do původního repozitáře otevřením pull requestu. Budeme pracovat s repozitářem https://gitlab.fel.cvut.cz/psy/pr-test. Do tohoto repozitáře nemáte právo zapisovat, proto je třeba si nejdříve vytvořit jeho kopii.

  1. Vytvořte si kopii ("fork") repozitáře https://gitlab.fel.cvut.cz/psy/pr-test pomocí tlačítka "Fork" vpravo nahoře.

  2. Naklonujte si svoji kopii repozitáře na váš lokální počítač: git clone

  3. Do souboru students.md doplňte ke svému jménu libovolný text, změny commitněte a nahrajte do vašeho GitLab repozitáře: git add, git commit, git push

  4. Nyní z vašich změn vytvořte nový pull request (v terminologii GitLabu "merge request") do původního repozitáře:

    • Otevřete stránku vašeho repozitáře na GitLabu.
    • Klikněte na tlačítko "Create merge request" (pokud se nezobrazuje, načtěte stránku znovu).
    • Přidejte popisek změn a merge request odešlete.

Bonus: Body za opravy chyb

Stránky předmětu jsou generované z repozitáře https://gitlab.fel.cvut.cz/psy/psy.pages.fel.cvut.cz. Pokud najdete na stránkách předmětu libovolnou chybu (překlep, nejasnost,...) můžete získat až 3 bonusové body za aktivitu (1 bod za každé PR), pokud chybu opravíte a vytvoříte pull request do výše uvedeného repozitáře, který bude schválen vyučujícím. Oprava musí být provedena lokálně na vašem počítači, nikoliv přes webové rozhraní GitLabu.

Než chybu opravíte a vytvoříte PR, zkontrolujte prosím, že už danou chybu neopravil v svém PR nějaký z vašich spolužáků. Pokud najdete více chyb, otevřete prosím pro každou opravu nové PR (smyslem je si procvičit práci s větvemi a forky, nejenom opravit chyby) – v takovém případě chcete každou chybu opravit v jiné větvi, z jedné větve lze vytvořit jen jedno PR.