Beginner’s Guide to Interactive Rebasing
@StrideStride
Information Technology and Services
Eerder dit jaar heb ik voor het eerst een interactieve rebase gedaan en ik was onder de indruk van wat men ermee kan doen. Ik vond het in het begin ook een beetje ingewikkeld. Hopelijk zal deze gids helpen om wat onzekerheid weg te nemen.
Ook, omdat het zo krachtig is en je in wezen de geschiedenis kunt herschrijven, een kleine waarschuwing voordat we beginnen: Er zijn veel verschillende meningen over Git en of rebasen een goed idee is of niet. Dit bericht zal niet in die discussies duiken en is puur bedoeld om door de basis van het gebruik van interactief rebasen te lopen.
TL;DR
- Interactief rebasen kan gebruikt worden voor het veranderen van commits op vele manieren, zoals bewerken, verwijderen, en squashen.
- Om Git te vertellen waar de interactieve rebase moet beginnen, gebruik je de SHA-1 of index van de commit die onmiddellijk voorafgaat aan de commit die je wilt wijzigen.
- Tijdens een interactieve rebase, als Git pauzeert bij een commit die je tagged om te bewerken, is de workflow niet anders dan een normaal commit proces – je staged bestanden en commit ze dan. Het enige verschil is dat je het commando
git commit --amend
gebruikt in plaats vangit commit
. - Interactieve rebasen zal nieuwe SHA-1’s aanmaken, daarom is het het beste om interactieve rebasen te gebruiken op commits die je niet naar een remote branch gepushed hebt.
Het Probleem
In dit voorbeeld, zullen we door een situatie werken waar we in een feature branch gewerkt hebben en we een paar commits hebben die we zouden willen veranderen of verwijderen. Hier is hoe ons git log eruit ziet:
Van het git log hierboven, hier zijn de twee commits die we willen veranderen: 4a4d705
– In deze commit hebben we per ongeluk een samenvoeg conflict gecommit6c01350
– In deze commit hebben we het samenvoeg conflict verwijderd
Wat we willen doen is terug in de tijd gaan naar 4a4d705
, het samenvoeg conflict in de commit verwijderen, en dan 6c01350
verwijderen omdat het samenvoeg conflict opgelost is en we deze commit niet langer nodig hebben. Dit zal een verbetering voor onze commit geschiedenis zijn, om twee redenen:
- We zullen geen gebroken commits (samenvoeg conflicten)
- We zullen alleen zinvolle commits hebben, geen commits die alleen maar gerelateerd zijn aan het repareren van een gemist samenvoeg conflict
De Oplossing
Deze situatie is een goede kandidaat voor interactief rebasen. Scott Chacon, in zijn boek Pro Git, beschrijft interactief rebasen als volgt: “Soms kan het herstelde ding… niet aangepast worden aan de niet helemaal perfecte commit die het herstelt, omdat die commit diep begraven is in een patch reeks. Dat is precies waar interactieve rebase voor is: gebruik het na veel, door commits te herschikken en te bewerken, en meerdere commits in één te squashen.”
Welke commits willen we wijzigen?
Om een interactieve rebase te starten, moeten we Git vertellen welke commits we willen wijzigen. We doen dit door te verwijzen naar de commit direct voorafgaand aan de vroegste commit die we willen wijzigen. Of, eenvoudig gezegd, we verwijzen naar “de laatste commit die we als-is willen behouden,” volgens Scott Chacon.
Laten we naar ons voorbeeld kijken om een beter begrip te krijgen. Er zijn twee manieren om naar deze commit te verwijzen:
Op SHA-1 – De laatste commit die we als-is willen behouden heeft een SHA-1 van 528f82e
, dus die kunnen we aan ons interactieve rebase commando meegeven.
Op Index – De laatste commit die we as-is willen behouden heeft een index positie van 3 (Git gebruikt indexering op basis van nul) dus kunnen we HEAD~3
aan ons interactieve rebase commando meegeven.
Note – Als je maar een paar commits hebt waarop je interactief wilt rebasen, is het voor de meeste mensen waarschijnlijk makkelijker om de index te gebruiken. Maar, als je veel commits hebt, is het waarschijnlijk makkelijker om de SHA-1 te gebruiken, zodat je niet het hele git log door hoeft te tellen.
Start interactieve rebasen
Gebaseerd op ons voorbeeld, zullen we ofwel:
$ git rebase -i 528f82e
Of
$ git rebase -i HEAD~3
Waardoor dit venster in Vim geopend wordt:
Merk op dat de commits in de tegenovergestelde volgorde staan van git log. In git log staat de meest recente commit bovenaan. In deze weergave, staat de meest recente commit onderaan. Merk ook op dat de opmerkingen hieronder een handige lijst geven van de geldige commando’s die we op elke commit kunnen gebruiken.
Als je Vim niet kent, klik dan gewoon op elk woord pick
dat je wilt bewerken en druk dan op de <i>
toets (voor invoegen modus). Als je klaar bent met typen, druk je op de <esc>
toets om de invoegmodus te verlaten.
In ons voorbeeld, hebben we het commando veranderd in edit
voor de commit die we willen wijzigen en we hebben het commando veranderd in drop
voor de commit die we willen verwijderen. Daarna voeren we :wq
uit om op te slaan en sluiten het Vim venster af.
Wijzig de commit
Terug in de terminal zien we deze boodschap:
Het is logisch dat we gestopt zijn bij 4a4d705
. Dit is de oudste commit in de serie van commits die we willen wijzigen. We zullen beginnen met deze commit en onze weg banen door elke commit tot de meest recente.
Als een herinnering, 4a4d705
was de commit met het samenvoeg conflict dat we per ongeluk hebben vastgelegd. Als we onze editor openen, zien we het samenvoeg conflict daar:
Dus we lossen het samenvoeg conflict op in het bestand, maar wat doen we nu? Bij twijfel, git status
:
Cool! Dit is eigenlijk wel nuttig. We zien dat we momenteel 4a4d705
aan het bewerken zijn, en we zien de volgende twee commits die na deze commits uitgevoerd moeten worden.
De rest van het bericht legt een bekende workflow aan ons uit. Git vertelt ons dat als we de commit willen wijzigen, we git commit --amend
moeten uitvoeren. Dit zal in essentie fungeren als onze typische git commit
die we in een normale werkstroom gebruiken. Onderaan dit bericht zien we dat ons bestand gewijzigd is, met de wijzigingen die we zojuist gemaakt hebben om het samenvoeg conflict te verwijderen. We moeten het bestand stagen voordat we vastleggen. Dit is niet anders dan een normale workflow.
Alles wat we doen is git add tempChanger.js
om het gewijzigde bestand te stagen en dan git commit --amend
om het ge-stage bestand vast te leggen! Dit opent nu weer een Vim venster met de commit boodschap:
We kunnen de commit boodschap aanpassen of laten zoals het is. Laten we ervoor kiezen om de commit boodschap hetzelfde te laten en we zullen :wq
typen om op te slaan en het venster te sluiten.
We hebben nu onze oude commit bewerkt. En wat nu? Start git status
:
Doorgaan met interactieve rebase
We hebben niets meer te veranderen in de commit dus laten we doorgaan!
We starten git rebase --continue
en we zien de volgende boodschap:
Woah, we zijn klaar? Maar hoe zit het met die andere twee commits? Nou, de volgende commit waar actie op ondernomen moest worden was 6c01350
. Deze commit hebben we gemarkeerd om te verwijderen (drop
) toen we de interactieve rebase startten. Git verwijderde het automatisch en ging verder met de volgende commit, 41aa9d2
. Deze was nooit gewijzigd in de initiële interactieve rebase. Zijn standaard commando was pick
, wat betekent dat de commit gebruikt zal worden. Git heeft die commit toegepast en omdat dat de laatste commit was, is de interactieve rebase voltooid.
Note, als we meer commits hadden om te wijzigen, zouden we gewoon naar de volgende commit gegaan zijn en het proces van wijzigen gestart zijn, net zoals we hierboven gedaan hebben. De cyclus gaat door totdat er geen commits meer over zijn.
De uitwerpknop
Het is de moeite waard om op te merken dat als we op enig punt in onze interactieve rebase dingen verknoeien en niet weten hoe we ze moeten repareren, we altijd kunnen afbreken. Op elk punt kunnen we git rebase --abort
in de terminal uitvoeren en de interactieve rebase zal worden afgebroken zonder dat de wijzigingen worden opgeslagen. We zouden dan de interactieve rebase opnieuw moeten starten.
Na interactieve rebase
Onze git log ziet er nu zo uit:
Je zult zien dat er een paar dingen veranderd zijn ten opzichte van voordat we de interactieve rebase startten:
- We hebben niet langer de commit
6c01350
met de commit boodschap “Verwijder samenvoegingsconflict”. Dit is de commit die we in onze interactieve rebase verwijderd hebben. - Onze commit die we bewerkt hebben,
4a4d705
, heeft een andere SHA-1,2b7443d
. - Onze meest recente commit van onze originele git log,
41aa9d2
, heeft ook een nieuwe SHA-1,2b95e92
. Deze commit was niet veranderd, maar was eenvoudigweg toegepast op de commit ervoor2b7443d
.
Side effects of interactive rebasen
Voor de twee meest recente commits in onze git log, omdat ze nieuwe SHA-1’s hebben, ziet Git ze als compleet nieuwe commits. Dit is zelfs waar voor onze laatste commit, 2b95e92
, waar noch de commit boodschap, noch de bestanden ook maar iets veranderd zijn. Dit brengt een belangrijk punt naar boven met interactief rebasen: Als je een commit wijzigt, dan zullen die commit en alle opeenvolgende commits nieuwe SHA-1’s hebben.
Dit zal niets beïnvloeden als de commits die je gewijzigd hebt niet naar een remote branch gepushed zijn. Maar, als je wel een interactieve rebase hebt uitgevoerd op commits die al naar een remote branch zijn gepushed en daarna je branch opnieuw hebt gepushed, dan zou je zien:
Technisch zou je dit kunnen omzeilen door git push --force
te gebruiken, maar dat is erg gevaarlijk. Als de remote branch commits van andere mensen heeft, maar je lokale branch heeft die commits nog niet, dan zul je effectief hun commits verwijderen.
Een andere oplossing is om git push --force-with-lease
te gebruiken, wat alleen jouw commits zal wijzigen, maar niet commits van anderen, hoewel dit ook problematisch kan zijn. Bijvoorbeeld, als een andere ontwikkelaar die commits al heeft die nieuwe SHA-1’s hebben gekregen op hun lokale branch, als ze de remote branch trekken, zullen ze samenvoeg conflicten hebben met elk van deze commits.
Wanneer --force-with-lease
te gebruiken valt buiten het bestek van deze blog post, maar het zou het beste zijn om andere leden van je team te raadplegen voordat je dit doet. U kunt hier meer lezen over git push --force-with-lease
.
Het belangrijkste dat u uit deze sectie meeneemt is dat het veel gemakkelijker en veiliger is om interactief rebasen te gebruiken op commits die nog niet naar een remote branch zijn gepushed.
Schreven door Blake DeBoer. Oorspronkelijk gepost op Dev.to
Senior, Lead, of Principal developer in NYC? Stride zoekt mensen! Wilt u uw technisch team op niveau brengen? Kijk hoe wij het doen! www.stridenyc.com
Tags
Maak uw gratis account aan om uw leeservaring op maat te ontgrendelen.
Leave a Reply