Jak mogę odzyskać utracone zatwierdzenie w Git?

Odpowiedzi:

586

git reflogjest twoim przyjacielem. Znajdź na liście zatwierdzenie, na którym chcesz być, i możesz je zresetować (na przykład git reset --hard e870e41:).

(Jeśli nie zatwierdziłeś zmian ... możesz mieć kłopoty - dokonaj wcześniej i często!)

Bursztyn
źródło
5
Spójrz na git log HEAD@{1}. Jeśli to wygląda na odpowiednią serię zatwierdzeń, możesz git reset HEAD@{1}.
Amber
4
Tylko jeśli kody są przemieszczane (przy użyciu git add), są przechowywane w git i można je łatwo znaleźć za pomocą poleceń takich jak git fsck --lost-found.
Landys
2
Przypadkowo upuściłem zatwierdzenie, które powinienem był zachować, kiedy się opierałem. To całkowicie uratowało mnie od ponownego zrobienia kilku godzin pracy.
Joseph
27
To uratowało mi życie.
Lutaaya Huzaifah Idris
6
To uratowało moje zdrowie psychiczne: D
Frank Fajardo
117

Zanim odpowiemy, dodajmy trochę tła, 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 - oznacza HEADto, że 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

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 również użyć reflog.
git reflog wyświetli każdą zmianę, która zaktualizowała HEADi sprawdzenie żądanego wpisu ponownego logowania spowoduje HEADpowró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 --hard <commit_id>

„Przesuń” HEAD 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.

git revert <sha-1>

„Cofnij” podany zakres zatwierdzania lub zatwierdzania.
Polecenie reset spowoduje „cofnięcie” wszelkich zmian dokonanych w danym zatwierdzeniu.
Nowe zatwierdzenie z łatką cofania zostanie zatwierdzone, podczas gdy oryginalne zatwierdzenie pozostanie również w historii.

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

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

Wpisz opis zdjęcia tutaj

CodeWizard
źródło
2
Jesteś bohaterem, sir
dylanh724,
4
To właśnie zaoszczędziło mi wiele godzin pracy. Użyłem „git reflog --date = iso”, aby zobaczyć datę / godzinę każdego wpisu, ponieważ nie mogłem tego stwierdzić bez znacznika czasu.
MetalMikester,
1
dla mnie git reset --hard <commit_id>usuwanie HEADdziałało! +1 za przedstawienie graficzne !!
reverie_ss
Wystarczy wspomnieć: jeśli znasz nazwę gałęzi: git reflog <branchname>może być całkiem przydatny, ponieważ widzisz zmiany tylko jednej gałęzi.
Markus Schreiber
35

Innym sposobem na przejście do usuniętego zatwierdzenia jest git fsckpolecenie.

git fsck --lost-found

Spowoduje to wyświetlenie czegoś takiego jak w ostatnim wierszu:

dangling commit xyz

Możemy sprawdzić, czy jest to ten sam zatwierdzenie, reflogco sugerowano w innych odpowiedziach. Teraz możemy zrobićgit merge

git merge xyz

Uwaga:
Nie możemy odzyskać zatwierdzenia, fsckjeśli już uruchomiliśmy git gcpolecenie, które usunie odwołanie do wiszącego zatwierdzenia.

Atri
źródło
3
Jest to jedyna odpowiedź, która działa, jeśli nie wskazałeś ostatnio na dane zatwierdzenie, na przykład podczas pobierania gałęzi, a następnie przypadkowego resetowania tej gałęzi w innym miejscu.
TamaMcGlinn