-
1. Kom igång
- 1.1 Om versionshantering
- 1.2 En kort historik av Git
- 1.3 Vad är Git?
- 1.4 Kommandoraden
- 1.5 Installera Git
- 1.6 Använda Git för första gången
- 1.7 Få hjälp
- 1.8 Sammanfattning
-
2. Grunder i Git
- 2.1 Skaffa ett Git-förvar
- 2.2 Spara ändringar till förvaret
- 2.3 Visa historiken
- 2.4 Ångra saker
- 2.5 Jobba med fjärrförvar
- 2.6 Taggning
- 2.7 Git alias
- 2.8 Sammanfattning
-
3. Git förgreningar
- 3.1 Grenar i ett nötskal
- 3.2 Grundläggande förgrening och sammanslagning
- 3.3 Hantera grenar
- 3.4 Arbetsflöde med grenar
- 3.5 Fjärrgrenar
- 3.6 Grenflytt
- 3.7 Sammanfattning
-
4. Git på servern
- 4.1 Protokollen
- 4.2 Skaffa Git på en server
- 4.3 Generera din publika SSH-nyckel
- 4.4 Konvigurera servern
- 4.5 Git Daemonen
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Alternativ tillhandahållna av tredje part
- 4.10 Sammanfattning
-
5. Distribuerade Git
-
6. GitHub
-
7. Git Tools
- 7.1 Revision Selection
- 7.2 Interactive Staging
- 7.3 Stashing and Cleaning
- 7.4 Signing Your Work
- 7.5 Searching
- 7.6 Rewriting History
- 7.7 Reset Demystified
- 7.8 Advanced Merging
- 7.9 Rerere
- 7.10 Debugging with Git
- 7.11 Submodules
- 7.12 Bundling
- 7.13 Replace
- 7.14 Credential Storage
- 7.15 Summary
-
8. Customizing Git
- 8.1 Git Configuration
- 8.2 Git Attributes
- 8.3 Git Hooks
- 8.4 An Example Git-Enforced Policy
- 8.5 Summary
-
9. Git and Other Systems
- 9.1 Git as a Client
- 9.2 Migrating to Git
- 9.3 Summary
-
10. Git Internals
- 10.1 Plumbing and Porcelain
- 10.2 Git Objects
- 10.3 Git References
- 10.4 Packfiles
- 10.5 The Refspec
- 10.6 Transfer Protocols
- 10.7 Maintenance and Data Recovery
- 10.8 Environment Variables
- 10.9 Summary
-
A1. Bilaga A: Git in Other Environments
- A1.1 Graphical Interfaces
- A1.2 Git in Visual Studio
- A1.3 Git in Eclipse
- A1.4 Git in Bash
- A1.5 Git in Zsh
- A1.6 Git in PowerShell
- A1.7 Summary
-
A2. Bilaga B: Embedding Git in your Applications
- A2.1 Command-line Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Bilaga C: Git Commands
- A3.1 Setup and Config
- A3.2 Getting and Creating Projects
- A3.3 Basic Snapshotting
- A3.4 Branching and Merging
- A3.5 Sharing and Updating Projects
- A3.6 Inspection and Comparison
- A3.7 Debugging
- A3.8 Patching
- A3.9 Email
- A3.10 External Systems
- A3.11 Administration
- A3.12 Plumbing Commands
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.
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 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:
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:
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:
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:
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:
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:
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.
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:
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:
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:
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:
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:
Ö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 |
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:
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
..
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
.
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.