„Cofnięcie” i „rollback” — terminy oznaczające powrót systemu, kodu lub danych do poprzedniego stanu. W programowaniu to fundamentalna operacja wbudowana w systemy kontroli wersji, bazy danych i mechanizmy wdrażania. Według Git Documentation, operacje cofania mogą być bezpieczne (revert z utworzeniem nowego commitu) i destrukcyjne (reset z utratą historii). Zrozumienie różnic między nimi pomaga uniknąć utraty danych przy powrocie do poprzedniej wersji.
Najważniejsze
Cofnięcie (rollback) — operacja powrotu systemu do poprzedniego stabilnego stanu. W kontekście programowania może to oznaczać anulowanie commitu w Git, wycofanie transakcji w bazie danych lub przywrócenie poprzedniej wersji aplikacji na serwerze. Termin pochodzi z angielskiego „rollback” i na stałe zakorzenił się w słowniku programistów wszystkich platform.
Konieczność cofnięcia pojawia się, gdy nowa zmiana psuje funkcjonalność, powoduje błędy lub nie przechodzi kontroli jakości. W dobrze zorganizowanym procesie programistycznym cofnięcie nie jest oznaką porażki, ale standardową procedurą wbudowaną w przepływ pracy. Im szybciej zespół może cofnąć problematyczną zmianę, tym mniejszy wpływ błędu na użytkowników.
Różne narzędzia oferują różne mechanizmy cofania: Git daje wybór między bezpiecznym revert a destrukcyjnym reset, bazy danych obsługują transakcyjny rollback, a systemy CI/CD potrafią przełączać ruch między wersjami. Wybór podejścia zależy od kontekstu i wymagań dotyczących zachowania historii zmian.
Git revert — bezpieczny sposób cofnięcia, który tworzy nowy commit cofający zmiany poprzedniego. Historia pozostaje liniowa, wszystkie stare commity są zachowane. To jedyny prawidłowy wybór do cofania we wspólnej gałęzi, nad którą pracuje kilku programistów. Polecenie git revert nie usuwa historii — dodaje fakt cofnięcia jako nową zmianę.
Git reset przesuwa wskaźnik bieżącej gałęzi na wskazany commit, odrzucając wszystkie późniejsze zmiany. W zależności od flagi — soft, mixed lub hard — reset różnie obsługuje katalog roboczy i indeks. Tryb hard całkowicie usuwa zmiany z historii, co czyni go niebezpiecznym dla wspólnych gałęzi i odpowiednim tylko do pracy lokalnej.
Revert stosuje się w gałęziach współdzielonych: main, develop, release. Zachowuje historię i pozwala innym programistom zrozumieć, że zmiana została cofnięta. Po revert można bezpiecznie wykonać git pull — system nie wygeneruje konfliktów związanych z przepisaną historią. W pracy zespołowej revert jest domyślnym standardem.
# Cofnij ostatni commit, tworząc nowy commit
git revert HEAD
# Cofnij konkretny commit według hasha
git revert a1b2c3d
Reset jest odpowiedni w lokalnej gałęzi, gdzie jeszcze nie opublikowałeś zmian. Jeśli eksperymentowałeś i chcesz całkowicie wyczyścić historię — reset hard to zrobi. W lokalnej gałęzi możesz użyć reset mixed, aby cofnąć commity, ale zachować zmiany w katalogu roboczym do ponownego commitu.
# Cofnij ostatni commit, zachowaj zmiany w katalogu roboczym
git reset HEAD~1
# Pełne cofnięcie — zmiany są trwale usunięte
git reset --hard HEAD~2
Rollback transakcji — operacja anulująca wszystkie zmiany dokonane w ramach bieżącej transakcji i przywracająca bazę danych do stanu z momentu jej rozpoczęcia. Gwarantuje to atomowość — jedną z czterech zasad ACID (Atomicity, Consistency, Isolation, Durability). Jeśli na którymkolwiek etapie transakcji wystąpi błąd, wykonywany jest rollback, a dane wracają do pierwotnego stanu.
Mechanizm rollback jest zaimplementowany poprzez dziennik zapisu wyprzedzającego (Write-Ahead Log, WAL). Przed zmianą strony danych SZBD zapisuje starą i nową wartość w dzienniku. Podczas rollback system odczytuje dziennik i przywraca pierwotne wartości dla wszystkich zmodyfikowanych stron. Gwarantuje to, że nawet przy awarii zasilania transakcja może zostać poprawnie anulowana.
BEGIN TRANSACTION;
UPDATE accounts
SET balance = balance - 100
WHERE id = 1;
-- Rollback on error
ROLLBACK;
W długich transakcjach wygodnie jest używać savepoint — pośrednich punktów zapisu, do których można się cofnąć bez kończenia całej transakcji. Pozwala to obsługiwać błędy wewnątrz złożonej operacji bez utraty postępu w innych jej częściach. Savepoint jest obsługiwany przez większość relacyjnych SZBD: PostgreSQL, MySQL, Oracle.
SAVEPOINT sp1;
UPDATE orders SET status = 'cancelled'
WHERE id = 42;
ROLLBACK TO sp1;
Cofnięcie wdrożenia — przywrócenie działającej aplikacji do poprzedniej wersji po nieudanym wdrożeniu. To krytycznie ważna funkcja dla środowiska produkcyjnego: czas odzyskiwania (MTTR) bezpośrednio wpływa na SLA i doświadczenie użytkownika. Nowoczesne platformy oferują kilka strategii cofania w zależności od architektury i wymagań dotyczących dostępności.
Blue-green — strategia, w której jednocześnie działają dwa identyczne środowiska: blue (bieżąca wersja) i green (nowa wersja). Ruch jest przełączany na green po udanym wdrożeniu. Jeśli nowa wersja działa nieprawidłowo, przełącznik ruchu wraca do blue. Cofnięcie wykonuje się błyskawicznie, bez ponownego wdrażania — wystarczy zmienić routing.
Canary deployment kieruje niewielką część ruchu na nową wersję i monitoruje metryki: liczbę błędów, czas odpowiedzi, odsetek udanych żądań. Jeśli metryki się pogarszają, system automatycznie cofa canary i kieruje cały ruch na stabilną wersję. Kubernetes i service meshe (Istio, Linkerd) obsługują tę strategię od razu po wyjęciu z pudełka.
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 10
strategy:
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
Rozważmy trzy typowe scenariusze, w których programista musi cofnąć zmiany. Każdy scenariusz wymaga własnego podejścia — od prostej komendy w terminalu do wieloetapowej procedury z udziałem CI/CD.
Przypadkowo wypchnąłeś commit z błędem do main. Twoim zadaniem jest cofnięcie zmian bez utraty historii dla zespołu. Użyj git revert do utworzenia cofającego commitu, a następnie git push. Wszyscy członkowie zespołu zobaczą fakt cofnięcia i będą mogli kontynuować pracę bez konfliktów. To najbezpieczniejszy i najbardziej przejrzysty sposób.
git checkout main
git pull origin main
git revert HEAD
git push origin main
Migracja bazy danych zakończyła się błędem, a część danych została uszkodzona. Użyj transakcyjnego rollback w skrypcie migracyjnym i przywrócenia z kopii zapasowej dla już zastosowanych zmian. W dobrze zaprojektowanym systemie każda migracja jest owinięta w transakcję — przy błędzie SZBD automatycznie wykonuje rollback.
Po wdrożeniu nowej wersji odkryłeś, że nie działa autoryzacja. Jeśli używasz blue-green, cofnięcie to przełączenie routera z powrotem. Jeśli rolling update — komenda kubectl rollout undo przywróci poprzednią wersję. W idealnym przypadku proces cofania powinien być zautomatyzowany i zajmować nie więcej niż minutę.
Często zadawane pytania
Revert tworzy nowy commit cofający zmiany i zachowuje historię. Reset przesuwa wskaźnik gałęzi wstecz i może usunąć commity. Dla wspólnych gałęzi używaj tylko revert.
Jeśli commity nie zostały zebrane przez garbage collector Gita, można je przywrócić przez git reflog. Jednak po czyszczeniu przywrócenie staje się niemożliwe. Używaj --hard tylko w lokalnych gałęziach.
Rollback anuluje wszystkie zmiany dokonane w bieżącej transakcji, używając dziennika zapisu wyprzedzającego (WAL). SZBD przywraca pierwotne wartości dla wszystkich zmodyfikowanych stron danych.
Savepoint — pośredni punkt zapisu wewnątrz transakcji. Pozwala cofnąć się do niego częściowo, bez anulowania całej transakcji. Przydatny w długich operacjach z wieloma krokami.
Skonfiguruj health check i monitorowanie metryk po wdrożeniu. Po przekroczeniu progu błędów uruchamiaj automatyczne cofnięcie przez skrypt lub narzędzie takie jak Spinnaker, ArgoCD lub GitLab Auto Rollback.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również