Skip to content

Latest commit

 

History

History
389 lines (257 loc) · 18 KB

git-workflow.md

File metadata and controls

389 lines (257 loc) · 18 KB

Git kolaboracija

Kad počnemo raditi na projektu, jedna osoba će stvoriti online repozitorij gdje će biti kod, a ostali će imati lokalne verzije koda. Svako malo, kako projekt bude napredovao dodavat će se novi kod kroz push i merge naredbe. Ovdje ćemo objasniti kako će to ići.
Postoji više pristupa kolaborativnom radu, ali mi ćemo objasniti 2.

Postavljanje repozitorija i dodavanje suradnika

Svi online repozitorij ima vlasnika i suradnike. Može imati i kontributore, ali njih ćemo zasad zanemariti (specifičniji su za open-source projekte). Za početak rada vlasnik treba inicijalizirati repo i dodati suradnike.
Suradnici trebaju samo klonirati repo ili dodati remote kroz git. Objasnit ćemo oba pristupa.

Vlasnik: Postavljanje repozitorija i dodavanje suradnika

Nakon što je stvoren repozitorij, osoba koja je vlasnik treba učiniti dvije stvari:

  • Dodati master branch kroz prvi commit
  • Dodati kolege kao kolaboratore

To se radi na GitHubu. Nakon što je repozitorij stvoren, potrebno je lokalno stvoriti projekt kao što je opisano u prvim vježbama.

Nakon što se inicijalizira projekt koristeći gatsby new, dodaje se remote i radi prvi push:

$ git remote add origin linkNaNoviPrazanRepo
$ git push -u origin master

Sada, koristeći GitHub sučelje, dodaju se kolaboratori:

Prvo idete na gear-icon Settings pa Manage access i onda na Invite a collaborator.

Kad kolaborator prihvati, pojavit će se ispod (vidite na slici da ja imam jednog kolaboratora). Tada i on može raditi push i pull commitova na vaš repo (to je moguće ograničiti, ali nema potrebe u našem primjeru).

Suradnik: dodati remote i napraviti pull

Suradnik se treba samo spojiti na GitHub repo vlasnika. To se može napraviti na dva načina (jednako su laka... bar ja mislim):

  • Suradnik ode na GitHub link repozitorija, kopira ga i klonira repo
  • Suradnik doda remote i napravi fetch

Prvi pristup (clone)

Objasnimo prvi pristup. Nakon što otvorite GitHub link projekta samo ga kopirate. Link imate na dva mjesta:

Kad je link kopiran, otvorite konzolu i upišete:

$ git clone kopiraniLink imeFoldera

Ime foldera je opcionalno. Ako ga ne stavite, git će dati ime repozitorija (na ovom primjeru bit će EulerProject).

Objasnimo drugi način

Drugi pristup (fetch / checkout)

Otvorite folder gdje želite stvoriti repozitorij u terminalu. Sad pišete sljedeće četiri naredbe jednu za drugom (ponovno vam treba link na repo):

$ git init
$ git remote add origin kopiraniLinkNaRepo
$ git fetch origin
$ git checkout master

Naredbe koje ste napravili iznad su zapravo naredbe koje čine git clone. Znači da radite git clone ručno :)
Na ovaj način možete dodati branch po branch, dok git clone dodaje sve odjednom.

To je to. U ovom trenutku imate lokalni repo spojen na remote i možete početi raditi. Kako ćete raditi objašnjeno je u sljedećem poglavlju.

Temeljne git naredbe

git add i git commit

git add označava datoteku ili folder koji dodajete u staging ili tzv. index. Ono što je dodano u index može se commitat sa git commit.

git commit sprema sve dodane promjene u indexu (git add) u commit. Commit je skup promjena nad datotekama. Ujedno je i gradivna jedinica git-a i git brancheva (grana).

git branch

Ako je git commit čvor u vezanoj listi commitova, onda je branch cijela lista. Tehnički to nije baš tako, ali vizualno je jako blizu istini. Branch mijenjamo sa git checkout naredbom. Možemo stvoriti branch i prebaciti se na njega istovremeno sa git checkout -b noviBranch. Sa git branch imeBrancha samo stvaramo novi branch na koji se onda prebacimo sa git checkout imeBrancha, dakle bez -b flaga ako branch već postoji. Branchevi se prikazuju kao liste.
Vjerojatno ste vidjeli ovakve slike:

Bitna napomena za sliku iznad. Strjelice prikazane zapravo bi trebale ići unazad jer git čuva pointer na parent, ne na child. Znači kad idete kroz commit history uvijek idete sa kraja prema početku, nikad obrnuto. Git nativno podržava koračanje unazad, ali ne podržava koračanje unaprijed (ne postoji sintaksa ni naredba za to). Ova vizualizacija je zbog jednostavnosti prikaza. Obje notacije se koriste u praksi pa neka vas ne zbune strjelice u suprotnom smjeru ako ih vidite.

Primijetite kako se branchevi izdvajaju iz mastera. To jest, da svaki branch nastaje iz (ili iza) nekog commita. Za jednostavan rad s gitom, gledajte na brancheve kao na vezane liste, a commitove kao čvorove.
Git uvijek dodaje commit na kraj liste, nikad ispred commita ili na početak. Branch je pokazivač na zadnji element liste. Pogledajte zeleni i plavi branch. Ime brancha pokazuje na zadnji element. Dodavanjem novog commita branch ide naprijed na novi commit.

Branch logički razdvaja vaš kod od onog što se događa na masteru. Sve promjene koje radite u branchu ostaju u tom branchu čak i ako ga pushate. Znači, sve greške, bugovi i ostali nered koji uvedete u kod se ne vidi van tog brancha. Jednom kad želite svoj kod pokazati svijetu (tj. ostalim kolegama), radite merge na master.

git merge

Merge je naredba kojom promjene iz jednog brancha dovodite u drugi branch. Najčešće radite merge u master.

Merge ima 2 tipa: FF i MC:

  • FF je fast-forward merge. To je merge koji se dogodi kad nema novih promjena na masteru nakon što smo se branchali. Znači master se samo brzo gurne naprijed na naš branch tj. zadnji commit (otud naziv)

  • MC je merge commit. To je kad postoje promjene na masteru nakon što smo se mi branchali. Merge commit onda sadrži naše promjene iz brancha i nove promjene u masteru

FF merge se uvijek događa kad radite sami pa nema nikog drugog da ubacuje promjene osim vas. MC se događa u grupnom radu. Slijedi par vizualnih primjera: Fast-Forward Merge:

Merge commit merge, također se zove i Three way merge zbog algoritma kojeg koristi:

git push and pull

Git push je jednostavan za shvatiti. On jednostavno gura na GitHub promjene koje smo radili lokalno pod uvjetom da je to moguće. To nije moguće ako GitHub ima promjene koje mi nemamo, tj. naš lokalni branch je stariji od onog na GH. Tada trebamo pull.

Pull radi 2 stvari: dohvaća promjene i onda radi merge u naš branch (najčešće master). Nakon toga se stvara Merge Commit i možemo napraviti push.

Git workflow

Samostalan rad uz git rad je jednostavan. Radite promjene, radite commit i onda push. Kad radite u timu taj flow se malo mijenja. Trebate se prilagoditi jedni drugima što može predstavljati problem.

Problem je što više ljudi mijenja isti kod i onda rade push na isti repo. Zašto je ovo problem postane očito jako brzo ako malo razmislite o ovome.

  1. Ako vam treba 2 dana za napraviti promjene, a vašim kolegama manje i oni završe prije vas i naprave push, onda će se dogoditi da se vaše promjene temelje na staroj verziji koda dok je na GitHubu nova.

  2. Ako vi i vaš kolega mijenjate istu datoteku i oboje napravite push, koje promjene će git uzeti?

  3. Ako vi radite Login na u 4 commita, a vaš kolega radi Footer u 3 i vi napravite push nakon 2 commita, kolega nakon 3 pa opet vi nakon 2, onda je git log nered u kojem se ne vidi kad je šta dodano i zašto.

Ovi problemi se rješavaju uz pomoć 2 alata: praćenje dogovorenog workflowa i korištenje git naredbi za to (merge, pull i branch).

Također, objasnit ćemo kako se rješavaju konflikti.

Git workflow: single master

Single master workflow je jednostavan i brz workflow za male timove između 2 i 4 čovjeka. Radi se jednostavno: svaki suradnik radi promjene na svom masteru lokalno i onda radi push. Kako se rješavaju problemi spomenuti iznad?

  1. Svaki put kad radite push, git će provjeriti je li vaša verzija koda starija od one na GitHubu. Ako jest, morate napraviti pull prvo. Pull će spojiti vaše promjene s promjenama na GithHbu. Pull naredba radi merge automatski. Nakon toga, možete push.

  2. Ako promjene na GH nad istim datotekama kao i vaše, imate merge conflict, tj. pull se ne može izvršiti do kraja. Potrebno je napraviti conflict resolution. Ovo se sastoji od toga da odaberete promjene koje želite zadržati (svoje ili kolegine) ili prilagodite svoje promjene da se uklapaju u novi kod koje je dodao vaš kolega. Kad napravite što je potrebno, potvrdite merge i pull će se izvršiti do kraja.

  3. Ovaj problem nažalost ostaje s ovim workflowom. Jedino rješenje je raditi push onda i samo onda kad ste gotovi s onim što radite. Tada se commitovi neće miješati.

Ovakav pristup je dosta sličan drugim alatima poput SVN-a. (ako nekog zanima)

Git workflow: feature branches

Daleko najpopularniji pristup. Upravo ovaj pristup definira git i izdvaja ga od drugih alata poput SVN-a. Flow ide ovako...

Svaki put kad počnete raditi na nečem novom, npr. radite Footer komponentu, stvarate branch za to. Kada završite s radom, tj. napravili ste Footer i zadovoljni ste, vrijeme je da uvedete te promjene u ostatak koda. U tom trenutku radite merge eksplicitno u master. Tada rješavate probleme 1 i 2 kao u workflowu iznad dok problem 3 uopće nemate zbog ovog pristupa:

  1. Kad napravite merge na master, ako nema drugih promjena merge prolazi glatko kao Fast-Forward ili ako ima kao 3-way merge.

  2. Ako postoji konflikt, rješava se isto kao i inače. Čak je poželjno periodički provjeriti je li se master mijenja. Ako je, možete dodati te promjene u svoj branch tako da napravite merge s mastera u njega. Ovo nije obavezno.

  3. Ovaj problem nemate! Sve promjene su logički grupirane i neovisne!

Pravila ovog pristupa:

  • NIKAD ne radite commit na masteru, samo merge u njega iz brancheva
  • Periodički provjeravate promjene na masteru i dodajete ih u svoj branch (poželjno)
  • Branch prije merga mora biti funkcionalan. NE smije biti bugova ili WIP brancheva
  • Preporučuje se online merge kroz Pull Request, ali nije nužno

Git i VSCode

Rad sa gitom dosta je olakšan VSCode-om. Možete vizualno raditi add, commit, merge i sync. Krenimo s add i commit.

VScode: add i commit

Trenutno dok pišem ovo imam 4 promjene u "kodu":

Koristeći plusić pored njih dodat ću sve osim .md datoteke.

Iznad napišem poruku tipa "adding docs resources"

Ctrl + ENTER (ili kvačica):

git status mi daje ovo:

Što je isto što i na slici iznad samo iz terminala.

A git log ovo:

VSCode: checkout and merge

VSCode vam dopušta mijenjanje brancheva i njihovo merganje.
Mijenjanje brancheva radite u donjem lijevom kutu:

Nakon što promijenite branch, možete ga merge i push. Za ovaj primjer, napravit ću merge ovog brancha bonus--git-workflow u master.

Prvo potrebno je commitati sve promjene. Zatim mijenjamo branch u master i na kraju radimo merge sve kroz VScode bez ijedne naredbe. Letz G0!


Prvo, dodajemo promjene (ja imam samo jednu):

Zatim mijenjamo branch na master:

I na kraju radimo merge:

Primijetite da imamo broj 2 uz uzlaznu strjelicu. Ako kliknemo na njega napravit će se push. Broj 0 pokazuje broj dolaznih commitova. Budući da radim sam, meni je to uvijek nula. Kod vas su to commitovi vaših kolega. Klik na taj button će napraviti sync: pull pa push.

VSCode: conflict resolution

Rješavanje konflikta bez VSCoda je dosta nezgodno, a U VSCodu je dosta jednostavno (jako smislena rečenica).

Za demonstraciju uzrokovat ću merge conflict i riješiti ga u VSCodu.
U tu svrhu napravio sam brancheve koje ću zvati mc-master i mc-ivan.

Krenimo ovako. Imamo 3 osobe:

  • Mate: Vlasnik repoa, on je napravio prvi commit
  • Jure: Kolega, on je napravio drugi commit
  • Ivan: Mi, radimo svoj commit

Prvo je Mate napravio svoj commit. Onda smo se mi branchali, tako da naš history sadrži samo prvi commit. Ovo je inicijalni commit:

function myFunction () {
  console.log("Hello this Mate!")
}

Nakon toga mi se branchamo i dodajemo ovo u svoj branch mc-ivan:

function myFunction () {
  console.log("Hello this Mate!")
  console.log("Hello this is Ivan")
}

Međutim, ono što mi ne znamo je da je u međuvremenu commit napravio i kolega Jure:

function myFunction () {
  console.log("Hello this Mate!")
  console.log("Hello this is Jure")
}

Zapravo imamo ovo:

Sad krećemo s mergeom u master. Prvo radimo checkout na mc-master i onda merge mc-ivan brancha. Vidimo da merge ne prolazi i imamo conflict:

Ako kliknemo na Accept Current Change git će izabrati crvene promjene. Time gubimo Hello Ivan. Ako odaberemo Accept Incoming Change gubimo crvene promjene tj. Hello Jure. Zato biramo obje: Accept Both Changes. To nam daje ovo:

Vidimo da se Mate pojavljuje dvaput. Izbrišimo ga:

I sad imamo finalne promjene. Potrebno je spremiti file (Ctrl + S) i potvrditi merge. Na lijevoj strani dodamo file sa + i commitamo na kvačicu. Merge je sad prošao.

Da smo radili na dvije različite datoteke ili mijenjali datoteku na dva različita mjesta ne bi došlo do konflikta. Zato je bitna podjela rada.

Savjeti za rad

Podijelite se po modulima ili po komponentama. Neka samo jedan radi na jednoj komponenti ili modulu. Pokušajte se što je manje moguće križati. Jedino mjesto gdje će tada doći do konflikta je pages folder kad dodajete modul ili komponentu u stranicu. Tada onaj koji radi pull samo odabere Accept Both Changes i nema problema.

U bilo kojem trenutku tijekom mergea možete napraviti abort sa git merge --abort. To će poništiti promjene mergea i vratiti vas na orginalni branch.

Znam da ovo neće ići glatko, zato smo tu za pomoć. Za sve probleme i pitanja oko gita javite se direktno kroz Teams i pomoći ću vam. Git nije dio zahtjeva ovog kolegija nego samo alat. Ne očekuje se od vas da naučite sve ovo, samo dovoljno za rad. Iako izgleda teško na prvu, nije toliko, pogotovo kad imate nekog za pitati :)

Korisni resursi

Na webu postoji nekoliko Git cheatsheet dokumenata i slika. Evo neki:

Slika: git-cheatsheet-black

Nešto predobro! Definitivno pogledajte:
Vizualizacija git naredbi!

Dokumentacija i objašnjenja naredbi: