Wróć do bloga

Git: jak cofnąć ostatni commit bez utraty zmian

3 września 2026

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ąć:

FlagaCommit cofnięty?Zmiany na dyskuW stagingu?Typowe użycie
--softTakZachowaneTakPonowny commit z drobnymi poprawkami
--mixed (domyślna)TakZachowaneNiePrzegroupowanie zmian, selektywny staging
--hardTakUsunięteWyrzucić robotę w całości
git revertNie (nowy commit)ZachowaneCofnąć 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

  1. Nie wypchnięty, chcesz poprawić i zacommitować ponowniegit reset --soft HEAD~1
  2. Nie wypchnięty, chcesz na nowo wybrać, co wchodzi do stagingugit reset HEAD~1 (mixed)
  3. Chcesz zmiany całkiem stąd wyrzucićgit reset --hard HEAD~1 (reflog pamięta, jeśli będziesz żałować)
  4. Już wypchnięty na współdzieloną gałąźgit revert HEAD
  5. 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.

self-hosted · no third parties · one-click unsubscribe

what is this?

journalctl: ściągawka na codzienną pracę z logami Linuksa

Podobają się teksty? Tak buduję zawodowo. zatrudnij mnie