Skrivet av mmarks:
"En annan feature med Gits grenkoncept är att SVN-rävar får en "reality check" och inte tror att det bara är att tuta och köra som tidigare :-)"
Vi använder SVN på jobbet, jag lärde mig grunderna i GIT i plugget för några år sedan men det sitter ganska långt inne nu.. Vad är det för reality check jag skulle riskera att stöta på menar du?
Även om SVN och Git på något plan har samma slutmål i att hantera revisioner av data, så skiljer sig den fundamentala designen sig åt ordentligt. Just när det handlar om vad båda dessa system menar med "grenar" så blir det extra tydligt.
Generellt så kan man i SVN prata om att "klona en gren", en "gren" är lokalt representerad som en separat katalog i filsystemet (och existerar i någon mån inte ens lokalt förrän den checkas ut), en "gren" är något som sköts av servern (eftersom SVN per design är ett centraliserat system) och en "commit" är alltid kopplad till en "gren". Inget av detta gäller i Git .
I Git är en "gren" bara en referens till en viss punkt i commitgrafen, som är det fundamentala objektet. En gren är bara ett "human readable" alias för en viss commit (jag brukar använda liknelsen "post-it-lapp"), med egenskapen att detta alias automatiskt följer med om du gör en ny commit på grenen* (post-it-lappen flyttas). Varje klon av ett repo inkluderar typiskt den fulla grafen så som den är känd vid tillfället av källan, samt en ögonblicksbild av referenser in i grafen (grenar och taggar) och dessa referenser kostar egentligen aldrig något i sig — allt som kostar är objekt som hör till de commits som hålls vid liv av de referenser som finns för stunden. Git Branching — Branches in a Nutshell för att se vad dokumentation själv säger.
Beroende på sin design är merge, rebase, etc., mellan grenar mindre dramatiskt i Git ("det bara fungerar" i mycket större utsträckning) vilket gör att utvecklare lockas att arbeta annorlunda, på ett sätt som jag skulle hävda också är "bättre" när det gäller versionshantering av kod. Featuregrenar och "pull requests" kan utan problem leva parallellt utan att någon behöver känna ångest inför vad som händer på huvudspåret för stunden, eller hur snirklig historiken kommer se ut när man väl är klar med kodgranskningen. "Grenar på grenar" och "pull requests till pull requests" är vanligt att se, utan att någon behöver känna sig begränsad under utvecklingen.
När man skapar en gren i Git är det en rent lokal operation. Att skapa en gren tar inte mycket längre tid än det tar att skriva 40 byte (OK, lite metadata också ) till disk, men vi snackar millisekunder även om din dator har en dålig dag. Att pusha en gren uppströms är också en smal sak: om den pekar på en commit som redan finns i grafen på fjärrsidan så är det återigen bara en post-it-lapp med ett namn och en commit-hash på som behöver pushas — nätverkslatensen för att sätta upp anropet är sannolikt det som tar majoriteten av tiden i dessa operationer. Om grenen pekar på delar av grafen som ännu inte finns uppströms så skickar man detta också, och någon som hämtar ögonblicksbilden från ett repo får alla dessa delar lokalt direkt.
Utan att fastna i detta för mycket så är en av SVNs "talking points" att det går "snabbt" att skapa grenar där också (om man gör "rätt") jämfört med CVS, men dels är "snabbt" relativt (och Git är bra mycket snabbare ), och dels är det egentligen inte skapandet av grenar som är det viktiga, utan hur snabbt det går att hantera dem därefter, och inte minst sammanfoga i ett senare skede.
När CVS (som SVN ärver mycket av sin design från) designades så var idén om fulla kopior på allas datorer orimlig beroende på nätverkshastigheter och lagringskapacitet ("Menar du att jag ska behöva ladda hem och lagra 50 kB extra bara för att Olof ändrat fem filer i sin temporära gren?!"), men idag är det otvivelaktigt så att sättet SVN arbetar på är mycket långsammare än distribuerade system i egentligen alla rimliga fall för källkodslagring†.
Typiskt när man jobbar i Git så ser den lokala ögonblicksbilden av grenarna annorlunda ut än hur andra ser på saken. En commit på en gren (som primärt innebär att man utökar commitgrafen, samtidigt som grenens referens automatiskt uppdateras till att peka på den nya committen) sker alltid lokalt. Det går snabbt, och ingen annan behöver ens veta något‡. Utvecklare masserar om grenar kontinuerligt för att kunna skulptera den mest användbara bilden av historiken för eftervärlden.
(Mercurial är mer likt Git, men även Git och Mercurial skiljer sig i hur de ser på "grenar", där det Mercurial kallar "bookmarks" är mer likt det Git menar med "gren", likt jag nämnde i ett tidigare inlägg. En vanligt arbetssätt i Mercurial är att man klonar hela repot när man checkar ut eller skapar en ny gren, och när en commit görs så sparas information om grenen i själva committen, vilket har större analoger med SVN, även om grunddesignen mellan systemen egentligen skiljer sig lika mycket som SVN och Git.)
Torvalds tidiga presentation om Git för Googles utvecklare fokuserar en del på hur grunddesignen skiljer sig:
Skrivet av Linus Torvalds:
If there are any SVN users in the audience, you might want to leave, because my hatred of CVS has meant that I see SVN as being the most pointless project ever started.
Edit: Jag tittade genom ovanstående klipp nu igen, och det var nästan ännu bättre än vad jag mindes. Extra intressant är det att höra hur saker har ändrats på de 10 åren sedan klippet spelades in. De flesta hade inte ens hört talas om Git, och bara någon enstaka person i publiken visste ens om något företag som använde ett distribuerat versionshanteringssystem i skarp produktion.
*: Jag minns att jag först verkligen insåg hur enkel en gren i Git var när jag märkte att man kunde stå på en gren och bara köra git reset --hard godtycklig-referens
för att på alla sätt övertyga hela systemet om att min gren nu pekade någon helt annanstans. Det finns ingen magisk extrasås någonstans: en gren är en pekare in i grafen, och ändrar jag vart den pekar så har jag ändrat allt grenen står för.
——
†: Det finns vissa atypiska användningsområden där SVN fortsätter leva — exempelvis i projekt som versionshanterar stora binärfiler (vanligt i exempelvis modellbaserad utveckling) där antagandet att nätverksöverföring och lokal lagring är "dyrt" fortfarande kan gälla. Personligen är jag snabb på att argumentera för att ett arbetssätt som bygger på samarbete kring versionshantering av binära blobbar är felaktigt från grunden och att de som tycker det är en bra idé bör ta en ordentligt funderare på sina utvecklares välmående (typiskt är operationer som merge, rebase och ens diff döda (eller åtminstone otroligt ineffektiva) i ett sådant arbetssätt, vilket gör att hela idén med versionshanteringssystem får en rätt stor smäll). Man kan självkritiskt ställa sig frågan varför majoriteten av världens mjukvaruutvecklare så snabbt migrerade till distribuerade system.
Det finns också Git LFS som adresserar många av dessa saker i en Git-kontext, om man strikt vill hålla kvar vid sina binära blobbar.
——
‡: Detta nämner SVN-material ibland som en fördel för centraliserade system, då exempelvis SVN "tvingar" alla att publicera sina grenar kontinuerligt, så att novisa programmerare inte i sin blyghet inför att visa upp sitt arbete hellre jobbar parallellt i tysthet med egna spår. Om något skulle jag argumentera för den direkta motsatsen, där det enda detta leder till är att de som inte vågar visa sitt arbete då helt går utanför versionshanteringssystemen och jobbar med "en katalog på min dator"-systemet vilket bara blir sämre för alla parter. Jag har åtminstone själv inte upplevt den hypotetiska situation SVN försöker adressera med detta argument.