Git 🌙
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