Cofanie commitów i zmian
W tej sekcji omówimy strategie i polecenia „cofania” dostępne w Git. Na wstępnie zaznaczmy, że w Git nie ma tradycyjnego systemu „cofania”, jak na przykład w edytorze tekstu. Warto powstrzymać się przed odwzorowywaniem operacji Git na dowolny tradycyjny model mentalny „cofania”. Ponadto Git stosuje własną nomenklaturę operacji „cofania”, z której najlepiej korzystać w dyskusji. Obejmuje ona pojęcia, takie jak resetowanie, przywracanie, wyewidencjonowanie, czyszczenie itp.
Oryginalnym spojrzeniem na Git może być potraktowanie go jako narzędzia do zarządzania osią czasu. Commity są migawkami momentów w czasie lub punktów zainteresowania wzdłuż osi czasu historii projektu. Dodatkowo możliwe jest zarządzanie wieloma osiami czasu dzięki wykorzystaniu gałęzi. Gdy wykonujesz operację „cofania” w Git, zwykle przechodzisz wstecz w czasie lub do innej osi czasu, gdzie błędy nie wystąpiły.
W tym samouczku omawiamy wszystkie umiejętności niezbędne do pracy z wcześniejszymi rewizjami projektu oprogramowania. Na początku pokazujemy, jak przeglądać stare commity, a następnie wyjaśniamy różnicę między przywracaniem publicznych commitów w historii projektu a resetowaniem niepublikowanych zmian na komputerze lokalnym.
Znajdowanie tego, co zostało utracone: przeglądanie starych commitów
Założeniem każdego systemu kontroli wersji jest przechowywanie „bezpiecznych” kopii projektu, dzięki czemu nie trzeba się martwić o nieodwracalne uszkodzenie bazy kodu. Po utworzeniu historii commitów w projekcie możesz przejrzeć wszystkie commity w historii i przejść do wybranych z nich. Jednym z najlepszych narzędzi do przeglądania historii repozytorium Git jest polecenie git log
. W poniższym przykładzie wykorzystujemy git log, aby uzyskać listę najnowszych commitów do popularnej biblioteki graficznej open source.
git log --oneline
e2f9a78fe Replaced FlyControls with OrbitControls
d35ce0178 Editor: Shortcuts panel Safari support.
9dbe8d0cf Editor: Sidebar.Controls to Sidebar.Settings.Shortcuts. Clean up.
05c5288fc Merge pull request #12612 from TyLindberg/editor-controls-panel
0d8b6e74b Merge pull request #12805 from harto/patch-1
23b20c22e Merge pull request #12801 from gam0022/improve-raymarching-example-v2
fe78029f1 Fix typo in documentation
7ce43c448 Merge pull request #12794 from WestLangley/dev-x
17452bb93 Merge pull request #12778 from OndrejSpanel/unitTestFixes
b5c1b5c70 Merge pull request #12799 from dhritzkiv/patch-21
1b48ff4d2 Updated builds.
88adbcdf6 WebVRManager: Clean up.
2720fbb08 Merge pull request #12803 from dmarcos/parentPoseObject
9ed629301 Check parent of poseObject instead of camera
219f3eb13 Update GLTFLoader.js
15f13bb3c Update GLTFLoader.js
6d9c22a3b Update uniforms only when onWindowResize
881b25b58 Update ProjectionMatrix on change aspect
materiały pokrewne
Git — ściągawka
POZNAJ ROZWIĄZANIE
Poznaj środowisko Git z rozwiązaniem Bitbucket Cloud
Każdy commit ma unikatowy skrót identyfikujący SHA-1. Te identyfikatory służą do nawigowania po osi czasu i ponownego odwiedzania commitów. Domyślnie polecenie git log
pokazuje tylko commity dla aktualnie wybranej gałęzi. Może się zdarzyć, że commit, którego szukasz, znajduje się w innej gałęzi. Aby wyświetlić wszystkie commity we wszystkich gałęziach, możesz wykonać polecenie git log --branches=*
. Polecenie git branch służy do wyświetlania i odwiedzania innych gałęzi. Wywołanie polecenia git branch -a
powoduje zwrócenie listy wszystkich znanych nazw gałęzi. Dla jednej z tych nazw gałęzi można następnie wyświetlić dziennik, korzystając z polecenia git log
.
Jeśli znajdziesz referencję commita do punktu w historii, który chcesz odwiedzić, możesz użyć polecenia git checkout
, aby przejść do tego commita. Polecenie git checkout
stanowi łatwy sposób na „załadowanie” którejkolwiek z tych zapisanych migawek na komputerze używanym do programowania. W trakcie standardowego przebiegu procesu programistycznego HEAD
zwykle wskazuje na gałąź główną (main
) lub inną gałąź lokalną, ale po wyewidencjonowaniu wcześniejszego commita HEAD
nie wskazuje już na gałąź, lecz bezpośrednio na commit. Jest to tak zwany stan „odłączonego wskaźnika HEAD
”, który można zwizualizować w następujący sposób:
Wyewidencjonowanie starego pliku nie powoduje przeniesienia wskaźnika HEAD
. Pozostaje on w tej samej gałęzi i w tym samym commicie, dzięki czemu nie dochodzi do stanu „odłączonego wskaźnika”. Następnie możesz wykonać commit starej wersji pliku w nowej migawce, tak jak w przypadku innych zmian. Oznacza to, że to zastosowanie polecenia git checkout
do pliku stanowi sposób na przywrócenie starej wersji pojedynczego pliku. Więcej informacji o tych dwóch trybach można znaleźć na stronie git checkout
Wyświetlanie starej wersji
W tym przykładzie założono, że rozpoczęto pewien szalony (crazy) eksperyment, ale nie masz pewności, czy chcesz go zachować. Aby podjąć decyzję, chcesz przyjrzeć się stanowi projektu sprzed rozpoczęcia eksperymentu. Najpierw musisz znaleźć identyfikator rewizji, którą chcesz wyświetlić.
git log --oneline
Załóżmy, że historia projektu wygląda mniej więcej tak:
b7119f2 Continue doing crazy things
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
Możesz użyć polecenia git checkout
, aby wyświetlić commit „Make some import changes to hello.txt”, w następujący sposób:
git checkout a1e8fb5
Dzięki temu katalog roboczy będzie dokładnie odpowiadał stanowi commita a1e8fb5
. Możesz przejrzeć pliki, skompilować projekt, uruchomić testy, a nawet edytować pliki bez obawy o utratę bieżącego stanu projektu. Nic, co tu zrobisz, nie zostanie zapisane w repozytorium. Aby kontynuować programowanie, musisz wrócić do „aktualnego” stanu projektu:
git checkout main
Założono tutaj, że programujesz w domyślnej gałęzi głównej (main
). Po powrocie do gałęzi main
możesz użyć polecenia git revert lub git reset, aby cofnąć wszelkie niepożądane zmiany.
Cofanie migawki, dla której wykonano commit
Z technicznego punktu widzenia istnieje kilka różnych strategii „cofania” commita. W poniższych przykładach założono, że mamy historię commitów, która wygląda następująco:
git log --oneline
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
Skoncentrujemy się na cofnięciu commita 872fa7e Try something crazy
. Być może eksperyment okazał się zbyt szalony.
Cofanie commita za pomocą polecenia git checkout
Za pomocą polecenia git checkout
możemy wyewidencjonować wcześniejszy commit, a1e8fb5
, umieszczając repozytorium w stanie sprzed szalonego commita (crazy). Wyewidencjonowanie konkretnego commita spowoduje umieszczenie repozytorium w stanie „odłączonego wskaźnika HEAD”. Oznacza to, że nie pracujesz już w żadnej gałęzi. W stanie odłączonym wszelkie nowe commity, które wykonasz, zostaną osierocone po zmianie gałęzi z powrotem na ustaloną gałąź. Osierocone commity są przeznaczone do usunięcia przez narzędzie usuwania zbędnych elementów Git. Narzędzie usuwania zbędnych elementów działa w skonfigurowanych odstępach czasu i trwale niszczy osierocone commity. Aby zapobiec usuwaniu osieroconych commitów, musimy upewnić się, że jesteśmy w gałęzi.
W stanie odłączonego wskaźnika HEAD możemy wykonać polecenie git checkout -b new_branch_without_crazy_commit
. Spowoduje to utworzenie nowej gałęzi o nazwie new_branch_without_crazy_commit
i przełączenie do tego stanu. Repozytorium znajduje się teraz na nowej osi czasu historii, w której commit 872fa7e
już nie istnieje. Teraz możemy kontynuować prace w tej nowej gałęzi, w której commit 872fa7e
już nie istnieje, i uznać go za „cofnięty”. Niestety jeśli potrzebujesz poprzedniej gałęzi, na przykład dlatego, że była to Twoja gałąź main
, ta strategia cofania nie jest właściwa. Przyjrzymy się innym strategiom „cofania”. Aby uzyskać więcej informacji i przykładów, zapoznaj się z naszym szczegółowym omówieniem polecenia git checkout.
Cofanie publicznego commita za pomocą polecenia git revert
Załóżmy, że wróciliśmy do naszego pierwotnego przykładu historii commitów. Ta historia zawiera commit 872fa7e
. Tym razem spróbujmy wykonać „cofnięcie” metodą przywracania. Jeśli wykonamy polecenie git revert HEAD
, w Git zostanie utworzony nowy commit z odwrotnością ostatniego commita. Spowoduje to dodanie nowego commita do bieżącej historii gałęzi i sprawi, że kod będzie wyglądać następująco:
git log --oneline
e2f9a78 Revert "Try something crazy"
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
W tym momencie w sensie technicznym znów udało nam się „cofnąć” commit 872fa7e
. Chociaż 872fa7e
nadal istnieje w historii, nowy commit e2f9a78
jest odwrotnością zmian w 872fa7e
. W przeciwieństwie do naszej poprzedniej strategii wyewidencjonowywania możemy nadal korzystać z tej samej gałęzi. To rozwiązanie jest zadowalającą metodą cofania. Idealnie sprawdza się w przypadku pracy z publicznymi współdzielonymi repozytoriami. Natomiast jeśli musisz zachować wyselekcjonowaną i minimalną historię Git, ta strategia może nie być odpowiednia.
Cofanie commita za pomocą polecenia git reset
W przypadku tej strategii cofania będziemy nadal używać naszego przykładu roboczego. git reset jest rozbudowanym poleceniem o wielu zastosowaniach i funkcjach. Jeśli wywołamy polecenie git reset --hard a1e8fb5
, historia commitów zostanie zresetowana do określonego commita. Sprawdzenie historii commitów za pomocą polecenia git log
będzie teraz wyglądać następująco:
git log --oneline
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
Dane dziennika pokazują, że commity e2f9a78
i 872fa7e
nie występują już w historii commitów. Teraz możemy kontynuować pracę i tworzyć nowe commity, tak jakby szalone commity nigdy nie powstały. Ta metoda cofania zmian pozwala uzyskać najczystszy wynik w historii. Wykonanie resetu świetne sprawdza się w przypadku lokalnych zmian, jednak powoduje komplikacje podczas pracy ze współdzielonym zdalnym repozytorium. Jeśli mamy współdzielone zdalne repozytorium, które zawiera commit 872fa7e
, i spróbujemy wykonać polecenie git push
dla gałęzi, w której zresetowaliśmy historię, Git wyłapie to i zgłosi błąd. Git zakłada, że wypychana gałąź nie jest aktualna ze względu na brakujące commity. W tych scenariuszach preferowaną metodą cofania powinno być polecenie git revert
.
Cofanie ostatniego commita
W poprzedniej sekcji omówiliśmy różne strategie cofania commitów. Wszystkie mają zastosowanie również do najnowszego commita. Jednak w niektórych przypadkach usuwanie lub resetowanie ostatniego commita może nie być konieczne. Może po prostu został on wykonany przedwcześnie. W takim przypadku możesz zmienić ostatni commit. Po wprowadzeniu dalszych zmian w katalogu roboczym i umieszczeniu ich w środowisku przejściowym w celu wykonania commita za pomocą polecenia git add możesz wykonać polecenie git commit --amend
. Dzięki temu Git otworzy skonfigurowany edytor systemowy i pozwoli na zmodyfikowanie komunikatu dotyczącego ostatniego commita. Nowe zmiany zostaną dodane do zmienionego commita.
Cofanie niezatwierdzonych zmian
Zanim zmiany zostaną wprowadzone do historii repozytorium, znajdują się w indeksie środowiska przejściowego i katalogu roboczym. Może być konieczne wycofanie zmian w tych dwóch obszarach. Indeks środowiska przejściowego i katalog roboczy są wewnętrznymi mechanizmami zarządzania stanem Git. Aby uzyskać bardziej szczegółowe informacje o działaniu tych dwóch mechanizmów, odwiedź stronę git reset, na której zostały dogłębnie omówione.
Katalog roboczy
Katalog roboczy jest zazwyczaj zsynchronizowany z lokalnym systemem plików. Aby cofnąć zmiany w katalogu roboczym, możesz edytować pliki tak, jak zwykle robisz to przy użyciu ulubionego edytora. Git oferuje kilka narzędzi, które pomagają zarządzać katalogiem roboczym. Jest dostępne polecenie git clean, które jest wygodnym narzędziem do cofania zmian w katalogu roboczym. Ponadto wywołanie polecenia git reset
z opcją --mixed
lub --hard
powoduje zresetowanie katalogu roboczego.
Indeks przechowalni
Polecenie git add służy do dodawania zmian do indeksu środowiska przejściowego. Polecenie git reset
służy przede wszystkim do cofania zmian indeksu środowiska przejściowego. Reset z opcją --mixed
powoduje przeniesie wszelkich oczekujących zmian z indeksu środowiska przejściowego z powrotem do katalogu roboczego.
Cofanie zmian publicznych
Podczas pracy w zespole ze zdalnymi repozytoriami cofanie zmian wymaga zachowania szczególnej uwagi. Polecenie git reset
należy zasadniczo uznać za „lokalną” metodę cofania. Podczas cofania zmian w gałęzi prywatnej należy korzystać z resetowania. Pozwala to na bezpieczne odizolowanie operacji usuwania commitów od innych gałęzi, które mogą być używane przez innych programistów. Problemy pojawiają się, gdy reset jest wykonywany na współdzielonej gałęzi, a ta gałąź jest następnie wypychana zdalnie za pomocą polecenia git push
. W tej sytuacji Git zablokuje polecenie push, zgłaszając, że wypychana gałąź jest nieaktualna względem gałęzi zdalnej, ponieważ brakuje w niej commitów.
Preferowaną metodą cofania w przypadku współdzielonej historii jest polecenie git revert
. Przywracanie jest bezpieczniejsze niż resetowanie, ponieważ nie powoduje usunięcia żadnych commitów ze współdzielonej historii. Przywracanie zachowuje commity, które chcesz cofnąć, i tworzy nowy commit, który odwraca niepożądany commit. Ta metoda jest bezpieczniejsza w przypadku współpracy w ramach współdzielonego zdalnego repozytorium, ponieważ programista pracujący zdalnie może ściągnąć gałąź i uzyskać nowy commit, który cofa niepożądany commit.
Podsumowanie
Omówiliśmy szereg ogólnych strategii umożliwiających cofanie w Git. Warto pamiętać, że w projekcie Git można wykonać „cofnięcie” na więcej niż jeden sposób. Większość kwestii poruszonych na tej stronie zahacza o obszerniejsze zagadnienia, które wyjaśniono dokładniej na stronach poświęconych odpowiednim poleceniom Git. Najczęściej używanymi narzędziami „cofania” są polecenia git checkout, git revert i git reset. Kilka kluczowych kwestii do zapamiętania:
- Po zatwierdzeniu zmian są one na ogół trwałe.
- Polecenie
git checkout
pozwala poruszać się po historii commitów i przeglądać ją. - Polecenie
git revert
jest najlepszym narzędziem do cofania współdzielonych zmian publicznych. - Polecenie
git reset
najlepiej sprawdza się w przypadku cofania lokalnych zmian prywatnych.
Oprócz podstawowych poleceń cofania przyjrzeliśmy się innym narzędziom Git: git log do znajdowania utraconych commitów, git clean do cofania niezatwierdzonych zmian oraz git add do modyfikowania indeksu środowiska przejściowego.
Każde z tych poleceń ma własną szczegółową dokumentację. Aby dowiedzieć się więcej o konkretnym wymienionym tutaj poleceniu, kliknij odpowiednie łącza.
Udostępnij ten artykuł
Następny temat
Zalecane lektury
Dodaj te zasoby do zakładek, aby dowiedzieć się więcej na temat rodzajów zespołów DevOps lub otrzymywać aktualności na temat metodyki DevOps w Atlassian.