Git
Chapters ▾ 2nd Edition

5.2 Distribuirani Git - Kako doprineti projektu

Kako doprineti projektu

Glavni problem kod opisivanja načina na koji treba doprinositi projektu je to što postoji veliki broj varijcija na koji se to može učiniti. Pošto je Git veoma fleksibilan, ljudi rade na mnogo načina, i problematično je opisati kako treba da doprinosite — svaki projekat je drugačiji. Neke od varijabli koje su uključene u to je broj ljudi koji aktivno doprinose, izabrani tok rada, pristup vašim komitovima, i mogućnost eksterne metode za doprinos.

Prva varijabla je broj ljudi koji aktivno učestvuje — pored ovoga, nameće se pitanje i koliko često. U mnogim slučajevima, imaćete dva ili tri developera sa nekoliko komitova na dan, ili možda manje za ne tako aktivne projekte. Za veće kompanije ili projekte, broj developera bi mogao da pređe nekoliko hiljada, sa stotinama ili hiljadama komitova na dan. Ovo je važno jer sa više developera možete da naiđete na više problema jer kôd neće uvek moći da se glatko spoji. Promene koje podnesete bi mogle da budu zastarele ili pregažene radom koji je neko spojio dok ste vi radili ili dok su vaše promene čekale na red da se prihvate ili primene. Kako da održite svoj kôd konstantno aktuelnim, a komitove validnim?

Sledeća varijabla je tok rada koji projekat koristi. Da li je centralizovan, gde svaki developer ima jednak pristup za pisanje glavnoj liniji? Da li projekat ima održavaoca ili rukovodioca integracijama koji proverava sve zakrpe? Da li se zakrpe pregleđuju i odobravaju? Da li ste vi uključeni u taj proces? Da li je primenjen sistem sa poručnicima, i da li morate prvo njima da pošaljete svoj rad?

Sledeći problem je pristup vaših komitova. Tok rada koji je potreban da biste doprineli projektu je mnogo drugačiji ako imate pristup pisanja projektu nego ako ga nemate. Ako nemate pristup pisanja, kako se odlučuje da li će vaš rad biti prihvaćen u projekat? Da li uopšte postoji takva politika? Koliko stvari menjate u jednom trenutku? Koliko često doprinosite?

Sva ova pitanja mogu da utiču na to kako efikasno treba doprinositi projektu i kakvi tokovi rada su prioritetni ili dostupni vama. Pokrićemo aspekte svega ovoga u seriji slučajeva korišćenja, krenuvši od najjednostavnijeg do najkomplikovanijeg; trebalo bi da možete da konstruišete specifične tokove rada koji se javljaju u praksi na osnovu ovih primera.

Smernice za komitove

Pre nego što pogledamo specifične slučajeve korišćenja, evo nekih brzih napomena o komit porukama. Imati dobre smernice za kreiranje komitova i pridržavati se njih će učiniti rad sa Gitom i kolaboraciju sa ostalima mnogo jednostavnijom. Git projekat snabdeva dokument koji opisuje brojne dobre savete za kreiranje komitova za slanje zakrpi — možete da ih pročitate u Gitovom izvornom kodu u fajlu Documentation/SubmittingPatches.

Prvo, ne želite da sabmitujete nikakve greške oko karaktera za razmak, tzv. razmak-greške (whitespace errors). Git ima jednostavan način da proverite ovo — pre nego što komitujete, pokrenite git diff --check, što će identifikovati moguće razmak-greške i izlistati vam ih.

Izlaz komande `git diff --check`.
Figure 57. Izlaz komande git diff --check.

Ako pokrenete tu komandu pre komitovanja, videćete ima li razmak-grešaka koje biste komitovali koje bi smetale drugim developerima.

Dalje, trudite se da svaki komit bude logički izdvojen skup promena. Ako možete, probajte da promene učinite lako svarljivim — nemojte da kodirate ceo vikend na pet različitih problema i da ih onda sve strpate u jedan komit u ponedeljak. Čak i ako ne komitujete tokom vikenda, koristite stejdž u ponedeljak da podelite svoj rad na barem jedan komit po problemu koji ste rešavali, sa korisnim porukama. Ako neke promene modifikuju isti fajl, probajte da korstite git add --patch da parcijalno stejdžujete fajl (detaljnije odrađeno u Interactive Staging). Snimak projekta na vrhu grane je isti bilo da komitujete jednom ili pet puta, sve dok sve promene budu dodate na kraju, zato se trudite da stvari učinite lakšim svojim programerima-kolegama kada budu gledali vaše promene. Sa ovim pristupom je lakše da se kasnije locira potencijalna greška ili da se vrati na neko od pređašnjih stanja. Rewriting History opisuje brojne korisne Git trikove za pisanje preko istorije i interaktivno stejdžovanje fajlova — koristite ove alate da pomognete sebi da izgradite čistu i jasnu istoriju pre nego što pošaljete svoj rad drugima.

Još jedna stvar koju treba da imate na umu jeste komit poruka. Sticanje navike da komit poruke budu kvalitetne učiniće korišćenje Gita i kolaboraciju sa drugima mnogo lakšom. Kao opšte pravilo, poruke treba da počnu jednom linijom koja nije duža od 50 karaktera i koja koncizno opisuje promenu, za kojom sledi prazna linija, a zatim detaljnije objašnjenje. Git projekat zahteva da detaljnije objašnjenje uključi motivaciju za promenu i da iskaže kontrast koji ima implementacija u odnosu na prethodno ponašanje — ovu smernicu je dobro pratiti. Takođe je dobra ideja koristiti imperativni prezent u porukama. Drugim rečima, izdajte naredbe. Umesto "adding test for" ili "I added tests for", korsitite "add test for". Evo originalne verzije obrasca koji je napisao Tim Poup:

Short (50 chars or less) summary of changes

More detailed explanatory text, if necessary.  Wrap it to
about 72 characters or so.  In some contexts, the first
line is treated as the subject of an email and the rest of
the text as the body.  The blank line separating the
summary from the body is critical (unless you omit the body
entirely); tools like rebase can get confused if you run
the two together.

Further paragraphs come after blank lines.

  - Bullet points are okay, too

  - Typically a hyphen or asterisk is used for the bullet,
    preceded by a single space, with blank lines in
    between, but conventions vary here

Ako sve vaše komit poruke izgledaju ovako, stvari će biti mnogo jednostavnije za vas i developere sa kojima radite. Git projekat ima dobro formatirane komit poruke — pokrenite git log --no-merges tamo da vidite kako izgleda lepo formatirana istorija komitova u projektu.

U sledećim primerima, i kroz većinu ostatka knjige, radi kratkoće ova knjiga neće imati lepo formatirane poruke; umesto toga, koristićemo -m opciju uz git commit. Radite kako vam kažemo, a ne kako mi radimo.

Mali privatni tim

Najjednostavnija postavka na koju ćete verovatno naići je privatni projekat sa jednim ili dva developera. "Privatni" u ovom kontekstu znači da je zatvorenog koda — nije dostupan ostatku sveta. Vi i svi ostali developeri imate dozovlu da gurate promene na repozitorijum.

U ovakvom okruženju, možete da pratite tok rada sličan onom koji imate kada koristite Subversion ili drugi centralizovan sistem. I dalje dobijate prednosti zbog stvari kao što su oflajn komitovanje i znatno jednostavnije grananje i spajanje, ali tok rada može da bude veoma sličan; glavna razlika je to što se spojevi dešavaju na strani klijenta umesto na strani servera tokom komitova. Da vidimo kako bi stvar mogla da izgleda kada dva developera počnu da rade na deljivom repozitorijumu. Prvi develpoer, Džon, klonira repozitorijum, napravi izmene i komituje lokalno. (Poruke protokola su zamenjene sa ... da bi se skratile.)

# John's Machine
$ git clone john@githost:simplegit.git
Initialized empty Git repository in /home/john/simplegit/.git/
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'removed invalid default value'
[master 738ee87] removed invalid default value
 1 files changed, 1 insertions(+), 1 deletions(-)

Drugi developer, Džesika, radi istu stvar — klonira repozitorijum i komituje promenu:

# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Initialized empty Git repository in /home/jessica/simplegit/.git/
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
 1 files changed, 1 insertions(+), 0 deletions(-)

Sad Džesika gura svoj rad na server:

# Jessica's Machine
$ git push origin master
...
To jessica@githost:simplegit.git
   1edee6b..fbff5bc  master -> master

Džon pokušava da gurne i svoje promene:

# John's Machine
$ git push origin master
To john@githost:simplegit.git
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to 'john@githost:simplegit.git'

Džonu nije dozvoljeno da gurne svoje promene jer je Džesika to u međuvremenu uradila. Ovo je posebno važno razumeti ako ste navikli na Subversion, jer ćete primetiti da njih dvoje nisu editovali isti fajl. Kada se edituju različiti fajlovi, Subversion automatski radi takve spojeve na serveru, dok u Gitu morate da spojite komitove lokalno. Džon mora da pribavi Džesikine promene i da ih spoji pre nego što mu bude dozvoljeno da gurne svoje:

$ git fetch origin
...
From john@githost:simplegit
 + 049d078...fbff5bc master     -> origin/master

Sada Džonov lokalni repozitorijum izgleda ovako nekako:

Džonova divergentna istorija.
Figure 58. Džonova divergentna istorija.

Džon ima referencu na promene koje je Džesika gurnula, ali mora da spoji sopstveni rad sa njima pre nego što mu se dozvoli guranje:

$ git merge origin/master
Merge made by recursive.
 TODO |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

Spoj prolazi glatko — Džonova istorija komitova sada izgleda ovako:

Džonov repozitorijum posle spajanja `origin/master`.
Figure 59. Džonov repozitorijum posle spajanja origin/master.

Sada Džon može da testira svoj kod da bi se uverio da radi kako valja, i onda može da gurne svoj novi spojeni rad na server:

$ git push origin master
...
To john@githost:simplegit.git
   fbff5bc..72bbc59  master -> master

Konačno, Džonova istorija komitova izgleda ovako:

Džonova istorija komitova posle guranja na `origin` server.
Figure 60. Džonova istorija komitova posle guranja na origin server.

U međuvremenu, Džesika je radila na tematskoj grani. Napravila je tematsku granu issue54 i napravila tri komita na toj grani. Još nije pribavila Džonove promene, tako da njena istorija komitova izgleda ovako:

Džesikina tematska grana.
Figure 61. Džesikina tematska grana.

Džesika želi da se sinhroniše sa Džonom, pa pribavlja podatke:

# Jessica's Machine
$ git fetch origin
...
From jessica@githost:simplegit
   fbff5bc..72bbc59  master     -> origin/master

Ovo povlači rad koji je Džon u međuvremenu gurnuo. Džesikina istorija sada izgleda ovako:

Džesikina istorija posle pribavljanja Džonovih promena.
Figure 62. Džesikina istorija posle pribavljanja Džonovih promena.

Džesika misli da je njena tematska grana spremna, pa želi da zna šta treba da spoji u svoj rad da bi mogla da gurne promene. Pokreće git log da sazna:

$ git log --no-merges issue54..origin/master
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date:   Fri May 29 16:01:27 2009 -0700

   removed invalid default value

issue54..origin/master sintaksa je filter za log koji traži od Gita da pokaže samo listu komitova koji su na drugoj grani (u ovom slučaju origin/master) a nisu na prvoj grani (u ovom slučaju issue54). Detaljnije ćemo obraditi ovu sintaksu u Commit Ranges.

Zasad, sa izlaza vidimo da postoji samo jedan komit koji je Džon napravio a da se Džesika nije spojila sa njim. Ako spoji origin/master, to je jedini komit koji će promeniti njen lokalni rad.

Sada Džesika može da spoji svoju tematsku granu u svoju master granu, da spoji Džonove promene (origin/master) u svoju master granu, i da onda gurne promene na server. Prvo, skače nazad na master granu da integriše sav svoj rad:

$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.

Može prvo da spoji bilo origin/master ili issue54 — obe se nalaze uzvodno, pa redosled nije važan. Krajnji snimak će biti identičan koji god redosled da izabere; samo će istorija biti neznatno drugačija. Bira da se prvo spoji sa issue54:

$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
 README           |    1 +
 lib/simplegit.rb |    6 +++++-
 2 files changed, 6 insertions(+), 1 deletions(-)

Ne javljaju se problemi; kao što se vidi, radilo se o jednostavnom motanju unapred. Sada se Džesika spaja u Džonov rad (origin/master):

$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by recursive.
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Sve se spaja bez problema, i Džesikina istorija izgleda ovako:

Džesikina istorija nakon spajanja sa Džonovim promenama.
Figure 63. Džesikina istorija nakon spajanja sa Džonovim promenama.

Sada je origin/master dostupan sa Džesikine master grane, tako da bi trebalo da može uspešno da gurne promene (pod pretpostavkom da Džon nije ponovo gurnuo neke svoje promene u međuvremenu):

$ git push origin master
...
To jessica@githost:simplegit.git
   72bbc59..8059c15  master -> master

Svi developeri su komitovali nekoliko puta i uspešno spojili svoj rad.

Džesikina istorija nakon guranja svih promena nazad na server.
Figure 64. Džesikina istorija nakon guranja svih promena nazad na server.

To je jedan od najjednostavnijih tokova rada. Radite neko vreme, u opštem slučaju na tematskoj grani, i spojite se u master granu kada ste spremni za integraciju. Kada želite da podelite taj rad, spojite to u sopstvenu master granu, i onda pribavite i spojite origin/master ako se promenio, i na kraju gurnete master granu na server. Opšta sekvenca izgleda nekako ovako:

Opšta sekvenca događaja za jednostavan tok rada sa više developera.
Figure 65. Opšta sekvenca događaja za jednostavan tok rada sa više developera.

Privatni tim sa rukovodstvom

U ovom scenariju, pogledaćemo uloge kontributora u većoj privatnoj grupi. Naučićete kako da radite u okruženju gde male grupe sarađuju na delovima koda i onda se takvi doprinosi na nivou tima integrišu od strane nekog drugog.

Recimo da Džon i Džesika rade zajedno na jednom delu, dok Džesika i Džozi rade na drugom. U ovom slučaju, kompanija koristi neku vrstu toka rada sa rukovodstvom za integracije gde se rad pojedinačnih grupa integriše samo od strane određenih inženjera, i master granu glavnog repozitorijuma mogu da apdejtuju samo oni. U ovom scenariju, sav rad se obavlja na timski baziranim granama i kasnije ga povlače integratori.

Hajde da pratimo Džesikin tok rada dok radi na dve strane, odnosno dok paralelno kolaborira sa dva različita developera u ovom okruženju. Pod pretpostavkom da već ima kloniran repozitorijum, odlučuje da prvo radi na featureA. Pravi novu granu za ovo i radi na njoj:

# Jessica's Machine
$ git checkout -b featureA
Switched to a new branch 'featureA'
$ vim lib/simplegit.rb
$ git commit -am 'add limit to log function'
[featureA 3300904] add limit to log function
 1 files changed, 1 insertions(+), 1 deletions(-)

Sada treba da podeli svoj rad sa Džonom, pa gura komitove sa featureA grane na server. Džesika nema dozvolu da gurne na master granu — samo integratori mogu to — pa mora da gurne na drugu granu da bi sarađivala sa Džonom:

$ git push -u origin featureA
...
To jessica@githost:simplegit.git
 * [new branch]      featureA -> featureA

Džesika šalje mejl Džonu da mu kaže da je gurnula neke stvari na granu koja se zove featureA i da on sada može da pogleda to. Dok čeka na povratnu informaciju od Džona, Džesika odlučuje da počne da radi na featureB sa Džozi. Za početak, počinje novu granu, i bazira je na master grani sa severa:

# Jessica's Machine
$ git fetch origin
$ git checkout -b featureB origin/master
Switched to a new branch 'featureB'

Sada Džesika pravi nekoliko komitova na grani featureB:

$ vim lib/simplegit.rb
$ git commit -am 'made the ls-tree function recursive'
[featureB e5b0fdc] made the ls-tree function recursive
 1 files changed, 1 insertions(+), 1 deletions(-)
$ vim lib/simplegit.rb
$ git commit -am 'add ls-files'
[featureB 8512791] add ls-files
 1 files changed, 5 insertions(+), 0 deletions(-)

Džesikin repozitorijum izgleda ovako:

Džesikina inicijalna istorija komitova.
Figure 66. Džesiina inicijalna istorija komitova.

Spremna je da gurne svoj rad, ali dobija mejl od Džozi da je grana sa nekim inicijalnim radom već gurnuta na server pod imenom featureBee. Džesika prvo mora da spoji te promene sa sobom pre nego što može da gurne promene na server. Ona pribavlja Džozine promene sa git fetch:

$ git fetch origin
...
From jessica@githost:simplegit
 * [new branch]      featureBee -> origin/featureBee

Džesika sada može da spoji ovo sa svojim radom pomoću git merge:

$ git merge origin/featureBee
Auto-merging lib/simplegit.rb
Merge made by recursive.
 lib/simplegit.rb |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

Ovde nastaje mali problem — treba da gurne spojeni rad na svojoj featureB grani na featureBee granu na server. To može da uradi tako što će specificirati lokalnu granu, zatim dve tačke (:) i na kraju udaljenu granu komandi git push:

$ git push -u origin featureB:featureBee
...
To jessica@githost:simplegit.git
   fba9af8..cd685d1  featureB -> featureBee

Ovo se zove refspec. Pogledajte Refspek za detaljniju diskusiju o Gitovim refspekovima i ranim stvarima koje možete da uradite pomoću njih. Primetite i -u zastavicu; ovo je skraćeno od --set-upstream, što konfiguriše grane za lakše guranje i povlačenje kasnije.

Sada, Džon pušta mejl Džesiki i kaže joj da je gurnuo neke promene na featureA i moli je da ih pogleda. Ona pokreće git fetch da povuče te promene:

$ git fetch origin
...
From jessica@githost:simplegit
   3300904..aad881d  featureA   -> origin/featureA

Onda može da vidi šta se promenilo sa git log:

$ git log featureA..origin/featureA
commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: John Smith <jsmith@example.com>
Date:   Fri May 29 19:57:33 2009 -0700

    changed log output to 30 from 25

Konačno, spaja Džonov rad u svoju featureA granu.

$ git checkout featureA
Switched to branch 'featureA'
$ git merge origin/featureA
Updating 3300904..aad881d
Fast forward
 lib/simplegit.rb |   10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)

Džesika želi da napravi neku malu promenu, pa komituje ponovo i gurne ovo nazad na server:

$ git commit -am 'small tweak'
[featureA 774b3ed] small tweak
 1 files changed, 1 insertions(+), 1 deletions(-)
$ git push
...
To jessica@githost:simplegit.git
   3300904..774b3ed  featureA -> featureA

Džesikina istorija komitova sada izgleda ovako:

Džesikina isotorija nakon komitovanja na `featureA` granu.
Figure 67. Džesikina isotorija nakon komitovanja na featureA granu.

Džesika, Džozi i Džon informišu integratore da su grane featureA i featureBee na serveru spremne za integraciju sa glavnom linijom. Nakon što integratori spoje ove grane u glavnu liniju, pribavljanje će dovesti novi spojni komit, pa će istorija izgledati ovako:

Džesikina istorija nakon spajanja obeju tematskih grana.
Figure 68. Džesikina istorija nakon spajanja obeju tematskih grana.

Mnoge grupe prelaze na Git zbog mogućnosti da imaju više timova koji rade paralelno, spajajući različite linije rada tokom procesa. Mogućnost manjih podgrupa timova da doprinose preko udaljenih grana a da ne smetaju čitavom timu je velika beneficija Gita. Sekvenca toka rada koju ste ovde videli izgleda ovako:

Osnovan sekvenca ovakvog toka rada privatnog tima sa rukovodstvom.
Figure 69. Osnovan sekvenca ovakvog toka rada privatnog tima sa rukovodstvom.

Forkovan javni projekat

Doprinos javnim projektima teče malo drugačije. Pošto nemate dozvolu da direktno menjate grane na projektu, morate da date svoj rad održavaocima projekta na neki drugi način. Prvi primer opisuje kontribuiranje preko forkovanja na Git hostovima koji podržavaju lako forkovanje.

Mnogi hostinzi podržavaju ovo (uključujući GitHub, BitBucket, Google Code, repo.or.cz, i drugi), i mnogi održavaoci projekta očekuju ovakav stil kontribuiranja. Za početak, verovatno treba da klonirate glavni repozitorijum, napravite tematsku granu za zakrpu ili seriju zakrpa na kojoj radite, i da tu radite svoj posao. Sekvenca u suštini izgleda ovako:

$ git clone (url)
$ cd project
$ git checkout -b featureA
# (work)
$ git commit
# (work)
$ git commit
Note

Možda ćete želeti da iskoristite rebase -i da zgnječite rad na jedan komit, ili da preuredite rad u komitovima da bi održavalac jednostavnije pregledao zakrpu — vidite Rewriting History za više informacija o interaktivnom rebaziranju.

Kada je vaš rad na grani obavljen i kada budete spremni da ga prosledite održavaocima, odite na originalnu stranicu projekta i kliknite na Fork dugme; tako pravite svoj lični fork projekta po kome možete pisati. Onda treba da dodate ovaj novi URL repozitorijuma kao drugi rimout, u ovom slučaju nazvan myfork:

$ git remote add myfork (url)

Onda treba da gurnete svoj rad na njega. Lakše je gurnuti tematsku granu na kojoj radite na svoj repozitorijum, nego da se spajate sa master granom i onda to gurnete. Razlog je to taj što, ako rad nije prihvaćen ili je čeripikovan, ne morate da motate svoju master granu unazad. Ako održavaoci spoje, rebaziraju ili čeripikuju vaš rad, svakako ćete ga kad-tad dobiti nazad tako što ćete povući sa njihovog repozitorijuma:

$ git push -u myfork featureA

Kada je vaš rad gurnut na fork, treba da obavestite održavaoca. Ovo se često radi zahtevom za povlačenje (pull request), i možete da ga generišete ili preko vebsajta — GitHub ima svoj mehanizam za zahteve za povlačenje koji ćemo obraditi u GitHub — ili možete da pokrenete git request-pull komandu i pošaljete izlaz na mejl održavaocu projekta manuelno.

Komanda request-pull uzima osnovnu granu u koju želite da povučete tematsku granu i URL Git repozitorijuma sa kog želite da povuku, i štampa sažetak svih promena koje tražite da se povuku. Na primer, ako Džesika želi da Džonu pošalje zahtev za povlačenje, a uradila je dva komita na tematskoj grani koju je upravo gurnula, može da pokrene ovo:

$ git request-pull origin/master myfork
The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
  John Smith (1):
        added a new function

are available in the git repository at:

  git://githost/simplegit.git featureA

Jessica Smith (2):
      add limit to log function
      change log output to 30 from 25

 lib/simplegit.rb |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

Izlaz može da se pošalje održavaocu — on mu govori odakle je rad izgranat, rezimira komitove i kaže mu odakle da povuče ovaj rad.

Na projektu gde vi niste održavalac, generalno je lakše da imate granu kao što je master koja uvek prati origin/master i da radite svoj posao na tematskim granama koje lako možete da odbacite ako budu bile odbijene. Imati teme za rad izolovane u tematskim granama takođe čini rebaziranje lakšim ako vrh glavnog repozitorijuma u međuvremenu bude pomeren i vaši komitovi se više ne uklpaju glatko. Na primer, ako želite da pošaljete drugu temu rada na projekat, nemojte nastavljati da radite na tematskoj grani koju ste upravo gurnuli — počnite iz početka, tj. od master grane repozitorijuma:

$ git checkout -b featureB origin/master
# (work)
$ git commit
$ git push myfork featureB
# (email maintainer)
$ git fetch origin

Sada je svaka od tema sadržana unutar silosa — slično kao red zakrpa (patch queue) — koje možete da rebazirate, modifikujete i pišete preko njih a da se teme ne mešaju međusobno i da ne zavise jedna od druge, ovako:

Inicijalna istorija komitova sa radom `featureB`.
Figure 70. Incijalna istorija komitova sa radom featureB.

Recimo da je održavalac projekta povukao gomilu drugih zakrpa i probao prvo vašu granu, ali ona se više ne spaja bez problema. U tom slučaju, možete da probate da rebazirate tu granu na vrh origin/master-a, da rešite konflikte za održavaoca, i onda ponovo pošaljete svoje promene.

$ git checkout featureA
$ git rebase origin/master
$ git push -f myfork featureA

Ovo piše preko vaše istorije koja će sada izgledati kao Istorija komitova posle rada featureA..

Istorija komitova posle rada `featureA`.
Figure 71. Istorija komitova posle rada featureA.

Pošto ste rebazirali granu, morate da specificirate -f komandi push da biste mogli da zamenite featureA granu na serveru komitom koji nije njegov sledbenik. Alternativa bi bila da gurnete ovaj novi rad na drugu granu na serveru (koja se recimo zove featureAv2).

Pogledajmo još jedan mogući scenario: održavalac je pogledao vaš rad u drugoj grani i sviđa mu se koncept ali bi voleo da napravite promenu u nekom detalju oko implementacije. Iskoristićete ovu priliku i da pomerite rad da bude baziran na trenutnoj master grani projekta. Počinjete novu granu baziranu na trenutnoj origin/master grani, gnječite featureB promene tamo, rešavate sve konflikte, pravite implementacionu promenu i onda gurate to kao novu granu:

$ git checkout -b featureBv2 origin/master
$ git merge --squash featureB
# (change implementation)
$ git commit
$ git push myfork featureBv2

Opcija --squash uzima sav rad na spojenoj grani i gnječi ga u jedan skup promena, praveći tako stanje repozitorijuma kao da se dogodio pravi spoj, a da zapravo niste napravili komit. Ovo znači da će vaš budući komit imati samo jednog roditelja i dozvoljava vam da uvedete sve promene sa druge grane i onda napravite još promena pre nego što zabeležite novi komit. Opcija --no-commit takođe može da bude korisna da odložite spojni komit u slučaju podrazumevanog procesa spajanja.

Sada možete da pošaljete održavaocu poruku da ste napravili zahtevane izmene i da mogu da nađu te izmene u vašoj featureBv2 grani.

Istorija komitova nakon rada na`featureBv2`.
Figure 72. IStorija komitova nakon rada na featureBv2.

Javni projekat preko mejla

Mnogi projekti imaju utvrđene procedure za prihvatanje zakrpi — moraćete da proverite specifična pravila za svaki projekat, jer će se razlikovati. Pošto ima nekoliko starijih većih projekata koje prihvataju zakrpe preko spisaka adresa developera, preći ćemo taj primer sada.

Tok rada je sličan kao u prethodnom slučaju — napravite tematske grane za svaku zakrpu na kojoj radite. Razlika je u tome kako ih šaljete projektu. Umesto da forkujete projekat i objavite svoju ličnu verziju po kojoj možete pisati, generisaćete mejl verzije svake serije komitova i poslati ih putem spiska adresa developera.

$ git checkout -b topicA
# (work)
$ git commit
# (work)
$ git commit

Sada imate dva komita koja želite da pošaljete spisku adresa. Koristite git format-patch da generišete fajlove formatirane kao mbox koje šaljete spisku putem mejla — tako pretvarate svaki komit u mejl gde se prva linija komit poruke shvata kao tema mejla a ostatak mejla kao preostali deo komit poruke plus zakrpa koju taj komit uvodi se shvata kao telo. Dobra stvar u vezi s ovime je to što prihvatanje zakrpe koja je generisala za mejl sa format-patch čuva sve inforamcije o komitu.

$ git format-patch -M origin/master
0001-add-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch

Komanda format-patch štampa imena zakrpa-fajlova koje kreira. Zastavica -M govori Gitu da potraži preimenovane fajlove. Fajlovi na kraju izgledaju ovako:

$ cat 0001-add-limit-to-log-function.patch
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

---
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit
   end

   def log(treeish = 'master')
-    command("git log #{treeish}")
+    command("git log -n 20 #{treeish}")
   end

   def ls_tree(treeish = 'master')
--
2.1.0

Možete i da edituje ove zakrpa-fajlove i da dodate više informacija koje ne želite da se pojave u komit poruci, ali želite da vide svi sa liste adresa. Ako dodate tekst između --- linije i početka zakrpe (linija diff --git), onda će developeri moći da ga pročitaju; ali primenjivanje zakrpe to neće uključiti.

Da pošaljete ovo na spisak adresa, možete da nalepite fajl u svom mejl programu ili da ga pošaljete preko komandne linije. Nalepljivanje teksta često stvara probleme pri formatiranju, pogotovo sa "pametnijim" klijentima koji ne održavaju nove linije i druge znakove razmaka kako treba. Srećom, Git ima alat koji će vam pomoći da pošaljete dobro formatirane zakrpe preko IMAP-a, što bi moglo da vam bude lakše. Demonstriraćemo kako da pošaljete zakrpu preko Gmail-a, što je mejl agent kog znamo najbolje; možete da pročitate detaljne instrukcije o mnogim mejl programima na kraju gorepomenutog fajla Documentation/SubmittingPatches u izvornom kodu Gita.

Prvo, treba da podesite imap odeljak u ~/.gitconfig fajlu. Možete da podesite svaku vrednost posebno serijom git config komandi, ili da ih dodate manuelno, ali na kraju će vaš config fajl izgledati nekako ovako:

[imap]
  folder = "[Gmail]/Drafts"
  host = imaps://imap.gmail.com
  user = user@gmail.com
  pass = p4ssw0rd
  port = 993
  sslverify = false

Ako vaš IMAP server ne koristi SSL, poslednje dve linije verovatno nisu neophne, i vrednost host će biti impa:// umesto imaps://. Kad je to gotovo, možete da pomoću git imap-send postavite seriju zakrpa u Drafts folder na specificiranom IMAP serveru:

$ cat *.patch |git imap-send
Resolving imap.gmail.com... ok
Connecting to [74.125.142.109]:993... ok
Logging in...
sending 2 messages
100% (2/2) done

Sada bi trebalo da možete da odete u Drafts folder, da promenite To polje u spisak adresa kome šaljete zakrpu, eventualno CC održavaoca ili osobu koje je odgovorna za taj odeljak, i da pošaljete mejl.

Možete da šaljete zakrpe i preko SMTP servera. Kao i ranije, možete da podesite svaku vrednost ponaosob serijom git config komandi, ili da ih dodate ručno u sendmail odeljku ~/.gitconfig fajla:

[sendemail]
  smtpencryption = tls
  smtpserver = smtp.gmail.com
  smtpuser = user@gmail.com
  smtpserverport = 587

Kada je ovo gotovo, možete pomoću git send-email da pošaljete svoje zakrpe:

$ git send-email *.patch
0001-added-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
Who should the emails appear to be from? [Jessica Smith <jessica@example.com>]
Emails will be sent from: Jessica Smith <jessica@example.com>
Who should the emails be sent to? jessica@example.com
Message-ID to be used as In-Reply-To for the first email? y

Git onda izbaci gomilu log informacija koje izgledaju nekako ovako za svaku zakrpu koju šaljete:

(mbox) Adding cc: Jessica Smith <jessica@example.com> from
  \line 'From: Jessica Smith <jessica@example.com>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
From: Jessica Smith <jessica@example.com>
To: jessica@example.com
Subject: [PATCH 1/2] added limit to log function
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>

Result: OK

Rezime

Ovaj odeljak je pokrio brojne česte tokove rada i način na koji se pristupa veoma različitim tipovima Git projekata na koje ćete verovatno naići, i predstavljeni su neki novi alati koji će vam pomoći da radite to. Sada ćemo pogledati kako da radite sa druge strane novčića: održavanje Git projekta. Naučićete kako da budete blagonakloni diktator ili rukovodilac integracijama.