Git 🌙
Chapters ▾ 2nd Edition

5.2 Porazdeljeni Git - Prispevek k projektu

Prispevek k projektu

Glavna težava z opisovanjem, kako prispevati projektu, je, da obstaja veliko število spremenljivk, kako je to narejeno. Ker je Git zelo prilagodljiv, ljudje lahko in tudi res delajo skupaj na mnoge načine in problematično je opisovati, kako bi morali prispevati — vsak projekt je nekoliko drugačen. Nekatere vključene spremenljivke so število aktivnih ljudi, ki prispevajo, izbrani potek dela, vaš dostop potrjevanja in po možnosti zunanja metoda prispevkov.

Prva spremenljivka je število aktivnih ljudi, ki prispevajo — koliko uporabnikov aktivno prispeva kodo temu projektu in kako pogosto? V mnogih primerih boste imeli dva ali tri razvijalce z nekaj potrditvami na dan ali po možnosti manj za projekte nekako v stanju mirovanja. Za večja podjetja ali projekte bi lahko število razvijalcev bilo v tisočih, s stotine ali tisoče potrditev, ki prihajajo vsak dan. To je pomembno, ker z več in več razvijalci naletite na večje težave, kako zagotavljati, da se vaša koda uporablja gladko oz. je enostavno združljiva. Spremembe, ki jih pošljete, lahko postanejo zastarele ali precej polomljene z delom, ki je bilo združeno, medtem ko ste delali, ali medtem ko vaše spremembe čakajo na odobritev ali uporabo. Kako lahko obdržite svojo kodo konsistentno posodobljeno in vaše potrditve veljavne?

Naslednja spremenljivka je potek dela, ki je v uporabi za projekt. Je centraliziran, kjer ima vsak razvijalec enak dostop pisanja v glavno linijo kode? Ali ima projekt vzdrževalca ali integracijskega upravitelja, ki preveri vse popravke? So vsi popravki strokovno pregledani in odobreni? Ali ste vključeni v ta proces? Ali je sistem poročnika na mestu in ali jim morate najprej poslati svoje delo?

Naslednja spremenljivka je vaš dostop potrditev. Potek dela, ki je zahtevan za prispevek k projektu, je veliko bolj drugačen, če imate dostop pisanja k projektu, kot če ga nimate. Če nimate dostopa za pisanje, kako ima projekt raje, da sprejme prispevano delo? Ali ima sploh pravilnik? Koliko dela prispevate na določen čas? Kako pogosto prispevate?

Vsa ta vprašanja lahko vplivajo, kako efektivno prispevati projektu in katere poteke dela imate raje, oziroma so vam na voljo. Pokrili bomo vidike vsakega od teh v seriji primerov uporabe in se premaknili od enostavnega do bolj kompleksnega; morali bi biti sposobni skonstruirati določen potek dela, ki ga potrebujete v praksi iz teh primerov.

Smernice potrjevanja

Preden začnemo gledati določene primere uporabe, je tu hitro obvestilo o sporočilih potrditev. Imeti dobre smernice za ustvarjanje potrditev in se jih držati, naredi delo z Gitom in sodelovanjem z ostalimi veliko enostavnejše. Projekt Git ponuja dokument, ki začrta število dobrih nasvetov za ustvarjanje potrditev, iz katerih se pošljejo popravki — to lahko preberete v izvorni kodi Git v datoteki Documentation/SubmittingPatches.

Kot prvo, ne želite poslati kakršnih koli napak praznih znakov. Git ponuja enostaven način, da to preverite — preden potrdite, poženite git diff --check, ki identificira vse možne napake praznih znakov in vam jih izpiše.

Izpis `git diff --check`
Slika 56. Izpis git diff --check

Če poženete ta ukaz preden potrdite, lahko poveste, ali ste tik pred tem, da potrdite tudi težave s praznimi znaki, ki lahko nagajajo ostalim razvijalcem.

Naslednje poskusite narediti vsako potrditev kot logičen ločen skupek sprememb. Če lahko, poskusite narediti svoje spremembe prebavljive — ne kodirajte cel vikend na petih različnih težavah in nato pošljite vse kot eno masovno potrditev v ponedeljek. Tudi če ne naredite potrditve med koncem tedna, uporabite področje priprave v ponedeljek, da se loči vaše delo v vsaj eno potrditev na težavo z uporabnim sporočilom na potrditev. Če nekatere spremembe spremenijo isto datoteko, poskusite uporabiti git add --patch za delno pripravo datoteke (podrobno pokrito v razdelku Interaktivno pripravljanje). Posnetek projekta pri vrhu veje je identičen, če naredite eno ali pa pet potrditev, dokler so vse spremembe dodane na neki točki, torej poskusite narediti stvari enostavne za svoje kolege razvijalce, ko bodo morali pregledati vaše spremembe.

Ta pristop naredi enostavnejše tudi vlečenje ali povrnitev ene izmed skupka sprememb, če to kasneje potrebujete. Razdelek Prepisovanje zgodovine opisuje število uporabnih trikov Git za prepisovanje zgodovine in interaktivno dajanje datotek v področje priprave — uporabite ta orodja, da vam pomagajo izdelati čisto in razumljivo zgodovino, preden pošljete delo nekomu drugemu.

Zadnja stvar za pomnjenje je sporočilo potrditve. Navaditi se ustvarjati kakovostna sporočila potrditev naredi uporabo in sodelovanje z Gitom veliko enostavnejše. Kot splošno pravilo bi se vaša sporočila morala začeti z eno vrstico, ki ni večja od 50 znakov in jedrnato opisuje skupek sprememb ter nato ji sledi prazna vrstica, ki ji sledi podrobnejša razlaga. Projekt Git zahteva, da bolj podrobna razlaga vključuje vašo motivacijo za spremembe in kontrast njene implementacije s prejšnjim obnašanjem — to je tudi dobra smernica za sledenje. Napišite svoja sporočila potrditev v velelniku: »Popravi hrošč« in ne »Popravljen hrošč« ali »To popravi hrošč«. Tu lahko sledite tej predlogi, ki smo jo malenkost prilagodili po tej, ki jo je prvotno napisal Tim Pope:

Capitalized, short (50 chars or less) summary

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 will confuse you if you run the
two together.

Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug."  This convention matches up with commit messages generated
by commands like git merge and git revert.

Further paragraphs come after blank lines.

- Bullet points are okay, too

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

- Use a hanging indent

Če vsa vaša sporočila potrditev sledijo temu modelu, so stvari veliko enostavnejše za vas in razvijalce, s katerimi delate. Projekt Git ima dobro oblikovana sporočila potrditev — poskusite tam pognati git log --no-merges, da vidite, kakšna je lepo oblikovana zgodovina potrditev projekta.

Opomba
Naredite, kot pravimo, in ne kot to mi počnemo.

Večina primerov v tej knjigi zaradi kratkosti nima lepo oblikovanih sporočil, kot je ta; namesto tega, uporabljamo možnost -m za git commit.

Na kratko, naredite, kot pravimo, in ne kot to mi počnemo.

Zasebna majhna ekipa

Najenostavnejša nastavitev, na katero boste verjetno naleteli, je zasebni projekt z enim ali dvema razvijalcema. »Zasebni« v tem kontekstu pomeni zaprto kodo — ni dostopna za zunanji svet. Vi in ostali razvijalci imate vsi dostop potiskanja v repozitorij.

V tem okolju lahko sledite poteku dela, ki je podoben, kakor ste morda delali, ko ste uporabljali Subversion ali drug centraliziran sistem. Še vedno dobite prednosti stvari, kot so potrjevanje brez povezave in prostrano enostavnejše razvejanje in združevanje, vendar potek dela je lahko zelo podoben; glavna razlika je, da se združevanje zgodi na strani odjemalca namesto na strežniku v času potrditve. Poglejmo, kako je lahko videti, ko dva razvijalca začneta delati skupaj z deljenim repozitorijem. Prvi razvijalec, John, klonira repozitorij, naredi spremembe in jih potrdi lokalno. Sporočila protokola so bila v teh primerih zamenjana s …​, da se nekako skrajšajo.

# John's Machine
$ git clone john@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'Remove invalid default value'
[master 738ee87] Remove invalid default value
 1 files changed, 1 insertions(+), 1 deletions(-)

Druga razvijalka, Jessica, naredi isto stvar — klonira repozitorij in potrdi spremembo:

# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'Add reset task'
[master fbff5bc] Add reset task
 1 files changed, 1 insertions(+), 0 deletions(-)

Sedaj Jessica potisne njeno delo na strežnik:

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

Zadnja vrstica izhoda zgoraj prikazuje uporabno sporočilo o vrnitvi iz operacije potiska. Osnovni format je <oldref>..<newref> fromref → toref, kjer oldref pomeni staro referenco, newref pomeni novo referenco, fromref je ime lokalne reference, ki jo potiskamo, in toref je ime oddaljene reference, ki jo posodabljamo. Podoben izhod boste videli spodaj v razpravah, zato bo osnovna ideja o pomenu pomagala pri razumevanju različnih stanj repozitorijev. Več podrobnosti najdete v dokumentaciji za git-push.

Če nadaljujemo s tem primerom, kmalu zatem John naredi nekaj sprememb, jih potrdi v svojem lokalnem repozitoriju in jih poskuša potisniti na isti strežnik:

# 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'

V tem primeru Johnov potisk ni uspešen, ker je vmes potisnila Jessica njene spremembe. To je posebej pomembno razumeti, če ste vajeni Subversiona, ker boste opazili, da dva razvijalca nista uredila iste datoteke. Čeprav Subversion naredi to združevanje avtomatično na strežniku, če se urejajo različne datoteke, morate z Gitom najprej združiti potrditve lokalno. Z drugimi besedami, John mora najprej prenesti zgornje spremembe Jessice in jih združiti v svoj lokalni repozitorij, preden bo smel potisniti.

Kot prvi korak John prenese delo Jessice (to samo prenese zgornje delo Jessice in ga še ne združi v Johnovo delo):

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

Na tej točki je Johnov lokalni repozitorij videti nekako takole:

Johnova drugačna zgodovina
Slika 57. Johnova drugačna zgodovina

Sedaj lahko John združi Jessicino delo, ki ga je prenesel v svoje lokalno delo:

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

Dokler gre to lokalno združevanje gladko, bo Johnova posodobljena zgodovina sedaj videti nekako takole:

Johnov repozitorij po združitvi `origin/master`
Slika 58. Johnov repozitorij po združitvi origin/master

Sedaj lahko John testira to novo kodo, da zagotovi, da nobeno delo Jessice ne vpliva na nobeno njegovo in dokler poteka vse ustrezno, lahko potisne novo združeno delo na strežnik:

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

Na koncu je Johnova zgodovina potrditev videti nekako takole:

Johnova zgodovina po potisku na strežnik `origin`
Slika 59. Johnova zgodovina po potisku na strežnik origin

Vmes je Jessica ustvarila novo tematsko vejo imenovano issue54 in na tej veji naredila tri potrditve. Ni pa še prenesla Johnovih sprememb, zato je njena zgodovina potrditev videti nekako takole:

Jessicina tematska veja
Slika 60. Jessicina tematska veja

Nenadoma Jessica izve, da je John potisnil nekaj novega dela na strežnik, in želi ga pogledati, torej lahko prenese vso novo vsebino iz strežnika, ki je še nima:

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

To povleče delo, ki ga je vmes John potisnil. Zgodovina Jessice je sedaj videti takole:

Zgodovina Jessice po prenosu Johnovih sprememb
Slika 61. Zgodovina Jessice po prenosu Johnovih sprememb

Jessica misli, da je njena tematska veja pripravljena, vendar želi vedeti, kateri del prenesenega Johnovega dela mora združiti v njeno delo, da lahko potisne. Požene git log, da ugotovi:

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

   Remove invalid default value

Sintaksa issue54..origin/master je dnevniški filter, ki vpraša Git, da prikaže samo seznam potrditev, ki so na slednji veji (v tem primeru origin/master) in ki niso na prvi veji (v tem primeru issue54). Skozi to sintakso bomo šli podrobneje v Obsegi potrditev.

Iz zgornjega izpisa lahko vidimo, da je ena potrditev, ki jo je naredil John, in je Jessica ni združila v njeno lokalno delo. Če ona združi origin/master, je to ena potrditev, ki bo spremenila njeno lokalno delo.

Sedaj lahko Jessica združi njeno tematsko delo v njeno vejo master, združi, Johnovo delo (origin/master) v njeno vejo master in nato potisne nazaj na strežnik.

Najprej, (ko je potrdila vso delo na svoji tematski veji issue54), preklopi nazaj na njeno vejo master v pripravi, da integrira vso to delo:

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

Jessica lahko najprej združi origin/master ali pa issue54 — obe sta iz povratnega toka, torej vrstni red ni pomemben. Zadnji posnetek bi moral biti identičen ne glede na vrstni red, ki ga izbere, samo zgodovina bo nekoliko drugačna. Najprej, izbere združiti vejo issue54:

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

Ne pride do nobenih problemov; kot lahko vidite, je šlo za enostaven fast-forward. Sedaj Jessica zaključi proces lokalnega združevanja in združi prej preneseno delo Johna, ki čaka v veji origin/master:

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

Vse se gladko združi in zgodovina Jessice je sedaj videti takole:

Jessicina zgodovina po združitvi Johnovih sprememb
Slika 62. Jessicina zgodovina po združitvi Johnovih sprememb

Sedaj je origin/master dosegljiv iz Jessicine veje master, da lahko uspešno potisne (ob predpostavki, da John vmes ni ponovno potisnil še več sprememb):

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

Vsak razvijalec je naredil nekaj potrditev in uspešno združil delo drug drugega.

Jessicina zgodovina po potisku vseh sprememb nazaj na strežnik
Slika 63. Jessicina zgodovina po potisku vseh sprememb nazaj na strežnik

To je eden najenostavnejših potekov dela. Nekaj časa delate, (v splošnem na tematski veji), in združite to delo v vašo vejo master, ko je pripravljeno za integracijo. Ko želite deliti to delo, prenesete in združite vašo vejo master iz origin/master, če se je kaj spremenilo, in na koncu potisnite na vejo master na strežniku. Splošno zaporedje je nekaj takega:

Splošno zaporedje dogodkov za enostaven potek dela Git z več razvijalci
Slika 64. Splošno zaporedje dogodkov za enostaven potek dela Git z več razvijalci

Zasebne upravljane ekipe

V tem naslednjem scenariju, boste pogledali vloge sodelavcev v večji zasebni skupini. Naučili se boste, kako delati v okolju, kjer sodelujejo manjše skupine na lastnostih, in nato so ti prispevki na osnovi ekip integrirani s strani druge stranke.

Recimo, da John in Jessica delata skupaj na eni lastnosti (recimo featureA), medtem ko Jessica in tretja razvijalka Josie delata na drugi (recimo featureB). V tem primeru podjetje uporablja tip poteka dela upravitelja integracije, kjer je delo posameznih skupin integrirano samo od določenih inženirjev in veja master glavnega repozitorija je lahko posodobljena samo s strani teh inženirjev. V tem scenariju je vse delo narejeno na vejah na osnovi ekip in kasneje povlečene skupaj s strani povezovalcev.

Sledimo poteku dela Jessice, kakor dela na dveh njenih lastnostih, vzporedno sodeluje z dvema različnima razvijalcema v tem okolju. Predpostavimo, da že ima svoj repozitorij kloniran in se odloči delati najprej na lastnosti featureA. Ustvari novo vejo za lastnost in naredi nekaj dela na njej:

# 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(-)

Na tej točki morate deliti nekaj dela z Johnom, torej potisne njene potrditve veje featureA na strežnik. Jessica nima dostopa potiskanja na vejo master — to imajo samo povezovalci — torej mora potisniti na drugo vejo, da lahko sodeluje z Johnom:

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

Jessica sporoči Johnu po e-pošti, da je potisnila nekaj dela v vejo imenovano featureA, in on lahko to sedaj pogleda. Medtem ko čaka na povratne informacije od Johna, se Jessica odloči začeti delati na lastnosti featureB z Josie. Da začne, ustvari novo vejo lastnosti, ki je osnovana na strežniški veji master:

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

Sedaj, Jessica naredi nekaj potrditev na veji featureB:

$ vim lib/simplegit.rb
$ git commit -am 'Make ls-tree function recursive'
[featureB e5b0fdc] Make 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(-)

Jessicin repozitorij je videti sedaj takole:

Jessicina prvotna zgodovina potrditev
Slika 65. Jessicina prvotna zgodovina potrditev

Pripravljena je potisniti njeno delo, vendar dobi e-pošto od Josie, da je veja featureB z nekaj začetnega dela na njej že potisnjena na strežnik kot featureBee. Jessica mora najprej združiti te spremembe v njeno lastno, preden lahko potisne svoje delo na strežnik. Jessica najprej prenese spremembe Josie z git fetch:

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

Ob predpostavki, da je Jessica še vedno na svoji izvlečeni veji featureB, lahko sedaj združi delo Josie v to vejo z git merge:

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

V tem trenutku Jessica želi vse združeno delo featureB potisniti nazaj na strežnik, vendar noče preprosto potisniti svoje veje featureB. Ker je Josie že začela z zgornjo vejo featureBee, želi Jessica potisniti na to vejo, kar stori s:

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

To se imenuje refspec. Glejte razdelek Refspec za bolj podrobno diskusijo refspec Gita in različnih stvari, ki jih lahko naredite z njimi. Bodite pozorni tudi na zastavico -u; to je okrajšava za --set-upstream, ki nastavi veje za enostavnejše kasnejše potiskanje in vlečenje.

Nenadoma Jessica prejme e-pošto od Johna, ki ji sporoči, da je potisnil nekaj sprememb na vejo featureA, na kateri sodelujeta, in jo prosi, naj si jih ogleda. Jessica ponovno zažene preprost ukaz git fetch, da prenese vse nove vsebine s strežnika, vključno (seveda) z Johnovim najnovejšim delom:

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

Jessica lahko prikaže dnevnik Johnovega novega dela s primerjavo vsebine na novo prenesene veje featureA s svojo lokalno kopijo iste veje:

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

    Increase log output to 30 from 25

Če je Jessici všeč, kar vidi, lahko združi novo delo Johna v njeno lokalno vejo featureA:

$ 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(-)

Nazadnje bi Jessica lahko želela narediti nekaj manjših sprememb na vsem tem združenem delu, zato je prosta, da naredi te spremembe, jih potrdi v svoji lokalni veji featureA in potisne končni rezultat nazaj na strežnik:

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

Zgodovina potrditev Jessice je sedaj videti nekako takole:

Jessicina zgodovina po potrditvi na veji lastnosti
Slika 66. Jessicina zgodovina po potrditvi na veji lastnosti

V nekem trenutku Jessica, Josie in John obvestijo povezovalce, da sta veji featureA in featureBee na strežniku pripravljeni za integracijo v glavno vejo. Ko povezovalci združijo ti veji v glavno vejo, bo prenos prinesel novo potrditev združitve, zaradi česar bo zgodovina videti takole:

Jessicina zgodovina po združitvi obeh njenih tematskih vej
Slika 67. Jessicina zgodovina po združitvi obeh njenih tematskih vej

Zaradi te zmožnosti mnoge skupine preklopijo na Git, da imajo več ekip, ki delajo vzporedno in združujejo na različnih vrsticah dela kasneje v procesu. Zmožnost manjših podskupin ekipe, da sodelujejo preko oddaljenih vej brez potrebe po vključevanju ali oviri celotne ekipe, je velika prednost Gita. Zaporedje poteka dela, ki ste ga tu videli, je nekaj takega:

Osnovno zaporedje tega poteka dela upravljane ekipe
Slika 68. Osnovno zaporedje tega poteka dela upravljane ekipe

Razvejan javni projekt

Prispevki k javnim projektom so nekoliko drugačni. Ker nimate dovoljenja neposredno posodobiti veje na projektu, morate nekako dati delo vzdrževalcem na drug način. Prvi primer opisuje prispevke preko razvejanja na gostiteljih Git, ki podpirajo enostavno razvejanje. Mnoge strani gostiteljev to podpirajo (vključno z GitHub, BitBucket, Google Code, repo.or.cz in ostalimi) in mnogi vzdrževalci projektov pričakujejo ta stil prispevkov. Naslednji razdelek se ukvarja s projekti, ki imajo raje sprejeti prispevke popravkov preko e-pošte.

Najprej boste verjetno želeli klonirati glavni repozitorij, ustvariti tematsko vejo za programski popravek ali serijo popravkov, ki jih planirate prispevati in narediti delo tam. Zaporedje je videti v osnovi takole:

$ git clone <url>
$ cd project
$ git checkout -b featureA
  ... work ...
$ git commit
  ... work ...
$ git commit
Opomba

Lahko boste želeli uporabiti rebase -i, da svoje delo stisnete v eno potrditev ali delo preuredite v potrditve, da naredite programski popravek enostavnejši za pregled razvijalcev — za več informacij o interaktivnem ponovnem baziranju glejte razdelek Prepisovanje zgodovine.

Ko je delo vaše veje končano in ste pripravljeni prispevati nazaj vzdrževalcem, pojdite na prvotno stran projekta in kliknite na gumb »Fork«, kar bo ustvarilo vašo lastno zapisljivo razvejitev projekta. Nato morate dodati ta novi URL repozitorija kot novo daljavo svojega lokalnega repozitorija; v tem primeru ga imenujmo myfork:

$ git remote add myfork <url>

Nato morate potisniti svoje novo delo v ta repozitorij. Najenostavnejše je potisniti tematsko vejo, na kateri delate, na vaš razvejan repozitorij namesto združevanja v vašo vejo master in potiskanja tega navzgor. Razlog je, da če delo ni sprejeto, ali so izbrane samo najboljše spremembe (angl. cherry picking), vam ni treba previti nazaj vaše veje master (operacija Gita cherry-pick je pokrita bolj podrobno v Poteki dela ponovnega baziranja in izbire najboljšega). Če vzdrževalci združijo, ponovno bazirajo ali izberejo samo najboljše spremembe vašega dela, ga boste tako ali tako eventualno povlekli nazaj iz njihovega repozitorija:

V kateremkoli primeru lahko potisnete svoje delo na naslednji način:

$ git push -u myfork featureA

Ko je bilo vaše delo potisnjeno na vašo razvejitev, morate obvestiti vzdrževalce prvotnega projekta, da imate delo, ki ga želite, da ga združijo. To je pogostokrat imenovano zahtevek potega in tak zahtevek običajno generirate preko spletne strani — GitHub ima svoj lastni mehanizem zahtevkov potega, ki jih bomo obravnavali v GitHub — ali pa poženete ukaz git request-pull in pošljete vzdrževalcu projekta dani izpis ročno po e-pošti.

Ukaz git request-pull vzame osnovno vejo, v katero želite povleči svojo tematsko vejo, in URL repozitorija Git, iz katerega želite, da ga povlečejo, ter izpiše povzetek vseh sprememb, za katere želite, da se povlečejo. Na primer, če Jessica želi poslati Johnu zahtevek potega in je končala dve potrditvi na tematski veji, ki jo je ravnokar potisnila, lahko požene tole:

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

are available in the git repository at:

  https://githost/simplegit.git featureA

Jessica Smith (2):
      Add limit to log function
      Increase log output to 30 from 25

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

Ta izpis se lahko pošlje vzdrževalcu — pove jim, od kod je delo razvejano, povzame potrditve in pove, od kod povleči to delo.

Na projektu, za katerega niste vzdrževalec, je v splošnem enostavnejše imeti vejo, kot je master, ki vedno sledi origin/master, in narediti vaše delo v tematskih vejah, ki jih lahko enostavno zavržete, če so zavrnjene. Delovne teme, izolirane v tematske veje, so vam tudi enostavnejše, da ponovno bazirate vaše delo, če se je konica glavnega repozitorija vmes premaknila in vaših potrditev ni več mogoče gladko uporabiti. Na primer, če želite poslati drugo temo dela projekta, ne nadaljujte delo na tematski veji, ki ste jo ravnokar potisnili, začnite raje znova iz veje master glavnega repozitorija:

$ git checkout -b featureB origin/master
  ... work ...
$ git commit
$ git push myfork featureB
$ git request-pull origin/master myfork
  ... email generated request pull to maintainer ...
$ git fetch origin

Sedaj je vsaka od vaših tem vsebovana znotraj silosa — podobno kot čakalna vrsta popravka — ki jo lahko prepišete in spremenite, brez da se teme med seboj vmešavajo ali so soodvisne druga od druge:

Začetna zgodovina potrjevanja dela `featureB`
Slika 69. Začetna zgodovina potrjevanja dela featureB

Recimo, da je vzdrževalec projekta povlekel veliko ostalih popravkov in poskusil vašo prvo vejo, vendar se ne združuje več gladko. V tem primeru lahko to vejo poskusite ponovno bazirati na vrh origin/master, rešite konflikte za vzdrževalca in nato ponovno pošljete svoje spremembe:

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

To prepiše vašo zgodovino, da je sedaj videti kot na sliki Zgodovina potrditev po delu featureA.

Zgodovina potrditev po delu `featureA`
Slika 70. Zgodovina potrditev po delu featureA

Ker ste vejo ponovno bazirali, morate določiti -f za vaš ukaz potiskanja, da lahko zamenjate vejo featureA na strežniku s potrditvijo, ki ni njen potomec. Alternativa bi bila potisniti to novo delo na drugo vejo na strežniku (mogoče imenovano featureAv2).

Poglejmo en bolj verjeten scenarij: vzdrževalec je pogledal delo v vaši drugi veji in mu je zasnova všeč, vendar bi rad, da spremenite podrobnost implementacije. To priložnost boste tudi vzeli, da premaknete delo, da bo osnovano na trenutni veji projekta master. Začnete novo vejo, ki je osnovana na trenutni veji origin/master, tam stisnite spremembe featureB, rešite kakršnekoli konflikte, naredite implementacijo sprememb in nato to potisnite kot novo vejo:

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

Možnost --squash vzame vso delo na združeni veji in jih stisne v en skupek sprememb, ki ustvari stanje repozitorija, kakor da bi se zgodilo resnično združevanje, ne da dejansko naredi potrditev združitve. To pomeni, da bo vaša prihodnja potrditev imela samo eno nadrejeno in vam omogoča uvedbo vseh sprememb iz druge veje ter nato naredite več sprememb pred snemanjem nove potrditve. Uporabna je lahko tudi možnost --no-commit, ki zakasni potrditev združitve v primeru privzetega procesa združevanja.

Sedaj lahko pošljete vzdrževalcu sporočilo, da ste naredili zahtevane spremembe in da te spremembe lahko najdejo v vaši veji featureBv2.

Zgodovina potrditev po delu `featureBv2`
Slika 71. Zgodovina potrditev po delu featureBv2

Javni projekt preko e-pošte

Mnogi projekti imajo ustaljene postopke za sprejemanje popravkov — preveriti boste morali določena pravila za vsak projekt, ker se razlikujejo. Odkar je na voljo nekaj starejših, večjih projektov, ki sprejemajo popravke preko razvijalskega e-poštnega seznama, bomo šli sedaj skozi primer tega.

Potek dela je podoben prejšnjemu primeru uporabe — ustvarite tematske veje za vsake serije popravka, na katerih delate. Razlika je, kako jih pošljete projektu. Namesto razvejanja projekta in potiskanja v svojo lastno zapisljivo različico generirate e-poštno različico za vsako od serij potrditev in jih pošljete po e-pošti razvijalskemu e-poštnemu seznamu:

$ git checkout -b topicA
  ... work ...
$ git commit
  ... work ...
$ git commit

Sedaj imate dve potrditvi, ki ju želite poslati na e-poštni seznam. Uporabili boste git format-patch, da generirate mbox oblikovane datoteke, ki jih lahko pošljete preko e-pošte na seznam — vsako potrditev pretvori v sporočilo e-pošte s prvo vrstico sporočila potrditve kot zadevo in preostanek sporočila ter programski popravek, ki ga potrditev predstavlja kot telo. Dobra stvar pri tem je, da uporaba popravka generiranega iz e-pošte s format-patch ustrezno ohrani vse informacije potrditve.

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

Ukaz format-patch izpiše imena datotek popravka, ki ga ustvari. Preklop -M pove Gitu, da išče preimenovanja. Datoteke so na koncu videti takole:

$ 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

Lahko tudi uredite te datoteke popravka, da dodate več informacij za seznam e-pošte, za katere ne želite, da se prikažejo v sporočilu potrditve. Če dodate besedilo med vrstico --- in začetek popravka (vrstica diff --git), potem ga razvijalci lahko preberejo, vendar proces popravka vsebino izključuje.

Da to pošljete po e-pošti na e-poštni seznam, lahko prilepite datoteko v vaš e-poštni program, ali pa pošljete preko programa ukazne vrstice. Lepljenje teksta pogostokrat povzroča težave oblikovanja, posebej s »pametnejšimi« odjemalci, ki ne ohranjajo ustrezno novih vrstic in ostalih praznih znakov. Na srečo, Git ponuja orodje, ki vam pomaga poslati ustrezno oblikovane popravke preko IMAP, kar je za vas lahko enostavnejše. Prikazali bomo, kako poslati programski popravek preko Gmaila, kar je e-poštni agent, ki ga najbolje poznamo; preberete lahko podrobna navodila za število poštnih programov na koncu zgoraj omenjene datoteke Documentation/SubmittingPatches v izvorni kodi Git.

Najprej morate nastaviti razdelek imap v vaši datoteki ~/.gitconfig. Nastavite lahko vsako vrednost ločeno s serijo ukazov git config ali pa jih dodate ročno, vendar na koncu bi vaša nastavitvena datoteka morala biti videti nekako takole:

[imap]
  folder = "[Gmail]/Drafts"
  host = imaps://imap.gmail.com
  user = user@gmail.com
  pass = YX]8g76G_2^sFbd
  port = 993
  sslverify = false

Če vaš strežnik IMAP ne uporablja SSL, zadnji dve vrstici verjetno nista potrebni in vrednost gostitelja bo imap:// namesto imaps://. Ko je to nastavljeno, lahko uporabite git imap-send, da dodate serijo popravkov v mapo Drafts določenega strežnika IMAP:

$ 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

V tem trenutku bi morali imeti dostop do vaše mape osnutkov (angl. Drafts), lahko spremenite polje »To« na seznam e-pošte, na katerega pošiljate programski popravek, opcijsko »CC« za vzdrževalca ali osebo, odgovorno za ta razdelek, in lahko ga pošljete.

Programski popravek lahko pošljete tudi preko strežnika SMTP. Kot prej, lahko nastavite vsako vrednost ločeno s serijo ukazov git config, ali pa jih dodate ročno v razdelek sendemail vaše datoteke ~/.gitconfig:

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

Ko je to narejeno, lahko uporabite git send-email, da pošljete svoje popravke:

$ git send-email *.patch
0001-add-limit-to-log-function.patch
0002-increase-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

Nato Git izpljune kopico informacij dnevnika, kar je videti nekako takole za vsak programski popravek, ki ga pošiljate:

(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] Add 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
Namig

Za pomoč, kako nastaviti vaš sistem in e-pošto, več nasvetov in trikov ter peskovnik za pošiljanje preizkusnega popravka preko e-pošte, obiščite git-send-email.io.

Povzetek

V tem razdelku smo obravnavali več potekov dela in razpravljali o razlikah med delom v majhni ekipi na zaprtem projektu in prispevku k velikemu javnemu projektu. Sedaj veste, kako pred potrditvijo preveriti napake praznih znakov in napisati znate odlično sporočilo potrditve. Naučili ste se, kako oblikovati popravke in kako jih pošljete po e-pošti na seznam razvijalcev. Razpravljali smo tudi o združevanju pri različnih potekih dela. Zdaj ste dobro pripravljeni za sodelovanje na katerem koli projektu.

V nadaljevanju boste videli, kako deluje druga plat medalje: vzdrževanje projekta Git. Naučili se boste, kako biti dobronamerni diktator ali integracijski upravitelj.

scroll-to-top