0%

Dingen ongedaan maken · oefening

Ik heb een commit gemaakt die geen commit had moeten zijn

Je hebt iets gecommit dat helemaal geen commit had moeten zijn. Deze keer geen verkeerd bericht en ook geen wijziging die je later wilt terugdraaien: de commit zelf was een vergissing en je wilt dat hij verdwijnt. Niemand anders heeft hem.

Amend zou hem vervangen door een andere commit, maar dat wil je niet. Je wilt er één minder.

Maak eerst de fout

De repository bevat een kladbestand, scratch.tmp, met twee persoonlijke herinneringen. Commit het alsof je even niet oplette:

git add scratch.tmp
git commit -m "wip"
git log

git add scratch.tmp zet het klaar, of dat al gebeurd was of niet. Dit werkt dus hetzelfde ongeacht hoe je bij deze les kwam. git log toont nu een commit met de naam wip, met daarin een privé-takenlijst. Die hoort helemaal niet in de projectgeschiedenis.

Verplaats de branch terug

Je werklijn heeft een naam, main. Die naam markeert de nieuwste commit van die lijn. git reset verplaatst de markering. Zet haar één commit terug en de commit wip hoort niet meer bij je geschiedenis:

git reset --soft HEAD~1
git log
git status

Die naam heet een branch. Hoofdstuk 5 legt dat uitgebreid uit. Hier heb je alleen het deel nodig waarop reset steunt: de naam markeert een commit. Door de naam te verplaatsen verander je welke commits bij je geschiedenis horen.

HEAD~1 betekent “één commit vóór waar ik nu ben”. --soft is het belangrijke deel: het verplaatst die naam en verder niets. Je bestanden blijven onaangeraakt. Alles wat de teruggenomen commit bevatte blijft in de staging area staan, klaar om opnieuw te committen als je wilt.

git log toont wip niet meer. git status toont scratch.tmp weer als staged, precies zoals vóór het committen. Je bent terug bij de beslissing, niet eraan voorbij.

Maak het af door het van de lijst te halen, zoals je eerder in dit hoofdstuk deed:

git restore --staged scratch.tmp
git status

De drie resets en de gevaarlijke variant

In de vorm die hier commits verplaatst, verplaatst git reset de branchwijzer. Het verschil zit in wat er verder verandert:

  • --soft verplaatst alleen de wijzer. Je wijzigingen blijven klaargezet. Er gaat niets verloren.

  • --mixed, de standaard als je geen optie noemt, verplaatst de wijzer en zet de staging area terug naar de doelcommit. In dit geval met HEAD~1 zijn de wijzigingen uit de teruggenomen commit daarna niet meer klaargezet. Je bestanden behouden hun inhoud, dus er gaat niets verloren, maar je moet die wijzigingen opnieuw klaarzetten.

  • --hard verplaatst de wijzer, zet de staging area terug en overschrijft bijgehouden bestanden zodat ze daarmee overeenkomen. Klaargezette of niet-klaargezette bewerkingen aan bijgehouden bestanden verdwijnen. Untracked bestanden blijven meestal staan, maar Git kan er een verwijderen als het een bijgehouden pad in de weg zit.

Lees die laatste twee keer. git reset --hard kan bijgehouden werk vernietigen waarvan je geen kopie hebt. Het is niet verboden en het is nuttig, maar voer het alleen uit nadat je git status hebt gelezen en hebt besloten dat elke klaargezette of niet-klaargezette bewerking aan bijgehouden bestanden weg mag.

De commit die je met reset achterlaat is een ander verhaal. Die is niet verwijderd; er wordt alleen niet meer naar verwezen. Daar gaat de laatste les van dit hoofdstuk over.

Wanneer je dit niet gebruikt

Reset haalt een commit uit je branch. Heeft iemand anders die commit al, dan staat hij nog in diens geschiedenis en niet meer in de jouwe. Die twee moet je dan met de hand weer op elkaar afstemmen.

Neem een commit alleen met reset terug zolang hij nog privé is.

Hier maakte je de commit wip zelf, een paar seconden geleden, in je eigen repository. Dat is de veilige situatie. De volgende les behandelt de andere.

Je voert git reset --soft HEAD~1 uit na een commit waar je spijt van hebt. Wat gebeurt er met de wijzigingen uit die commit?

Hierna: dezelfde fout, maar nu heeft iemand anders de commit al.