För att verkligen förstå hur Git hanterar grenar behöver vi ta ett steg tillbaka och titta på hur Git lagrar data.
Som du kanske minns från ch01-getting-started.asc lagrar Git inte data som en serie ändringar eller ändringsmängder, utan som en serie ögonblicksbilder.
När du gör en incheckning sparar Git ett incheckningsobjekt som innehåller en pekare till ögonblicksbilden av innehållet du köade. Objektet innehåller också författarens namn och e-postadress, meddelandet du skrev och pekare till de incheckningar som kom direkt före (dess föräldrar): inga föräldrar för den första incheckningen, en förälder för en vanlig incheckning och flera föräldrar för en incheckning som är resultatet av en sammanslagning av två eller fler grenar.
För att visualisera detta kan vi anta att du har en katalog med tre filer, att du köar dem och gör en incheckning. När du köar filerna beräknas en kontrollsumma för varje fil (SHA-1-hashen som nämndes i ch01-getting-started.asc), Git lagrar filversionen i kodförrådet (Git kallar dem blobbar) och lägger kontrollsumman i köytan:
$ git add README test.rb LICENSE
$ git commit -m 'Initial commit'När du skapar incheckningen med git commit beräknar Git en kontrollsumma för varje underkatalog (i det här fallet bara projektets rotkatalog) och lagrar dem som ett trädobjekt i kodförrådet.
Git skapar sedan ett incheckningsobjekt med metadata och en pekare till projektets rotträd så att ögonblicksbilden kan återskapas vid behov.
Ditt Git-kodförråd innehåller nu fem objekt: tre blobbar (var och en representerar innehållet i en av de tre filerna), ett träd som listar katalogens innehåll och pekar ut vilka filnamn som motsvarar vilka blobbar, och en incheckning med pekare till rotträdet och dess metadata.
Om du gör ändringar och checkar in igen sparar nästa incheckning en pekare till den som kom direkt före.
En gren i Git är helt enkelt en lätt flyttbar pekare till en av dessa incheckningar.
Standardgrenens namn i Git är master.
När du börjar göra incheckningar får du en master-gren som pekar på den senaste incheckningen.
Varje gång du checkar in flyttas master-pekaren framåt automatiskt.
|
Note
|
“master”-grenen i Git är inte något särskilt.
Den är precis som vilken annan gren som helst.
Det enda skälet till att nästan alla kodförråd har den är att |
Vad händer när du skapar en ny gren?
Du skapar helt enkelt en ny pekare som du kan flytta runt.
Säg att du vill skapa en gren som heter testing.
Det gör du med git branch:
$ git branch testingDet här skapar en ny pekare till samma incheckning som du står på just nu.
Hur vet Git vilken gren du står på?
Den håller en särskild pekare som heter HEAD.
Observera att detta skiljer sig från HEAD i andra VCS:er som Subversion eller CVS.
I Git är det en pekare till den lokala gren du för närvarande står på.
I det här fallet är du fortfarande på master.
git branch skapade bara en ny gren – den bytte inte till den.
Du kan lätt se detta genom att köra git log med flaggan --decorate, som visar var grenpekare ligger.
$ git log --oneline --decorate
f30ab (HEAD -> master, testing) Add feature #32 - ability to add new formats to the central interface
34ac2 Fix bug #1328 - stack overflow under certain conditions
98ca9 Initial commitDu ser att master och testing pekar på samma incheckning f30ab.
För att byta till en befintlig gren kör du git checkout.
Vi byter till den nya grenen testing:
$ git checkout testingDet flyttar HEAD så att den pekar på testing.
Vad betyder det? Vi gör en incheckning:
$ vim test.rb
$ git commit -a -m 'Make a change'Din testing-gren har nu flyttat fram, medan master fortfarande pekar på incheckningen du stod på när du bytte gren.
Vi byter tillbaka till master:
$ git checkout master|
Note
|
git log visar inte alltid alla grenarOm du kör Grenen finns kvar; Git visar bara den historik den tror att du är intresserad av.
Som standard visar För att visa historiken för den gren du vill se behöver du ange den explicit: |
Kommandot gjorde två saker.
Det flyttade HEAD-pekaren tillbaka till master och återställde filerna i arbetskatalogen till ögonblicksbilden som master pekar på.
Det betyder också att ändringar du gör från och med nu kommer att divergera från en äldre version av projektet.
I praktiken spolar det tillbaka arbetet du gjorde i testing så att du kan gå i en annan riktning.
|
Note
|
Byta gren ändrar filer i arbetskatalogen
Tänk på att när du byter gren i Git ändras filerna i arbetskatalogen. Om du byter till en äldre gren återställs arbetskatalogen till hur den såg ut när du senast checkade in på den grenen. Om Git inte kan göra detta utan konflikter får du inte byta gren. |
Vi gör några ändringar och checkar in igen:
$ vim test.rb
$ git commit -a -m 'Make other changes'Nu har projektets historik divergerat (se Divergerad historik).
Du skapade och bytte till en gren, gjorde arbete där, och bytte sedan tillbaka till huvudgrenen och gjorde annat arbete.
Båda ändringarna är isolerade i separata grenar: du kan byta fram och tillbaka mellan dem och sammanfoga dem när du är redo.
Och allt detta gjorde du med branch, checkout och commit.
Du kan också se detta med git log.
Om du kör git log --oneline --decorate --graph --all skrivs hela historiken ut, samt var grenpekare finns och hur historiken har divergerat.
$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) Make other changes
| * 87ab2 (testing) Make a change
|/
* f30ab Add feature #32 - ability to add new formats to the central interface
* 34ac2 Fix bug #1328 - stack overflow under certain conditions
* 98ca9 Initial commit of my projectEftersom en gren i Git i grunden är en fil som innehåller den 40 tecken långa SHA-1-kontrollsumman för incheckningen den pekar på, är grenar billiga att skapa och ta bort. Att skapa en ny gren är i praktiken lika enkelt som att skriva 41 byte till en fil (40 tecken plus radbrytning).
Detta står i skarp kontrast till äldre VCS-verktyg där grenar innebär att hela projektets filer kopieras till en ny katalog. Det kan ta sekunder eller minuter beroende på projektets storlek, medan Git alltid är omedelbart. Eftersom vi lagrar föräldrarna till varje incheckning hittar Git automatiskt en lämplig bas för sammanslagningar, vilket gör dem enkla att genomföra. Detta uppmuntrar utvecklare att skapa och använda grenar ofta.
Vi ser varför.
|
Note
|
Skapa och byta gren samtidigt
Det är vanligt att vilja skapa en ny gren och byta till den direkt.
Det kan göras i ett steg med |








