TL;DR: żeby cofnąć ostatni commit i zachować zmiany, wykonaj git reset --soft HEAD~1 (zmiany zostają w stagingu) albo git reset HEAD~1 (zmiany zostają w drzewie roboczym). Jeśli commit jest już wypchnięty, wykonaj zamiast tego git revert HEAD — tworzy nowy commit, który go unieważnia bez przepisywania historii. Te trzy komendy załatwiają niemal każdy moment typu „zacommitowałem za wcześnie”. Reszta przewodnika przechodzi przez każdy przypadek z komendami do wklejenia, wyjaśnia różnicę między --soft, --mixed i --hard i pokazuje, jak się ratować, gdy coś pójdzie nie tak. Każda komenda poniżej działa na każdej współczesnej instalacji Gita na Linuksie, macOS i Windows.
Jak cofnąć ostatni commit, ale zachować zmiany?
Najczęstsza sytuacja: zacommitowałeś, potem wypatrzyłeś literówkę, brakujący plik albo zrozumiałeś, że zmiana pasuje do innego commita. Nic nie jest wypchnięte. Cofnij commit i odłóż wszystko na miejsce:
# Commit znika z historii — zmiany wracają do stagingu
git reset --soft HEAD~1
# Zmiany wracają za to do drzewa roboczego (poza stagingiem)
git reset HEAD~1 HEAD~1 znaczy „jeden commit przed tym, na co wskazuje teraz HEAD”. Po każdej z tych komend twoje pliki są nietknięte na dysku — ruszył się tylko wskaźnik gałęzi. Sprawdź git status: z --soft zmiany są w stagingu, gotowe do ponownego commita z poprawkami w środku; bez flagi są poza nim, więc możesz najpierw swobodnie edytować.
Bezpieczniejszy nawyk, gdy chcesz tylko dorzucić pliki do ostatniego commita, to w ogóle go nie cofać:
git add forgotten-file.txt
git commit --amend --no-edit --amend podmienia ostatni commit w miejscu (tu bez zmiany komunikatu). Uwaga: amendowanie wypchniętego commita przepisuje historię — o tym niżej.
Jaka jest różnica między —soft, —mixed i —hard?
To jest część do zapamiętania, bo flaga decyduje, gdzie wylądują twoje zmiany — i czy w ogóle mogą zginąć:
| Flaga | Commit cofnięty? | Zmiany na dysku | W stagingu? | Typowe użycie |
|---|---|---|---|---|
--soft | Tak | Zachowane | Tak | Ponowny commit z drobnymi poprawkami |
--mixed (domyślna) | Tak | Zachowane | Nie | Przegroupowanie zmian, selektywny staging |
--hard | Tak | Usunięte | — | Wyrzucić robotę w całości |
git revert | Nie (nowy commit) | Zachowane | — | Cofnąć commit, który już wypchnąłeś |
--hard to jedyna niebezpieczna: wyrzuca commit i zmiany. Przed każdym reset --hard odłóż to, co masz, do stash albo gałęzi:
git branch backup-before-reset # tanie ubezpieczenie
git reset --hard HEAD~1 # commit + zmiany znikają Jeśli niebezpieczną wersję już wykonałeś, nie wszystko stracone — git reflog pamięta, gdzie HEAD bywał:
git reflog # znajdź hash utraconego commita
git reset --hard HEAD@{1} # albo: git reset --hard <hash> Reflog trzyma wiszące commity przez około 90 dni domyślnie, więc „zrobiłem hard-reset przez pomyłkę” jest prawie zawsze do odrobienia, jeśli zdążysz przed garbage collection.
A jeśli commit już wypchnąłem?
Jeśli commit siedzi na współdzielonej gałęzi (cokolwiek poza twoją własną feature’ową gałęzią), nie przepisuj historii. Użyj git revert, który wylicza odwrotną zmianę i commituje ją:
git revert HEAD
git push Każdy, kto zrobi pull, dostaje po prostu nowy commit usuwający zmiany starego. Bez force-pusha, bez zepsutych kolegów. Jeśli masz cofnąć serię commitów, zrób revert zakresu: git revert --no-commit HEAD~3..HEAD && git commit.
Alternatywa — git reset --hard HEAD~1 && git push --force-with-lease — jest akceptowalna tylko na gałęzi, na której nikt inny nie buduje, a --force-with-lease (nigdy goły --force) to jedyna bezpieczna forma, bo odmawia nadpisu, gdy ktoś w międzyczasie wypchnął. Force-pushowanie współdzielonych gałęzi to sposób, w jaki zespoły tracą commity, a logi CI tajemniczo przestają pasować do checkoutu kogokolwiek.
Jak cofnąć ostatni commit, ale zachować go na później?
Czasem commit to dobra robota na złym adresie — na złej gałęzi albo za wcześnie. Zamiast go cofać, przesuń go:
git branch stash-commit # zaparkuj commita na nowej gałęzi
git reset --hard HEAD~1 # potem posprzątaj bieżącą gałąź Albo zabierz tylko ten commit na inną gałąź, nie dotykając bieżącej:
git cherry-pick <hash> # będąc na gałęzi docelowej Między reset --soft, cherry-pick i revert nie ma commita, którego nie da się przenieść albo unieważnić — trik polega na wybraniu „przenieś” kontra „cofnij” zanim sięgniesz po flagę.
Którego cofania użyć? Szybki przewodnik decyzyjny
- Nie wypchnięty, chcesz poprawić i zacommitować ponownie →
git reset --soft HEAD~1 - Nie wypchnięty, chcesz na nowo wybrać, co wchodzi do stagingu →
git reset HEAD~1(mixed) - Chcesz zmiany całkiem stąd wyrzucić →
git reset --hard HEAD~1(reflog pamięta, jeśli będziesz żałować) - Już wypchnięty na współdzieloną gałąź →
git revert HEAD - Commit pasuje na inną gałąź →
cherry-pick, nie cofaj
Ostatnia rada operacyjna: jeśli zły commit dotarł aż na serwer — spartaczony hook deployu, źle zachowujący się runner CI po force-pushu — następne miejsce do zajrzenia to logi maszyny, nie Git. Na każdym systemdowym boxie journalctl -u <service> -n 100 pokaże dokładnie, co się wykonało i kiedy; nasza ściągawka z journalctl ma wzory do wklejenia. A jeśli twój workflow obejmuje lokalne narzędzia LLM do przeglądania diffów, oba główne warianty porównaliśmy w Ollama vs LM Studio.
— mrsaynothing
Get the next one by email
One email per post. No spam, no algorithms.
what is this?journalctl: ściągawka na codzienną pracę z logami Linuksa
Podobają się teksty? Tak buduję zawodowo. zatrudnij mnie