Chapters ā–¾ 2nd Edition

5.2 Distribuerade Git - Medverka i ett projekt

Medverka i ett projekt

Det svĆ„ra med att beskriva hur du gƶr fƶr att bidra till ett projekt Ƥr att medverkan kan ske pĆ„ mƤngder av olika sƤtt. Tack vare Gits flexibelt skiljer sig anvƤndningen Ć„t, vilket gƶr det nƤst intill omƶjligt att sƤga hur du borde gƶra — varje projekt arbetar pĆ„ sitt sƤtt. Faktorer som pĆ„verkar hur ett projekt Ƥr organiserat Ƥr antalet aktivt involverade, ƶverenskomna arbetsprocesser och fƶrdelningen av behƶrigheter fƶr att checka in kod Det finns dock nĆ„gra generella riktlinjer som kan hjƤlpa dig att komma igĆ„ng.

Fƶr det fƶrsta — hur mĆ„nga involverade bidrar aktivt med kƤllkod och hur ofta? I mindre pojekt Ƥr det vanligt att ett par, tre utvecklare gƶr nĆ„gra fĆ„ incheckningar om dagen, kanske Ƥnnu fƤrre om projektet Ƥr vilande. I stƶrre projekt, eller fƶretag fƶr den delen, kan hundratals utvecklare arbeta aktivt med kodbasen och bidra med tusentals incheckningar varje dag.

Det Ƥr viktigt att kƤnna till ungefƤr hur mĆ„nga som arbetar aktivt i kodbasen. Ju fler utvecklare, ju mer problem kan du stƶta pĆ„ fƶr att fĆ„ din kod att lƤggas till och integreras sƶmlƶst. Under tiden du arbetar med dina Ƥndringar, eller vƤntar pĆ„ att fĆ„ dem godkƤnda, kan ny kod gƶra dem ofunktionella — eller rentav inaktuella. Hur kan du dĆ„ gƶra fƶr att din egen kodbas ska hĆ„llas uppdaterad och dina incheckningar aktuella?

Fƶr det andra, hur ser projektets beslutade arbetsprocess ut? Ƅr det en centraliserad process, sĆ„ att varje utvecklare har samma skrivrƤttigheter till koden pĆ„ huvudgrenen? Har projektet en fƶrvaltare eller integrationsansvarig som granskar alla patcher? Ska samtliga patcher granskas och godkƤnnas av en annan utvecklare? Kommer du att vara involverad i den processen? Eller finns det ett kvalitetsledningssystem med testare pĆ„ plats som du behƶver skicka dina Ƥndringar till fƶrst?

Till sist spelar behƶrigheter fƶr incheckningar in. Din medverkan kommer att skilja sig mycket Ƅt beroende pƄ om du har skrivrƤttigheter till kodbasen eller inte. Om du inte har det, hur ser processen ut fƶr att granska och godkƤnna bidrag? Finns det ens en sƄdan process? Hur mƄnga Ƥndringar ska skickas med i taget? Hur ofta?

Alla dessa frƄgor pƄverkar hur du bƤst bidrar till ett projekt, liksom vilka arbetssƤtt du sjƤlv fƶredrar eller har tillgƄng till. Vi kommer att gƄ igenom tillvƤgagƄngssƤtten ur olika aspekter i en serie anvƤndarfall, frƄn enkla till mer komplexa. Du borde kƤnna igen det specifika arbetssƤtt du fƶrvƤntas anvƤnda i dessa exempel.

Riktlinjer fƶr incheckningar

Innan vi gƄr in pƄ anvƤndarfallen kommer en kort kommentar om incheckningsmeddelanden. Att ha bra riktlinjer fƶr incheckningar, och att hƄlla sig till dem, gƶr det betydligt enklare att anvƤnda Git tillsammans med andra. I Git-projektet finns ett dokument med flera bra tips pƄ saker att tƤnka pƄ fƶr att gƶra incheckningar till en patch. Du hittar det i filen Documentation/SubmittingPatches i Gits kƤllkod.

Fƶrst av allt, sĆ„ bƶr dina bidrag inte ha nĆ„gra felaktiga mellanslag. Git har ett lƤtt sƤtt att kontrollera det — innan du gƶr en incheckning, kƶr kommandot git diff --check. Det ger dig en lista ƶver mƶjliga mellanslag som kan vara felaktiga.

Output av `git diff --check`.
Figur 57. Output of git diff --check.

Kƶr kommandot innan en incheckning fƶr att snabbt kontrollera om du Ƥr pƄ vƤg att checka in mellanslag som kan irritera andra utvecklare.

Fƶr det andra, fƶrsƶk att gƶra varje incheckning till logiskt separat enhet. Om du kan, fƶrsƶk att hĆ„lla dina Ƥndringar lƤttsmƤlta - koda inte en hel helg pĆ„ fem olika uppgifter, fƶr att sen skicka dem som en enda gigantisk incheckning pĆ„ mĆ„ndan. Ƅven om du inte har checkat in pĆ„ en hel helg, anvƤnd kƶomrĆ„det fƶr att dela upp ditt arbete i minst fem incheckningar pĆ„ mĆ„ndagen, med ett tydligt meddelande per incheckning. Om nĆ„gra av Ƥndringarna Ƥr i samma fil, fƶrsƶk att anvƤnda git add --patch fƶr att delvis kƶa filer (lƤs mer i Interactive Staging). Projektets ƶgonblicksbild lƤngst ut pĆ„ grenen kommer att se likadan ut oavsett om du gƶr en incheckning eller fem, sĆ„ lƤnge som alla Ƥndringar lƤggs till fƶrr eller senare. Fƶrsƶk dƤrfƶr att gƶra det sĆ„ enkelt som mƶjligt fƶr dina kollegor nƤr de ska granska dina Ƥndringar.

Med det tillvƤgagĆ„ngssƤttet blir det ocksĆ„ enklare att dra ut eller Ć„terstƤlla nĆ„gon av Ƥndringarna i efterhand, om det skulle behƶvas. I avsnittet Rewriting History finns en mƤngd anvƤndbara tips fƶr att skriva om Git-historiken och interaktivt kƶa filer — anvƤnd dessa verktyg fƶr att fĆ„ en logisk och fƶrstĆ„elig historik innan du skickar arbetet vidare till nĆ„gon annan.

Slutligen behƶvs en struktur fƶr incheckningsmeddelandet. Med vanan att alltid skriva bra meddelanden blir anvƤndningen av - och samarbetet i - Git betydligt enklare. Tumregeln Ƥr att dina meddelanden ska bƶrja med en mening pĆ„ max 50 tecken som sammanfattar Ƥndringen, fƶljt av en blank rad och en mer detaljerad beskrivning. Git-projektet gƶr gƤllande att beskrivningen bƶr inkludera anledningen till Ƥndringen och en jƤmfƶrelse med tidigare beteende — det Ƥr en bra riktlinje att fƶlja. Det Ƥr ocksĆ„ bra att skriva i imperativ form. Med andra ord, ge order. IstƤllet fƶr ā€œJag lade till test fƶrā€ eller ā€œLƤgger till test fƶr,ā€ skriv ā€œLƤgg till test fƶrā€ HƤr Ƥr en mall ursprungligen skriven av Tim Pope:

Kort (50 tecken max), befallande sammanfattning

Mer detaljerad text, om nƶdvƤndigt. HƄll den till cirka 72 tecken eller
sƄ. Fƶrsta raden kan ofta jƤmfƶras med Ƥmnet pƄ ett mejl och resten av
innehƄllet med brƶdtexten. Den tomma raden mellan titel och brƶdtext
Ƥr absolut nƶdvƤndig (om du inte utelƤmnar innehƄllet helt); verktyg som
ombasera kan bli fƶrvirrade om de skrivs ihop.

Ytterligare paragrafer skrivs efter en tom rad.

  - Punktlistor Ƥr ocksƄ ok

  - Efter en tom rad och ett inledande mellanslag anvƤnds ofta
    bindestreck eller asterisk som punkt, men det finns olika
    konventioner.

Om alla dina incheckningsmeddelande fƶljer den hƤr mallen kommer det att bli lƤttare, bĆ„de fƶr dig och dem du samarbetar med. Git-projektet har vƤlformatterade incheckningsmeddelanden — kƶr git log --no-merges dƤr fƶr att fĆ„ inspiration till hur en vƤl formatterad incheckningshistorik kan se ut.

Notera
Gƶr som vi sƤger och inte som vi gƶr

Fƶr att vara helt Ƥrliga, mƄnga av exemplen i den hƤr boken har inte sƄ vƤrst vƤlformatterade incheckningsmeddelanden; vi anvƤnder ofta -m efter git commit, helt enkelt.

Som sagt, gƶr som vi sƤger, inte som vi gƶr.

Privat, litet team

Det enklaste arbetssƤttet du sannolikt kommer stƶta pĆ„ Ƥr ett privat projekt med en eller tvĆ„ involverade utvecklare. I den hƤr kontexten betyder ā€œprivatā€ sluten kƤllkod — den Ƥr inte tillgƤnglig fƶr nĆ„gon utomstĆ„ende. Du och de andra utvecklarna har skrivbehƶrigheter till arkivet.

I den hƤr uppsƤttningen liknar arbetssƤttet det som du kanske stƶter pƄ nƤr du anvƤnder Subversion eller nƄgot annat centraliserat versionshanteringssystem. Du behƄller fƶrdelarna med saker som att kunna checka in offline, en betydligt enklare fƶrgrening och sammanslagning, men arbetsprocesserna Ƥr mycket lika; den stƶrsta skillnaden Ƥr att sammanslagningar sker i klienten istƤllet fƶr frƄn servern vid incheckning. LƄt oss ta ett exempel pƄ hur det kan gƄ till nƤr tvƄ utvecklare bƶrjar samarbeta i ett gemensamt arkiv. Den fƶrsta utvecklaren, John, klonar arkivet och gƶr en Ƥndring som checkas in lokalt. (Informationsmeddelandena har ersatts med ... fƶr att korta ner exemplen.)

# Johns dator
$ git clone john@githost:simplegit.git
Klonar till 'simplegit'...
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'remove invalid default value'
[master 738ee87] remove invalid default value
 1 fil Ƥndrad, 1 tillagd(+), 1 borttagen(-)

Jessika, den andra utvecklaren, gƶr samma sak — klonar arkivet och checkar in en Ƥndring:

# Jessikas dator
$ git clone jessika@githost:simplegit.git
Klonar till 'simplegit'...
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
 1 fil Ƥndrad, 1 tillagd(+), 0 borttagen(-)

Sen skickar Jessika sina Ƥndringar till servern, vilket funkar bra:

# Jessikas dator
$ git push origin master
...
Till jessika@githost:simplegit.git
   1edee6b..fbff5bc  master -> master

Den sista raden i outputen Ƥr ett anvƤndbart meddelande frƄn sƤndningen. Formateringen Ƥr <gammalref>..<nyref> frƄnref -> tillref, dƤr gammalref betyder tidigare referens, nyref Ƥr den nya referensen, frƄnref Ƥr namnet pƄ den lokala referens som Ƥndringen kommer frƄn och tillref Ƥr fjƤrreferensen som har blivit uppdaterad. Du kommer att se liknande output i exemplen nedanfƶr, en grundfƶrstƄelse kommer gƶra det lƤttare att fƶrstƄ innebƶrden av arkivens varierade stadier. Mer detaljer finns i git-push dokumentation.

Fƶr att fortsƤtta med det hƤr exemeplet — kort efterĆ„t gƶr John nĆ„gra Ƥndringar, checkar in dem lokalt och fƶrsƶker skicka dem till samma server som Jessika:

# Johns dator
$ git push origin master
Till john@githost:simplegit.git
 ! [refuserad]        master -> master (ej snabbspolad)
error: misslyckades sƤnda vissa referenser till 'john@githost:simplegit.git'

I det hƤr fallet kan John inte skicka sina incheckningar pƄ grund av Jessikas tidigare incheckning av sina Ƥndringar. Det hƤr Ƥr sƤrskilt viktigt att fƶrstƄ om du tidigare har anvƤnt Subversion, fƶr du kommer att mƤrka att de tvƄ utvecklarna inte Ƥndrade i samma fil. Subversion gƶr en sammanslagning automatiskt pƄ servern om olika filer har Ƥndrats, men med Git behƶver du sjƤlv fƶrst sammanfoga incheckningarna lokalt. Med andra ord, John mƄste fƶrst hƤmta Jessikas Ƥndringar i fjƤrrarkivet och sammanfoga dem i sitt lokala arkiv innan han kommer att fƄ tillƄtelse att skicka Ƥndringarna.

Som ett fƶrsta steg hƤmtar John Jessikas Ƥndringar(Jessikas Ƥndringar hƤmtas bara, de slƄs inte ihop med hans filer):

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

Johns arkiv ser nu ut ungefƤr sƄ hƤr:

Johns divergerande historik.
Figur 58. Johns divergerande historik.

Nu kan John slƄ ihop de Ƥndringar han hƤmtade av Jessika med filerna pƄ sin dator:

$ git merge origin/master
Sammanslagning gjord med metoden 'recursive'.
 TODO |    1 +
 1 fil Ƥndrad, 1 tillƤgg(+), 0 borttagna(-)

Om den lokala sammanslagningen gƄr smidigt kommer Johns uppdaterade historik se ut ungefƤr sƄ hƤr:

Johns arkiv efter sammanslagning av Ƥndringar frƄn `origin/master`.
Figur 59. Johns arkiv efter sammanslagning av Ƥndringar frƄn origin/master.

Nu kanske John vill testa den nya koden fƶr att vara helt sƤker pƄ att ingen av Jessikas Ƥndringar pƄverkat hans, och om allt gƄr bra kan han slutligen skicka sina sammanslagna Ƥndringar till servern:

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

Till sist ser Johns incheckningshistorik ut sƄ hƤr:

Johns historik efter att ha skickat sina Ƥndringar till servern `origin`.
Figur 60. Johns historik eftervatt ha skickat sina Ƥndringar till servern origin.

Under tiden har Jessika skapat en ny gren med namnet issue54, och gjort tre incheckningar till den nya grenen. Hon har inte hƤmtat Johns Ƥndringar Ƥn, sƄ hennes incheckningshistorik ser ut sƄ hƤr:

Jessikas gren.
Figur 61. Jessikas gren.

Plƶtsligt fƄr Jessika veta att John har skickat nya Ƥndringar till servern och vill kika pƄ dem, sƄ hon hƤmtar alla Ƥndringar frƄn servern med kommandot:

# Jessikas dator
$ git fetch origin
...
FrƄn jessika@githost:simplegit
   fbff5bc..72bbc59  master     -> origin/master

Nu hƤmtas Johns incheckade Ƥndringar ner. Jessikas historik kommer att se ut sƄ hƤr:

Jessikas historik efter att ha hƤmtat Johns Ƥndringar.
Figur 62. Jessikas historik efter att ha hƤmtat Johns Ƥndringar.

Jessika tycker att Ƥndringarna pƄ hennes nya gren Ƥr klara, men hon vill veta vilka delar av Johns arbete som hon mƄste slƄ ihop med sitt arbete sƄ att hon kan skicka dem. Hon kƶr git log fƶr att fƄ reda pƄ det:

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

   ta bort ogiltigt standardvƤrde

Syntaxen issue54..origin/master anvƤnds fƶr att filtrera loggar. Git ombeds att bara visa de incheckningar i den senare referensen (origin/master i det hƤr fallet) som inte finns pƄ den fƶrsta referensen (hƤr issue54). Vi kommer att gƄ igenom syntaxen i detalj i avsnitt Commit Ranges.

FrƄn ovanstƄende output kan vi utlƤsa att det bara Ƥr en enda av Johns incheckningar som Jessika inte har slagit ihop med sitt arbete lokalt. Om hon slƄr ihop sina Ƥndringar med Ƥndringarna pƄ origin/master Ƥr det bara den incheckningen som kommer att pƄverka hennes lokala arkiv.

Nu kan Jessika slƄ ihop sin lokala funktionsgren med sin huvudgren, slƄ samman Johns Ƥndringar (origin/master) med sin master gren och sen skicka sitt arbete till servern igen. .

NƤr alla Ƥndringar pƄ grenen issue54 har checkats in, bƶrjar Jessika med att byta tillbaka till sin huvudgren:

$ git checkout master
Byter till gren 'master'
Din gren ligger efter 'origin/master' med 2 incheckningar, kan snabbspolas.

Jessika kan slĆ„ ihop antingen origin/master eller issue54 fƶrst — de Ƥr bĆ„da uppstrƶms, sĆ„ ordningen spelar ingen roll. Den slutliga ƶgonblicksbilden blir identisk oavsett vilken ordning hon vƤljer, det Ƥr bara historiken som kommer att skilja sig Ć„t. Hon bestƤmmer sig fƶr att slĆ„ ihop grenen issue54 fƶrst:

$ git merge issue54
Uppdaterar fbff5bc..4af4298
Snabbspolar
 README           |    1 +
 lib/simplegit.rb |    6 +++++-
 2 filer Ƥndrade, 6 tillƤgg(+), 1 borttagen(-)

Inget ovƤntat hƤnder, som du kan se var det en sammanslagning som kunde snabbspolas framƄt. Jessika kan nu avsluta sammanslagningarna lokalt genom att slƄ ihop de Ƥndringar hon hƤmtade tidigare frƄn John och som Ƥr vƤntar kvar pƄ origin/master:

$ git merge origin/master
SlƄr ihop lib/simplegit.rb automatiskt
Sammanslagning gjorde med metoden 'recursive'.
 lib/simplegit.rb |    2 +-
 1 fil Ƥndrad, 1 tillƤgg(+), 1 borttagning(-)

Allt slogs ihop smidigt, Jessikas historik ser nu ut sƄ hƤr:

Jessikas historik efter att ha slagit ihop Johns Ƥndringar infogats.
Figur 63. Jessikas historik efter att ha slagit ihop Johns Ƥndringar.

FjƤrreferensen origin/master kan nƄs frƄn Jessikas huvudgren, sƄ hon borde kunna skicka sina Ƥndringar utan problem (fƶrutsatt att John inte har skickat fler Ƥndringar under tiden):

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

BƄda utvecklarna har nu checkat in sina versioner av filerna nƄgra gƄnger och fƄtt in varandras Ƥndringar i sina lokala kodbaser.

Jessikas historik efter att ha skickat tillbaka Ƥndringarna till servern.
Figur 64. Jessikas historik efter att ha skickat tillbaka Ƥndringarna till servern.

Det hƤr Ƥr en av de enklaste arbetsprocesserna.

Du arbetar ett tag (vanligtvis i en funktionsgren), och slƄr ihop arbetet i huvudgrenen nƤr det Ƥr klart. NƤr du vill dela ditt arbete, hƤmtar du och slƄr ihop din huvudgren med origin/master och skickar tillbaka din huvudgren till servern. Den generella arbetsprocessen ser ut ungefƤr sƄ hƤr:

Generell arbetsprocess med Git fƶr flera utvecklare.
Figur 65. Generell arbetsprocess med Git fƶr flera utvecklare.

Privat stƶrre team

NƤsta exempel Ƥr medverkan i ett stƶrre, privat team. HƤr tittar vi nƤrmre pƄ hur arbetsprocessen kan se ut nƤr mindre team samarbetar pƄ features, som dƤrefter slƄs ihop av andra team.

SƤg att John och Jessika arbetar tillsammans pĆ„ en funktion (vi kallar den ā€œfeatureAā€). Samtidigt samarbetar Jessika och en tredje utecklare, Josie, pĆ„ en annan, (ā€œfeatureBā€). I det hƤr fallet anvƤnder sig fƶretaget av en slags integrationsstyrt arbetsprocess, dƤr arbetet av ett enskilt team slĆ„s samman med huvudgrenen av specifika ingengƶrer. Arkivets huvudgren kan endast uppdateras av dessa. Allt arbete sker pĆ„ fƶrgreningar som sedan slĆ„s ihop av andra i ett senare skede.

Vi fƶljer med Jessika medan hon arbetar pƄ sina features parallellt, med tvƄ olika utvecklare, i en sƄdan hƤr miljƶ. Vi utgƄr ifrƄn att hon redan har klonat arkivet, nƤr hon bestƤmmer sig fƶr att bƶrja med featureA. Hon skapar en ny gren fƶr funktionen och jobbar lite pƄ den:

# Jessikas dator
$ git checkout -b featureA
Bytte till en ny gren 'featureA'
$ vim lib/simplegit.rb
$ git commit -am 'add limit to log function'
[featureA 3300904] add limit to log function
 1 fil Ƥndrades, 1 tillƤgg(+), 1 borttagning(-)

I det hƤr lƤget behƶver hon dela sitt jobb med John, sƄ hon skickar sin featureA-gren med incheckningarna till servern. Jessika har inte behƶrighet att slƄ ihop sina Ƥndringar med huvuudgrenen, sƄ hon behƶver skicka dem till en annan gren fƶr att kunna samarbeta med John:

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

Jessika mejlar John fƶr att berƤtta att hon har skickat Ƥndringar till en gren med namnet featureA och att han kan kolla pƄ dem nu. Medan hon vƤntar pƄ feedback frƄn John bestƤmmer hon sig fƶr att bƶrja jobba pƄ featureB tillsammans med Josie. Hon bƶrjar med att skapa en ny gren frƄn serverns huvudgren:

# Jessikas dator
$ git fetch origin
$ git checkout -b featureB origin/master
Bytte till en ny gren 'featureB'

Nu gƶr Jessika ett par inckeckningar pƄ `featureB`grenen:

`[source,console]

$ vim lib/simplegit.rb
$ git commit -am 'made the ls-tree function recursive'
[featureB e5b0fdc] made the ls-tree function recursive
 1 fil Ƥndrad, 1 tillƤgg(+), 1 borttagen(-)
$ vim lib/simplegit.rb
$ git commit -am 'add ls-files'
[featureB 8512791] add ls-files
 1 fil Ƥndrad, 5 tillƤgg(+), 0 borttagna(-)

Jessikas arkiv ser nu ut sƄ hƤr:

Jessikas initiala versionshistorik.
Figur 66. Jessikas initiala versionshistorik.

Hon Ƥr redo att skicka sina Ƥndringar nƤr hon fƄr ett mejl frƄn Josie som skriver att en gren hon har bƶrjat pƄ fƶr featureB redan har skickats till servern som grenen featureBee. Jessika behƶver slƄ ihop de Ƥndringarna med sina innan hon kan skicka sitt arbete till den gren Josie skickat till servern. Jessika hƤmtar fƶrst Josies Ƥndringar med git fetch:

$ git fetch origin
...
FrƄn jessika@githost:simplegit
 * [new branch]      featureBee -> origin/featureBee

Om vi antar att Jessika fortfarande Ƥr utcheckad pƄ grenen featureB, sƄ kan hon nu slƄ Josies arbete med den grenen med kommandot git merge:

$ git merge origin/featureBee
SlƄr ihop lib/simplegit.rb automatiskt.
Sammanslagning gjord med metoden 'recursive'.
 lib/simplegit.rb |    6 ++++++
 1 fil Ƥndrad, 6 tillƤgg(+), 0 borttagna(-)
Sammanslagning gjord med metoden 'recursive'.
 lib/simplegit.rb |    4 ++++
 1 fil Ƥndrad, 4 tillƤgg(+), 0 borttagna(-)

I det hƤr lƤget vill Jessika skicka allt som finns pƄ featureB tillbaka till servern, men utan att skicka upp sin egna gren. Eftersom Josie redan har pƄbƶrjat en uppstrƶms featureBee-gren sƄ vill Jessika skicka till den grenen. Det gƶr hon med:

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

Detta kallas fƶr en referensspecifikation. Se The Refspec fƶr mer information om Gits referensspecifikationer och hur du kan anvƤnda dem. LƤgg ocksƄ mƤrke till -u-flaggan; det Ƥr en kortversion av kommandot --set-upstream, som sparar en referens till den fjƤrrgren som din lokala gren spƄrar.

Plƶtsligt fĆ„r Jessika ett mail frĆ„n John, som berƤttar att han har skickat nĆ„gra Ƥndringar till featureA-grenen och ber henne kolla pĆ„ dem. ƅterigen kƶr Jessika ett enkelt git fetch fƶr att hƤmta allt nytt innehĆ„ll frĆ„n servern, inklusive Johns senaste arbete:

$ git fetch origin
...
FrƄn jessika@githost:simplegit
   3300904..aad881d  featureA   -> origin/featureA

Jessika kan nu lƤsa loggarna med Johns senaste Ƥndringar genom att jƤmfƶra innehƄllet som hƤmtades fƶr featureA med den lokala kopian av samma gren:

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

    changed log output to 30 from 25

Om Jessika gillar det hon ser kan hon fusionera Johns nya arbete till sin lokala featureA gren med:

$ git checkout featureA
Bytte till gren 'featureA'
$ git merge origin/featureA
Uppdaterar 3300904..aad881d
Snabbspolar
 lib/simplegit.rb |   10 +++++++++-
1 fil Ƥndrad, 9 tillƤgg(+), 1 borttagen(-)

Till sist kanske Jessika vill gƶra nƄgra mindre Ƥndringar i det sammanslagna innehƄllet. Hon har full frihet att gƶra sina Ƥndringar, checka in dem till sin lokala gren featureA och skicka tillbaka slutresultatet till servern.

$ git commit -am 'small tweak'
[featureA 774b3ed] small tweak
 1 fil Ƥndrad, 1 tillƤgg(+), 1 borttagen(-)
$ git push
...
Till jessika@githost:simplegit.git
   3300904..774b3ed  featureA -> featureA

Jessikas incheckningshistorik kommer nu att se ut ungefƤr sƄ hƤr:

Jessikas historik efter incheckningar pƄ funktionsgrenen.
Figur 67. Jessikas historik efter incheckningar till funktionsgrenen.

Vid nƄgon tidpunkt kommer Jessika, John och Josie att behƶva informera dem som ansvarar fƶr huvudgrenen att featureA och featureB Ƥr redo att slƄs ihop med den. NƤr sammanslagningen med huvudgrenen dƄ Ƥr klar, kommer en hƤmtning av den att fƄ med den nya versionsincheckningen. Historiken kommer dƄ att se ut sƄ hƤr:

Jessikas historik efter sammanslagning av Ƥmnesgrenar med huvudgren.
Figur 68. Jessikas historik efter sammanslagning av Ƥmnesgrenar med huvudgren.

MƄnga byter till Git pƄ grund av mƶjligheten fƶr flera team att arbeta parallellt och kombinera sina fƶrgreningar sent i processen. Mƶjligheten att mindre grupperingar inom ett team kan samarbeta via fjƤrrgrenar utan att nƶdvƤndigtvis behƶva involvera hela teamet Ƥr utan tvekan en av Gits stora fƶrdelar. Arbetsprocessen som precis har beskrivts ser ut ungefƤr sƄhƤr:

GrundlƤggande arbetsflƶde fƶr flera team.
Figur 69. GrundlƤggande arbetsprocess fƶr flera team.

Ɩppet, litet projekt

Att bidra till ƶppna projekt Ƥr ofta lite annorlunda Ƥn privata. Eftersom du vanligtvis inte har behƶrighet att gƶra Ƥndringar direkt i projektet behƶver fƶrvaltarna fƄ ditt arbete pƄ nƄgot annat sƤtt. I det fƶrsta exemplet ska vi titta pƄ hur man fƶrgrenar ett arkiv pƄ de hostingsajter fƶr Git som tillƄter det. MƄnga hostingsajter har stƶd fƶr fƶrgreningar, (sƄsom GitHub, BitBucket, repo.or.cz med flera) och mƄnga projektansvariga fƶrvƤntar sig att andra medverkar pƄ det sƤttet. Det andra exemplet beskriver arbetsprocessen i de projekt som istƤllet fƶredrar att acceptera patchade bidrag via mejl.

Det fƶrsta du behƶver gƶra Ƥr troligen att klona grundarkivet och skapa en funktionsgren fƶr patcherna du planerar att bidra med Flƶdet ser helt enkelt ut sƄ hƤr:

$ git clone <url>
$ cd project
$ git checkout -b featureA
  ... arbeta ...
$ git commit
  ... arbeta ...
$ git commit
Notera

Du kanske kommer att vilja anvƤnda rebase -i fƶr att komprimera ditt arbete till en enda incheckning, eller arrangera om incheckningnarna sĆ„ att de blir enklare fƶr de ansvariga att granska — se Rewriting History fƶr mer information om att ombasera grenar interaktivt.

NƤr arbetet Ƥr klart och du Ƥr redo att dela det med fƶrvaltarnas, gƄ till ursprungsarkivets projektsida och klicka pƄ knappen ``Fork`` fƶr att skapa en kopia av projektet som du har full behƶrighet till. DƤrefter lƤgger du till det nya repots URL som ett nytt fjƤrrarkiv fƶr ditt lokala arkiv; i det hƤr exemplet kan vi kalla det fƶr mingaffel:

$ git remote add mingaffel <url>

Sedan behƶver du skicka ditt arbete till det hƤr arkivet. Det Ƥr enklare att skicka den finessgren du arbetar pƄ till ditt kopierade arkiv Ƥn att fusionera det arbetet i din huvudgren och fusionera den. Om ditt arbete inte bli godkƤnt, eller om din incheckning inte blir cherry-pickad, sƄ slipper du spola tillbaka din huvudgren (lƤs mer om Gits cherry-pick i Arbetsflƶden med ombasering och plocka russin ur kakan). Om de ansvariga Ƅ andra sidan slƄr ihop, ombaserar eller cherry-pickar din funktion, sƄ kommer du att fƄ tillbaka den genom att dra ner Ƥndringar frƄn deras repo ƤndƄ. Hur du Ƥn gƶr kan du skicka ditt arbete med:

$ git push -u mingaffel featureA

NƤr ditt arbete har skickats till din fƶrgrening av arkivet behƶver du meddela fƶrvaltarna av originalprojektet att du har arbete som du skulle vilja att de slĆ„r samman. Detta kallas ofta fƶr en pull request och du behƶver vanligtvis gƶra en sĆ„dan begƤran antingen via websida — GitHub har sin egen ``Pull Request``-mekanism som vi kommer att gĆ„ igenom i GitHub — eller sĆ„ kan du kƶra kommandot git request-pull och mejla den efterfƶljande utdatan till de ansvariga.

Kommandot git request-pull tar basgrenenen, det vill sƤga den gren du vill att din funktionsgren dras in i, och Git-arkivets URL som du vill att de accepterar kod ifrƄn, och sammanfattar alla Ƥndringar du begƤr ska tas in. Om Jessika till exempel vill skicka en pull request till John, och hon har gjort tvƄ incheckningar pƄ funktionsgrenen som hon just har skickat, sƄ kan hon anvƤnda det sƄ hƤr:

$ git request-pull origin/master mingaffel
Fƶljande Ƥndringar sen incheckning 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
Jessika Smith (1):
        added a new function

Ƥr tillgƤngliga i git-arkivet pƄ:

  git://githost/simplegit.git featureA

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

 lib/simplegit.rb |   10 +++++++++-
 1 fil Ƥndrad, 9 tillƤgg(+), 1 borttagning(-)

Den hƤr utdatan kan skickas till de ansvariga — den beskriver frĆ„n vilken gren arbetet fƶrgrenades, ger en sammanfattning av incheckningarna och varifrĆ„n den nya funktionen kan hƤmtas.

I ett projekt dƤr du inte Ƥr ansvarig Ƥr det oftast enklast att ha en huvudgren, t.ex master, som alltid fƶljer origin/master och sen arbeta i funktionsgrenar som du enkelt kan radera om de inte godkƤnns. Att isolera funktioner tll funktionsgrenar gƶr det ocksĆ„ lƤttare fƶr dig att flytta ditt arbete om Ƥnden pĆ„ huvudarkivet har rƶrt sig under tiden du arbetat sĆ„ att din version inte lƤngre kan sammanfogas pĆ„ ett smidigt sƤtt. Om du till exempel vill skicka in en andra funktionsgren till projektet, fortsƤtt inte att arbeta pĆ„ den funktionsgren du nyss skickade upp — bƶrja istƤllet om frĆ„n arkivets huvudgren:

$ git checkout -b featureB origin/master
  ... arbeta ...
$ git commit
$ git push mingaffel featureB
$ git request-pull origin/master myfork
  ... e-postbrevet genererar fƶrfrƄgan att hƤmta till ansvarig ...
$ git fetch origin

Now, each of your topics is contained within a silo — similar to a patch queue — that you can rewrite, rebase, and modify without the topics interfering or interdepending on each other, like so: Nu Ƥr bĆ„da dina funktioner i varsitt silo — som en kƶ fƶr patchar — som du kan skriva om, ombasera och Ƥndra utan att funktionerna pĆ„verkar eller blir beroende av varandra:

Initial versionshistorik fƶr `featureB`.
Figur 70. Initial versionshistorik fƶr featureB.

Om vi sƤger att projektets ansvariga har dragit in ett gƤng andra patches innan de testar din fƶrsta gren, sƄ kan den inte sammanfogas automatiskt. I det hƤr fallet kan du fƶrsƶka att ombasera den grenen sƄ att den hamnar lƤngst ut pƄ toppen av origin/master, lƶsa eventuella konflikter och skicka in din version igen:

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

Det hƤr skriver om historiken enligt bilden nedan Versionshistorik efter avslutat arbete med featureA..

Versionshistorik efter avslutat arbete med `featureA`.
Figur 71. Versionshistorik efter avslutat arbete med featureA.

Eftersom du flyttade grenen behƶver du ange -f till ditt kommando fƶr att kunna ersƤtta serverns featureA-gren med en annan incheckning Ƥn den ursprungliga. Ett alternativ vore att skicka det hƤr nya arbetet till en annnan gren pƄ servern (som kanske kan heta featureAv2),

Vi tittar nƤrmre pƄ ytterligare ett alternativ: ansvariga har tittat Ƥndringarna i din andra gren och gillar dem mestadels, men de skulle vilja att du gjorde en justering. Du anvƤnder mƶjligheten att flytta fƶrgreningen frƄn featureA till huvudgrenen.

Du kan gƶra det hƤr genom att skapa en ny gren frƄn origin/master, sammanfoga featureB dƤr, lƶsa eventuella konflikter, gƶra Ƥndringen och skicka det som en ny gren:

$ git checkout -b featureBv2 origin/master
$ git merge --squash featureB
  ... justera ...
$ git commit
$ git push mingaffel featureBv2

Flaggan --squash komprimerar alla incheckningar pƄ grenen som ska slƄs ihop till en enda versionsƤndring, vilket ger samma status i arkivet som vid en sammanslagning. Det innnebƤr att dina framtida incheckningar bara kommer att ha en fƶrƤlder och ger dig mƶjlighet att dra in alla Ƥndringar frƄn en annan gren och gƶra fler Ƥndringar innan den nya incheckningen kommer pƄ prƤnt. Ibland kan det vara anvƤndarbart att anvƤnda flaggan --no-commit fƶr att fƶrdrƶja en ny incheckning vid en sammanslagning istƤllet fƶr som i den ordinarie sammanslagningsprocessen. I det hƤr lƤget kan du meddela ansvarig att du har gjort de begƤrda Ƥndringarna och att de kan hitta dessa i din featureBv2.

Versionshistorik efter `featureBv2`.
Figur 72. Versionshistorik efter featureBv2.

Ɩppet, stƶrre projekt via mejl

MĆ„nga projekt har sina rutiner fƶr att acceptera patchar — du behƶver kolla upp de specifika reglerna fƶr varje projekt, eftersom de kommer att skilja sig Ć„t. Eftersom det finns flera Ƥldre, stƶrre projekt som endast accepterar patchar via en mejllista fƶr utvecklare, sĆ„ kommer vi att gĆ„ igenom ett exempel pĆ„ hur det gĆ„r till.

Arbetsprocessen liknar den i fƶregĆ„ende exemplet — du skapar finessgrenar som du arbetar pĆ„. Den stora skillnaden Ƥr att du inte kan skicka dina inceckningar till fjƤrrarkivet. IstƤllet behƶver du mejla varje commit till en mejllista fƶr utvecklare.

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

Nu har du tvĆ„ incheckningar som du vill skicka till mejllistan. Fƶr att generera mbox-formatterade filer som du kan mejla till listan, anvƤnder du git format-patch — det gƶr om varje incheckning till ett mejl med den fƶrsta raden i incheckningsmeddelandet som Ƥmne och resten av meddelandet plus patchen som innehĆ„ll. Det fina med det hƤr Ƥr att nƤr en patch frĆ„n ett mejl genererat med format-patch appliceras, sĆ„ bevaras incheckningsinformationen korrekt.

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

format-patch-kommandot skriver ut namnen pƄ de patchfiler som skapas. Flaggan -M talar om fƶr Git att leta efter omdƶpta filer. Filerna kommer att se ut sƄ hƤr:

$ cat 0001-add-limit-to-log-function.patch
Av 330090432754092d704da8e76ca5c05c198e71a8 MƄn Sep 17 00:00:00 2001
FrƄn: Jessica Smith <jessica@example.com>
Datum: Sƶn, 6 apr 2008 10:17:23 -0700
Ƅmne: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

---
 lib/simplegit.rb |    2 +-
 1 fil Ƥndrad, 1 tillagd(+), 1 borttagen(-)

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

Du kan ocksƄ redigera patchfilerna fƶr att lƤgga till mer information till mejllistan som du inte vill ska visas i incheckningsmeddelandet. Om du lƤgger till text mellan raden --- och bƶrjan av patchen (inleds med raden diff --git), sƄ kan utvecklarna lƤsa meddelandet, men det ignoreras i patchningsprocessen. Det Ƥr en bra plats att lƤgga till information om varfƶr du gjorde Ƥndringarna, eller om du har nƄgra speciella instruktioner fƶr att testa dem.

Fƶr att skicka patchfilen till mejllistan kan du antingen klistra in innehĆ„llet i ditt mejlprogram eller skicka det via kommandoraden. Att klistra in texten orsakar ofta formatteringsproblem, speciellt med ā€œsmartareā€ klienter som inte bevarar radbrytningar och mellanslag korrekt. Som tur Ƥr har Git ett verktyg som hjƤlper dig att skicka korrekt formatterade patchar via IMAP, vilket gƶr det enklare. Vi kommer att visa hur du skickar en patch via Gmail, som rĆ„kar vara den e-postklient vi kƤnner till bƤst. Du kan lƤsa detaljerade instruktioner fƶr en mƤngd e-postklienter i slutet av filen Documentation/SubmittingPatches i Gits kƤllkod.

Fƶrst behƶver du sƤtta upp IMAP-sektionen i din ~/.gitconfig-fil. Du kan sƤtta varje vƤrde separat med en serie git config-kommandon, eller lƤgga till dem manuellt. I slutƤnden ska din konfigurationsfil se ut nƄgot sƄ hƤr:

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

Om din IMAP-server inte anvƤnder SSL sƄ Ƥr de tvƄ sista raderna nog inte nƶdvƤndiga, och vƤrdet fƶr host kommer dƄ att vara imap:// istƤllet fƶr imaps://. NƤr det Ƥr instƤllt kan du anvƤnda git imap-send fƶr att placera patchserien i mappen Drafts pƄ den angivna IMAP-servern:

$ cat *.patch |git imap-send
Analyserar imap.gmail.com... ok
Ansluter till [74.125.142.109]:993... ok
Loggar in...
skickar 2 meddelanden
100% (2/2) klart

Nu borde du kunna gƄ till din Drafts-mapp, Ƥndra To-fƤltet till mejllistan du ska skicka patchen till, eventuellt lƤgga till cc:a till den person som Ƥr ansvarig, och skicka ivƤg det.

Du kan ocksƄ skicka patcharna via en SMTP-server. Precis som tidigare kan du sƤtta varje vƤrde separat med en serie git config-kommandon, eller lƤgga till dem manuellt i ~/.gitconfig-filen:

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

NƤr det Ƥr instƤllt kan du anvƤnda git send-email fƶr att skicka patcharna:

$ git send-email *.patch
0001-added-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
FrƄn vem ska breven skickas? [Jessica Smith <jessica@example.com>]
E-postbreven kommer att skickas frƄn: Jessica Smith <jessica@example.com>
Till vem ska breven sƤndas (om nƄgon)? jessica@example.com
Message-ID att anvƤnda som In-Reply-To fƶr det fƶrsta brevet? y

Git kommer att stƤlla en rad frƄgor om hur du vill att e-posten ska se ut fƶr varje skickad patch. De kommer att se ut ungefƤr sƄ hƤr:

(mbox) LƤgger till cc: Jessica Smith <jessica@example.com> frƄn
  \line 'From: Jessica Smith <jessica@example.com>'
OK. Loggen sƤger:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
FrƄn: Jessica Smith <jessica@example.com>
Till: jessica@example.com
Ƅmne: [PATCH 1/2] added limit to log function
Datum: 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

Sammanfattning

I den hƤr delen har vi gƄtt igenom en mƤngd olika arbetsflƶden fƶr olika slags Git-projekt som du troligen kommer att stƶta pƄ, samt introducerat ett par nya verktyg fƶr att hjƤlpa dig att hantera processerna. I nƤsta del kommer du att fƄ lƤra dig hur du hanterar den andra sidan av myntet: att underhƄlla ett Git-projekt. Du fƄr lƤra dig att vara en vƤlvillig diktator eller integrationsansvarig.

scroll-to-top