Widziałem ciekawe posty wyjaśniające subtelności git reset
.
Niestety, im więcej o tym czytam, tym bardziej wydaje się, że nie rozumiem go w pełni. Pochodzę z SVN, a Git to zupełnie nowy paradygmat. Łatwo dostałem rtęć, ale Git jest o wiele bardziej techniczny.
Myślę, że git reset
jest blisko hg revert
, ale wydaje się, że istnieją różnice.
Co dokładnie robi git reset
? Proszę podać szczegółowe wyjaśnienia dotyczące:
- opcje
--hard
,--soft
a--merge
; - dziwna notacja, której używasz, na
HEAD
przykładHEAD^
iHEAD~1
; - konkretne przypadki użycia i przepływy pracy;
- konsekwencje dla kopii roboczej
HEAD
oraz globalnego poziomu stresu.
Odpowiedzi:
Ogólnie rzecz biorąc,
git reset
funkcja polega na pobraniu bieżącej gałęzi i zresetowaniu jej, aby wskazywała gdzieś indziej, i ewentualnie zabraniu ze sobą indeksu i drzewa roboczego. Mówiąc konkretniej, jeśli twoja główna gałąź (obecnie wypisana) wygląda następująco:i zdajesz sobie sprawę, że chcesz, aby mistrz wskazywał na B, a nie na C, użyjesz
git reset B
go tam:Dygresja: różni się od kasy. Gdybyś biegł
git checkout B
, dostałbyś to:Skończyło się na odłączeniu HEAD.
HEAD
, drzewo pracy, indeksuj wszystkie pasująceB
, ale gałąź master pozostała w miejscuC
. Jeśli dokonasz nowego zatwierdzeniaD
w tym momencie, otrzymasz to, co prawdopodobnie nie jest tym, czego chcesz:Pamiętaj, że reset nie dokonuje zatwierdzeń, po prostu aktualizuje gałąź (która jest wskaźnikiem zatwierdzenia), aby wskazać inne zatwierdzenie. Reszta to tylko szczegóły tego, co dzieje się z twoim indeksem i drzewem pracy.
Przypadków użycia
Omawiam wiele głównych przypadków użycia w
git reset
ramach moich opisów różnych opcji w następnej sekcji. Można go naprawdę używać do wielu różnych rzeczy; wspólny wątek polega na tym, że wszystkie wymagają resetowania gałęzi, indeksu i / lub drzewa roboczego, aby wskazać / dopasować dane zatwierdzenie.Rzeczy, na które należy uważać
--hard
może spowodować, że naprawdę stracisz pracę. Zmienia twoje drzewo pracy.git reset [options] commit
może powodować (poniekąd) utratę zatwierdzeń. W powyższym przykładzie zabawki straciliśmy zatwierdzenieC
. Nadal jest w repozytorium i można go znaleźć, patrząc nagit reflog show HEAD
lubgit reflog show master
, ale w rzeczywistości nie jest już dostępny z żadnej gałęzi.Git trwale usuwa takie zatwierdzenia po 30 dniach, ale do tego czasu możesz odzyskać C, ponownie wskazując na niego gałąź (
git checkout C; git branch <new branch name>
).Argumenty
Parafrazując stronę podręcznika, najczęstszym zastosowaniem jest forma
git reset [<commit>] [paths...]
, która zresetuje podane ścieżki do ich stanu z podanego zatwierdzenia. Jeśli ścieżki nie zostaną podane, całe drzewo zostanie zresetowane, a jeśli zatwierdzenie nie zostanie podane, zostanie uznane za HEAD (bieżące zatwierdzenie). Jest to powszechny wzór w poleceniach git (np. Checkout, diff, log, choć dokładna semantyka jest różna), więc nie powinno być zbyt zaskakujące.Na przykład
git reset other-branch path/to/foo
resetuje wszystko w ścieżce / do / foo do stanu w innej gałęzi,git reset -- .
resetuje bieżący katalog do stanu w HEAD, a prostygit reset
resetuje wszystko do stanu w HEAD.Główne drzewo pracy i opcje indeksu
Istnieją cztery główne opcje kontrolowania tego, co dzieje się z drzewem pracy i indeksem podczas resetowania.
Pamiętaj, że indeks jest „obszarem przejściowym” gita - tam gdzie idą rzeczy, kiedy mówisz
git add
w ramach przygotowań do zatwierdzenia.--hard
dopasowuje wszystko do zatwierdzonego resetu. Prawdopodobnie jest to najłatwiejszy do zrozumienia. Wszystkie lokalne zmiany zostaną zablokowane. Jednym z podstawowych zastosowań jest zdmuchnięcie twojej pracy, ale nie zmiana zatwierdzeń:git reset --hard
oznaczagit reset --hard HEAD
, tzn. Nie zmieniaj gałęzi, ale pozbądź się wszystkich lokalnych zmian. Drugim jest po prostu przenoszenie gałęzi z jednego miejsca do drugiego i utrzymywanie synchronizacji drzewa indeksu / pracy. Jest to ten, który może naprawdę spowodować utratę pracy, ponieważ modyfikuje twoje drzewo pracy. Bądź bardzo pewny, że chcesz odrzucić pracę lokalną, zanim ją uruchomiszreset --hard
.--mixed
jest wartością domyślną, tj .git reset
oznaczagit reset --mixed
. Resetuje indeks, ale nie drzewo robocze. Oznacza to, że wszystkie twoje pliki są nienaruszone, ale wszelkie różnice między oryginalnym zatwierdzeniem a tym, którego zresetowałeś, pojawią się jako lokalne modyfikacje (lub nieśledzone pliki) ze statusem git. Użyj tego, gdy zdasz sobie sprawę, że popełniłeś złe błędy, ale chcesz zachować całą pracę, którą wykonałeś, aby to naprawić i ponownie uruchomić. Aby zatwierdzić, musisz ponownie dodać pliki do indeksu (git add ...
).--soft
nie dotyka indeksu ani drzewa pracy. Wszystkie twoje pliki są nienaruszone jak przy--mixed
, ale wszystkie zmiany pokazują się jakchanges to be committed
przy statusie git (tj. Sprawdzone w przygotowaniu do zatwierdzenia). Użyj tego, gdy zdasz sobie sprawę, że popełniłeś złe błędy, ale praca jest dobra - wszystko, co musisz zrobić, to ponownie ją uruchomić. Indeks jest nietknięty, więc możesz zatwierdzić natychmiast, jeśli chcesz - wynikowe zatwierdzenie będzie miało taką samą treść, jak w miejscu, w którym byłeś przed zresetowaniem.--merge
został dodany niedawno i ma na celu pomóc w przerwaniu nieudanego scalenia. Jest to konieczne, ponieważgit merge
faktycznie pozwoli ci podjąć próbę scalenia z brudnym drzewem roboczym (jednym z lokalnymi modyfikacjami), o ile modyfikacje te znajdują się w plikach, na które nie ma wpływu scalanie.git reset --merge
resetuje indeks (jak--mixed
- wszystkie zmiany są wyświetlane jako modyfikacje lokalne) i resetuje pliki, na które wpływa scalanie, ale pozostawia inne w spokoju. Miejmy nadzieję, że przywróci to wszystko tak, jak było przed złym połączeniem. Zazwyczaj używasz go jakogit reset --merge
(znaczącegogit reset --merge HEAD
), ponieważ chcesz tylko zresetować scalenie, a nie przesunąć gałąź. (HEAD
nie został jeszcze zaktualizowany, ponieważ scalenie nie powiodło się)Aby być bardziej konkretnym, załóżmy, że zmodyfikowałeś pliki A i B i próbujesz scalić w gałęzi, która zmodyfikowała pliki C i D. Scalanie z jakiegoś powodu kończy się niepowodzeniem i decydujesz się go przerwać. Ty używasz
git reset --merge
. Powoduje, że C i D wracają do tego, jak byłyHEAD
, ale pozostawia twoje modyfikacje w A i B w spokoju, ponieważ nie były one częścią próby scalenia.Chcieć wiedzieć więcej?
Sądzę, że
man git reset
jest to całkiem dobre - być może potrzebujesz trochę sposobu, w jaki działa git, aby naprawdę się zagłębili. W szczególności, jeśli poświęcisz trochę czasu na ich uważne przeczytanie, bardzo pomocne są te tabele przedstawiające stany plików w indeksie i drzewie pracy dla wszystkich różnych opcji i przypadków. (Ale tak, są bardzo gęste - przekazują bardzo dużo powyższych informacji w bardzo zwięzłej formie).Dziwna notacja
„Dziwny zapis” (
HEAD^
iHEAD~1
), o którym wspominasz, jest po prostu skrótem do określania zatwierdzeń, bez konieczności używania nazwy skrótu takiej jak3ebe3f6
. Jest to w pełni udokumentowane w sekcji „określanie wersji” strony podręcznika dla git-rev-pars, z dużą ilością przykładów i powiązanej składni. Karetka i tylda faktycznie oznaczają różne rzeczy :HEAD~
jest skrótem odHEAD~1
i oznacza pierwszego rodzica zatwierdzenia.HEAD~2
oznacza pierwszego rodzica pierwszego zatwierdzenia. Pomyśl o tym,HEAD~n
jak „n zobowiązuje się przed HEAD” lub „przodek HEAD n-tej generacji”.HEAD^
(lubHEAD^1
) oznacza również pierwszego rodzica zatwierdzenia.HEAD^2
oznacza drugiego rodzica zatwierdzenia . Pamiętaj, że normalne zatwierdzenie scalania ma dwoje rodziców - pierwszym rodzicem jest zatwierdzone scalenie, a drugim rodzicem jest scalone zatwierdzenie. Zasadniczo połączenia mogą mieć dowolnie wielu rodziców (połączenia ośmiornic).^
i~
operatorzy mogą być połączone razem, tak jak wHEAD~3^2
, drugi macierzysty przodka trzeciej generacjiHEAD
,HEAD^^2
, drugi macierzysty pierwszego rodzicaHEAD
lub nawetHEAD^^^
, co jest równoważneHEAD~3
.źródło
Pamiętaj, że
git
masz w sobie:HEAD
wskaźnik , który mówi, co popełnienia pracujesz naW porządku rosnącym niebezpieczeństw:
--soft
porusza się,HEAD
ale nie dotyka obszaru przeciwności ani drzewa roboczego.--mixed
przesuwaHEAD
i aktualizuje obszar przemieszczania, ale nie działające drzewo.--merge
przesuwa sięHEAD
, resetuje obszar przemieszczania i próbuje przenieść wszystkie zmiany z drzewa roboczego do nowego drzewa roboczego.--hard
przesuwaHEAD
i dostosowuje obszar postoju i drzewo robocze do nowegoHEAD
, wyrzucając wszystko.--soft
gdy chcesz przejść do innego zatwierdzenia i załatać rzeczy bez „utraty swojego miejsca”. Bardzo rzadko potrzebujesz tego.-
-
Użyj
--mixed
(która jest domyślna), jeśli chcesz zobaczyć, jak wyglądają inne zatwierdzenia, ale nie chcesz stracić żadnych zmian, które już masz.Użyj,
--merge
gdy chcesz przenieść się w nowe miejsce, ale uwzględnij zmiany, które już wprowadziłeś, do działającego drzewa.Użyj,
--hard
aby wymazać wszystko i rozpocząć nową tablicę przy nowym zatwierdzeniu.źródło
reset --merge
. Nie wykonuje łączenia trójstronnego. To tak naprawdę tylko do resetowania konfliktów scalania, jak opisano w dokumentacji. Będziesz chciał wykorzystaćcheckout --merge
to, o czym mówisz. Jeśli chcesz również przenieść gałąź, myślę, że jedynym sposobem jest kontynuacja kasy / resetowania, aby przeciągnąć ją dalej.reset --merge
z żadnym innym celem (domyślnym)HEAD
, ponieważ w przypadkach innych niż przerwanie konfliktu scalenia, zostanie ono odrzucone informacje, które w innym przypadku można zapisać.git reset
igit reset -- .
.Post Wyczyść Demystified w blogu Pro Git daje bardzo nie myślenia wyjaśnienie
git reset
igit checkout
.Po wszystkich pomocnych dyskusjach u góry tego postu autor ogranicza reguły do następujących trzech prostych kroków:
źródło
Kiedy coś popełniasz, musisz najpierw wprowadzić zmiany (dodać do indeksu). Oznacza to, że musisz dodać wszystkie pliki, które chcesz dołączyć do tego zatwierdzenia, zanim git uzna je za część zatwierdzenia. Najpierw spójrzmy na obraz repozytorium git:
więc teraz jest to proste. Musimy pracować w katalogu roboczym, tworząc pliki, katalogi i tak dalej. Te zmiany nie są śledzone. Aby je śledzić, musimy dodać je do indeksu git za pomocą polecenia git add . Po dodaniu do indeksu git. Możemy teraz zatwierdzić te zmiany, jeśli chcemy przekazać je do repozytorium git.
Ale nagle przekonaliśmy się podczas zatwierdzania, że mamy jeden dodatkowy plik, który dodaliśmy w indeksie, nie jest wymagany do wypchnięcia repozytorium git. Oznacza to, że nie chcemy tego pliku w indeksie. Teraz pytanie brzmi: jak usunąć ten plik z indeksu git, skoro użyliśmy git add, aby umieścić je w indeksie, logiczne byłoby użycie git rm ? Źle! git rm po prostu usunie plik i doda usunięcie do indeksu. Co więc teraz zrobić:
Posługiwać się:-
Czyści indeks, pozostawia nietknięty katalog roboczy. (po prostu wszystko inscenizuje).
Może być używany z wieloma opcjami. Istnieją trzy główne opcje do użycia z git reset: --hard, --soft i --mixed . Mają one wpływ na to, co zostanie zresetowane oprócz wskaźnika HEAD po zresetowaniu.
Po pierwsze --hard resetuje wszystko. Twój bieżący katalog byłby dokładnie taki, jak gdybyś śledził cały ten oddział. Katalog roboczy i indeks są zmieniane na to zatwierdzenie. To jest wersja, której najczęściej używam. git reset --hard jest czymś w rodzaju svn revert .
Następnie całkowite przeciwieństwo —miękkie ” nie resetuje działającego drzewa ani indeksu. Porusza tylko wskaźnikiem HEAD. To pozostawia twój aktualny stan z wszelkimi zmianami innymi niż zatwierdzenie, do którego się przełączasz, na miejscu w twoim katalogu i „przemieszczane” do zatwierdzenia. Jeśli dokonujesz zatwierdzenia lokalnie, ale nie wypchnąłeś go na serwer git, możesz zresetować do poprzedniego zatwierdzenia i ponownie uruchomić z dobrym komunikatem zatwierdzenia.
Wreszcie --mixed resetuje indeks, ale nie działające drzewo. Tak więc wszystkie zmiany są nadal obecne, ale są „nieetapowane” i trzeba by je dodać git add'ed lub git commit -a . używamy tego czasami, jeśli popełniliśmy więcej niż zamierzaliśmy za pomocą git commit -a, możemy wycofać zatwierdzenie za pomocą git reset --mixed, dodać rzeczy, które chcemy zatwierdzić i po prostu je zatwierdzić.
Różnica między git revert i git reset : -
Krótko mówiąc, git reset to polecenie „napraw błędy niezatwierdzone”, a git revert to polecenie „napraw błąd popełniony” .
Oznacza to, że jeśli popełniliśmy błąd w jakiejś zmianie, zatwierdziliśmy go i wypchnęliśmy to samo do git repo, to git revert jest rozwiązaniem. A jeśli w przypadku zidentyfikowania tego samego błędu przed wypchnięciem / zatwierdzeniem, możemy użyć git reset, aby naprawić problem.
Mam nadzieję, że pomoże ci to pozbyć się zamieszania.
źródło
git reset HEAD
domyślnie?--hard
,--soft
Lub--mixed
? Świetna odpowiedź btw.git reset --hard
co spowoduje utratę części danych. I jest punkt, który może być błędny (choć nie jestem w 100% pewien ... Wciąż się uczę!): Mówiąc o--mixed
tobie, mówisz, że „używamy tego czasami, jeśli popełniliśmy więcej niż zamierzaliśmy za pomocą git commit -a”. Czy miałeś na myśli: „jeśli wystawiliśmy więcej niż zamierzaliśmy zgit stage .
”? Jeśli naprawdę to popełniłeś, myślę, że jest już za późno (jak powiedziałeś na końcu, git reset to polecenie „napraw błędy niezamierzone”)TL; DR
DŁUŻSZA WERSJA
Ale to oczywiście uproszczone, stąd wiele raczej pełnych odpowiedzi. Bardziej sensowne było dla mnie czytanie
git reset
w kontekście cofania zmian. Np. Zobacz to:Od https://www.atlassian.com/git/tutorials/undoing-changes/git-reset
i to
Od https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations
źródło
Należy pamiętać, że jest to uproszczone wyjaśnienie, które jest pierwszym krokiem do zrozumienia tej złożonej funkcjonalności.
Może być pomocny dla uczniów wizualnych, którzy chcą wizualizować, jak wygląda stan projektu po każdym z tych poleceń:
Dla tych, którzy używają Terminalu z włączonym kolorem (git config --global color.ui auto):
git reset --soft A
a zobaczysz rzeczy B i C w kolorze zielonym (wyreżyserowane i gotowe do zatwierdzenia)git reset --mixed A
(lubgit reset A
), a zobaczysz rzeczy B i C na czerwono (nie zainscenizowane i gotowe do przygotowania (na zielono), a następnie popełnione)git reset --hard A
i nigdzie nie zobaczysz zmian B i C (będzie tak, jakby nigdy nie istniały)Lub dla tych, którzy korzystają z programu GUI, takiego jak „Tower” lub „SourceTree”
git reset --soft A
i zobaczysz rzeczy B i C w obszarze „pliki przemieszczane” gotowe do zatwierdzeniagit reset --mixed A
(lubgit reset A
), a zobaczysz rzeczy B i C w obszarze „pliki niestacjonarne” gotowe do przeniesienia na etapowe, a następnie zatwierdzonegit reset --hard A
i nigdzie nie zobaczysz zmian B i C (będzie tak, jakby nigdy nie istniały)źródło
Kasa wskazuje na konkretne zatwierdzenie.
Resetuj wskazuje gałąź na konkretny zatwierdzenie. (Gałąź jest wskaźnikiem zatwierdzenia.)
Nawiasem mówiąc, jeśli twoja głowa nie wskazuje na zatwierdzenie, na które wskazuje również gałąź, to masz odłączoną głowę.(okazało się błędne. Zobacz komentarze ...)źródło