In de fundamentele Git-workflow ontwikkel je een nieuwe functie in een speciale topictak en voeg je hem vervolgens weer in een productietak zodra deze is voltooid. Dit maakt git fuseren
een integraal hulpmiddel voor het combineren van branches. Het is echter niet de enige die Git aanbiedt.
Als alternatief voor het bovenstaande scenario zou je de takken kunnen combineren met de git rebase
commando. In plaats van de takken samen te binden met een samenvoegverbintenis, verplaatst rebasen de volledige kenmerktak naar de top van meester
zoals hieronder getoond.
Dit dient hetzelfde doel als git fuseren
, integratie van commits uit verschillende branches. Maar er zijn twee redenen waarom we zouden kunnen kiezen voor een rebase via een samenvoeging:
In deze zelfstudie onderzoeken we deze twee veelvoorkomende gebruiksmogelijkheden van git rebase
. Helaas zijn de voordelen van git rebase
kom op tegen een compromis. Als het verkeerd wordt gebruikt, kan dit een van de gevaarlijkste bewerkingen zijn die u in een Git-repository kunt uitvoeren. We zullen dus ook goed kijken naar de gevaren van rebasen.
Deze tutorial gaat ervan uit dat je bekend bent met de standaard Git-commando's en samenwerkingsworkflows. Je zou het op een comfortabele manier moeten opnemen en vastleggen van snapshots, functies ontwikkelen in geïsoleerde takken, takken samenvoegen en takken duwen / trekken naar / van externe opslagplaatsen.
De eerste use-case die we zullen verkennen, betreft een uiteenlopende projectgeschiedenis. Overweeg een opslagplaats waar uw productietak is vooruitgegaan terwijl u een functie aan het ontwikkelen was:
Om de voorzien zijn van
vertakken naar de meester
branch, zou je de volgende commando's uitvoeren:
git checkout functie git rebase master
Dit transplanteert het voorzien zijn van
aftakking van de huidige locatie naar de top van de meester
tak:
Er zijn twee scenario's waar u dit zou willen doen. Ten eerste, als de functie is gebaseerd op de nieuwe commits in meester
, het zou nu toegang hebben tot hen. Ten tweede, als de functie was voltooid, zou deze nu worden ingesteld voor een snel doorsturen naar meester
. In beide gevallen resulteert rebasen in een lineaire geschiedenis, terwijl git fuseren
zou resulteren in onnodige merge commits.
Overweeg bijvoorbeeld wat er zou gebeuren als u de upstream commits zou integreren met een fusie in plaats van een rebase:
git checkout feature git merge master
Dit zou ons een extra merge commit hebben gegeven in de voorzien zijn van
tak. Wat meer is, dit zou elke keer gebeuren dat je upstream commits in je feature wilde opnemen. Uiteindelijk zou je projectgeschiedenis bezaaid zijn met zinloze samenvoegingsbevoegdheden.
Ditzelfde voordeel kan worden gezien bij het samenvoegen in de andere richting. Zonder een rebase, het voltooide integreren voorzien zijn van
vertakken naar meester
vereist een merge commit. Hoewel dit eigenlijk een zinvolle merge commit is (in de zin dat het een voltooide functie vertegenwoordigt), is de resulterende geschiedenis vol met vorken:
Wanneer je rebase voor het samenvoegen, kan Git snel vooruitspoelen meester
naar het puntje van voorzien zijn van
. U zult een lineair verhaal vinden over hoe uw project is geëvolueerd in de git log
output - de commits in voorzien zijn van
zijn netjes gegroepeerd bovenop de commits in meester
. Dit is niet noodzakelijk het geval wanneer takken samen worden gebonden met een samenvoegverbintenis.
Wanneer je rent git rebase
, Git neemt elke commit in de branch en verplaatst ze één voor één naar de nieuwe basis. Als een van deze commits dezelfde regel (s) code wijzigt als de stroomopwaartse commits, resulteert dit in een conflict.
De git fuseren
Met de opdracht kunt u alle conflicten van de branch oplossen aan het einde van de samenvoeging, wat een van de primaire doelen van een samenvoeg-commit is. Het werkt echter een beetje anders wanneer je rebaseert. Conflicten worden per commit opgelost. Dus indien git rebase
vindt een conflict, het stopt de rebase-procedure en geeft een waarschuwing weer:
Readme.txt automatisch samenvoegen CONFLICT (inhoud): conflict samenvoegen in readme.txt kon de wijzigingen niet samenvoegen ... Als u dit probleem hebt opgelost, voert u "git rebase --continue" uit. Als u liever deze patch overslaat, voert u in plaats daarvan "git rebase --skip" uit. Om de originele branch te bekijken en te stoppen met rebasen, voer je "git rebase --abort" uit.
Visueel is dit hoe uw projectgeschiedenis eruitziet wanneer git rebase
ontmoet een conflict:
De conflicten kunnen worden geïnspecteerd door te hardlopen git status
. De uitvoer lijkt erg op een samenvoegconflict:
Onverharde paden: (gebruik "git reset HEAD... "unstage) (gebruik" git add " ... "om de resolutie te markeren) beide aangepast: readme.txt geen wijzigingen toegevoegd aan commit (gebruik" git add "en / of" git commit -a ")
Als u het conflict wilt oplossen, opent u het conflicterende bestand (readme.txt in het bovenstaande voorbeeld), zoekt u de betreffende regels en bewerkt u deze handmatig naar het gewenste resultaat. Vertel Git vervolgens dat het conflict is opgelost door het bestand te organiseren:
git voeg readme.txt toe
Let op: dit is exact dezelfde manier waarop u een a markeert git fuseren
conflict als opgelost. Maar onthoud dat je midden in een rebase zit - je wilt de rest van de commits die verplaatst moeten worden niet vergeten. De laatste stap is om Git te vertellen dat je moet rebasen met de --doorgaan met
keuze:
git rebase - vervolg
Hierdoor worden de rest van de commits een voor een verplaatst en als er andere conflicten optreden, moet je dit proces helemaal opnieuw herhalen.
Als u het conflict niet wilt oplossen, kunt u kiezen voor de --overspringen
of --afbreken
vlaggen. Dit laatste is vooral handig als je geen idee hebt wat er aan de hand is en gewoon weer veilig wilt zijn.
# Negeer de commit die het conflict veroorzaakte git rebase --skip # Annuleer de volledige rebase en ga terug naar de tekentafel git rebase --abort
Tot nu toe hebben we alleen gebruikt git rebase
om takken te verplaatsen, maar het is veel krachtiger dan dat. Door het -ik
vlag, kunt u een interactieve rebasing-sessie starten. Met interactieve rebasing kun je precies definiëren hoe elke commit naar het nieuwe basisstation wordt verplaatst. Dit geeft u de mogelijkheid om de geschiedenis van een functie op te schonen voordat u deze met andere ontwikkelaars deelt.
Stel bijvoorbeeld dat u klaar bent met uw werk voorzien zijn van
branch en je bent klaar om het te integreren meester
. Om een interactieve rebasesessie te starten, voert u de volgende opdracht uit:
git uitcheck functie git rebase -i master
Dit opent een editor met daarin alle commits voorzien zijn van
die op het punt staan verplaatst te worden:
kies 5c43c2b [Beschrijving voor oudste commit] pick b8f3240 [Beschrijving voor 2e oudste commit] pick c069f4a [Beschrijving voor meest recente commit]
Deze lijst definieert wat de voorzien zijn van
tak zal er na de rebase uitzien. Elke regel vertegenwoordigt een commit en de plukken
commando voordat elke commit hash definieert wat er met de rebase zal gebeuren. Merk op dat de commits worden opgesomd van oudste naar meest recente. Door deze aanbieding te wijzigen, verkrijgt u volledige controle over uw projectgeschiedenis.
Als u de volgorde van de commits wilt wijzigen, kunt u de regels gewoon opnieuw ordenen. Als u het bericht van een commit wilt veranderen, gebruik dan de met andere woorden uitdrukken
commando. Als u twee commits wilt combineren, wijzigt u de plukken
commando om squash
. Dit zal alle veranderingen in die commit naar die erboven gooien. Als u bijvoorbeeld de tweede commit in de bovenstaande lijst hebt geplet, is de voorzien zijn van
branch ziet er als volgt uit na het opslaan en sluiten van de editor:
De Bewerk
commando is bijzonder krachtig. Wanneer het de opgegeven commit bereikt, zal Git de rebase-procedure pauzeren, net zoals wanneer het een conflict tegenkomt. Dit geeft je de mogelijkheid om de inhoud van de commit te wijzigen git commit --amend
of voeg zelfs meer commits toe met de standaard git add
/Git commit
commando's. Elke nieuwe commit die je toevoegt, zal deel uitmaken van de nieuwe branch.
Interactief rebasen kan een grote impact hebben op uw ontwikkelworkflow. In plaats van je zorgen te maken over het verbreken van je wijzigingen in ingekapselde commits, kun je je richten op het schrijven van je code. Als je uiteindelijk hebt vastgelegd wat een enkele wijziging in vier afzonderlijke snapshots zou moeten zijn, dan is dat geen probleem - herschrijf de geschiedenis met git rebase -i
en plet ze allemaal in een zinvolle commit.
Nu dat je het begrijpt git rebase
, we kunnen praten over wanneer we het niet moeten gebruiken. Intern leidt het rebasen eigenlijk niet tot commits naar een nieuwe vestiging. In plaats daarvan worden er nieuwe commits gemaakt die de gewenste wijzigingen bevatten. Met dit is geest, rebasen wordt beter gevisualiseerd als het volgende:
Na de rebase, de commits in voorzien zijn van
zal verschillende commit hashes hebben. Dit betekent dat we niet alleen een filiaal hebben gerepositioneerd, we hebben onze projectgeschiedenis letterlijk herschreven. Dit is een zeer belangrijk neveneffect van git rebase
.
Wanneer je alleen aan een project werkt, is het herschrijven van de geschiedenis geen probleem. Zodra u in een samenwerkingsomgeving begint te werken, kan het echter zeer gevaarlijk worden. Als je commits herschrijft die andere ontwikkelaars gebruiken (bijv. Commits op de meester
tak), het zal eruit zien alsof die commits verdwenen zijn de volgende keer dat ze proberen je werk op te halen. Dit resulteert in een verwarrend scenario dat moeilijk te herstellen is.
Met dit is geest, zou je nooit commits moeten rebasen die naar een openbare repository zijn geduwd, tenzij je zeker weet dat niemand hun werk op hen heeft gebaseerd.
Deze tutorial introduceerde de twee meest voorkomende gebruiksmogelijkheden van git rebase
. We hebben veel gesproken over het verplaatsen van branches, maar onthoud dat rebasen eigenlijk gaat over het beheersen van je projectgeschiedenis. De kracht om commits opnieuw te schrijven maakt je vrij om je te concentreren op je ontwikkeltaken in plaats van je werk op te delen in geïsoleerde snapshots.
Merk op dat rebasen een volledig optionele toevoeging is aan je Git-toolbox. Je kunt nog steeds alles doen wat je nodig hebt met gewoon oud git fuseren
commando's. Inderdaad, dit is veiliger omdat het de mogelijkheid van het herschrijven van de openbare geschiedenis vermijdt. Echter, als u de risico's begrijpt, git rebase
kan een veel schonere manier zijn om branches te integreren in vergelijking met het samenvoegen van commits.