Geschiedenis herschrijven
Git commit --amend en andere methoden om geschiedenis te herschrijven
Inleiding
Deze tutorial bespreekt verschillende methoden om de Git-geschiedenis te herschrijven en te wijzigen. Git gebruikt een paar verschillende methoden om wijzigingen vast te leggen. We bespreken de sterke en zwakke punten van de verschillende methoden en geven voorbeelden van hoe je ze gebruikt. Deze tutorial bespreekt enkele van de meest voorkomende redenen voor het overschrijven van gecommitte snapshots en laat zien hoe je de valkuilen vermijdt.
De belangrijkste taak van Git is ervoor te zorgen dat je nooit een gecommitte wijziging kwijtraakt. Maar de tool is ook ontworpen om je volledige controle te bieden over je ontwikkelingsworkflow. Dit houdt in dat je precies kunt definiëren hoe je projectgeschiedenis eruitziet. Daardoor ontstaat echter ook een kans om commits te verliezen. Git biedt zijn opdrachten voor het herschrijven van geschiedenis onder het voorbehoud dat het gebruik ervan kan leiden tot verloren inhoud.
Git heeft verschillende mechanismen om geschiedenis te registreren en wijzigingen op te slaan. Deze mechanismen omvatten: Commit --amend
, git rebase
en git reflog
. Deze opties bieden je krachtige mogelijkheden om je workflow aan te passen. Aan het einde van deze tutorial ken je de opdrachten waarmee je je Git-commits kunt herstructureren en weet je hoe je valkuilen kunt vermijden die vaak voorkomen bij het herschrijven van geschiedenis.
gerelateerd materiaal
Git cheat sheet
Oplossing bekijken
Git leren met Bitbucket Cloud
De laatste commit wijzigen: git commit --amend
De opdracht git commit --amend
biedt een handige manier om de meest recente commit te wijzigen. Hiermee kun je gefaseerde wijzigingen combineren met de vorige commit in plaats van een heel nieuwe commit te maken. Hij kan ook worden gebruikt om eenvoudigweg het vorige commit-bericht te bewerken zonder het snapshot te wijzigen. Een wijziging past echter niet de meest recente commit aan, maar vervangt deze volledig. Dat betekent dat de gewijzigde commit een nieuwe entiteit zal zijn met een eigen ref. Voor Git ziet het eruit als een gloednieuwe commit, die in het onderstaande diagram wordt aangeduid met een sterretje (*). Er zijn een paar veelvoorkomende scenario's voor het gebruik van git commit --amend
. In de volgende onderdelen behandelen we een aantal gebruiksvoorbeelden.
Het meest recente Git commit-bericht wijzigen
git commit --amend
Stel dat je net een wijziging hebt gecommit en een fout hebt gemaakt in het logbericht voor je commit. Als je deze opdracht uitvoert wanneer er niets is gefaseerd, kun je het bericht van de vorige commit bewerken zonder het snapshot ervan te wijzigen.
Vroegtijdige commits vinden de hele tijd plaats tijdens je dagelijkse ontwikkeling. Het is gemakkelijk om te vergeten een bestand op te voeren of je commit-bericht een verkeerde indeling te geven De markering --amend
biedt een handige manier om deze kleine fouten op te lossen.
git commit --amend -m "an updated commit message"
Door de optie -m
toe te voegen, kun je vanuit de opdrachtregel een nieuw bericht doorgeven zonder dat je de editor hoeft te openen.
Bevestigde bestanden wijzigen
Het volgende voorbeeld toont een veelvoorkomend scenario in ontwikkeling op basis van Git. Laten we zeggen dat we een paar bestanden hebben bewerkt die we in één snapshot willen committen, maar vervolgens vergeten we om tijdens de eerste keer een van de bestanden toe te voegen. Je kunt de fout gewoon oplossen door het andere bestand te stagen en te committen met de markering --amend
:
# Edit hello.py and main.py
git add hello.py
git commit
# Realize you forgot to add the changes from main.py
git add main.py
git commit --amend --no-edit
Met de markering --no-edit
kun je de wijziging in je commit aanbrengen zonder het commit-bericht te wijzigen. De resulterende commit vervangt de onvolledige en zal eruit zien alsof we de wijzigingen in hello.py
en main.py
in één snapshot hebben doorgevoerd.
Openbare commits niet wijzigen
Gewijzigde commits zijn eigenlijk geheel nieuwe commits, en de vorige commit zal niet langer op je huidige branch staan. Dit heeft dezelfde gevolgen als het opnieuw instellen van een openbaar snapshot. Vermijd het wijzigen van een commit waarop andere ontwikkelaars hun werk hebben gebaseerd. Dit is verwarrend voor ontwikkelaars en herstellen is ingewikkeld.
Samenvatting
Terugkijkend: met git commit --amend
kun je de meest recente commit nemen en er nieuwe gestagede wijzigingen aan toevoegen. Je kunt wijzigingen toevoegen of verwijderen in het Git-staging-gedeelte en ze toepassen met een --amend
-commit. Als er geen wijzigingen zijn gestaged, zal een --amend
je nog steeds vragen om de laatste log van commit-berichten te wijzigen. Wees voorzichtig bij het gebruik van --amend
voor commits die met andere teamleden zijn gedeeld. Het wijzigen van een commit die met een andere gebruiker wordt gedeeld, vereist mogelijk verwarrende en langdurige oplossingen voor samenvoegingsconflicten.
Oudere of meerdere commits wijzigen
Om oudere of meerdere commits te wijzigen, kun je git rebase
gebruiken. Daarmee combineer je een reeks commits tot een nieuwe basiscommit. In de standaardmodus kun je met git rebase
de geschiedenis letterlijk herschrijven – en automatisch commits in je huidige werkbranch toepassen op de doorgegeven branch-head. Omdat je nieuwe commits de oude zullen vervangen, is het belangrijk om git rebase
niet te gebruiken op commits die openbaar zijn gepusht. Anders lijkt het erop dat je projectgeschiedenis is verdwenen.
In deze of vergelijkbare gevallen waarin het belangrijk is om een schone projectgeschiedenis te behouden, kun je de optie -i
toevoegen aan git rebase
om rebase interactive
uit te voeren. Dit biedt je de mogelijkheid om individuele commits in het proces te veranderen in plaats van alle commits te verplaatsen. Je kunt meer te weten komen over het interactief rebasen en over aanvullende rebase-opdrachten op de git rebase-pagina.
Bevestigde bestanden wijzigen
Tijdens een rebase pauzeert de 'edit'-opdracht, ook wel e
, het afspelen van de rebase op die commit en kun je aanvullende wijzigingen aanbrengen met git commit --amend
. Git zal het afspelen onderbreken en een bericht tonen:
Stopped at 5d025d1... formatting
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Meerdere berichten
Elke reguliere Git-commit heeft een logbericht waarin wordt uitgelegd wat er in de commit is gebeurd. Deze berichten geven waardevol inzicht in de projectgeschiedenis. Je kunt tijdens een rebase een paar opdrachten uitvoeren op commits om commit-berichten te wijzigen.
Squash-commits voor een schone geschiedenis
De 'squash'-opdracht s
toont het échte nut van rebase. Met squash kun je aangeven welke commits je wilt samenvoegen in de vorige commits. Dit maakt een 'schone geschiedenis' mogelijk. Tijdens het afspelen van rebase zal Git de opgegeven rebase-opdracht uitvoeren voor elke commit. In het geval van squash-commits zal Git je geconfigureerde teksteditor openen en vragen om de opgegeven commit-berichten te combineren. Dit hele proces kan als volgt worden gevisualiseerd:
Merk op dat de commits die zijn gewijzigd met een rebase-opdracht een andere ID hebben dan de oorspronkelijke commits. Commits die zijn gemarkeerd met 'pick' hebben een nieuwe ID als de vorige commits zijn herschreven.
Moderne Git-hostingoplossingen zoals Bitbucket bieden nu 'automatische squash-functies' bij het samenvoegen. Deze functies zullen de commits van een branch automatisch rebasen en squashen wanneer je de gebruikersinterface van de gehoste oplossingen gebruikt. Raadpleeg 'Squash-commits bij het samenvoegen van een Git-branch met Bitbucket' voor meer informatie.
Samenvatting
Git rebase geeft je de mogelijkheid om je geschiedenis aan te passen en met interactieve rebasing kun je dit doen zonder een 'rommelig' spoor achter te laten. Dit creëert de vrijheid om fouten te maken en te corrigeren en je werk te verfijnen met behoud van een schone, lineaire projectgeschiedenis.
Het veiligheidsnet: git reflog
Referentielogboeken, ofwel 'reflogs', zijn een mechanisme dat Git gebruikt om updates op te nemen die zijn toegepast op tips van branches en andere commit-referenties. Met reflog kun je teruggaan naar commits –ook al wordt er niet naar verwezen door een branch of tag. Nadat de geschiedenis is herschreven, bevat de reflog informatie over de oude staat van branches en kun je zo nodig teruggaan naar die staat. Elke keer dat je branch-tip om welke reden dan ook wordt bijgewerkt (door van branches te wisselen, nieuwe wijzigingen in te voeren, geschiedenis te herschrijven of gewoon door nieuwe commits toe te voegen), wordt er een nieuwe regel toegevoegd aan de reflog. In deze sectie zullen we de opdracht git reflog
op hoog niveau bekijken en enkele veelvoorkomende toepassingen verkennen.
Gebruik
git reflog
Dit toont de reflog voor de lokale repository.
git reflog --relative-date
Dit toont de reflog met relatieve datuminformatie (bijv. 2 weken geleden).
Voorbeeld
Laten we een voorbeeld bekijken om git reflog
te begrijpen.
0a2e358 HEAD@{0}: reset: moving to HEAD~2
0254ea7 HEAD@{1}: checkout: moving from 2.2 to main
c10f740 HEAD@{2}: checkout: moving from main to 2.2
De reflog hierboven toont een checkout van main naar de 2.2-branch en terug. Van daaruit is er een harde reset naar een oudere commit. De laatste activiteit wordt weergegeven aan de bovenkant, met het label HEAD@{0}
.
Als blijkt dat je per ongeluk terug bent gegaan, bevat de reflog de commit main die verwijst naar (0254ea7)
voordat je per ongeluk 2 commits verwijderde.
git reset --hard 0254ea7
Met behulp van 'git reset' kun je nu 'main' weer terugzetten naar de eerdere commit. Dit levert een vangnet op voor het geval de geschiedenis per ongeluk werd gewijzigd.
Het is belangrijk op te merken dat de reflog alleen een vangnet biedt als er wijzigingen zijn aangebracht in je lokale repository en dat er alleen ontwikkelingen in de branch-tip van de repository's worden bijgehouden. Bovendien hebben reflog-vermeldingen een vervaldatum. De standaard vervaltijd voor reflog-items is 90 dagen.
Zie onze git reflog-pagina voor meer informatie.
Samenvatting
In dit artikel bespraken we verschillende methoden om de git-geschiedenis te veranderen en git-wijzigingen ongedaan te maken. We hebben op hoog niveau gekeken naar het git rebase-proces. Dit zijn de belangrijkste leerpunten:
- Er zijn veel manieren om geschiedenis te herschrijven met git.
- Gebruik
git commit --amend
om je laatste logbericht te wijzigen; - Gebruik
git commit --amend
om wijzigingen aan te brengen in de meest recente commit; - Gebruik
git rebase
om commits te combineren en de geschiedenis van een branch te wijzigen; git rebase -i
geeft veel meer gedetailleerde controle over wijzigingen in de geschiedenis dan een standaard 'git rebase'.
Lees meer over de opdrachten die we hebben behandeld op hun specifieke pagina's:
Deel dit artikel
Volgend onderwerp
Aanbevolen artikelen
Bookmark deze resources voor meer informatie over soorten DevOps-teams of voor voortdurende updates over DevOps bij Atlassian.