Resetten, uitchecken en terugzetten | Atlassian Git-tutorials

Resetten, uitchecken en terugzetten

De opdrachten git reset, git checkout en git revert zijn een paar van de handigste tools in je Git-toolbox. Ze laten je allemaal een wijziging in je repository ongedaan maken, en de eerste twee opdrachten kunnen gebruikt worden om commits of afzonderlijke bestanden te manipuleren.

Omdat ze zo op elkaar lijken, is het heel eenvoudig door elkaar te halen welke opdracht in een bepaald ontwikkelingsscenario gebruikt moet worden. In dit artikel vergelijken we de meest voorkomende configuraties van git reset, git checkout en git revert. Hopelijk kun je hierna vol vertrouwen met een van deze opdrachten door je repository navigeren.

De drie bomen van Git

Het helpt om over elke opdracht na te denken in termen van hun effect op de drie mechanismen voor statusbeheer van een Git-repository: de werkmap, de gestagede momentopname en de commit-geschiedenis. Deze componenten worden ook wel "de drie bomen" van Git genoemd. We gaan wat dieper in op de drie bomen op de pagina git reset. Houd deze mechanismen in gedachten terwijl je dit artikel leest.

Een checkout is een bewerking waarbij de ref-pointer HEAD naar een gespecificeerde commit wordt verplaatst. Bekijk het volgende voorbeeld waarin we dit aantonen.

Verplaats de HEAD-ref-pointer naar een gespecificeerde commit

Dit voorbeeld toont een reeks commits op de branch main. De referentie HEAD en de branch main verwijzen momenteel naar commit d. Laten we nu git checkout b uitvoeren

Volgorde van commits in de master-branch

Dit is een update van de boom 'commitgeschiedenis'. De opdracht git checkout kan worden gebruikt in een commit of op bestandsniveau. Bij uitchecken op bestandsniveau wordt de inhoud van het bestand gewijzigd in de inhoud van de specifieke commit.

Een terugdraaiing is een handeling waarbij een specifieke commit gebruikt wordt en een nieuwe commit gemaakt wordt die de gespecificeerde commit omkeert. git revert kan alleen worden uitgevoerd op commit-niveau en heeft geen functionaliteit op bestandsniveau.

Een reset is een handeling waarbij een specifieke commit nodig is en de 'drie bomen' opnieuw worden ingesteld zodat ze overeenkomen met de status van de repository in die specifieke commit. Een reset kan aangeroepen worden in drie verschillende modi die overeenkomen met de drie bomen.

Uitchecken en resetten worden over het algemeen gebruikt om lokaal of privé 'ongedaan te maken'. Ze wijzigen de geschiedenis van een repository, wat tot conflicten kan leiden bij het pushen naar externe gedeelde repository's. Terugdraaien wordt beschouwd als een veilige handeling voor 'openbaar ongedaan maken' omdat er een nieuwe geschiedenis wordt gecreëerd die op afstand kan worden gedeeld en de geschiedenis waar teamleden op afstand afhankelijk van kunnen zijn, niet overschrijft.

Referentie van git reset vs. revert vs. checkout

De tabel hieronder geeft een overzicht van de meest voorkomende toepassingen van al deze opdrachten. Zorg ervoor dat je deze referentie bij de hand houdt, want je zult er ongetwijfeld minstens een paar moeten gebruiken tijdens je Git-carrière.

Opdracht Scope Veelgebruikte usecases
git reset Commit-niveau Verwerp commits in een privébranch of gooi niet-gecommitte wijzigingen weg
git reset Bestandsniveau Een bestand ontstagen
Git Checkout Commit-niveau Tussen branches schakelen of oude momentopnamen bekijken
Git Checkout Bestandsniveau Wijzigingen in de werkmap negeren
git revert Commit-niveau Commits in een openbare branch ongedaan maken
git revert Bestandsniveau (n.v.t.)

Handelingen op commit-niveau

De parameters die je doorgeeft aan git reset en git checkout bepalen de scope ervan. Als je geen bestandspad als parameter opgeeft, werken ze op basis van volledige commits. Dat bekijken we in dit gedeelte. Let op, git revert heeft geen tegenhanger op bestandsniveau.

Een specifieke commit resetten

Op commit-niveau is resetten een manier om het uiterste van een branch naar een andere commit te verplaatsen. Dit kan worden gebruikt om commits uit de huidige branch te verwijderen. Met de volgende opdracht wordt de branch hotfix bijvoorbeeld twee commits terug geplaatst.

git checkout hotfix git reset HEAD~2

De twee commits die aan het einde van de hotfix stonden, zijn nu losstaande, oftewel verweesde commits. Dit betekent dat ze worden verwijderd de volgende keer dat Git een verwijdering uitvoert. Met andere woorden: je zegt dat je deze commits wilt weggooien. Dit kan als volgt worden gevisualiseerd:

De hotfix-branch opnieuw instellen als HEAD-2

Dit gebruik van git reset is een eenvoudige manier om wijzigingen ongedaan te maken die nog nooit met iemand anders zijn gedeeld. Dat is je voorkeursopdracht als je aan een functie begint te werken en merkt dat je denkt: 'Verdorie, waar ben ik mee bezig? Ik eigenlijk maar opnieuw beginnen.'

Naast het verplaatsen van de huidige branch, kun je met git reset de gestagede momentopname en/of de werkmap wijzigen door er een van de volgende vlaggen aan toe te voegen:

  • --soft: de gestagede momentopname en werkmap worden op geen enkele manier gewijzigd.
  • --mixed: de gestagede momentopname is bijgewerkt zodat deze overeenkomt met de opgegeven commit, maar dit heeft geen invloed op de werkmap. Dit is de standaardoptie.
  • --hard: de gestagede momentopname en de werkmap zijn beide bijgewerkt zodat ze overeenkomen met de opgegeven commit.

Het is makkelijker om deze modi te beschouwen als definities van de scope van een git reset-handeling. Ga voor meer gedetailleerde informatie naar de pagina git reset.

Oude commits uitchecken

De opdracht git checkout wordt gebruikt om de status van de repository bij te werken naar een specifiek punt in de geschiedenis van het project. Als er een branchnaam wordt doorgegeven, kun je tussen branches schakelen.

 git checkout hotfix

Intern verplaatst de bovenstaande opdracht alleen maar HEAD naar een andere branch en werkt deze de werkmap bij zodat deze overeenkomt. Aangezien dit lokale wijzigingen kan overschrijven, dwingt Git je om alle wijzigingen in de werkmap die verloren gaan tijdens het uitchecken, door te voeren of te stashen. In tegenstelling tot git reset verplaatst git checkout geen branches.

HEAD van master naar hotfix verplaatsen

Je kunt ook willekeurige commits uitchecken door de commit-referentie door te geven in plaats van een branch. Hierdoor wordt precies hetzelfde gedaan als bij het uitchecken van een branch: het verplaatst de HEAD-referentie naar de gespecificeerde commit. De volgende opdracht checkt bijvoorbeeld het hoogst gelegen item uit van de huidige commit:

 git checkout HEAD~2
'HEAD' verplaatsen naar een willekeurige commit

Dit is handig om snel een oude versie van je project te inspecteren. Aangezien er echter geen branchverwijzing is naar de huidige HEAD, zit je in een aparte HEAD-status. Dit kan gevaarlijk zijn als je nieuwe commits gaat toevoegen, omdat je daar niet meer naar terug kunt als je naar een ander branch overschakelt. Daarom moet je altijd een nieuwe branch aanmaken voordat je commits toevoegt aan een aparte HEAD.

Openbare commits ongedaan maken met Revert

Terugdraaien maakt een commit ongedaan door een nieuwe commit aan te maken. Dit is een veilige manier om wijzigingen ongedaan te maken, aangezien er geen kans is dat de commit-geschiedenis wordt herschreven. De volgende opdracht berekent bijvoorbeeld de wijzigingen in de voorlaatste commit, maakt een nieuwe commit aan om deze wijzigingen ongedaan te maken, en wijst de nieuwe commit toe aan het bestaande project.

git checkout hotfix git revert HEAD~2

Dit kan als volgt worden gevisualiseerd:

De voorlaatste commit terugzetten

Vergelijk dit met git reset, wat wel de bestaande commit-geschiedenis verandert. Om deze reden moet git revert gebruikt worden om wijzigingen ongedaan te maken in een openbare branch, en git reset moet gereserveerd worden voor het ongedaan maken van wijzigingen in een privébranch.

Je kunt git revert ook zien als tool om gecommitte wijzigingen ongedaan te maken, terwijl git reset HEAD bedoeld is om niet-gecommitte wijzigingen ongedaan te maken.

Net als git checkout kan git revert bestanden in de werkmap overschrijven. Je zult dus gevraagd worden om te committen of wijzigingen te stashen die verloren zouden gaan tijdens het terugzetten.

Handelingen op bestandsniveau

De opdrachten git reset en git checkout accepteren ook een optioneel bestandspad als parameter. Dit verandert het gedrag ervan ingrijpend. In plaats van volledige momentopnamen te maken, worden ze gedwongen de handeling te beperken tot één bestand.

Git reset van een specifiek bestand

Wanneer opgeroepen met een bestandspad, wordt de gestagede momentopname bijgewerkt door git reset zodat deze overeenkomt met de versie van de gespecificeerde commit. Deze opdracht haalt bijvoorbeeld de versie van foo.py op in de voorlaatste commit en staget deze voor de volgende commit:

git reset HEAD~2 foo.py

Net als bij de versie op commit-niveau van git reset, wordt dit vaker gebruikt met HEAD in plaats van met een willekeurige commit. Het uitvoeren van git reset HEAD foo.py zorgt dat foo.py ontstaged wordt. De daarin opgenomen wijzigingen zijn nog steeds aanwezig in de werkmap.

Een bestand verplaatsen van de commit-geschiedenis naar de gestagede momentopname

De vlaggen --soft, --mixed en --hard hebben geen enkel effect op de bestandsversie van git reset, aangezien de gestagede momentopname altijd wordt bijgewerkt en de werkmap nooit wordt bijgewerkt.

git checkout van bestand

Een bestand uitchecken is vergelijkbaar met het gebruik van git reset met een bestandspad, maar nu wordt de werkmap bijgewerkt in plaats van het staginggebied. In tegenstelling tot de commit-versie van deze opdracht wordt hiermee de HEAD-referentie niet verplaatst, wat betekent dat je niet van branch wisselt.

Een bestand verplaatsen van de commit-geschiedenis naar de werkmap

De volgende opdracht zorgt er bijvoorbeeld voor dat foo.py in de werkmap overeenkomt met dat van de voorlaatste commit:

git checkout HEAD~2 foo.py

Net zoals bij het aanroepen van git checkout op commit-niveau kan dit worden gebruikt om oude versies van een project te inspecteren, maar de scope is beperkt tot het opgegeven bestand.

Als je het uitgecheckte bestand staget en commit, wordt deze 'teruggezet' naar de oude versie van dat bestand. Let op dat hiermee alle daaropvolgende wijzigingen aan het bestand worden verwijderd, terwijl de opdracht git revert alleen de wijzigingen ongedaan maakt die door de opgegeven commit zijn geïntroduceerd.

Zoals bij git reset wordt dit vaak gebruikt met HEAD als commit-referentie. git checkout HEAD foo.py heeft bijvoorbeeld tot gevolg dat niet-gestagede wijzigingen in foo.py genegeerd worden. Dit gedrag lijkt op dat bij git reset HEAD --hard, maar het werkt alleen op het opgegeven bestand.

Samenvatting

Je zou nu over alle tools moeten beschikken die je nodig hebt om wijzigingen ongedaan te maken in een Git-repository. De opdrachten git reset, git checkout en git revert kunnen verwarrend zijn, maar als je nadenkt over de effecten ervan op de werkmap, de gestagede momentopname en de commit-geschiedenis, zou het eenvoudiger moeten zijn om te onderscheiden welke opdracht past bij de ontwikkelingstaak die voor de boeg ligt.