Wróć do bloga

Git revert vs reset: który uratuje twoją historię?

15 września 2026

TL;DR: git revert dodaje nowy commit, który cofa stary — historia zostaje zachowana, bezpieczne na gałęziach, które inni już pobrali. git reset przesuwa wskaźnik gałęzi do tyłu — historia jest przepisywana, bezpieczne tylko dla commitów, których nie wypchnąłeś. Na wspólnych gałęziach revert, do porządków lokalnych reset. reset --hard kasuje przy okazji niezacommitowane zmiany w drzewie roboczym — to on zjada prawdziwą pracę.

Czym różnią się git revert i git reset?

Oba sprawiają, że projekt wygląda, jakby jakiś dawny commit nigdy nie zaistniał. Różnią się tym, jak to robią:

  • git revert <sha> liczy odwrotny patch commita i commituje go. Historia rośnie o jeden commit mówiący „cofnij tamten”. Zły commit zostaje w logu, po nim jego odwołanie. SHA wszystkiego innego pozostają nietknięte.
  • git reset <sha> przesuwa wskaźnik bieżącej gałęzi na <sha>. Commity po nim zostają odpięte — wciąż siedzą w bazie obiektów aż do garbage collection, ale nie da się do nich dotrzeć z żadnej gałęzi ani z git log.

Jeden niczego nie przepisuje, drugi udaje, że nic się nie stało. Ta jedna własność rozstrzyga, czego wymaga dana sytuacja:

# Demo: jednorazowe repo, które da się odpalić
git init /tmp/revert-vs-reset && cd /tmp/revert-vs-reset
echo one > file.txt && git add . && git commit -m "one"
echo two > file.txt && git add . && git commit -m "two"

# Revert: historia zachowuje oba commity, plus trzeci, który cofa "two"
git revert --no-edit HEAD
git log --oneline        # 3 commity: revert, two, one

# Reset: wskaźnik gałęzi cofa się, "two" znika z logu
git reset --hard HEAD~1
git log --oneline        # 1 commit: one

Odpal oba i zajrzyj do git log — asymetria to cała odpowiedź.

Co tak naprawdę robią git reset —soft, —mixed i —hard?

Trzy tryby kontrolują, gdzie przeżyją twoje zmiany po przesunięciu wskaźnika:

TrybWskaźnik gałęziStaging areaDrzewo roboczeTwoje zmiany
--softcofa sięzostaje w stagingunietkniętezachowane w całości
--mixed (domyślny)cofa sięwypadają ze stagingunietkniętezachowane, poza stagingiem
--hardcofa sięresetresetusunięte

Konkretne odczyty tej tabeli:

  • git reset --soft HEAD~1 — „zacommitowałem za wcześnie”. Wszystko wraca do stagingu, gotowe do ponownego commita, może razem z kolejną pracą.
  • git reset HEAD~1 (mixed) — „zastage’owałem złe pliki”. Zmiany przeżywają w drzewie roboczym, nic nie jest staged. W parze z git remove untracked files, gdy chcesz też pozbyć się zbłąkanych plików.
  • git reset --hard HEAD~1 — „ten commit i moje niezacommitowane zmiany to śmieci”. Git nie będzie pytał dwa razy; nie ma undo dla części z drzewa roboczego, chyba że wcześniej zrobiłeś stash albo commit.

revert nie ma trybów, bo niczego nie niszczy — dodaje wyłącznie kompensujący commit.

Kiedy użyć git revert zamiast git reset?

Zadaj jedno pytanie: czy ktokolwiek inny pobrał już ten commit? Jeśli tak, reset odpada.

Zresetowanie gałęzi, na której inni oparli pracę, przepisuje wspólną historię. Ich następny pull spotyka rozjechane gałęzie, a „naprawa” to zwykle force-push, który zamienia twój błąd w problem wszystkich. Revert dokłada zwykły commit, więc czysty git pull merguje się wszystkim bez dramatu — dlatego revert to domyślna odpowiedź na main i w pull requestach na GitHubie, gdzie przycisk „Revert” istnieje właśnie dlatego, że przepisanie historii zmergowanego PR-a nie wchodzi w grę.

Reset jest na okno przed udostępnieniem: commit sprzed trzydziestu sekund, pomyłka w stagingu, lokalna gałąź eksperymentalna. Jeśli jedyna kopia pracy jest na twojej maszynie, możesz przestawiać historię do woli — o to właśnie chodzi w oknie przed pushem.

Jest przypadek pośredni: wypchnąłeś na własną gałąź funkcjonalną i nikt inny na niej nie buduje. Force-push po resecie jest tam społecznie akceptowalny, ale revert i tak kosztuje mniej koordynacji. Force-pushe rezerwuj na gałęzie, które masz na wyłączność.

Czy git revert jest bezpieczniejszy od git reset dla wspólnych gałęzi?

Tak, strukturalnie — nie tylko z konwencji:

  • Revert tworzy zwykły commit; CI na nim działa, diff daje się zreviewować, a git log tłumaczy przyszłemu tobie, czemu zmiana zniknęła.
  • Reset po cichu wyrzuca stan pośredni. Nikt przeglądający później nie zobaczy, co zostało cofnięte i kiedy, bo log pokazuje prostą linię, która nigdy tego nie zawierała.

Dwie praktyczne pułapki:

  • Cofnięcie commita mergującego wymaga git revert -m 1 <sha> (zostań przy linii pierwszego rodzica). Bez -m git odmówi i zostawi ci samemu czytać komunikat błędu.
  • Revert to nie wehikuł czasu: cofa diff jednego commita. Jeśli późniejsze commity ruszały te same linie, możesz dostać konflikty — to git mówiący ci, że cofnięcie jest poplątane z resztą historii, co jest użyteczną informacją, a nie usterką.

Do samego cofania ostatniego commita — z zachowaniem albo wyrzuceniem jego zmian — opcje rozpisane są w git undo last commit: keep the changes.

A co z git restore — gdzie ma swoje miejsce?

git restore (i git switch, jego odpowiednik) przyszły w gicie 2.23, by przejąć zadania, które reset wykonywał źle przez przeciążenie jednej nazwy:

ZadanieStary sposóbCzytelny sposób
Odrzucenie zmian pliku w drzewie roboczymgit checkout -- file / git reset --hardgit restore file
Wyjęcie pliku ze stagingugit reset HEAD filegit restore --staged file
Przesunięcie gałęzi na inny commitgit reset <sha>git reset <sha> (bez zamiennika — to zostaje)

Nowoczesny podział brzmi: restore naprawia pliki, reset przesuwa gałęzie, revert cofa opublikowane commity. Autouzupełnianie pokazuje, że ludzie szukają „git revert vs reset vs restore” razem i nie bez powodu — to jeden model mentalny rozdzielony na trzy komendy. Stare formy git checkout dalej działają wszędzie; nowe po prostu chronią cię przed wysłaniem całej gałęzi do shreddera, gdy chciałeś tylko wyjąć jeden plik ze stagingu.

Jeśli celem jest skopiowanie dobrego commita do przodu zamiast wymazania złego, to robota dla cherry-picka — zobacz git cherry-pick: multiple commits, branches, conflicts.

Szybkie podsumowanie decyzji

  1. Commit jest publiczny (wypchnięty, inni pobrali) → git revert <sha>.
  2. Commit tylko lokalny, chcesz go przerobić → git reset --soft albo --mixed i nowy commit.
  3. Tylko lokalny, ma zniknąć razem z niezacommitowanym bałaganem → git reset --hard, po jednej uczciwej chwili przyjrzenia się, co jeszcze trzyma drzewo robocze.
  4. Zepsuł się jeden plik → git restore <file> i zostaw gałąź w spokoju.

Jedyna naprawdę groźna pozycja na tej liście to --hard — wszystko inne da się odwrócić przez git reflog. Trwałe straty w gicie są wąskie i w większości wymagają, żebyś wpisał to wprost; nawyk wart wyrobienia to półsekundowa pauza przed --hard, a nie unikanie ostrych narzędzi gita.

— 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?

Usługa systemd nie startuje? Jak to naprawić

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