Czy można cofnąć zmiany spowodowane następującym poleceniem? Jeśli tak to jak?
git reset --hard HEAD~1
--hard
odrzuca niezatwierdzone zmiany. Ponieważ nie są one śledzone przez git, nie ma możliwości ich przywrócenia za pomocą git.
Czy można cofnąć zmiany spowodowane następującym poleceniem? Jeśli tak to jak?
git reset --hard HEAD~1
--hard
odrzuca niezatwierdzone zmiany. Ponieważ nie są one śledzone przez git, nie ma możliwości ich przywrócenia za pomocą git.
Odpowiedzi:
Pat Notz ma rację. Możesz odzyskać zatwierdzenie, o ile upłynęło kilka dni. git tylko śmieci są zbierane po około miesiącu, chyba że wyraźnie powiesz mu, aby usunąć nowsze obiekty BLOB.
$ git init
Initialized empty Git repository in .git/
$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file1
$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file2
$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1
$ cat file2
cat: file2: No such file or directory
$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2
$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2
$ cat file2
added new file
Możesz zobaczyć w przykładzie, że plik2 został usunięty w wyniku twardego resetu, ale został przywrócony na miejscu, gdy zresetowałem przez dziennik reflog.
git log -g
może być nieco ładniejszym sposobem na przeglądanie dziennika niż git reflog
.
git reflog
po git log -g
prostu dlatego, że masz wszystkie informacje w jednym wierszu z sha1, HEAD info i zatwierdzasz wiadomości w jednej linii. O wiele łatwiejszy do odczytania.
To, co chcesz zrobić, to określić sha1 zatwierdzenia, które chcesz przywrócić. Możesz uzyskać sha1, sprawdzając reflog ( git reflog
), a następnie wykonując polecenie
git reset --hard <sha1 of desired commit>
Ale nie czekaj zbyt długo ... po kilku tygodniach git w końcu zobaczy to zatwierdzenie jako niepowiązane i usunie wszystkie obiekty BLOB.
Odpowiedź jest ukryta w szczegółowej odpowiedzi powyżej, możesz po prostu zrobić:
$> git reset --hard HEAD@{1}
(Zobacz wyniki git reflog show )
Można go odzyskać, jeśli Git nie zebrał jeszcze śmieci.
Uzyskaj przegląd zwisających zatwierdzeń dzięki fsck
:
$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf
Odzyskaj zwisające zatwierdzenie z rebase:
$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf
Jeśli masz szczęście, tak jak ja, możesz wrócić do edytora tekstu i nacisnąć „cofnij”.
Wiem, że to nie jest właściwa odpowiedź, ale zaoszczędziło mi to pół dnia pracy, więc mam nadzieję, że zrobi to samo dla kogoś innego!
o ile wiem, --hard
odrzuca niezaangażowane zmiany. Ponieważ nie są one śledzone przez git. ale możesz cofnąć discarded commit
.
$ git reflog
wyświetli:
b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....
gdzie 4bac331
jest discarded commit
.
Teraz wystarczy przesunąć głowę do tego zatwierdzenia:
$ git reset --hard 4bac331
$ git fsck --lost-found
Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a <- it's this one
$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a
commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>
Date: Wed Aug 15 08:41:30 2012 +0200
*MY COMMIT MESSAGE IS DISPLAYED HERE*
diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*
$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a
First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.
W zależności od stanu, w jakim znajdowało się Twoje repozytorium, gdy uruchomiłeś polecenie, efekty git reset --hard
mogą być różne: od trywialnego do cofania, w zasadzie niemożliwe.
Poniżej wymieniłem szereg różnych możliwych scenariuszy i sposoby ich odzyskania.
Taka sytuacja zwykle występuje, gdy uruchamiasz git reset
z argumentem, jak w git reset --hard HEAD~
. Nie martw się, łatwo to odzyskać!
Jeśli po prostu pobiegłeś git reset
i od tamtej pory nie zrobiłeś nic więcej, możesz wrócić do miejsca, w którym byłeś, dzięki tej linijce:
git reset --hard @{1}
Spowoduje to zresetowanie bieżącej gałęzi bez względu na jej stan przed ostatnią modyfikacją (w twoim przypadku najnowszą modyfikacją gałęzi będzie twardy reset, który próbujesz cofnąć).
Jeśli jednak użytkownik nie dokonano innych zmian w swojej branży od resetu, jedno-liner powyżej nie będą działać. Zamiast tego powinieneś uruchomić, aby zobaczyć listę wszystkich ostatnich zmian dokonanych w oddziale (w tym resetów). Ta lista będzie wyglądać mniej więcej tak:git reflog
<branchname>
7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit
Znajdź operację na tej liście, którą chcesz „cofnąć”. W powyższym przykładzie byłby to pierwszy wiersz, który mówi „reset: przejście do HEAD ~”. Następnie skopiuj reprezentację zatwierdzenia przed (poniżej) tą operacją. W naszym przypadku będzie to master@{1}
(lub 3ae5027
oba reprezentują ten sam zatwierdzenie) i uruchomi się, git reset --hard <commit>
aby przywrócić bieżącą gałąź do tego zatwierdzenia.
git add
, ale nigdy się nie popełniłem. Teraz moje zmiany zniknęły!Jest to nieco trudniejsze do odzyskania. git nie mają kopie plików dodanych, ale ponieważ kopie te nie były związane z żadnym konkretnym popełnić nie można przywrócić zmian naraz. Zamiast tego musisz zlokalizować poszczególne pliki w bazie danych git i przywrócić je ręcznie. Możesz to zrobić za pomocą git fsck
.
Aby uzyskać szczegółowe informacje na ten temat, zobacz Cofnij resetowanie git - twarde z nieproszonymi plikami w obszarze przemieszczania .
git add
i nigdy nie popełniłem. Teraz moje zmiany zniknęły!O o. Nie chcę ci tego mówić, ale prawdopodobnie nie masz szczęścia. git nie przechowuje zmian, których nie dodajesz ani nie zatwierdzasz, i zgodnie z dokumentacją dlagit reset
:
--ciężko
Resetuje indeks i działające drzewo. Wszelkie zmiany w śledzonych plikach w działającym drzewie, ponieważ
<commit>
zostały odrzucone.
Jest możliwe, że może być w stanie odzyskać swoje zmiany z pewnego rodzaju narzędzia do odzyskiwania dysku lub profesjonalnych usług odzyskiwania danych, ale w tym momencie to chyba więcej kłopotów niż to warte.
Jeśli jeszcze nie wyrzuciłeś śmiecia ze swojego repozytorium (np. Używając git repack -d
lub git gc
, ale zauważ, że zbieranie śmieci może również nastąpić automatycznie), to twoje zatwierdzenie wciąż tam jest - po prostu nie jest już dostępne przez HEAD.
Możesz spróbować znaleźć swoje zatwierdzenie, przeglądając dane wyjściowe git fsck --lost-found
.
Nowsze wersje Gita mają coś, co nazywa się „reflog”, który jest dziennikiem wszystkich zmian, które są dokonywane w refach (w przeciwieństwie do zmian, które są dokonywane w zawartości repozytorium). Na przykład za każdym razem, gdy zmieniasz HEAD (tj. Za każdym razem, gdy zmieniasz git checkout
gałęzie), które będą rejestrowane. I, oczywiście, git reset
manipulowałeś również HEAD, więc też został zalogowany. Możesz uzyskać dostęp do starszych stanów swoich referencji w podobny sposób, jak możesz uzyskać dostęp do starszych stanów swojego repozytorium, używając @
znaku zamiast znaku ~
, jak git reset HEAD@{1}
.
Trochę czasu zajęło mi zrozumienie, jaka jest różnica między HEAD @ {1} a HEAD ~ 1, więc oto małe wyjaśnienie:
git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog
HEAD~1
Oznacza to , że „przejdź do zatwierdzenia przed zatwierdzeniem, na które HEAD obecnie wskazuje”, natomiast HEAD@{1}
oznacza „przejdź do zatwierdzenia, na które HEAD wskazał, zanim wskazał, gdzie aktualnie wskazuje”.
To z łatwością pozwoli ci znaleźć utracone zatwierdzenie i je odzyskać.
Przed odpowiedzią dodajmy tło, wyjaśniając, co to jest HEAD
.
First of all what is HEAD?
HEAD
jest po prostu odniesieniem do bieżącego zatwierdzenia (najnowszego) w bieżącej gałęzi.
W HEAD
danym momencie może być tylko jeden . (z wyłączeniem git worktree
)
Zawartość HEAD
jest przechowywana w środku .git/HEAD
i zawiera 40 bajtów SHA-1 bieżącego zatwierdzenia.
detached HEAD
Jeśli nie korzystasz z ostatniego zatwierdzenia, co oznacza, że HEAD
nazywa się to wcześniejszym zatwierdzeniem w historii detached HEAD
.
W wierszu polecenia będzie to wyglądać tak: SHA-1 zamiast nazwy gałęzi, ponieważ HEAD
nie wskazuje ona końca wierzchołka bieżącej gałęzi
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 HEAD
i sprawdzenie żądanego wpisu ponownego logowania spowoduje HEAD
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
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.
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 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 && checkout
zmodyfikuj HEAD
.
git reset HEAD --hard <commit_id>
przykład pochodzi z stackoverflow.com/questions/4114095/... - Jeśli tak jest, czy możesz edytować atrybucję?
git reflog
git cherry-pick <the sha>
Wiem, że to stary wątek ... ale ponieważ wiele osób szuka sposobów na cofnięcie rzeczy w Git, nadal uważam, że dobrym pomysłem może być dalsze udzielanie wskazówek tutaj.
Gdy wykonujesz „dodawanie git” lub przenosisz cokolwiek z lewego górnego do lewego dolnego w git gui, zawartość pliku jest przechowywana w obiekcie blob, a zawartość pliku można odzyskać z tego obiektu blob.
Można więc odzyskać plik, nawet jeśli nie został on zatwierdzony, ale należy go dodać.
git init
echo hello >> test.txt
git add test.txt
Teraz obiekt blob został utworzony, ale jest do niego odwoływany przez indeks, więc nie będzie wymieniony w git fsck, dopóki nie zresetujemy. Więc resetujemy ...
git reset --hard
git fsck
dostaniesz wiszącą kroplę ce013625030ba8dba906f756967f9e9ca394464a
git show ce01362
przywróci zawartość pliku „cześć”
Aby znaleźć niereferencyjne zatwierdzenia, znalazłem wskazówkę sugerującą to.
gitk --all $(git log -g --pretty=format:%h)
Mam to jako narzędzie w git gui i jest to bardzo przydatne.
git fsck --lost-found
może pomóc.
Jeśli korzystasz z JetBrains IDE (cokolwiek opartego na IntelliJ), możesz odzyskać nawet niezaangażowane zmiany za pomocą funkcji „Historii lokalnej”.
Kliknij prawym przyciskiem myszy katalog najwyższego poziomu w drzewie plików, znajdź „Historię lokalną” w menu kontekstowym i wybierz „Pokaż historię”. Otworzy się widok, w którym można znaleźć ostatnie zmiany, a gdy znajdziesz wersję, do której chcesz wrócić, kliknij ją prawym przyciskiem myszy i kliknij „Przywróć”.
Właśnie wykonałem twardy reset niewłaściwego projektu. Tym, co uratowało mi życie, była lokalna historia Eclipse. Mówi się, że IntelliJ Idea też go ma, podobnie jak twój edytor, warto sprawdzić:
Stworzono mały skrypt, aby nieco łatwiej było znaleźć zatwierdzenie, którego szuka:
git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'
Tak, można go znacznie upiększyć za pomocą awk lub czegoś podobnego, ale jest to proste i właśnie tego potrzebowałem. Może uratować kogoś innego 30 sekund.
Mój problem jest prawie podobny. Mam nieprzypisane pliki przed wejściem git reset --hard
.
Na szczęście Udało mi się pominąć wszystkie te zasoby. Po tym, jak zauważyłem, że mogę po prostu cofnąć ( ctrl-z
). Just Chcę tylko dodać to do wszystkich powyższych odpowiedzi.
Uwaga. Nie można ctrl-z
otworzyć nieotwartych plików.
To uratowało mi życie:
https://medium.com/@CarrieGuss/how-to-recover-from-a-git-hard-reset-b830b5e3f60c
Zasadniczo musisz uruchomić:
for blob in $(git fsck --lost-found | awk ‘$2 == “blob” { print $3 }’); do git cat-file -p $blob > $blob.txt; done
Następnie ręcznie przechodząc przez ból, aby ponownie uporządkować pliki do właściwej struktury.
Na wynos: nigdy nie używaj, git reset --hard
jeśli nie do końca w 100% rozumiesz, jak to działa, najlepiej go nie używać.