Jak przywrócić repozytorium Git do poprzedniego zatwierdzenia?


7630

Jak przywrócić z obecnego stanu do migawki wykonanej przy określonym zatwierdzeniu?

Jeśli tak git log, to otrzymuję następujące dane wyjściowe:

$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <me@me.com>
Date:   Thu Nov 4 18:59:41 2010 -0400

blah blah blah...

commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <me@me.com>
Date:   Thu Nov 4 05:13:39 2010 -0400

more blah blah blah...

commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <me@me.com>
Date:   Thu Nov 4 00:55:06 2010 -0400

And yet more blah blah...

commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <me@me.com>
Date:   Wed Nov 3 23:56:08 2010 -0400

Yep, more blah blah.

Jak powrócić do zatwierdzenia od 3 listopada, tj. Zatwierdzenia 0d1d7fc?



116
Oto bardzo jasny i dokładny post o rozwiązywaniu problemów w git, prosto z Github.
Nobita,

3
Powiązane: Cofnij do starego zatwierdzenia Git w publicznym repozytorium . Zauważ, że to pytanie dodaje ograniczenie, że repo jest publiczne.

58
Uwielbiam git, ale fakt, że jest 35 odpowiedzi na coś, co powinno być niezwykle proste, ujawnia ogromny problem z git. A może to dokumenty?
The Muffin Man

2
W jaki sposób język „pułapka” w używaniu tego słowa do przywrócenia jako potocznie oznacza zresetowanie, nawet nie jest tutaj adresowany? Jak dotąd 6594 głosów pozytywnych, a nie edycja w ten sposób, żeby podkreślić różnicę? Nie byłoby bardziej mylące odniesienie do „zapisywania pliku” z wyrażeniem „
zatwierdzanie

Odpowiedzi:


9719

Wiele zależy od tego, co rozumiesz przez „cofnięcie”.

Tymczasowo przełącz na inne zatwierdzenie

Jeśli chcesz tymczasowo wrócić do niego, wygłupiać się, a następnie wrócić do tego, gdzie jesteś, wszystko, co musisz zrobić, to sprawdzić pożądane zatwierdzenie:

# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32

Lub jeśli chcesz dokonywać zatwierdzeń, gdy tam jesteś, idź i stwórz nowy oddział, gdy jesteś przy nim:

git checkout -b old-state 0d1d7fc32

Aby wrócić do miejsca, w którym byłeś, po prostu sprawdź gałąź, w której byłeś. (Jeśli dokonałeś zmian, jak zwykle podczas zmiany gałęzi, będziesz musiał sobie z nimi poradzić, jeśli to konieczne. Możesz zresetować, aby je wyrzucić; możesz ukryć, wykupić, ukryć pop, aby zabrać je ze sobą; możesz zatwierdzić je do oddziału tam, jeśli chcesz tam oddziału.)

Twarde usuwanie niepublikowanych zatwierdzeń

Z drugiej strony, jeśli naprawdę chcesz pozbyć się wszystkiego, co zrobiłeś od tego czasu, są dwie możliwości. Po pierwsze, jeśli nie opublikowałeś żadnego z tych zatwierdzeń, po prostu zresetuj:

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

Jeśli się zepsujesz, już wyrzuciłeś swoje lokalne zmiany, ale możesz przynajmniej wrócić do poprzedniego stanu, resetując ponownie.

Cofnij opublikowane zatwierdzenia z nowymi zatwierdzeniami

Z drugiej strony, jeśli opublikowałeś pracę, prawdopodobnie nie chcesz zresetować gałęzi, ponieważ to skutecznie przepisuje historię. W takim przypadku rzeczywiście można cofnąć zatwierdzenia. W Git revert ma bardzo konkretne znaczenie: utwórz zatwierdzenie z odwrotną łatką, aby go anulować. W ten sposób nie przepisujesz żadnej historii.

# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053

# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD

#Similarly, you can revert a range of commits using commit hashes:
git revert a867b4af..0766c053 

# Reverting a merge commit
git revert -m 1 <merge_commit_sha>

# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .

# Then commit. Be sure and write a good message describing what you just did
git commit

Strona git-revertpodręcznika zawiera wiele z tego w swoim opisie. Innym przydatnym linkiem jest ta sekcja git-scm.com omawiająca git-revert .

Jeśli zdecydujesz, że mimo wszystko nie chcesz przywracać, możesz przywrócić przywrócenie (jak opisano tutaj) lub przywrócić do stanu sprzed przywrócenia (patrz poprzednia sekcja).

Pomocna może być również ta odpowiedź:
Jak przenieść HEAD z powrotem do poprzedniej lokalizacji? (Odłączona głowa)


118
@ Komentarzu Rod jest na git revert HEAD~3jak najlepszej wat powrócić 3zobowiązuje AM jest ważne umowy.
Nowa Aleksandria,

19
Czy mógłbyś napisać cały numer? jak:git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Spoeken

16
@MathiasMadsenStav Tak, możesz oczywiście określić zatwierdzenia przez pełny SHA1. Użyłem skróconych skrótów, aby odpowiedź była bardziej czytelna, a ty również używasz ich, jeśli piszesz. Jeśli kopiujesz i wklejasz, na pewno użyj pełnego skrótu. Zobacz Określanie poprawek w man git rev-parsie, aby uzyskać pełny opis tego, jak nazwać zatwierdzenia.
Cascabel,

59
Możesz użyć, git revert --no-commit hash1 hash2 ...a następnie po prostu zatwierdzić każde git commit -m "Message"
cofnięcie

6
Co w tym kontekście oznacza „publikuj”?
Howiecamp,

1847

Wiele skomplikowanych i niebezpiecznych odpowiedzi tutaj, ale w rzeczywistości jest to łatwe:

git revert --no-commit 0766c053..HEAD
git commit

Spowoduje to przywrócenie wszystkiego z HEAD z powrotem do skrótu zatwierdzenia, co oznacza, że ​​odtworzy ten stan zatwierdzenia w drzewie roboczym tak, jakby każde zatwierdzenie od czasu cofnięcia. Następnie możesz zatwierdzić bieżące drzewo, a utworzy ono nowe zatwierdzenie zasadniczo równoważne zatwierdzeniu, do którego „przywróciłeś”.

( --no-commitFlaga pozwala gitowi cofnąć wszystkie zatwierdzenia naraz - w przeciwnym razie zostaniesz poproszony o komunikat dla każdego zatwierdzenia w zakresie, zaśmiecając twoją historię niepotrzebnymi nowymi zatwierdzeniami).

Jest to bezpieczny i łatwy sposób na przywrócenie poprzedniego stanu . Żadna historia nie jest niszczona, więc można jej użyć do zatwierdzeń, które zostały już upublicznione.


23
Jeśli naprawdę chcesz mieć indywidualne zatwierdzenia (zamiast cofania wszystkiego za pomocą jednego dużego zatwierdzenia), możesz przekazać --no-editzamiast --no-commit, abyś nie musiał edytować komunikatu zatwierdzenia dla każdej zmiany.

87
Jeśli jeden z zatwierdzeń między 0766c053..HEAD jest scaleniem, pojawi się błąd wyskakujący (dotyczy to nieokreślenia -m). Może to pomóc osobom, które się z tym spotkają: stackoverflow.com/questions/5970889/…
timhc22

7
Aby zobaczyć różnice przed zatwierdzeniem, użyj git diff --cached.
John Erck,

21
$ git revert --no-commit 53742ae..HEADzwracafatal: empty commit set passed
Alex G.

10
@AlexG to dlatego, że musisz wprowadzić wartość skrótu przed tym, do którego chcesz wrócić. W moim przypadku skróty były jak: 81bcc9e HEAD{0}; e475924 HEAD{1}, ...(z git reflog) i chciałem cofnąć to, co zrobiłem 81bcc9e, a potem musiałem to zrobićgit revert e475924..HEAD
EpicPandaForce

1611

Rogue Coder?

Pracujesz sam i chcesz, żeby działało? Postępuj zgodnie z poniższymi instrukcjami, od lat działają niezawodnie dla mnie i wielu innych.

Pracujesz z innymi? Git jest skomplikowane. Przeczytaj komentarze poniżej tej odpowiedzi, zanim zrobisz coś pochopnego.

Przywracanie kopii roboczej do najnowszego zatwierdzenia

Aby powrócić do poprzedniego zatwierdzenia, ignorując wszelkie zmiany:

git reset --hard HEAD

gdzie HEAD jest ostatnim zatwierdzeniem w twoim bieżącym oddziale

Przywracanie kopii roboczej do starszego zatwierdzenia

Aby powrócić do zatwierdzenia, które jest starsze niż najnowsze zatwierdzenie:

# Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced 

# Moves pointer back to previous HEAD
git reset --soft HEAD@{1}

git commit -m "Revert to 56e05fced"

# Updates working copy to reflect the new commit
git reset --hard

Kredyty trafiają do podobnego pytania dotyczącego przepełnienia stosu. Czy powrócić do zatwierdzenia przez skrót SHA w Git? .


33
Zrobiłem to, ale potem nie byłem w stanie zatwierdzić i wypchnąć do zdalnego repozytorium. Chcę, aby konkretny starszy zobowiązał się do HEAD ...
Lennon

7
Oznacza to, że już wprowadziłeś zobowiązania, które chcesz cofnąć. Może to powodować wiele problemów dla ludzi, którzy sprawdzili Twój kod i pracowali nad nim. Ponieważ nie mogą bezproblemowo zastosować twojego zatwierdzenia do ich. W takim przypadku lepiej wykonaj polecenie git. Jeśli jesteś jedynym, który korzysta z repozytorium. Wykonaj polecenie git push -f (ale zastanów się dwa razy, zanim to zrobisz)
vinothkr

6
Właśnie też chcę podkreślić, że alternatywnie do miękkiego resetu rozwiązanie, zamiast robić mieszaną resetu pierwszy i twardy reset ostatni, można rzeczywiście zrobić pierwszy twardy reset w następujący sposób: git reset --hard 56e05fc; git reset --soft HEAD@{1}; git commit.

5
@nuton linus pauling sam, twórca git, skrytykował go za zbyt skomplikowany. Zapisał, że był „zszokowany”, że git stał się tak popularny, biorąc pod uwagę jego złożoność
boulder_ruby

5
@boulder_ruby Myślę, że miałeś na myśli Linusa Torvaldsa, twórcę git. Ale myślę, że Linus Pauling prawdopodobnie zgodziłby się, że git jest skomplikowany.
Suncat2000

215

Najlepszą opcją dla mnie i prawdopodobnie innych jest opcja resetowania Git:

git reset --hard <commidId> && git clean -f

To była dla mnie najlepsza opcja! To jest proste, szybkie i skuteczne!


** Uwaga: ** Jak wspomniano w komentarzach, nie rób tego, jeśli udostępniasz swój oddział innym osobom, które mają kopie starych zatwierdzeń

Również z komentarzy, jeśli chciałbyś zastosować mniej „kulistą” metodę, której możesz użyć

git clean -i

37
Ostrzeżenie obowiązkowe: nie rób tego, jeśli udostępniasz swój oddział innym osobom, które mają kopie starych zatwierdzeń, ponieważ użycie twardego resetu, takiego jak ten, zmusi ich do ponownej synchronizacji pracy z nowo zresetowanym oddziałem. Aby znaleźć rozwiązanie, które szczegółowo wyjaśnia, jak bezpiecznie przywracać zatwierdzenia bez utraty pracy przy twardym resecie, zobacz tę odpowiedź .

7
Po drugie ostrzegam @ Cupcake ... bądź bardzo świadomy konsekwencji. Zauważ jednak, że jeśli naprawdę chcesz, aby te zatwierdzenia zniknęły z historii na zawsze, zrobi to ta metoda reset + clean i będziesz musiał wymusić zepchnięcie zmodyfikowanych gałęzi z powrotem na wszystkie piloty.
ashnazg

5
git clean -f NIEBEZPIECZEŃSTWO NIEBEZPIECZEŃSTWO
Tisch

2
To ustawia nagłówek mojej lokalnej kopii na żądany zatwierdzenie. Ale wtedy nie mogę wcisnąć żadnych zmian, ponieważ jest za pilotem. A jeśli ściągnę z pilota, to skończy się tam, gdzie był najpóźniej zatwierdzić na zdalnej gałęzi. Jak całkowicie wymazać (zewsząd) kilka zatwierdzeń z mojej lokalnej kopii, które zostały wypchnięte?
Ade

2
@ Pomóż .. Możesz użyć git push -fflagi ... Ale uważaj, to zastąpi pilota .. Upewnij się, że wiesz, co chcesz zrobić ...
Pogrindis

176

Zanim odpowiemy, dodajmy tło, wyjaśniając, co to HEADjest.

First of all what is HEAD?

HEADjest po prostu odniesieniem do bieżącego zatwierdzenia (najnowszego) w bieżącej gałęzi. W HEADdanym momencie może być tylko jeden (wyłączając git worktree).

Zawartość HEADjest przechowywana w środku .git/HEADi zawiera 40 bajtów SHA-1 bieżącego zatwierdzenia.


detached HEAD

Jeśli nie korzystasz z ostatniego zatwierdzenia - to znaczy HEAD to, nazywa się to wcześniejszym zatwierdzeniem w historii detached HEAD.

Wpisz opis zdjęcia tutaj

W wierszu poleceń będzie to wyglądać tak - SHA-1 zamiast nazwy gałęzi, ponieważ HEADnie wskazuje ona końcówki bieżącej gałęzi:

Wpisz opis zdjęcia tutaj


Kilka opcji odzyskiwania po odłączeniu HEAD:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Spowoduje to pobranie nowej gałęzi wskazującej żądany zatwierdzenie. To polecenie pobierze do danego zatwierdzenia.

W tym momencie możesz utworzyć gałąź i od tego momentu zacząć pracować:

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Zawsze możesz użyć reflog . git reflogwyświetli każdą zmianę, która została zaktualizowana, HEADa sprawdzenie żądanego wpisu ponownego logowania spowoduje ustawienieHEAD powrót do tego zatwierdzenia.

Za każdym razem, gdy HEAD zostanie zmodyfikowany, pojawi się nowy wpis w reflog

git reflog
git checkout HEAD@{...}

Spowoduje to powrót do żądanego zatwierdzenia

Wpisz opis zdjęcia tutaj


git reset HEAD --hard <commit_id>

„Przesuń” głowę z powrotem do żądanego zatwierdzenia.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • Uwaga: ( od wersji Git 2.7 ) możesz również korzystać z nich git rebase --no-autostash.

Ten schemat ilustruje, które polecenie robi co. Jak widać, reset && checkoutzmodyfikuj HEAD.

Wpisz opis zdjęcia tutaj


6
Doskonała wskazówka git reflog, właśnie tego potrzebowałem
smac89,

4
Auć! To wszystko wydaje się strasznie skomplikowane ... czy nie ma prostego polecenia, które cofnie cię o krok? Jak przejście z wersji 1.1 w swoim projekcie z powrotem do wersji 1.0? Spodziewałbym się czegoś takiego: git stepback_one_commit czy coś ....
Kokodoko,

znajduje się: git reset HEAD^--hard`
CodeWizard

3
@Kokodoko Tak, to jest strasznie skomplikowane ... i jest doskonałym przykładem tego, jak mało eksperci zwracają uwagę na ludzi, którzy dopiero zaczynają. Proszę odnieść się do mojej odpowiedzi tutaj, a także do polecanej w niej książki. Git NIE jest czymś, co można po prostu intuicyjnie odebrać. I mogę być absolutnie pewien, że CodeWizard tego nie zrobił.
Mike Rodent

145

Jeśli chcesz „odrzucić”, skasować ostatni komunikat zatwierdzenia i przywrócić zmodyfikowane pliki do przemieszczania, użyj polecenia:

git reset --soft HEAD~1
  • --soft wskazuje, że niezatwierdzone pliki powinny zostać zachowane jako pliki robocze, w przeciwieństwie do plików --hard nich, które je odrzuciłyby.
  • HEAD~1jest ostatnim zatwierdzeniem. Jeśli chcesz wycofać 3 zatwierdzenia, możesz użyć HEAD~3. Jeśli chcesz przywrócić do określonego numeru wersji, możesz to zrobić również przy użyciu skrótu SHA.

Jest to niezwykle przydatne polecenie w sytuacjach, w których popełniłeś błąd i chcesz cofnąć to ostatnie zatwierdzenie.

Źródło: http://nakkaya.com/2009/09/24/git-delete-last-commit/


3
Jest to delikatne i łagodne: bez ryzyka, jeśli nie
pchnąłeś

124

Możesz to zrobić za pomocą następujących dwóch poleceń:

git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f

Spowoduje to usunięcie poprzedniego zatwierdzenia Git.

Jeśli chcesz zachować zmiany, możesz także użyć:

git reset --soft [previous Commit SHA id here]

Następnie zapisze twoje zmiany.


2
Próbowałem 1/2 tuzina odpowiedzi w tym poście, dopóki nie dotarłem do tego jednego ... wszystkich innych, moja konfiguracja git ciągle dawała mi błąd podczas próby wypchnięcia. Ta odpowiedź zadziałała. Dzięki!
Gene Bo

Jeden szczegół dla mnie polegał na tym, że zgubiłem diff .., które chciałem zachować, aby zobaczyć, co zrobiłem w zatwierdzeniu, które nie działało. Więc następnym razem po prostu zapiszę te dane przed wydaniem tego polecenia resetowania
Gene Bo,

1
To był dla mnie jedyny sposób, aby cofnąć złe scalenie, w tym przypadku funkcja przywracania nie działała. Dzięki!
Dave Cole,

Najlepsza odpowiedź. Dzięki
Imran Pollob

Najlepsza odpowiedź, dziękuję.
user1394

114

Próbowałem wielu sposobów, aby przywrócić lokalne zmiany w Git i wydaje się, że działa to najlepiej, jeśli chcesz po prostu przywrócić ostatni stan zatwierdzenia.

git add . && git checkout master -f

Krótki opis:

  • NIE utworzy żadnych zatwierdzeń, jak to git revertrobi.
  • NIE odłączy twojej HEAD jak to git checkout <commithashcode>robi.
  • Zastąpi wszystkie lokalne zmiany i USUŃ wszystkie dodane pliki od ostatniego zatwierdzenia w gałęzi.
  • Działa tylko z nazwami gałęzi, więc możesz przywrócić tylko najnowsze zatwierdzenie w gałęzi w ten sposób.

Znalazłem znacznie wygodniejszy i prostszy sposób na osiągnięcie powyższych wyników:

git add . && git reset --hard HEAD

gdzie HEAD wskazuje na ostatnie zatwierdzenie w twoim aktualnym oddziale.

Jest to ten sam kod, co sugerowany przez boulder_ruby, ale dodałem git add .wcześniej, git reset --hard HEADaby usunąć wszystkie nowe pliki utworzone od czasu ostatniego zatwierdzenia, ponieważ większość ludzi spodziewa się, że powrócę do ostatniego zatwierdzenia.


83

OK, powrót do poprzedniego zatwierdzenia w Git jest dość łatwy ...

Cofnij się bez zachowywania zmian:

git reset --hard <commit>

Wróć z zachowaniem zmian:

git reset --soft <commit>

Objaśnienie: usinggit reset można zresetować do określonego stanu. Powszechnie używa się go z hashem zatwierdzającym, jak widać powyżej.

Ale jak widzisz, różnica polega na użyciu dwóch flag --softi --harddomyślnie git resetużyciu --softflagi, ale dobrą praktyką jest zawsze używanie flagi, wyjaśniam każdą flagę:


--miękki

Domyślna flaga, jak wyjaśniono, nie musi jej dostarczać, nie zmienia działającego drzewa, ale dodaje wszystkie zmienione pliki gotowe do zatwierdzenia, więc wracasz do stanu zatwierdzenia, który zmiany w plikach stają się niestabilne.


--ciężko

Uważaj na tę flagę. Resetuje działające drzewo i wszystkie zmiany w śledzonych plikach i wszystko zniknie!


Stworzyłem również poniższy obraz, który może się zdarzyć w prawdziwym życiu podczas pracy z Git:

Przywróć reset do zatwierdzenia



70

Zakładając, że mówisz o mistrzu i w tej gałęzi (powiedział, że może to być dowolna działająca gałąź, o którą się martwisz):

# Reset local master branch to November 3rd commit ID
git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50

# Reset remote master branch to November 3rd commit ID
git push -f origin 0d1d7fc32e5a947fbd92ee598033d85bfc445a50:master

Znalazłem odpowiedź w poście na blogu (teraz już nie istnieje)

Zauważ, że jest to resetowanie i wymuszanie zmiany na pilocie, więc jeśli inni w twoim zespole już to zrobili, spowodujesz dla nich problemy. Niszczycie historię zmian, co jest ważnym powodem, dla którego ludzie używają git w pierwszej kolejności.

Lepiej użyć cofania (zobacz inne odpowiedzi) niż resetowania. Jeśli jesteś drużyną jednoosobową, prawdopodobnie nie ma to znaczenia.


6
Czym różni się ta odpowiedź od niezliczonych innych?
Matsmath,

To niefortunne. Wysłałem e-maila do blogera - mam nadzieję, że nadal go ma!
markreyes


2
W większości innych sugestii dotyczących sposobu rozwiązania tego problemu brakuje składni wypychania. Działa świetnie.
jpa57

61

Załóżmy, że masz następujące zatwierdzenia w pliku tekstowym o nazwie ~/commits-to-revert.txt(kiedyś git log --pretty=onelineje otrzymywałem)

fe60adeba6436ed8f4cc5f5c0b20df7ac9d93219
0c27ecfdab3cbb08a448659aa61764ad80533a1b
f85007f35a23a7f29fa14b3b47c8b2ef3803d542
e9ec660ba9c06317888f901e3a5ad833d4963283
6a80768d44ccc2107ce410c4e28c7147b382cd8f
9cf6c21f5adfac3732c76c1194bbe6a330fb83e3
fff2336bf8690fbfb2b4890a96549dc58bf548a5
1f7082f3f52880cb49bc37c40531fc478823b4f5
e9b317d36a9d1db88bd34831a32de327244df36a
f6ea0e7208cf22fba17952fb162a01afb26de806
137a681351037a2204f088a8d8f0db6e1f9179ca

Utwórz skrypt powłoki Bash, aby przywrócić każdy z nich:

#!/bin/bash
cd /path/to/working/copy
for i in `cat ~/commits-to-revert.txt`
do
    git revert $i --no-commit
done

Spowoduje to przywrócenie wszystkiego do poprzedniego stanu, w tym tworzenie i usuwanie plików i katalogów, zatwierdzanie ich w oddziale i zachowanie historii, ale przywrócono ją do tej samej struktury plików. Dlaczego Git nie ma a git revert --to <hash>jest poza mną.


41
Możesz zrobić a, git revert HEAD~3aby usunąć ostatnie 3 zatwierdzenia
Rod

25
@Rod - Nie, to nie w porządku. To polecenie przywróci zatwierdzenie, które jest trzecim dziadkiem HEAD (a nie ostatnie trzy zatwierdzenia).
kflorence

1
@kflorence Ok dzięki za informację. Czy git revert -n master~3..master~1zadziała? (Jak widać z kernel.org/pub/software/scm/git/docs/git-revert.html )
Rod

3
@Rod - Brzmi dobrze, na pewno jest to brzydka składnia, prawda? Zawsze znajdowałem sprawdzanie zatwierdzenia, do którego chcę „przywrócić”, a następnie zatwierdzanie go bardziej intuicyjnie.
kflorence

7
Jest o wiele łatwiejszy sposób na zrobienie tego teraz niż za pomocą takiego skryptu, po prostu użyj git revert --no-commit <start>..<end>, ponieważ git revertakceptuje zakres zatwierdzania w nowych (lub wszystkich?) Wersjach Gita. Pamiętaj, że początek zakresu nie jest uwzględniony w cofnięciu.

58

Dodatkowe alternatywy dla rozwiązań Jefromi

Rozwiązania Jefromi są zdecydowanie najlepsze i zdecydowanie powinieneś ich używać. Jednak ze względu na kompletność chciałem również pokazać te inne alternatywne rozwiązania, których można również użyć do cofnięcia zatwierdzenia (w tym sensie, że tworzysz nowe zatwierdzenie, które anuluje zmiany w poprzednim zatwierdzeniu , tak jak git revertrobi to ).

Żeby było jasne, te alternatywy nie są najlepszym sposobem na cofnięcie zatwierdzeń , rozwiązania Jefromi są , ale chcę tylko podkreślić, że możesz również użyć tych innych metod, aby osiągnąć to samo, cogit revert .

Alternatywa 1: Resety twarde i miękkie

To jest bardzo nieznacznie zmodyfikowana wersja rozwiązania Charlesa Baileya dotyczącego przywracania zatwierdzenia przez skrót SHA w Git? :

# Reset the index to the desired commit
git reset --hard <commit>

# Move the branch pointer back to the previous HEAD
git reset --soft HEAD@{1}

# Commit the changes
git commit -m "Revert to <commit>"

Zasadniczo działa to na podstawie faktu, że miękkie resetowanie pozostawi stan poprzedniego zatwierdzenia przemieszczonego w obszarze indeksu / przemieszczania, który można następnie zatwierdzić.

Alternatywa 2: Usuń bieżące drzewo i zastąp je nowym

To rozwiązanie pochodzi od rozwiązania Svicka do Checkout starego zatwierdzenia i uczyni go nowym zatwierdzeniem :

git rm -r .
git checkout <commit> .
git commit

Podobnie jak w wariancie nr 1, odtwarza to stan <commit>w bieżącej kopii roboczej. Należy to zrobić git rmnajpierw, ponieważ git checkoutnie usunie plików, które zostały dodane od tego czasu <commit>.


Co do alternatywy 1, jedno szybkie pytanie: robiąc to, nie tracimy czasu między zatwierdzeniami, prawda?
Bogac,

2
@Bogac - kropki wskazują ścieżkę pliku, w tym przypadku bieżący katalog, więc zakłada się, że uruchamiasz go z katalogu głównego kopii roboczej.
Tom

Ostrzeżenie jest powtarzany kilkakrotnie w odpowiedzi, ale może ktoś dodać dlaczego to nie najlepszy sposób - w porównaniu do czegoś jak git revert HEAD~2..HEADz @ (@ Jefromi'S) połączonego rozwiązania Kaskabel użytkownika. Nie widzę problemu.
Joshua Goldberg

55

Oto znacznie prostszy sposób na powrót do poprzedniego zatwierdzenia (i pozostawienie go w niezaangażowanym stanie, aby zrobić z nim cokolwiek zechcesz):

git reset HEAD~1

Nie trzeba więc podawać identyfikatorów i tak dalej :)


nie działało, po tym git pull: błąd: lokalne zmiany w następujących plikach zostałyby zastąpione przez scalenie:
malhal

1
@malhal To dlatego, że miałeś nieoczekiwane zmiany. Ukryj je / zresetuj, a wtedy będzie działać bez tego błędu.
Paul Walczewski

39

Istnieje polecenie (nie jest częścią podstawowego Git, ale znajduje się w pakiecie git-dodatków ) specjalnie do przywracania i ustawiania starych commits:

git back

Na stronie podręcznika może być również używany jako taki:

# Remove the latest three commits
git back 3

38

Najlepszym sposobem jest:

git reset --hard <commidId> && git push --force

Spowoduje to zresetowanie gałęzi do konkretnego zatwierdzenia, a następnie załaduje serwer zdalny z tymi samymi zatwierdzeniami, co w lokalnym (całkowicie wyeliminuje to polecenia po tym konkretnym zatwierdzeniu)

Uważaj, aby --forceflaga usuwa wszystkie kolejne zatwierdzenia po wybranym zatwierdzeniu bez opcji ich odzyskania.


3
działało jak urok!
Gaurav Gupta

Zgłosiłem się negatywnie, ponieważ nie widzę, w jaki sposób twoja odpowiedź zawiera nowe informacje, które nie zostały jeszcze podane, na przykład stackoverflow.com/a/37145089/1723886 , stackoverflow.com/a/27438379/1723886 lub stackoverflow.com/a/48756719/1723886 . W rzeczywistości większość zatwierdzeń już wspomina o git reset --hard, a wiele innych wspomina o użyciu --force lub -f do wypychania.
Alex Telon

Działa za pomocą jednego polecenia, jasne i proste. Jeśli nie podoba ci się to, możesz głosować za moją odpowiedzią.
david.t_92

1
Inną opcją do rozważenia w przyszłości jest zasugerowanie edycji wcześniejszej odpowiedzi lub dodanie komentarza stwierdzającego, że „można to również zrobić w jednym wierszu, na przykład używając &&”. W ten sposób każdy może zobaczyć poprawioną odpowiedź w jednym miejscu.
Alex Telon

36

Po wprowadzeniu wszystkich zmian po naciśnięciu wszystkich tych poleceń może być konieczne użycie:

git push -f ...

I nie tylko git push.


15
Ostrzeżenie obowiązkowe: nie rób tego, jeśli udostępniasz swój oddział innym osobom, które mają kopie starych zatwierdzeń, ponieważ użycie wymuszonego push zmusi ich do ponownej synchronizacji pracy. Aby znaleźć rozwiązanie, które szczegółowo wyjaśnia, jak bezpiecznie przywracać zatwierdzenia bez utraty pracy przy użyciu siły, zobacz tę odpowiedź .

3
Czasami tego właśnie chcesz. Przykład: zatwierdzono i przekazano kilka zatwierdzeń do niewłaściwej gałęzi (gałąź A). Po pobraniu wiśni do gałęzi B chcę usunąć te zatwierdzenia z gałęzi A. Nie chciałbym przywracać, ponieważ przywrócenie zostanie później zastosowane, gdy gałęzie A i B zostaną połączone. Wykonanie resetu --hard <commitId> w gałęzi A, a następnie wymuszone usunięcie usuwa te zatwierdzenia z gałęzi, zachowując je w gałęzi B. Mogę to uciec, ponieważ wiem, że nikt inny nie rozwija się w gałęzi A.
Doug R

Dzięki! Nie mogłem wymyślić, jak ustawić gałąź zdalną tak, aby pasowała do mojej gałęzi lokalnej, wystarczyło użyć siły.
Mido

32

Możesz wykonać wszystkie te wstępne kroki samodzielnie i wypchnąć z powrotem do repozytorium Git.

  1. Pobierz najnowszą wersję swojego repozytorium z Bitbucket za pomocą git pull --allpolecenia.

  2. Uruchom polecenie Git log za pomocą -n 4 poziomu terminala. Liczba po -nokreśla liczbę zatwierdzeń w dzienniku, zaczynając od ostatniego zatwierdzenia w lokalnej historii.

    $ git log -n 4
    
  3. Zresetuj nagłówek historii swojego repozytorium, używając git reset --hard HEAD~NN gdzie liczba zatwierdzeń, którą chcesz cofnąć. W poniższym przykładzie nagłówek cofnąłby jeden zatwierdzenie do ostatniego zatwierdzenia w historii repozytorium:

  4. Wciśnij zmianę do repozytorium Git za pomocą git push --force aby wymusić zmianę.

Jeśli chcesz, aby repozytorium Git zawierało poprzednie zatwierdzenie:

git pull --all
git reset --hard HEAD~1
git push --force


28

Wybierz wymagane zatwierdzenie i sprawdź przez

git show HEAD
git show HEAD~1
git show HEAD~2 

dopóki nie otrzymasz wymaganego zatwierdzenia. Aby HEAD wskazywał na to, zrób to

git reset --hard HEAD~1

lub git reset --hard HEAD~2cokolwiek.


7
Ostrzeżenie obowiązkowe: nie rób tego, jeśli udostępniasz swój oddział innym osobom, które mają kopie starych zatwierdzeń, ponieważ użycie twardego resetu, takiego jak ten, zmusi ich do ponownej synchronizacji pracy z nowo zresetowanym oddziałem. Aby znaleźć rozwiązanie, które szczegółowo wyjaśnia, jak bezpiecznie przywracać zatwierdzenia bez utraty pracy przy twardym resecie, zobacz tę odpowiedź .

2
Ponadto, dla jasności, git show HEADjest to równoznaczne z samym użyciem git log HEAD -1.

25

Jeśli sytuacja jest pilna , a chcesz po prostu zrobić to, o co pytający pytał w szybki i brudny sposób, zakładając, że twój projekt znajduje się w katalogu o nazwie na przykład „mój projekt”:


SZYBKIE I BRUDNE : w zależności od okoliczności, szybkie i brudne mogą być naprawdę DOBRE. Moje rozwiązanie tutaj NIE zastępuje nieodwracalnie plików, które masz w katalogu roboczym, plikami wyciągniętymi / wyodrębnionymi z głębi repozytorium git czającym się pod twoim katalogiem .git / za pomocą diabelnie sprytnych i diabolicznie potężnych poleceń git, których są wiele. NIE MUSISZ ROBIĆ TAKIEGO NURKOWANIA NA GŁĘBOKIM MORZU, ABY ODZYSKAĆ ​​coś, co może się wydawać katastrofalną sytuacją, a próba zrobienia tego bez wystarczającej wiedzy specjalistycznej może okazać się śmiertelna .


  1. Skopiuj cały katalog i nazwij go czymś innym, na przykład „mój projekt - skopiuj”. Zakładając, że pliki repozytorium git („repo”) znajdują się w katalogu „mój projekt” (ich domyślne miejsce, w katalogu o nazwie „.git”), skopiujesz teraz zarówno pliki robocze, jak i pliki repo.

  2. Zrób to w katalogu „mój projekt”:

    .../my project $ git reset --hard [first-4-letters&numbers-of-commit's-SHA]
    

Spowoduje to przywrócenie stanu repozytorium w „moim projekcie” do stanu, w którym dokonano tego zatwierdzenia („zatwierdzenie” oznacza migawkę plików roboczych). Wszystkie zatwierdzenia od tego czasu zostaną utracone na zawsze pod „moim projektem”, ALE ... nadal będą obecne w repozytorium pod „moim projektem - skopiuj”, ponieważ skopiowałeś wszystkie te pliki - w tym te pod… /. Git /.

Masz wtedy dwie wersje w swoim systemie ... możesz sprawdzać, kopiować lub modyfikować interesujące Cię pliki lub cokolwiek innego, z poprzedniego zatwierdzenia. Możesz całkowicie odrzucić pliki w obszarze „mój projekt - skopiuj”, jeśli zdecydowałeś się na nową pracę, ponieważ przywrócone zatwierdzenie nigdzie nie poszło ...

Oczywistą rzeczą jest to, że jeśli chcesz kontynuować stan projektu bez faktycznego odrzucenia pracy, ponieważ to odzyskane zatwierdzenie polega na ponownej zmianie nazwy katalogu: Usuń projekt zawierający odzyskane zatwierdzenie (lub nadaj mu tymczasową nazwę) i zmień nazwę swojego „ mój projekt - skopiuj „katalog z powrotem do„ mojego projektu ”. Więc może spróbuj zrozumieć niektóre z innych odpowiedzi tutaj i prawdopodobnie wkrótce wykonasz kolejne zatwierdzenie.

Git jest genialnym dziełem, ale absolutnie nikt nie jest w stanie po prostu „odebrać go w locie”: także ludzie, którzy zbyt często próbują to wyjaśnić zakładają wcześniejszą wiedzę o innych systemach kontroli wersji VCS i sięgają za daleko zbyt wcześnie i popełniaj inne przestępstwa, takie jak używanie wymiennych terminów do „sprawdzania” - w sposób, który czasami wydaje się prawie wyliczony, by wprowadzić w błąd początkującego.

Aby zaoszczędzić sobie stresu, ucz się od moich blizn. Musisz przeczytać książkę na temat Gita - polecam „Kontrola wersji z Git” . Zrób to wcześniej niż później. Jeśli tak, pamiętaj, że duża część złożoności Git wynika z rozgałęziania, a następnie ponownego łączenia się: możesz pominąć te części w dowolnej książce. Z twojego pytania nie ma powodu, dla którego ludzie powinni cię oślepiać nauką .

Zwłaszcza jeśli, na przykład, jest to desperacka sytuacja i jesteś nowicjuszem w Git!

PS: Jeszcze jedna myśl: w rzeczywistości (obecnie) bardzo łatwo jest przechowywać repozytorium Git w katalogu innym niż ten z działającymi plikami. Oznaczałoby to, że nie musisz kopiować całego repozytorium Git przy użyciu powyższego szybkiego i brudnego rozwiązania. Zobacz odpowiedź Fryer za pomocą --separate-git-dir tutaj . Ostrzegamy jednak: jeśli masz repozytorium „osobnego katalogu”, którego nie kopiujesz i wykonujesz twardy reset, wszystkie wersje następujące po zatwierdzeniu resetowania zostaną utracone na zawsze, chyba że masz, jak absolutnie powinieneś, regularnie tworzył kopie zapasowe repozytorium, najlepiej w chmurze (np. na Dysku Google ).

W tym temacie „tworzenia kopii zapasowych w chmurze” następnym krokiem jest otwarcie konta (oczywiście za darmo) w GitHub lub (co moim zdaniem) w GitLab . Następnie możesz regularnie wykonywać git pushpolecenia, aby aktualizowanie repozytorium Cloud było „prawidłowe”. Ale znowu mówienie o tym może być za dużo za wcześnie.


23

Jest to jeszcze jeden sposób na bezpośrednie zresetowanie do ostatniego zatwierdzenia

git stash
git stash clear

Bezpośrednio usuwa wszystkie zmiany, które wprowadziłeś od ostatniego zatwierdzenia.

PS: Ma mały problem; usuwa również wszystkie ostatnio zapisane zmiany skrytki. Co w większości przypadków nie powinno mieć znaczenia.


UWAGA: Nowe pliki, które nie zostały dodane do indeksu, nie są ukryte. Ty też je dodajesz lub usuwasz ręcznie.
andreyro

Po co och, skasować skrytkę Oprócz tego, że nie jest rozwiązaniem, jest to w rzeczywistości szkodliwe. Przeczytanie pierwszego zdania pytania natychmiast unieważnia rozwiązanie ukryte (co może być użyteczne TYLKO w celu zresetowania do OSTATNIEGO zatwierdzenia).
RomainValeri

22

Aby całkowicie wyczyścić katalog programisty z przypadkowych zmian, użyliśmy:

git add -A .
git reset --hard HEAD

Po prostu git reset --hard HEADpozbędzie się modyfikacji, ale nie pozbędzie się „nowych” plików. W ich przypadku przypadkowo przeciągnęli ważny folder gdzieś losowo, a wszystkie te pliki były traktowane przez Git jako nowe, więc reset --hardnie naprawiono tego. Uruchamiając git add -A .wcześniej, jawnie śledził je wszystkie za pomocą git, aby zostały usunięte przez reset.


21

Aby zachować zmiany z poprzedniego zatwierdzenia do HEAD i przejść do poprzedniego zatwierdzenia, wykonaj:

git reset <SHA>

Jeśli zmiany nie są wymagane od poprzedniego zatwierdzenia w HEAD i po prostu odrzuć wszystkie zmiany, wykonaj:

git reset --hard <SHA>

20

Wierzę, że niektórzy ludzie mogą przyjść na to pytanie, chcąc wiedzieć, jak cofnąć zatwierdzone zmiany, które wprowadzili w swoim mistrzu - tj. Wyrzucić wszystko i wrócić do origin / master, w takim przypadku wykonaj następujące czynności:

git reset --hard origin/master

/superuser/273172/how-to-reset-master-to-origin-master


18

Cofnij to polecenie wycofania zatwierdzeń.

git revert <commit1> <commit2> 

Próba:

git revert 2h3h23233

Może mierzyć zasięg HEAD jak poniżej. Tutaj 1 mówi „cofnij ostatnie zatwierdzenie”.

git revert HEAD~1..HEAD

a następnie zrobić git push


14

Spróbuj zresetować do żądanego zatwierdzenia -

git reset <COMMIT_ID>

(aby sprawdzić użycie COMMIT_ID git log)

Spowoduje to zresetowanie wszystkich zmienionych plików do stanu bez dodania.

Teraz możesz checkoutwszystkie pliki, które nie zostały dodane przez

git checkout .

Sprawdź, git logaby zweryfikować zmiany.

AKTUALIZACJA

Jeśli masz tylko jedno zatwierdzenie w repozytorium, spróbuj

git update-ref -d HEAD


13

Ponieważ twoje zatwierdzenia są wypychane zdalnie, musisz je usunąć. Załóżmy, że twoja gałąź się rozwija i jest zepchnięta na pochodzenie .

Najpierw musisz usunąć wywoływanie z pochodzenia :

git push origin :develop (note the colon)

Następnie musisz rozwinąć się do pożądanego stanu, pozwól mi założyć, że skrótem zatwierdzenia jest EFGHIJK:

git reset --hard EFGHIJK

Wreszcie, push rozwijaj ponownie:

git push origin develop

13

Uwaga! To polecenie może spowodować utratę historii zatwierdzeń, jeśli użytkownik błędnie wprowadzi nieprawidłowe zatwierdzenie. Zawsze miej dodatkową kopię zapasową swojego gita, gdzie indziej, na wypadek, gdybyś popełnił błędy, niż jesteś nieco bezpieczniejszy. :)

Miałem podobny problem i chciałem wrócić do wcześniejszego zatwierdzenia. W moim przypadku nie byłem zainteresowany zachowaniem nowszego zatwierdzenia, dlatego skorzystałem Hard.

Oto jak to zrobiłem:

git reset --hard CommitId && git clean -f

Spowoduje to przywrócenie lokalnego repozytorium, a tutaj po użyciu git push -fzaktualizuje zdalne repozytorium.

git push -f

13

W GitKraken możesz to zrobić:

  1. Kliknij prawym przyciskiem myszy na zatwierdzenie, które chcesz zresetować, wybierz: Zresetuj do tego zatwierdzenia / Hard :

    Wpisz opis zdjęcia tutaj

  2. Kliknij ponownie zatwierdzenie prawym przyciskiem myszy, wybierz: Bieżąca nazwa oddziału / Wciśnij :

    Wpisz opis zdjęcia tutaj

  3. Kliknij na Force Push :

    Wpisz opis zdjęcia tutaj

Obs. : Musisz być ostrożny, ponieważ cała historia zatwierdzeń po twardym resecie zostaje utracona, a działanie to jest nieodwracalne. Musisz być pewien, co robisz.


11

Jeśli chcesz poprawić błąd w ostatnim zatwierdzeniu, dobrą alternatywą byłoby użycie polecenia git commit --amend . Jeśli ostatnie zatwierdzenie nie jest wskazywane przez żadne odniesienie, to załatwi sprawę, ponieważ tworzy zatwierdzenie z tym samym rodzicem, co ostatnie zatwierdzenie. Jeśli nie ma odniesienia do ostatniego zatwierdzenia, zostanie po prostu odrzucone, a to zatwierdzenie będzie ostatnim zatwierdzeniem. Jest to dobry sposób korygowania zatwierdzeń bez cofania zatwierdzeń. Ma jednak swoje ograniczenia.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.