Resetting, checking out & reverting
The git reset, git checkout, and git revert commands are some of the most useful tools in your Git toolbox. They all let you undo some kind of change in your repository, and the first two commands can be used to manipulate either commits or individual files.
Ponieważ są tak do siebie podobne, bardzo łatwo jest zapomnieć, które polecenie należy zastosować w danym przypadku. W tym artykule porównamy najpopularniejsze konfiguracje git reset
, git checkout
i git revert
. Mamy nadzieję, że po przeczytaniu tego tekstu nabierzesz pewności siebie w poruszaniu się po repozytorium za pomocą każdego z tych poleceń.
It helps to think about each command in terms of their effect on the three state management mechanisms of a Git repository: the working directory, the staged snapshot, and the commit history. These components are sometimes known as "The three trees" of Git. We explore the three trees in depth on the git reset page. Keep these mechanisms in mind as you read through this article.
Wyewidencjonowanie to operacja, która przesuwa wskaźnik odnośnika HEAD
do określonego commitu. Aby to zademonstrować, rozważmy następujący przykład.
materiały pokrewne
Jak przenieść pełne repozytorium Git
POZNAJ ROZWIĄZANIE
Poznaj środowisko Git z rozwiązaniem Bitbucket Cloud
Powyższy przykład przedstawia sekwencję commitów na gałęzi main
. Odwołania HEAD
i main
wskazują obecnie na commit d. Wykonajmy teraz polecenie git checkout b
.
Na ilustracji widzimy aktualizację drzewa „historii commitów”. Polecenie git checkout
można zastosować na poziomie commitu lub na poziomie pliku. Wyewidencjonowanie na poziomie pliku zmieni jego zawartość na zawartość określonego commitu.
Przywrócenie to operacja, która powoduje pobranie określonego commitu i utworzenie nowego, odwracającego ten poprzedni. Polecenie git revert
można uruchamiać tylko w zakresie poziomu commitu i nie obejmuje funkcjonalności poziomu pliku.
Resetowanie to operacja, która powoduje przywrócenie „trzech drzew” do takiego stanu, aby pasowały do repozytorium dla określonego commitu. Reset można wywołać w trzech różnych trybach, które odpowiadają poszczególnym drzewom.
Wyewidencjonowanie i reset zwykle używa się do dokonywania lokalnych lub prywatnych „cofnięć”. Modyfikują historię repozytorium, co może powodować konflikty podczas przepychania do zdalnych repozytoriów współdzielonych. Przywrócenie uznaje się za bezpieczniejsze rozwiązanie do „cofnięć publicznych”, ponieważ tworzy nową historię, która może być udostępniana zdalnie i nie nadpisuje dotychczasowej, od której mogą być zależni zdalni członkowie zespołu.
Git reset vs revert vs checkout reference
Poniższa tabela stanowi podsumowanie najczęstszych przypadków użycia każdego z tych poleceń. Warto zawsze ją mieć pod ręką, ponieważ może się nieraz przydać podczas używania systemu Git.
Polecenie | Zakres | Popularne przykłady zastosowania |
---|---|---|
| Zakres Poziom commitu | Popularne przykłady zastosowania Discard commits in a private branch or throw away uncommitted changes |
| Zakres Poziom pliku | Popularne przykłady zastosowania Wycofanie pliku z przechowalni |
| Zakres Poziom commitu | Popularne przykłady zastosowania Przełączanie między gałęziami lub przeglądanie starszych migawek |
| Zakres Poziom pliku | Popularne przykłady zastosowania Odrzucenie zmian w katalogu roboczym |
| Zakres Poziom commitu | Popularne przykłady zastosowania Cofnięcie commitów w gałęzi publicznej |
| Zakres Poziom pliku | Popularne przykłady zastosowania (nie dotyczy) |
Commit level operations
Parametry, które przekazujesz do poleceń git reset
i git checkout
, określają ich zakres. Jeśli nie uwzględnisz ścieżki pliku jako parametru, operują na całych commitach. To właśnie będziemy omawiać w tej sekcji. Zauważ, że polecenie git revert
nie ma odpowiednika na poziomie pliku.
Reset a specific commit
Na poziomie commitu resetowanie służy do przesunięcia końcówki gałęzi do innego commitu. Można to wykorzystać do usunięcia commitów z bieżącej gałęzi. Na przykład poniższe polecenie przesuwa gałąź hotfix
do tyłu o dwa commity.
git checkout hotfix git reset HEAD~2
Dwa commity, które znajdowały się na końcu gałęzi hotfix
, to teraz commity „zwisające” lub „osierocone”. Oznacza to, że zostaną usunięte następnym razem, gdy Git wykona procedurę eliminacji zbędnych elementów. Innymi słowy zaznaczasz, że chcesz się pozbyć tych commitów. Można to zwizualizować w następujący sposób:
Ten sposób użycia git reset
stanowi prostą metodę cofnięcia zmian, które nie zostały jeszcze udostępnione nikomu innemu. To przydatne polecenie na wypadek, gdy zaczniesz pracować nad funkcją, ale nagle pomyślisz „O kurczę, co ja robię? Muszę zacząć od nowa”.
Oprócz przeniesienia bieżącej gałęzi możesz również użyć git reset
do modyfikacji migawki w przechowalni i/lub katalogu roboczego przez przekazanie jednej z następujących flag:
--soft
— migawka w przechowalni i katalog roboczy nie zostają zmienione w żaden sposób.—mixed
— migawka w przechowalni zostaje aktualizowana tak, aby pasowała do określonego commitu, ale katalog roboczy nie ulega zmianie. To jest opcja domyślna.—hard
— migawka w przechowalni i katalog roboczy zostają aktualizowane tak, aby pasowały do określonego commitu.
It’s easier to think of these modes as defining the scope of a git reset
operation. For further detailed information visit the git reset page.
Wyewidencjonowanie starych commitów
Polecenie git checkout
służy do aktualizacji stanu repozytorium do określonego punktu w historii projektu. W przypadku przekazania z nazwą gałęzi umożliwia przełączanie się między gałęziami.
git checkout hotfix
Wewnętrznie, jedynym efektem powyższego polecenia jest przeniesienie wskaźnika HEAD
do innej gałęzi i uaktualnienie katalogu roboczego, aby do niej pasował. Ponieważ może to spowodować nadpisanie lokalnych zmian, system Git wymusza na użytkowniku zatwierdzenie lub dodanie do schowka zmian w katalogu roboczym, które zostaną utracone podczas operacji wyewidencjonowania. W przeciwieństwie do git reset
polecenie git checkout
nie przenosi gałęzi.
Możesz także wyewidencjonować dowolne commity przez przekazanie odniesień do commitów zamiast gałęzi. Daje to ten sam efekt co wyewidencjonowanie gałęzi: przenosi odniesienie HEAD
do określonego commitu. Na przykład następujące polecenie spowoduje wyewidencjonowanie elementu nadrzędnego w drugim stopniu względem bieżącego commitu:
git checkout HEAD~2
Przydaje się to do uzyskania szybkiego podglądu starszej wersji projektu. Ponieważ nie ma jednak odniesienia gałęzi do bieżącego wskaźnika HEAD
, to powoduje ustawienie w stanie odłączonego wskaźnika HEAD
. Może to być problematyczne w przypadku dodawania nowych commitów, ponieważ nie będzie możliwości powrotu do nich po przejściu na inną gałąź. Z tego względu przed dodaniem commitów do odłączonego wskaźnika HEAD
zawsze należy utworzyć nową gałąź.
Undo public commits with revert
Przywrócenie powoduje cofnięcie commitu przez utworzenie nowego commitu. To bezpieczny sposób cofania zmian, ponieważ nie grozi nadpisaniem historii commitów. Na przykład poniższe polecenie spowoduje wyszukanie zmian zawartych w przedostatnim commicie, utworzenie nowego commitu cofającego te zmiany oraz dołączenie nowego commitu do istniejącego projektu.
git checkout hotfix git revert HEAD~2
Można to zwizualizować w następujący sposób:
Porównaj to z poleceniem git reset
, które zmienia istniejącą historię commitów. Z tego względu do cofania zmian w gałęzi publicznej należy używać polecenia git revert
, zaś git reset
powinno służyć wyłącznie do cofania zmian w gałęzi prywatnej.
Można powiedzieć, że git revert
to narzędzie do cofania zatwierdzonych zmian, podczas gdy git reset HEAD
służy do cofania zmian niezatwierdzonych.
Tak samo jak git checkout
polecenie git revert
może nadpisać pliki w katalogu roboczym, dlatego poprosi o zatwierdzenie lub dodanie do schowka zmian, które mogłyby zostać utracone podczas operacji przywracania.
File-level operations
Polecenia git reset
i git checkout
również dopuszczają opcjonalną ścieżkę pliku jako parametr. To znacząco zmienia ich działanie. Zamiast działać na całych migawkach, zostają zmuszone do ograniczenia zakresu do pojedynczego pliku.
Git reset a specific file
Po wywołaniu ze ścieżką pliku polecenie git reset
aktualizuje migawkę w przechowalni tak, aby pasowała do wersji z określonego commitu. Na przykład polecenie to powoduje pobranie wersji foo.py
w przedostatnim commicie i jej przeniesienie do przechowalni na potrzeby następnego commitu:
git reset HEAD~2 foo.py
Podobnie jak w przypadku git reset
na poziomie commitu rozwiązanie to częściej stosuje się względem wskaźnika HEAD
niż dowolnie wybranego commitu. Uruchomienie polecenia git reset HEAD foo.py
spowoduje cofnięcie pliku foo.py
z przechowalni. Zawarte w nim zmiany będą nadal obecne w katalogu roboczym.
Flagi --soft
, --mixed
i --hard
nie mają wpływu na git reset
na poziomie plików, ponieważ migawka w przechowalni jest zawsze aktualizowana, a katalog roboczy nigdy nie jest aktualizowany.
Git checkout file
Wyewidencjonowanie pliku przypomina użycie polecenia git reset
ze ścieżką pliku, z tym, że aktualizuje katalog roboczy zamiast przechowalni. W przeciwieństwie do polecenia na poziomie commitu nie powoduje to przesunięcia odniesienia HEAD
, więc nie będzie możliwe przełączanie między gałęziami.
Na przykład poniższe polecenie powoduje dopasowanie pliku foo.py
w katalogu roboczym do tego z przedostatniego commitu:
git checkout HEAD~2 foo.py
Podobnie jak wywołanie git checkout
na poziomie commitu może to być używane do sprawdzania starszych wersji projektu — zakres ograniczony jest jednak do określonego pliku.
Gdy przenosisz do przechowalni i zatwierdzasz wyewidencjonowany plik, daje to efekt „przywrócenia” jego starszej wersji. Oznacza to usunięcie wszystkich kolejnych zmian w pliku, podczas gdy polecenie git revert
cofa wyłącznie zmiany wprowadzone przez określony commit.
Podobnie jak git reset
polecenie to jest powszechnie używane wraz ze wskaźnikiem HEAD
jako odniesienie do commitu. Na przykład polecenie git checkout HEAD foo.py
powoduje odrzucenie zmian spoza przechowalni w pliku foo.py
. Jest to zachowanie podobne, jak w przypadku polecenia git reset HEAD --hard
, ale dotyczy tylko określonego pliku.
Podsumowanie
You should now have all the tools you could ever need to undo changes in a Git repository. The git reset, git checkout, and git revert commands can be confusing, but when you think about their effects on the working directory, staged snapshot, and commit history, it should be easier to discern which command fits the development task at hand.
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.