git reset
De opdracht git reset
is een complexe en veelzijdige tool om wijzigingen ongedaan te maken. Er zijn drie primaire vormen van aanroeping. Deze vormen komen overeen met opdrachtregelargumenten: --soft, --mixed, --hard
. De drie argumenten komen elk overeen met de drie interne mechanismen voor statusbeheer van Git, de Commit-structuur (HEAD
), de Staging-index en de Werkmap.
Git reset en de drie bomen van Git
Om het gebruik van git reset
goed te begrijpen, moeten we eerst de systemen voor intern statusbeheer van Git begrijpen. Soms worden deze mechanismen de 'drie bomen' van Git genoemd. Bomen kunnen een verkeerde benaming zijn, aangezien het strikt traditionele gegevensstructuren van bomen niet zijn. Het zijn echter datastructuren gebaseerd op knooppunten en punten die Git gebruikt om een tijdlijn van bewerkingen bij te houden. De beste manier om deze mechanismen te demonstreren is door een changeset aan te maken in een repository en die door de drie bomen heen te volgen.
Om te beginnen maken we een nieuwe repository aan met de onderstaande opdrachten:
$ mkdir git_reset_test
$ cd git_reset_test/
$ git init .
Initialized empty Git repository in /git_reset_test/.git/
$ touch reset_lifecycle_file
$ git add reset_lifecycle_file
$ git commit -m"initial commit"
[main (root-commit) d386d86] initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 reset_lifecycle_file
De bovenstaande voorbeeldcode maakt een nieuwe git-repository aan met één leeg bestand, reset_lifecycle_file
. Op dit moment heeft de voorbeeldrepository één commit (d386d86
) door het toevoegen van reset_lifecycle_file
.
gerelateerd materiaal
Git cheat sheet
Oplossing bekijken
Git leren met Bitbucket Cloud
De werkmap
De eerste boom die we zullen onderzoeken is 'De Werkmap'. Deze boom is gesynchroniseerd met het lokale bestandssysteem en vertegenwoordigt de rechtstreekse wijzigingen die worden aangebracht in de inhoud van bestanden en mappen.
$ echo 'hello git reset' > reset_lifecycle_file
$ git status
On branch main
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: reset_lifecycle_file
In onze demo-repository passen we de reset_lifecycle_file
aan en voegen we daar wat inhoud aan toe. Het aanroepen van de git-status
geeft aan dat Git op de hoogte is van de wijzigingen in het bestand. Deze wijzigingen maken momenteel deel uit van de eerste boomstructuur, 'de Werkmap'. Git-status
kan worden gebruikt om wijzigingen in de Werkmap weer te geven. Ze worden in het rood weergegeven met een voorvoegsel van 'gewijzigd'.
Staging-index
De volgende is de boom van de 'Staging-index'. Deze boomstructuur houdt wijzigingen in de Werkmap bij, die met git add
zijn gepromoot, en worden opgeslagen in de volgende commit. Deze boom is een complex mechanisme voor intern cachen. Git probeert over het algemeen de implementatiegegevens van de Staging-index voor de gebruiker te verbergen.
Om de status van de Staging-index nauwkeurig te kunnen bekijken, moeten we een minder bekende Git-opdracht gebruiken: git ls-files
. De opdracht git ls-files
is in wezen een hulpprogramma voor foutopsporing om de status van de boom voor Staging-index te inspecteren.
git ls-files -s
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 reset_lifecycle_file
Hier hebben we git ls-files
uitgevoerd met de optie -s
of --stage
. Zonder de optie -s
is de output van git ls-files
gewoon een lijst met bestandsnamen en paden die momenteel deel uitmaken van de index. De optie -s
geeft aanvullende metagegevens weer voor de bestanden in de Staging-index. Deze metagegevens zijn de modusbits, de objectnaam en het stage-nummer van de gestagede inhoud. Hier zijn we geïnteresseerd in de objectnaam, de tweede waarde (d7d77c1b04b5edd5acfc85de0b592449e5303770
). Dit is een standaard SHA-1-hash voor Git-objecten. Het is een hash van de inhoud van de bestanden. De Commit-geschiedenis slaat het eigen SHA-object op voor het identificeren van pointers naar commits en refs, en de Staging-index heeft zijn eigen object-SHA's voor het bijhouden van versies van bestanden in de index.
Vervolgens promoten we het aangepaste reset_lifecycle_file
naar de Staging-index.
$ git add reset_lifecycle_file
$ git status
On branch main Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: reset_lifecycle_file
Hier hebben we git add reset_lifecycle_file
aangeroepen, waarmee het bestand wordt toegevoegd aan de Staging-index. Als je de git-status
aanroept, wordt reset_lifecycle_file
nu groen weergegeven onder 'Changes to be committed'. Het is belangrijk op te merken dat de git status
geen waarheidsgetrouwe weergave is van de Staging-index. De opdrachtuitvoer van git status
geeft de wijzigingen weer tussen de Commit-geschiedenis en de Staging-index. Laten we nu eens kijken naar de inhoud van de Staging-index.
$ git ls-files -s 100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file
We kunnen zien dat het SHA-object voor reset_lifecycle_file
is bijgewerkt van e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
naar d7d77c1b04b5edd5acfc85de0b592449e5303770
.
Commit-geschiedenis
De laatste boom is de Commit-geschiedenis. De opdracht git commit
voegt wijzigingen toe aan een permanente momentopname die in de Commit-geschiedenis staat. Deze momentopname bevat ook de status van de Staging-index op het moment van de commit.
$ git commit -am"update content of reset_lifecycle_file"
[main dc67808] update content of reset_lifecycle_file
1 file changed, 1 insertion(+)
$ git status
On branch main
nothing to commit, working tree clean
Hier hebben we een nieuwe commit gemaakt met het bericht 'update content of resetlifecyclefile'
. De changeset is toegevoegd aan de Commit-geschiedenis. Als je nu de git-status
aanroept, laat dat zien dat er in geen van de bomen wijzigingen in behandeling zijn. Bij het uitvoeren van het git log
wordt de Commit-geschiedenis weergegeven. Nu we deze changeset door de drie bomen heen hebben gevolgd, kunnen we beginnen met het gebruik van git reset
.
Hoe het werkt
Op het eerste gezicht lijkt het gedrag van git reset
op dat van git checkout
. Waar git checkout
uitsluitend werkt met de HEAD
ref-pointer, verplaatst git reset
de HEAD
ref-pointer en de huidige ref-pointer van de branch. Bekijk het volgende voorbeeld om dit gedrag beter te demonstreren:
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
en git reset b
uitvoeren en vergelijken.
git checkout b
Met git checkout
verwijst de main
ref nog steeds naar d
. De HEAD
ref is verplaatst en wijst nu naar commit b
. De repo bevindt zich nu in een status 'detached HEAD
'.
git reset b
Ter vergelijking: git reset
, verplaatst zowel de HEAD
als de branch-refs naar de opgegeven commit.
Naast het bijwerken van de ref-pointers van de commit, zal git reset
de status van de drie bomen aanpassen. De ref-pointer wordt altijd gewijzigd en het is een update van de derde boom, de Commit-boom. De opdrachtregelargumenten --soft, --mixed
en --hard
sturen hoe je de Staging-index- en de Werkmap-bomen kunt aanpassen.
Belangrijkste opties
De standaardaanroep van git reset
heeft impliciete argumenten van --mixed
en HEAD
. Dit betekent dat het uitvoeren van een git reset
gelijk is aan het uitvoeren van git reset --mixed HEAD
. In deze vorm is HEAD
de opgegeven commit. In plaats van HEAD
kan elke Git SHA-1 commit-hash worden gebruikt.
'--hard
Dit is de meest directe, GEVAARLIJKE en meest gebruikte optie. Indien --hard
is doorgevoerd, dan worden de ref-pointers van de Commit-geschiedenis bijgewerkt naar de opgegeven commit. Vervolgens worden de Staging-index en de Werkmap opnieuw ingesteld zodat ze overeenkomen met die van de opgegeven commit. Alle wijzigingen in de Staging-index en de Werkmap die eerder in behandeling waren, worden opnieuw ingesteld op basis van de status van de Commit-boom. Dit betekent dat al het werk dat nog in behandeling was in de Staging-index en Werkmap verloren gaat.
Om dit aan te tonen, gaan we verder met de drie boomvoorbeelden van repo die we eerder hebben ingesteld. Laten we eerst enkele wijzigingen aanbrengen in de repo. Voer de volgende opdrachten uit in de voorbeeldrepo:
$ echo 'new file content' > new_file
$ git add new_file
$ echo 'changed content' >> reset_lifecycle_file
Met deze opdrachten is er een nieuw bestand met de naam new_file
gemaakt en aan de repo toegevoegd. Daarnaast wordt de inhoud van reset_lifecycle_file
aangepast. Nu deze wijzigingen zijn doorgevoerd, laten we nu de status van de repo bekijken met behulp van de git status
.
$ git status
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
new file: new_file
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: reset_lifecycle_file
Hier hebben we git add reset_lifecycle_file
aangeroepen, waarmee het bestand wordt toegevoegd aan de Staging-index. Als je de git-status
aanroept, wordt reset_lifecycle_file
nu groen weergegeven onder 'Changes to be committed'. Het is belangrijk op te merken dat de git status
geen waarheidsgetrouwe weergave is van de Staging-index. De opdrachtuitvoer van git status
geeft de wijzigingen weer tussen de Commit-geschiedenis en de Staging-index. Laten we nu eens kijken naar de inhoud van de Staging-index.
$ git ls-files -s
100644 8e66654a5477b1bf4765946147c49509a431f963 0 new_file
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file
We kunnen zien dat new_file
aan de index is toegevoegd. We hebben reset_lifecycle_file
bijgewerkt, maar de Staging-index SHA (d7d77c1b04b5edd5acfc85de0b592449e5303770
) blijft ongewijzigd. Dit gedrag wordt verwacht omdat git add
niet wordt gebruikt om deze wijzigingen naar de Staging-index te promoten. Deze wijzigingen zijn te vinden in de Werkmap.
Laten we nu git reset --hard
uitvoeren en de nieuwe status van de repository onderzoeken.
$ git reset --hard
HEAD is now at dc67808 update content of reset_lifecycle_file
$ git status
On branch main
nothing to commit, working tree clean
$ git ls-files -s
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file
Hier hebben we een 'hard reset' uitgevoerd met de optie --hard
. Git geeft de output weer die aangeeft dat HEAD
naar de laatste commit, dc67808
, verwijst. Vervolgens controleren we de status van de repo met de git status
. Git geeft aan dat er geen wijzigingen in behandeling zijn. We bekijken ook de status van de Staging-index en bekijken we of deze is teruggezet naar een punt voordat new_file
werd toegevoegd. Onze aanpassingen aan reset_lifecycle_file
en de toevoeging van new_file
zijn vernietigd. Dit gegevensverlies kan niet ongedaan worden gemaakt. Dit is van cruciaal belang om in gedachten te houden.
'--mixed
Dit is de standaard bedieningsmodus. De ref-pointers zijn bijgewerkt. De Staging-index wordt teruggezet naar de status van de opgegeven commit. Alle wijzigingen die ongedaan zijn gemaakt in de Staging-index worden verplaatst naar de Werkmap. Laten we doorgaan.
$ echo 'new file content' > new_file
$ git add new_file
$ echo 'append content' >> reset_lifecycle_file
$ git add reset_lifecycle_file
$ git status
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
new file: new_file
modified: reset_lifecycle_file
$ git ls-files -s
100644 8e66654a5477b1bf4765946147c49509a431f963 0 new_file
100644 7ab362db063f9e9426901092c00a3394b4bec53d 0 reset_lifecycle_file
In het bovenstaande voorbeeld hebben we enkele wijzigingen aangebracht in de repository. Nogmaals, we hebben een new_file
toegevoegd en de inhoud van reset_lifecycle_file
aangepast. Deze wijzigingen worden vervolgens toegepast op de Staging-index met git add
. Nu de repo zich in deze toestand bevindt, zullen we nu de reset uitvoeren.
$ git reset --mixed
$ git status
On branch main
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: reset_lifecycle_file
Untracked files:
(use "git add ..." to include in what will be committed)
new_file
no changes added to commit (use "git add" and/or "git commit -a")
$ git ls-files -s
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file
Hier hebben we een 'mixed reset' uitgevoerd. Nogmaals, --mixed
is de standaardmodus en hetzelfde effect als het uitvoeren van een git reset
. Als we de output van git status
en git ls-files
onderzoeken, blijkt dat de Staging-index is teruggezet naar een toestand waarin reset_lifecycle_file
het enige bestand in de index is. De object-SHA voor reset_lifecycle_file
is teruggezet naar de vorige versie.
Het belangrijkste om op te merken is dat de git status
ons laat zien dat er wijzigingen zijn in reset_lifecycle_file
en dat er een bestand is dat niet wordt bijgehouden: new_file
. Dit is het expliciete gedrag van --mixed
. De Staging-index is opnieuw ingesteld en de openstaande wijzigingen zijn verplaatst naar de Werkmap. Vergelijk dit eens met de --hard
reset waarbij de Staging-index werd gereset en ook de Werkmap werd gereset, waardoor deze updates verloren gingen.
'--soft
Wanneer het argument --soft
wordt doorgegeven, worden de ref-pointers bijgewerkt en stopt de reset daar. De Staging-index en de Werkmap blijven onaangeroerd. Dit gedrag kan moeilijk duidelijk aan te tonen zijn. Laten we doorgaan met ons demo-repo en het klaarmaken voor een soft reset.
$ git add reset_lifecycle_file
$ git ls-files -s
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file
$ git status
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: reset_lifecycle_file
Untracked files:
(use "git add ..." to include in what will be committed)
new_file
Ook hier hebben we git add
gebruikt om het aangepaste reset_lifecycle_file te
te promoten naar de Staging-index. We bevestigen dat de index is bijgewerkt met de output van git ls-files
. De output van de git status
geeft nu 'Changes to be committed' weer in het groen. De new_file
uit onze vorige voorbeelden zweeft in de Werkmap rond als een niet-getraceerd bestand. Laten we snel rm new_file
uitvoeren om het bestand te verwijderen, aangezien we het niet nodig hebben voor de volgende voorbeelden.
Nu de repository zich in deze toestand bevindt, voeren we een soft reset uit.
$ git reset --soft
$ git status
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: reset_lifecycle_file
$ git ls-files -s
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file
We hebben een 'soft reset' uitgevoerd. Als we de repostatus onderzoeken met git status
en git ls-files
, blijkt dat er niets is veranderd. Dit is verwacht gedrag. Een soft reset zal enkel de Commit-geschiedenis resetten. Git reset
wordt standaard aangeroepen met HEAD
als doel-commit. Aangezien onze Commit-geschiedenis al op HEAD
stond en we impliciet zijn teruggezet naar HEAD
, is er eigenlijk niets gebeurd.
Voor een beter begrip en een beter gebruik van --soft
hebben we een doel-commit nodig die niet HEAD
is. Er staat reset_lifecycle_file
klaar in de Staging-index. Laten we een nieuwe commit aanmaken.
$ git commit -m"prepend content to reset_lifecycle_file"
Op dit moment zou onze repo drie commits moeten hebben. We gaan terug in de tijd naar de eerste commit. Hiervoor hebben we de ID van de eerste commit nodig. Deze kan gevonden worden door de output van git log
te bekijken.
$ git log
commit 62e793f6941c7e0d4ad9a1345a175fe8f45cb9df
Author: bitbucket
Date: Fri Dec 1 15:03:07 2017 -0800
prepend content to reset_lifecycle_file
commit dc67808a6da9f0dec51ed16d3d8823f28e1a72a
Author: bitbucket
Date: Fri Dec 1 10:21:57 2017 -0800
update content of reset_lifecycle_file
commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4
Author: bitbucket
Date: Thu Nov 30 16:50:39 2017 -0800
initial commit
Houd er rekening mee dat ID's van Commit-geschiedenis voor elk systeem uniek zijn. Dit betekent dat de commit-ID's in dit voorbeeld anders zijn dan wat je op je computer ziet. De commit-ID waarin we geïnteresseerd zijn voor dit voorbeeld is 780411da3b47117270c0e3a8d5dcfd11d28d04a4
. Dit is de ID die overeenkomt met de 'initiële commit'. Zodra we deze ID hebben gevonden, gebruiken we deze als doelwit voor onze soft reset.
Voordat we terug in de tijd gaan, moeten we eerst de huidige status van de repo controleren.
$ git status && git ls-files -s
On branch main
nothing to commit, working tree clean
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file
Hier voeren we een combinatieopdracht uit van git status en
git ls-files -s
. Dit laat ons zien dat er nog wijzigingen in de repo zijn, en reset_lifecycle_file
in de Staging-index heeft een versie van 67cc52710639e5da6b515416fd779d0741e3762e
. Laten we met dit in gedachten een soft reset uitvoeren terug naar onze eerste commit.
$git reset --soft 780411da3b47117270c0e3a8d5dcfd11d28d04a4
$ git status && git ls-files -s
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: reset_lifecycle_file
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file
De bovenstaande code voert een 'soft reset' uit en roept ook een combinatie van de opdrachtengit status
en git ls-files
aan, waarmee de status van de repository wordt weergegeven. We kunnen de output van de repostatus bekijken en enkele interessante observaties noteren. Ten eerste geeft de git status
aan dat er wijzigingen zijn in reset_lifecycle_file
en worden deze gemarkeerd om aan te geven dat het om wijzigingen gaat die gestaged zijn voor de volgende commit. Ten tweede geeft de input van git ls-files
aan dat de Staging-index niet is gewijzigd en blijft de SHA 67cc52710639e5da6b515416fd779d0741e3762e behouden die we eerder hadden.
Laten we de git log
bekijken om verder te verduidelijken wat er is gebeurd tijdens deze reset:
$ git log commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4 Author: bitbucket Date: Thu Nov 30 16:50:39 2017 -0800 initial commit
De output van de log toont nu aan dat er één commit in de Commit-geschiedenis is. Dit helpt om duidelijk te maken wat --soft
heeft gedaan. Zoals bij alle aanroepen van git reset
, wordt als eerste actie van de reset de commit-boom opnieuw ingesteld. Onze vorige voorbeelden, met --hard
en --mixed
, waren beide tegen de HEAD
en hebben de Commit-boom niet terug in de tijd verplaatst. Bij een soft reset is dit alles wat er gebeurt.
Dit kan dan verwarrend zijn waarom de git status
aangeeft dat er gewijzigde bestanden zijn. --soft
heeft niets te maken met de Staging-index, dus de updates van onze Staging-index volgden ons terug in de tijd tijdens de commit-geschiedenis. Dit kan bevestigd worden door de output van git ls-files -s
, waaruit blijkt dat de SHA voor reset_lifecycle_file
ongewijzigd is. Ter herinnering: de git status
geeft niet de toestand van 'de drie bomen' weer, maar het toont in wezen een verschil tussen de drie bomen. In dit geval wordt weergegeven dat de Staging-index voorloopt op de wijzigingen in de Commit-geschiedenis, alsof we ze al gestaged hebben.
Resetten versus terugzetten
Als git revert een 'veilige' manier is om wijzigingen ongedaan te maken, kun je git reset
als de gevaarlijke methode beschouwen. Er is een werkelijk risico om werk te verliezen met git reset
. Git reset
zal nooit een commit verwijderen, maar commits kunnen 'verweesd' worden, wat betekent dat er geen directe toegang is vanaf een ref. Deze verweesde commits kunnen meestal gevonden en hersteld worden met git reflog. Git zal alle verweesde commits permanent verwijderen nadat de interne vuilnisophaler is gestart. Git is standaard geconfigureerd om de vuilnisophaler elke 30 dagen te laten draaien. Commit-geschiedenis is een van de 'drie git-bomen', de andere twee, Staging-index en Werkmap, zijn niet zo permanent als Commits. Wees voorzichtig wanneer je deze tool gebruikt, want het is een van de weinige Git-opdrachten waarmee je mogelijk werk verliest.
Waar terugzetten bedoeld is om een openbare commit veilig ongedaan te maken, is git reset
ontworpen om lokale wijzigingen in de Staging-index en Werkmap ongedaan te maken. Vanwege hun verschillende doelen zijn de twee opdrachten verschillend geïmplementeerd: bij resetten wordt een changeset volledig verwijderd, terwijl bij terugdraaien de oorspronkelijke changeset behouden blijft en een nieuwe commit wordt gebruikt om het ongedaan maken toe te passen.
Reset openbare geschiedenis niet
Je moet git reset
nooit gebruiken als momentopnamen na
Het verwijderen van een commit die andere teamleden voortdurend hebben ontwikkeld, levert ernstige problemen op voor de samenwerking. Als ze proberen te synchroniseren met je repository, zal het lijken alsof een deel van de projectgeschiedenis abrupt is verdwenen. De onderstaande volgorde laat zien wat er gebeurt als je probeert een openbare commit opnieuw in te stellen. De origin/main
-branch is de versie van de centrale repository van je lokale main
-branch.
Zodra je nieuwe commits toevoegt na de reset, zal Git denken dat je lokale geschiedenis anders is dan die van origin/main
, en de merge-commit die nodig is om je repository's te synchroniseren, zal je team waarschijnlijk verwarren en frustreren.
Het punt is, zorg ervoor dat je git reset <commit>
gebruikt voor een lokaal experiment dat fout is gegaan, niet voor gepubliceerde wijzigingen. Als je een openbare commit moet herstellen, is de opdracht git revert
speciaal voor dit doeleinde ontworpen.
Voorbeelden
git reset <file>
Verwijder het opgegeven bestand uit het staging-gebied, maar laat de werkmap ongewijzigd. Hiermee wordt het stagen van een bestand ongedaan gemaakt zonder eventuele wijzigingen te overschrijven.
git reset
Stel het testgebied opnieuw in zodat het overeenkomt met de meest recente commit, maar laat de werkmap ongewijzigd. Hiermee worden alle bestanden ongestaged zonder wijzigingen te overschrijven, zodat je de gestagede momentopname helemaal opnieuw kunt samenstellen.
git reset --hard
Reset het staging-gebied en de werkmap om overeen te komen met de meest recente commit. Naast het ongedaan maken van wijzigingen, geeft de markering --hard
aan Git de opdracht om ook alle wijzigingen in de werkmap te overschrijven. Anders gezegd: hiermee worden alle vrijblijvende veranderingen vernietigd, dus zorg ervoor dat je echt je lokale ontwikkelingen weg wilt gooien voordat je het gebruikt.
git reset
Verplaats de huidige branchtip naar achteren om een commit te maken
, stel het staging-gebied opnieuw in zodat het overeenkomt, maar laat de werkmap met rust. Alle wijzigingen die sinds de <commit>
zijn aangebracht, bevinden zich in de werkmap, zodat je de projectgeschiedenis opnieuw kunt committen met behulp van schonere, meer atomische momentopnamen.
git reset --hard
Verplaats de tip van de huidige branch naar achteren naar <commit>
en reset het staging-gebied en de werkmap om overeen te komen. Hiermee worden niet alleen de wijzigingen zonder commits vernietigd, maar ook alle wijzigingen die daarna worden doorgevoerd.
Een bestand ontstagen
De opdracht git reset
komt vaak voor tijdens het voorbereiden van de gestagede momentopname. In het volgende voorbeeld wordt ervan uitgegaan dat je twee bestanden hebt, genaamd hello.py
en main.py
, die je al hebt toegevoegd aan de repository.
# Edit both hello.py and main.py
# Stage everything in the current directory
git add .
# Realize that the changes in hello.py and main.py
# should be committed in different snapshots
# Unstage main.py
git reset main.py
# Commit only hello.py
git commit -m "Make some changes to hello.py"
# Commit main.py in a separate snapshot
git add main.py
git commit -m "Edit main.py"
Zoals je ziet helpt git reset
om je commits zeer gericht te houden door je wijzigingen die niets met de volgende commit te maken hebben, te laten ontstagen.
Lokale commits verwijderen
Het volgende voorbeeld toont een meer geavanceerde usecase. Het laat zien wat er gebeurt als je al een tijdje aan een nieuw experiment werkt, maar besluit het helemaal weg te gooien nadat je een paar momentopnamen hebt gemaakt.
# Create a new file called `foo.py` and add some code to it
# Commit it to the project history
git add foo.py
git commit -m "Start developing a crazy feature"
# Edit `foo.py` again and change some other tracked files, too
# Commit another snapshot
git commit -a -m "Continue my crazy feature"
# Decide to scrap the feature and remove the associated commits
git reset --hard HEAD~2
De opdracht git reset HEAD~2
verplaatst de huidige branch met twee commits naar achteren, waardoor de twee momentopnamen die we zojuist hebben gemaakt, in feite worden verwijderd uit de projectgeschiedenis. Onthoud dat dit soort resets alleen mogen worden gebruikt voor niet-gepubliceerde commits. Voer bovenstaande bewerking nooit uit als je je commits al naar een gedeelde repository hebt gepusht.
Samenvatting
Git reset
is een krachtige opdracht die wordt gebruikt om lokale wijzigingen in de status van een Git-repo ongedaan te maken. Git reset
werkt met 'De drie bomen van Git'. Deze bomen zijn de Commit-geschiedenis (HEAD
), de Staging-index en de Werkmap. Er zijn drie opdrachtregelopties die overeenkomen met de drie bomen. De opties --soft, --mixed
en --hard
kunnen worden doorgegeven aan git reset
.\
In dit artikel hebben we verschillende andere Git-opdrachten gebruikt om de resetprocessen te demonstreren. Meer informatie over deze opdrachten vind je op hun afzonderlijke pagina's op: git status, git log, git add, git checkout, git reflog, en git revert.
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.