Jaka jest różnica między „git reset” a „git checkout”?

440

Zawsze o tym myślałem git reset i git checkouttak samo, w tym sensie, że oba przywracają projekt do konkretnego zatwierdzenia. Uważam jednak, że nie mogą być dokładnie takie same, ponieważ byłoby to zbędne. Jaka jest faktyczna różnica między nimi? Jestem trochę zdezorientowany, ponieważ svn musi tylko svn cocofnąć zatwierdzenie.

DODANY

VonC i Charles wyjaśnia różnice między git reseti git checkoutnaprawdę dobrze. Moje obecne rozumienie jest takie, że git resetprzywraca wszystkie zmiany do konkretnego zatwierdzenia, podczas gdy git checkoutmniej więcej przygotowuje się do odgałęzienia. Znalazłem następujące dwa diagramy całkiem przydatne w zrozumieniu:

http://a.imageshack.us/img651/1559/86421927.png http://a.imageshack.us/img801/1986/resetr.png

DODANO 3

Od http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html , kasy i reset mogą emulować rebase.

wprowadź opis zdjęcia tutaj

git checkout bar 
git reset --hard newbar 
git branch -d newbar 

wprowadź opis zdjęcia tutaj

prosseek
źródło
Odp: „Czy to źle, czy nadmiernie uproszczone?” Tak, ten pierwszy schemat wprowadza w błąd co do różnicy między kasą a resetem. (Może być OK w odniesieniu do -- fileswariantów; nie jestem pewien.) Ten schemat pokazuje, że główna różnica polega na tym, czy wpływają one na indeks, czy na WD. Zobacz moją odpowiedź na ten temat. Drugi i trzeci schemat są bardzo pomocne, aby zobaczyć prawdziwą różnicę. Czwarty i piąty schemat są przydatne do sprawdzenia, czy rozumiesz, co robią te polecenia, ale tak naprawdę nie pomoże ci się tam dostać.
LarsH,
Znalazłem sekcję „Sprawdź to” w „Git Tools Reset Demystified”, aby dać najbardziej pomocne podsumowanie.
Josiah Yoder,
1
prosseek: Jeśli zgadzasz się z @LarsH, że pierwszy diagram wprowadza w błąd, czy możesz go usunąć, proszę?
Josiah Yoder,
Należy pamiętać, że kasa i resetowanie tylko emulują drugą część bazy, a dodatkowe kroki (podane w powiązanym think-like-a-git.netartykule) są wymagane, aby zapobiec utracie danych.
cowlinator

Odpowiedzi:

198
  • git resetdotyczy w szczególności aktualizacji indeksu , przesunięcia HEAD.
  • git checkoutdotyczy aktualizacji drzewa roboczego (do indeksu lub określonego drzewa). Zaktualizuje HEAD tylko wtedy, gdy kasujesz gałąź (jeśli nie, kończy się odłączoną HEAD ).
    (w rzeczywistości w przypadku Git 2.23 Q3 2019 nie będzie to git restorekonieczne git checkout)

Dla porównania, ponieważ svn nie ma indeksu, tylko działające drzewo svn checkoutskopiuje daną wersję do osobnego katalogu.
Bliższy odpowiednik dla git checkout:

  • svn update (jeśli jesteś w tej samej gałęzi, co oznacza ten sam adres URL SVN)
  • svn switch (jeśli kasujesz na przykład ten sam oddział, ale z innego adresu URL repozytorium SVN)

Wszystkie te trzy pracujące modyfikacje drzewa ( svn checkout, update, switch) mają tylko jedno polecenie git: git checkout.
Ale ponieważ git ma również pojęcie indeksu („obszaru przejściowego” między repozytorium a działającym drzewem), ty także git reset.


Thinkeye wspomina w komentarzach artykuł „ Reset Demystified ”.

Na przykład, jeśli mamy dwie gałęzie „ master” i „ develop” wskazujące na różne zatwierdzenia, a my jesteśmy obecnie na develop”(więc HEAD wskazuje na to) i biegniemy git reset master, develop” samo będzie teraz wskazywać na to samo zatwierdzenie, które „ master' robi.

Z drugiej strony, jeśli zamiast tego uciekniemy git checkout master, „ develop” się nie poruszy, HEADsam się poruszy . HEADbędzie teraz wskazywać na „master ”.

Tak więc w obu przypadkach zamierzamy HEADwskazać na popełnienie A, ale sposób, w jaki to robimy, jest zupełnie inny. resetprzeniesie HEADpunkty gałęzi do, kasa przesunie HEADsię, aby wskazać inną gałąź.

http://git-scm.com/images/reset/reset-checkout.png

Jednak w tych kwestiach:

LarsH dodaje w komentarzach :

Pierwszy akapit tej odpowiedzi jest jednak mylący: „ git checkout... zaktualizuje HEAD tylko wtedy, gdy przejdziesz do oddziału (jeśli nie, skończysz z odłączonym HEAD)”.
Nieprawda: git checkoutzaktualizuje HEAD, nawet jeśli kasujesz zatwierdzenie, które nie jest gałęzią (i tak, kończy się odłączonym HEAD, ale wciąż jest aktualizowane).

git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novo zgadza się w komentarzach :

@LarsH jest poprawny.
Druga kula ma błędne wyobrażenie o tym, w czym jest HEAD, zaktualizuje HEAD tylko wtedy, gdy kasujesz gałąź.
HEAD idzie gdziekolwiek jesteś, jak cień.
Sprawdzanie niektórych referencji niezwiązanych z gałęziami (np. Znacznika) lub zatwierdzenia bezpośrednio spowoduje przeniesienie HEAD. Odłączona głowa nie oznacza, że ​​odłączyłeś się od HEAD, oznacza to, że głowa jest odłączona od referencji gałęzi, z której możesz zobaczyć np git log --pretty=format:"%d" -1.

  • Dołączone stany głowy zaczną się od (HEAD -> ,
  • odłączony nadal będzie pokazywał (HEAD, ale nie będzie miał strzałki do oznaczenia gałęzi.
VonC
źródło
7
Powiedziałbym, że git resetchodzi o modyfikację „etykiety” gałęzi i opcjonalną aktualizację indeksu lub drzewa roboczego jako efekt uboczny. git checkoutdotyczy aktualizacji działającego drzewa i przełączania aktualnie „wybranej” gałęzi (the HEAD).
Mikko Rantalainen,
2
@MikkoRantalainen nie. git resetjest w 100% na temat HEAD. Działa nawet w odłączonym trybie HEAD ( stackoverflow.com/a/3965714/6309 ), co oznacza, że ​​nie ma gałęzi (!). git checkout działa również w trybie odłączonej HEAD, lub może być użyty do wyewidencjonowania SHA1 w odłączonym trybie HEAD: ponownie żadna gałąź nie jest w tym przypadku zaangażowana.
VonC
3
Dalsza lektura dla wszystkich zagubionych dusz przesłanych tutaj przez wyszukiwarkę, myślę, że warto: git-scm.com/blog/2011/07/11/reset.html
Thinkeye
2
@Thinkeye dobre referencje. Umieściłem go wraz z odpowiednim wyciągiem w odpowiedzi dla większej widoczności.
VonC
2
Wyjaśnienie Reset Demystified jest doskonałe. Pierwszy akapit tej odpowiedzi jest jednak mylący: „git checkout ... zaktualizuje HEAD tylko wtedy, gdy kasujesz gałąź (jeśli nie, to masz odłączoną HEAD)”. Nieprawda ... git checkout zaktualizuje HEAD, nawet jeśli kasujesz zatwierdzenie, które nie jest oddziałem (i tak, kończy się odłączonym HEAD, ale wciąż jest aktualizowane). Może nie rozumiem, co rozumiesz przez „aktualizacja”? git checkout a839e8faktualizuje HEAD, aby wskazywał na zatwierdzenie a839e8f.
LarsH
67

W najprostszej formie resetresetuje indeks bez dotykania działającego drzewa, natomiastcheckout zmienia działające drzewo bez dotykania indeksu.

Resetuje indeks, aby dopasować HEAD, działające drzewo pozostawione w spokoju:

git reset

Koncepcyjnie, to sprawdza indeks do działającego drzewa. Aby to zrobić, musisz zrobić to, -faby wymusić zastąpienie wszelkich lokalnych zmian. Jest to funkcja bezpieczeństwa zapewniająca, że ​​forma „bez argumentów” nie jest destrukcyjna:

git checkout

Po rozpoczęciu dodawania parametrów prawdą jest, że nakładają się na siebie.

checkoutjest zwykle używany z odgałęzieniem, znacznikiem lub zatwierdzeniem. W takim przypadku zresetuje sięHEAD i indeks do danego zatwierdzenia, a także indeksu do działającego drzewa.

Ponadto, jeśli dostarczy --hardsię resetmożna zwrócićreset , aby zastąpić drzewo pracuje jak resetowanie indeksu.

Jeśli obecnie masz sprawdzony oddział, istnieje zasadnicza różnica między nimi reset i checkoutkiedy podasz alternatywny oddział lub zatwierdzasz. resetzmieni bieżącą gałąź, aby wskazywała na wybrane zatwierdzenie, podczas gdy checkoutpozostawi bieżącą gałąź w spokoju, ale zamiast tego pobierze dostarczoną gałąź lub zatwierdzenie.

Inne formy reseti commitścieżki zaopatrzenia.

Jeśli podasz ścieżki do reset , nie możesz podać --hardi resetzmienisz tylko wersję indeksu dostarczonych ścieżek do wersji w dostarczonym zatwierdzeniu (lub HEADjeśli nie określisz zatwierdzenia).

Jeśli podasz ścieżki do checkout, resetto tak jak zaktualizuje wersję indeksu podanych ścieżek, aby pasowała do podanego zatwierdzenia (lub HEAD), ale zawsze będzie pobierać wersję indeksu podanych ścieżek do działającego drzewa.

CB Bailey
źródło
2
Nie jest prawdą stwierdzenie, że „kasa” nie zmienia indeksu: zmienia go, gdy jest używany do przechodzenia z jednej gałęzi do drugiej.
wiki1000
W najprostszej formie reset resetuje indeks bez dotykania działającego drzewa, natomiast kasa zmienia działające drzewo bez dotykania indeksu. : Jakie to mylące: |
Aditya Gupta,
41

Jeden prosty przypadek użycia podczas
cofania zmiany: 1. Użyj resetowania, jeśli chcesz cofnąć inscenizację zmodyfikowanego pliku.
2. Użyj kasy, jeśli chcesz odrzucić zmiany w niestabilnych plikach.

nieznany z nazwiska
źródło
1
Idealna odpowiedź. Dziękuję Ci.
user358591,
11

Najważniejsza różnica w pigułce polega na tym, że reset przenosi bieżące odniesienie do gałęzi , natomiastcheckout nie przesuwa (przesuwa HEAD).

Jak wyjaśnia książka Pro Git w temacie Reset Demystified ,

Pierwszą rzeczą reset, którą należy zrobić, jest przesunięcie tego, na co wskazuje HEAD . To nie jest to samo, co sama zmiana HEAD (co checkoutrobi); reset przesuwa gałąź, na którą wskazuje HEAD. Oznacza to, że jeśli HEAD jest ustawiony na mastergałąź (tzn. Jesteś obecnie w mastergałęzi), bieganie git reset 9e5e6a4rozpocznie się od masterwskazania na 9e5e6a4. [podkreślenie dodane]

Zobacz także odpowiedź VonC na bardzo pomocny fragment tekstu i diagramu z tego samego artykułu, którego tutaj nie powielę.

Oczywiście jest o wiele więcej szczegółów na temat tego, jakie efekty checkouti jakie resetmogą mieć na indeks i drzewo robocze, w zależności od używanych parametrów. Istnieje wiele podobieństw i różnic między tymi dwoma poleceniami. Ale, jak widzę, najważniejsza różnica polega na tym, czy poruszają wierzchołkiem bieżącej gałęzi.

LarsH
źródło
2
Dobra opinia, oprócz mojej starszej odpowiedzi. +1
VonC
2

Te dwa polecenia (reset i kasy) są całkowicie różne.

checkout X NIE JEST reset --hard X

Jeśli X jest nazwą gałęzi, checkout Xzmieni bieżącą gałąź, a reset --hard Xnie zmieni.

wiki1000
źródło
2
Ale jeśli X jest plikiem lub folderem, to są takie same.
Ted Bigham
1

krótkie mnemoniki:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
Филя Усков
źródło