I det grundläggande Git-arbetsflödet utvecklar du en ny funktion i en dedikerad ämnesgren och slår sedan tillbaka den till en produktionsgren när den är klar. Detta gör git-sammanslagning
ett integrerat verktyg för att kombinera grenar. Det är dock inte den enda Git erbjuder.
Som ett alternativ till ovanstående scenario kan du kombinera grenarna med git rebase
kommando. Istället för att binda grenarna tillsammans med ett sammanslagningsfördrag flyttar återhämtning hela funktionsgrenen till toppen av bemästra
enligt nedanstående.
Detta tjänar samma syfte som git-sammanslagning
, integrering åtar sig från olika grenar. Men det finns två anledningar till att vi kanske vill välja en rabatt över en sammanslagning:
I denna handledning undersöker vi dessa två vanliga fall av git rebase
. Tyvärr fördelarna med git rebase
komma på en trade-off. När den används felaktigt kan den vara en av de farligaste operationerna du kan utföra i ett Git-arkiv. Så vi ska också noggrant titta på farorna med att återuppta.
Denna handledning förutsätter att du är bekant med de grundläggande Git-kommandona och samarbetsflödena. Du bör vara bekväm att placera och begå ögonblicksbilder, utveckla funktioner i isolerade grenar, sammanfoga grenar tillsammans och trycka / dra grenar till / från avlägsna repositorier.
Det första användningsfallet vi ska utforska innebär en divergerande projekthistorik. Tänk på ett förråd där din produktionsgren har gått framåt medan du utvecklade en funktion:
Att rebase funktion
gren på bemästra
gren, du skulle köra följande kommandon:
git checkout funktion git rebase master
Detta transplanterar funktion
gren från sin nuvarande plats till toppen av bemästra
gren:
Det finns två scenarier där du vill göra det här. För det första om funktionen åberopade den nya förpliktelsen i bemästra
, det skulle nu ha tillgång till dem. För det andra, om funktionen var klar skulle den nu vara inställd för en snabb framåtfogning bemästra
. I båda fallen ger återhämtning resultat i en linjär historia, medan git-sammanslagning
skulle leda till onödiga sammanslagningar.
Tänk på vad som skulle hända om du integrerar uppströmsförbindelserna med en sammanslagning istället för en rebase:
git checkout funktion git merge master
Detta skulle ha gett oss ett extra sammanslagningsfördrag i funktion
gren. Dessutom skulle detta hända varje gång du ville integrera uppströms förbindelser i din funktion. Så småningom kommer din projekthistoria att fyllas med meningslösa sammanslagningar.
Samma fördel kan ses vid sammanslagning i andra riktningen. Utan en rebase, integrera den färdiga funktion
gren in i bemästra
kräver sammanslagning. Även om detta faktiskt är en meningsfull sammanslagning (i den meningen att den representerar en färdig funktion) är den resulterande historien full av gafflar:
När du reser innan du går ihop kan Git spola framåt bemästra
till toppen av funktion
. Du hittar en linjär historia om hur ditt projekt har utvecklats i git logg
output-förbinder sig i funktion
är snyggt grupperade på toppen av förbindelserna bemästra
. Detta är inte nödvändigtvis fallet när filialer är bundna ihop med ett sammanslagningsfördrag.
När du kör git rebase
, Git tar varje förpliktelse i grenen och flyttar dem, en för en, till den nya basen. Om någon av dessa förbinder ändrar samma linje (er) av kod som uppströmsförbindelsen, leder det till konflikt.
De git-sammanslagning
kommandot låter dig lösa alla grenens konflikter i slutet av sammanslagningen, vilket är ett av de främsta syftet med ett sammanslagningsfördrag. Det fungerar dock lite annorlunda när du återkommer. Konflikter löses på grundval av befogenheter. Så om git rebase
finner en konflikt, kommer det att stoppa återbetalningsförfarandet och visa ett varningsmeddelande:
Automatisk sammansmältning readme.txt CONFLICT (innehåll): Sammanfoga konflikt i readme.txt Misslyckades att slå samman i ändringarna ... När du har löst det här problemet kör du "git rebase - continuinue". Om du föredrar att hoppa över denna patch, kör "git rebase - skip" istället. För att kolla in den ursprungliga filialen och sluta återställa, kör "git rebase --abort".
Visuellt är det här vad din projekthistorik ser ut när git rebase
möter en konflikt:
Konflikten kan inspekteras genom att springa git status
. Produktionen ser mycket ut som en sammanslagningskonflikt:
Unmerged paths: (använd "git reset HEAD... "till unstage) (använd" git add ... "för att markera upplösning) båda modifierade: readme.txt inga ändringar läggas till för att begå (använd" git add "och / eller" git commit -a ")
För att lösa konflikten öppnar du den konflikta filen (readme.txt i ovanstående exempel), hitta de drabbade raderna och manuellt redigera dem till önskat resultat. Därefter berätta för Git att konflikten är löst genom att ställa in filen:
git lägg till readme.txt
Observera att detta är exakt samma sätt som du markerar en git-sammanslagning
konflikt som löst. Men kom ihåg att du är mitt i en rebase-du vill inte glömma resten av de förpliktelser som behöver flyttas. Det sista steget är att berätta för Git att avsluta återhämtning med --Fortsätta
alternativ:
git rebase - fortsätt
Detta kommer att flytta resten av förbindelserna, en för en, och om några andra konflikter uppstår måste du upprepa processen helt och hållet igen.
Om du inte vill lösa konflikten kan du välja antingen --hoppa
eller --avbryta
flaggor. Den senare är särskilt användbar om du inte har någon aning om vad som händer och bara vill komma tillbaka till säkerheten.
# Ignorera det åtagande som orsakade konflikten git rebase - skip # Avbryt hela rebasen och gå tillbaka till ritbordet git rebase --abort
Hittills har vi bara använt git rebase
att flytta grenar, men det är mycket kraftfullare än det. Genom att passera -jag
flagga, kan du börja en interaktiv återkommande session. Interaktiv återställning kan du definiera exakt hur varje commit kommer att flyttas till den nya basen. Detta ger dig möjlighet att städa upp en funktions historia innan du delar den med andra utvecklare.
Låt oss säga att du slutat arbeta med din funktion
gren och du är redo att integrera den i bemästra
. För att starta en interaktiv återkommande session, kör följande kommando:
git checkout funktion git rebase -i master
Detta öppnar en redaktör som innehåller alla förpliktelser i funktion
som håller på att flyttas:
välj 5c43c2b [Beskrivning för äldsta commit] välj b8f3240 [Beskrivning för 2: e äldsta commit] välj c069f4a [Beskrivning för senaste commit]
Denna lista definierar vad funktion
gren kommer att se ut efter rebasen. Varje rad representerar en commit och plocka
kommando före varje commit hash definierar vad som kommer att hända under repasen. Observera att åtagandena är listade från äldsta till senaste. Genom att ändra den här listan får du fullständig kontroll över din projekthistorik.
Om du vill ändra ordningen för förpliktelserna, ordnar du bara raderna. Om du vill ändra ett buds meddelande, använd omformulera
kommando. Om du vill kombinera två förbindelser, ändra plocka
kommandot till squash
. Detta kommer att rulla alla ändringar i det åtagandet till det ovanstående. Till exempel, om du squashed det andra engagemanget i ovanstående notering, den funktion
gren skulle se ut som följer efter att ha sparat och stängt redigeraren:
De redigera
kommandot är särskilt kraftfullt. När det når det angivna åtagandet, kommer Git pausa återbetalningsförfarandet, ungefär som när det möter en konflikt. Detta ger dig möjlighet att ändra innehållet i förbindelsen med git commit --amend
eller till och med lägga till mer förpliktelser med standarden git lägg till
/git commit
kommandon. Någon ny förbinder dig att lägga till kommer att vara en del av den nya filialen.
Interaktiv återhämtning kan få en djupgående inverkan på ditt utvecklingsarbete. I stället för att oroa dig för att bryta upp dina ändringar i inkapslade förpliktelser kan du fokusera på att skriva din kod. Om du slutade begå vad som skulle vara en enda ändring i fyra separata ögonblicksbilder, så är det inte en problemskrivningshistoria med git rebase -i
och squash dem alla till ett meningsfullt engagemang.
Nu när du förstår git rebase
, vi kan prata om när vi inte ska använda den. Internt, återföring flyttar faktiskt inte till en ny filial. I stället skapar det helt nya begåvningar som innehåller önskade ändringar. Med det här är sinnet, är återhämtning bättre visualiserad som följande:
Efter rebasen begås i funktion
kommer att ha olika fördragshastigheter. Det innebär att vi inte bara bytte ut en filial - vi har bokstavligen omskrivit vår projekthistoria. Detta är en mycket viktig bieffekt av git rebase
.
När du arbetar ensam på ett projekt är omskrivning av historia inte en stor sak. Men så fort du börjar arbeta i en samarbetsmiljö kan det bli mycket farligt. Om du skriver om, förbinder du att andra utvecklare använder (t.ex. förbinder sig på bemästra
gren), det kommer att se ut som om de begås försvinner nästa gång de försöker dra in ditt arbete. Detta resulterar i ett förvirrande scenario som är svårt att återhämta sig från.
Med det här är det, bör du aldrig begå förpliktelser som har drivits till ett offentligt förråd, såvida du inte är positiv att ingen har byggt sitt arbete av dem.
Denna handledning introducerade de två vanligaste användningsfallen av git rebase
. Vi pratade mycket om att flytta grenar runt, men kom ihåg att återuppbyggnad handlar om att styra din projekthistoria. Förmågan att skriva om på nytt förbjuder dig att fokusera på dina utvecklingsuppgifter istället för att bryta ner ditt arbete i isolerade ögonblicksbilder.
Observera att återhämtning är ett helt valfritt tillägg till din Git-verktygslåda. Du kan fortfarande göra allt du behöver med vanlig gammal git-sammanslagning
kommandon. Det är faktiskt säkrare eftersom det undviker möjligheten att skriva om den offentliga historien. Men om du förstår riskerna, git rebase
kan vara ett mycket renare sätt att integrera filialer jämfört med sammanslagningar.