-
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
-
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
3.6 Git fƶrgreningar - Grenflytt
Grenflytt
I Git finns i huvusak tvƄ sƤtt att integrera Ƥndringar frƄn en gren in i en annan: sammanslagning (merge
) eller grenflytt (rebase
).
I detta avsnitt kokker du fƄr lƤra dig vad en grenflytt Ƥr, hur man gƶr det och varfƶr det Ƥr ett ganska hƤpnadsvƤckande verktyg, samt i vilka fall du inte vill anvƤnda det.
Den grundlƤggande grenflytten
Om du gƄr tillbaks till ett tidigare exempel frƄn GrundlƤggande sammanslagning, kan du se att du divergerade ditt arbete och gjorde versioner pƄ tvƄ olika grenar.

Det Ƥnklaste sƤttet att integrera grenar Ƥr, som vi redan gƄtt igenom, kommandot merge
.
Den genomfƶr en trevƤgssammanslagning mellan de tvƄ senaste ƶgonblicksbilderna (C3
och C4
) och den senaste gemensamma versionen av de tvƄ grenarna (C2
) och skapar en ny ƶgonblicksbild (och version).

Det finns emellertid ett annat sƤtt: Du kan ta Ƥndringarna som introducerades i C4
och tillƤmpa den pƄ toppen av C3
.
I Git kallas detta fƶr grenflytt (eng. rebasing).
Med kommandot rebase
kan du ta alla Ƥndringar som sparats i en gren och spela upp dem pƄ en annan gren.
I detta exemplet kommer du checka ut experiment
-grenen och sedan flytta grenen till master
-grenen som fƶljer:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
Denna operation fungerar genom att hitta den senaste gemensamma versionen fƶr de tvƄ grenarna (den du stƄr pƄ och den du skall flytta din gren till), ta reda pƄ skillnaderna som introducerats i varje version av den gren du stƄr pƄ, spara dessa i temporƤra filer, peka om den aktuella grenen till toppen av den gren som du skall flytta din aktuella gren till, och sedan applicera Ƥndringarna i turordning.

C4
pƄ toppen av C3
Nu kan du gƄ tillbaka till master
-grenen och gƶra en sammanslagning via snabbspolning.
$ git checkout master
$ git merge experiment

Ćgonblicksbilden som C4'
pekar pƄ Ƥr exakt samma som den som C5
pekade pƄ i the merge example.
Det finns ingen skillnad i slutprodukten av integrationen, men att flytta grenen gƶr att historiken blir renare.
Om du undersƶker historiken av en flyttad gren kommer den vara linjƤr: det verkar som att allt arbete har skett sekvensiellt, trots att det egentligen skedde parallellt.
Ofta vill du gƶra detta fƶr att sƤkerstƤlla att dina versioner kan lƤggas till rent pĆ„ en fjƤrrgrenāāākanske i ett projekt som du fƶrsƶker bidra till men som du inte underhĆ„ller.
I detta fall gƶr du ditt arbete i en gren och sedan flyttar ditt arbet in i origin/master
nƤr du Ƥr redo att publicera dina Ƥndringar till huvudprojektet.
PĆ„ detta vis behƶver inte den som underhĆ„ller projektet gƶra nĆ„got integrationsarbeteāāāendast snabbspola eller lƤgga till Ƥndringarna rent.
Notera att ƶgonblicksbilden som pekas pĆ„ av den slutliga versionen, oavsett om det Ƥr den senaste av de flyttade versionerna fƶr en grenflytt eller den slutliga versionen efter en sammanslagning Ƥr samma ƶgonblicksbildāāādet Ƥr bara historiken som skiljer. Grenflytt spelar upp Ƥndringarna frĆ„n en arbetshistorik pĆ„ toppen av en annan i samma ordning de introducerades, medan sammanslagning tar Ƥndpunkterna pĆ„ varje gren och slĆ„r ihop dem.
Mer intressanta grenflyttar
Du kan ocksƄ spela upp din historik pƄ nƄgot annat Ƥn den ursprungliga basgrenen.
Ta en historik som Historik med en gren frƄn en annan gren, till exempel.
Du gjorde en gren (server
) fƶr att lƤgga till lite serverfunktionalitet till ditt projekt och skapade en ny version.
DƤrefter gjorde du en gren frƄn denna fƶr att gƶra motsvarande Ƥndringar hos klienten (client
) och gjorde nƄgra nya versioner.
Slutligen gick du tillvaks till din servergren och gjorde nƄgra fler versioner.

Antag att du beslutar att du vill slƄ samman din klientfunktionalitet till ditt huvudspƄr fƶr att frislƤppa dem, men att du vill avvakta serverƤndringarna tills dessa Ƥr testade.
Du kan ta klietƤndringarna som inte Ƥr pƄ server (C8
och C9
) och spela upp dem pƄ din master
gren genom att anvƤnda flaggan --onto
till git rebase
:
$ git rebase --onto master server client
Detta betyder i praktiken āTa client
grenen, ta reda pƄ de patchar sedan den divergerade frƄn server
grenen, och spela upp dem pƄ klient
delen som om de vore baserade direkt frƄn master
grenen istƤllet.ā
Det Ƥr lite komplext, men resultatet Ƥr rƤtt hƤftigt.

Nu kan du snabbspola din master
gren (se Snabbspola din master-gren till att inkludera klientgrenens Ƥndringar):
$ git checkout master
$ git merge client

SƤg att du beslutar att dra in din servergren ocksƄ.
Du kan spela upp servergrenen pƄ master
grenen utan att behƶva checka ut den fƶrst genom att kƶra git rebase <basgren> <stickspƄr>
āāāvilket checkar ut stickspĆ„ret (server
i detta fall) fƶr dig och spelar up den pƄ basgrenen (master
):
$ git rebase master server
Detta spelar upp ditt arbete i server
ovan pƄ ditt arbete i master
, som synes i Flytta din servergren til toppen av din mastergren.

DƤrefter kan du snabbspola din basgren (master
):
$ git checkout master
$ git merge server
Du kan ta bort grenarna client
och server
eftersom allt arbete Ƥr integrerat, vilket ger dig en historik fƶr denna process likt Slutlig versionshistorik:
$ git branch -d client
$ git branch -d server

Farorna med grenflyttar
Ahh, lyckan med grenflytt Ƥr inte helt utan nackdelar, vilka kan sammanfattas i en mening:
Flytta inte versioner som existerar utanfƶr ditt lokala repo som andra kan ha baserat sitt arbete pƄ.
Fƶljer du det tipset sƄ kommer allt gƄ bra. Om inte, kommer folk hata dig och du kommer att hƄnas av dina vƤnner och familj.
NƤr du flyttar om saker ƶverger du existerande versioner och skapar nya som Ƥr lika, men annorlunda.
Om du publicerar versioner nƄgonstans och andra hƤmtar dem och baserar arbete pƄ dem och du sedan skriver om historiken med git rebase
och publicerar dessa Ƥndringarna igen, kommer dina medarbetare att behƶva Ƅterintegrera sitt arbete och saker kommer bli krƄnligt nƤr du fƶrsƶker integrera deras Ƥndringar i dina.
LƄt oss ta ett exempel pƄ hur det kan uppstƄ problem om du skriver om arbete som du gjort publikt. Antag att du klonar frƄn en central server och sedan gƶr lite arbete pƄ det. Din versionshistorik ser ut sƄhƤr:

Nu gƶr nƄgon annan mer arbete som inkluderar en sammanslagning och publicerar det arbetet till den centrala servern. Du hƤmtar det och slƄr ihop fjƤrrgrenen in i ditt arbete vilket gƶr att din versionshistorik ser ut ungefƤr sƄhƤr:

Sedan bestƤmmer sig personen som publicerade Ƥndringarna att gƄ tillbaks och skriva om sin historik istƤllet; de gƶr git push --force
fƶr att skriva ƶver den historik som finns pƄ servern.
Du hƤmtar sedan frƄn den server, och fƄr hem de nya versionerna.

Nu sitter ni bƄda i skiten.
Om du gƶr git pull
kommer du skapa en sammanslagningsversion som inkluderar bƄda versionstidslinjerna, och ditt repo kommer se ut sƄhƤr:

Om du kƶr git log
nƤr din historik ser ut sƄhƤr kommer du se tvƄ versioner som har samma fƶrfattare, datum och meddelande, vilket kommer vara fƶrvirrande.
Vidare, om du publicerar denna historik tillbaks till servern, kommer du Ƅterintroducera alla de tidigare omskrivna versionerna vilket kan fƶrvirra andra ocksƄ.
Man kan vara ganska sƤker pƄ att den andra utvecklaren inte vill att C4
och C6
skall vara i historiken; det Ƥr dƤrfƶr de skrev om historiken frƄn bƶrjan.
Flytta en gren nƤr du flyttar en gren
Om du dƤremot finner att du Ƥr i en liknande sitiation, sƄ har Git lite ytterligare magi som kan komma vƤl till pass. Om nƄgon i ditt team trycker ut en Ƥndring som skriver ƶver arbete som du baserar arbete pƄ, blir din utmaning att ta reda pƄ vad som Ƥr ditt och vad de har skrivit om.
Det faller sig sĆ„ att utƶver till versionens SHA-1 checksimma, berƤknar Git ocksĆ„ en checksumma baserat pĆ„ just den patch som introducerades med versionen. Denna kallas fƶr āpatch-idā.
Om du hƤmtar hem arbete som var omskrivet och gƶr en egen omskrivning pƄ toppen av versionerna frƄn din kollega, kan Git ofta lista ut vad som Ƥr unikt ditt och och applicera dina Ƥndringar ovanpƄ den nya grenen.
Till exempel, i fƶregƄende scenario, om du istƤllet fƶr att slƄ ihop Ƥndringarna vid NƄgon publicerar omskriven historik, och ƶverger versioner pƄ vilka du baserat arbete och kƶr git rebase teamone/master
, kommer Git att:
-
Ta reda pƄ vilket arbete som Ƥr unikt fƶr vƄr gren (C2, C3, C4, C6, C7)
-
Ta reda pƄ vilka som inte Ƥr sammanslagningsversioner (C2, C3, C4)
-
Ta reda pƄ vad som inte har skrivits om i mƄlgrenen (bara C2 och C3, eftersom C4 Ƥr samma patch som C4')
-
Applicera de Ƥndringarna ovanpƄ
teamone/master
SƄ istƤllet fƶr resultatet i Du integrerar samma arbete igen i en ny sammanslagningsversion kommer vi fƄ ett slutligt resultat liknande Grenflytt till toppen av en tvingande publicering av omskriven historik.

Detta fungerar bara om C4 och C4' som din kollega gjort Ƥr nƤst intill samma patch. Annars kommer Git inte kunna avgƶra att de Ƥr duplikat och kommer lƤgga till ytterligare en C4-lik patch (som fƶrmodligen inte kommer gƄ att applicera rent, eftersom Ƥndringarna bitvis redan Ƥr pƄ plats).
Du kan ocksƄ fƶrenklad detta genom att kƶra git pull --rebase
istƤllet fƶr en vanlig git pull
.
Eller sƄ kan du gƶra det manuellt genom git fetch
fƶljt av git rebase teamone/master
i detta fallet.
AnvƤnder du git pull
och vill gƶra --rebase
till normalfallet, kan du sƤtta konfigureringsparametern pull.rebase
med nƄgot liknande git config --global pull.rebase true
.
Om du nƤgonsin skriver om historik som bara finns lokalt pƄ din dator kommer du vara helt sƤker. Om du skriver om historik som Ƥr publicerade, men som ingen annan baserat versioner pƄ, kommer du ocksƄ vara helt sƤker. Om du skriver om versionshistorik som redan har publicerats publikt, och som folk har baserat arbete pƄ, kommer du hamna i frustrerande trubbel och hƄnas av dina teammedlemmar.
Om du eller en kollega anser det vara nƶdvƤndigt vid nƄgot tillfƤlle, se till att alla vet om att de skall kƶra git pull --rebase
fƶr att gƶra den efterfƶljande pinan nƄgot lƤttare.
Omskrivning vs. Sammanslagning
Nu nƤr du sett hur omskrivning och sammanslagning fungerar, kanske du undrar vilken som Ƥr bƤst. Innan vi kan svara pƄ det, lƄt oss ta ett steg tillbaka och prata om vad historik betyder.
En infallsvinkel pƄ det Ƥr att dit repos versionshistorik Ƥr en beskrivning ƶver vad som faktiskt hƤnde. Det Ƥr ett historiskt dokument, vƤrdefull i sig sjƤlv, och skall inte manipuleras. Med denna vinkel Ƥr Ƥndring av versionshistoriken nƤrmast blasfemi; du ljuger om vad som faktisk skedde. Vad gƶr det om det Ƥr en stƶkig historik av sammanslagningsversioner? Det var sƄ det hƤnde, och repot skall bevara det fƶr eftervƤrlden.
En motstƄende infallsvinkel Ƥr att versionshistoriken Ƥr berƤttelsen av hur ditt projekt skapades. Du publicerar inte fƶrsta utkastet av en bok, och manualen fƶr hur du underhƄller din mjukvara fƶrtjƤnar noggrann redigering. Detta Ƥr lƤgret som anvƤnder verktyg som omskrivning och filter-grenar fƶr att berƤtta historien som bƤst lƤmpar sig fƶr framtida lƤsare.
Nu till frƄgan huruvida sammanslagning eller omskrivning Ƥr bƤttre: fƶrhoppningsvis inser du att det inte Ƥr sƄ enkelt. Git Ƥr ett kraftfullt verktyg och tillƄter dig att gƶra mƄnga saker med din historik, men alla team och alla projekt Ƥr olika. Nu nƤr du vet hur bƄda dessa verktyg fungerar, Ƥr det upp till dig att avgƶra vilken metod som Ƥr bƤst lƤmpad i din specifika situation.
I allmƤnhet, fƶr att fƄ det bƤsta frƄn tvƄ vƤrldar, Ƥr att skriva om lokala Ƥndringar du gjort men Ƥnnu inte delat innan du publicerar dem i syfte att rensa upp din historik, men att aldrig skriva om historik du publicerat nƄnstans.