Cofanie „git push”


591

Oto, co zrobiłem z moją rzekomo stabilną gałęzią ...

% git rebase master
First, rewinding head to replay your work on top of it...
Fast-forwarded alpha-0.3.0 to master.
% git status
# On branch alpha-0.3.0
# Your branch is ahead of 'origin/alpha-0.3.0' by 53 commits.
#
nothing to commit (working directory clean)
% git push
Fetching remote heads...
  refs/
  refs/heads/
  refs/tags/
  refs/remotes/
'refs/heads/master': up-to-date
updating 'refs/heads/alpha-0.3.0'
  from cc4b63bebb6e6dd04407f8788938244b78c50285
  to   83c9191dea88d146400853af5eb7555f252001b0
    done
'refs/heads/unstable': up-to-date
Updating remote server info

To wszystko było błędem, jak później zrozumiałem. Chciałbym cofnąć cały ten proces i przywrócić gałąź alfa-0.3.0 z powrotem do tego, co to było.

Co powinienem zrobić?



4
To nie jest tak naprawdę taka sama sytuacja, cofnięcie bazy jest scenariuszem lokalnego repozytorium, cofnięcie wypychania git wymaga zdalnego repozytorium i może być trudniejsze w zależności od posiadanego dostępu.
CB Bailey,

Steen - masz rację - prawdopodobnie powinienem był przypuszczać. Doszedłem do wniosku, że błogosławione repozytorium, z którego wszyscy pobierają, jest raczej zadaniem administratora, a więc należy tutaj, gdzie git po stronie klienta jest pytaniem o przepełnienie stosu.
Cyrus

Szybkie wyjaśnienie - Zgaduję, że jeśli odwołujesz się do zatwierdzenia git przez częściową wartość skrótu, git zakłada, że ​​mówisz o zatwierdzeniu, którego skrót zaczyna się od tego ciągu?
Gershom

Odpowiedzi:


943

Musisz upewnić się, że żaden inny użytkownik tego repozytorium nie pobiera niepoprawnych zmian lub nie próbuje budować na podstawie zatwierdzeń, które chcesz usunąć, ponieważ masz zamiar przewinąć historię.

Następnie musisz „wymusić” naepchnięcie starej referencji.

git push -f origin last_known_good_commit:branch_name

lub w twoim przypadku

git push -f origin cc4b63bebb6:alpha-0.3.0

Być może receive.denyNonFastForwardsustawiłeś w zdalnym repozytorium. W takim przypadku pojawi się błąd zawierający wyrażenie [remote rejected].

W tym scenariuszu będziesz musiał usunąć i ponownie utworzyć gałąź.

git push origin :alpha-0.3.0
git push origin cc4b63bebb6:refs/heads/alpha-0.3.0

Jeśli to nie zadziała - być może dlatego, że masz receive.denyDeletesustawione, musisz mieć bezpośredni dostęp do repozytorium. W zdalnym repozytorium musisz wykonać coś takiego jak następujące polecenie hydrauliczne.

git update-ref refs/heads/alpha-0.3.0 cc4b63bebb6 83c9191dea8

16
Idealna i dobrze wyjaśniona odpowiedź - bardzo dziękuję. Dla każdego, kto natknie się na to, z powodów akademickich wypróbowałem oba pierwsze dwa podejścia i oba działały - oczywiście jeśli pierwsze działa, jest to najczystsze podejście. Gdybym podniósł cię 10 razy Charles, zrobiłbym to. :)
Cyrus,

139
W git push -f origin last_known_good_commit:branch_name
skrócie

5
git push -f origin cc4b63bebb6: alpha-0.3.0 => ten pomógł mi, Uwaga alpha-0.3.0 to nazwa gałęzi, a cc4b63bebb6 to identyfikator zatwierdzenia, do którego chcemy wrócić. więc po wykonaniu tego polecenia będziemy w cc4b63bebb6 commit id.
kumar

22
To rozwiązanie jest bardzo niebezpieczne, jeśli pracujesz we wspólnym repozytorium. Najlepszą praktyką jest to, że wszystkie zatwierdzenia przekazane do zdalnego repozytorium, które są współużytkowane, należy uznać za „niezmienne”. Zamiast tego użyj „git revert”: kernel.org/pub/software/scm/git/docs/…
Saboosh

1
jww - w porównaniu do wszystkiego innego, git jest najbardziej bogatym w funkcje i wydajnym narzędziem do kontroli źródła. Każdy zespół używa go inaczej. Warto spędzić weekend na zabawie ze świeżym repozytorium i na przejrzeniu wszystkich typowych scenariuszy. Gdy poświęcisz trochę czasu na pracę, rozwój jest o wiele mniej stresujący.
user1491819,

165

Wierzę, że możesz to również zrobić:

git checkout alpha-0.3.0
git reset --hard cc4b63bebb6
git push origin +alpha-0.3.0

Jest to bardzo podobne do ostatniej metody, z tym wyjątkiem, że nie musisz się chować w zdalnym repozytorium.


9
To również działało dla mnie, ale warto zauważyć, że spowoduje to „ponowne zapisanie” historii na pilocie. To może być to, czego chcesz, ale może nie być!
Tom

3
+1 za tę odpowiedź, która naprawdę mi pomogła. Chciałem również dodać (i wyjaśnić), że identyfikator zatwierdzenia (który pojawia się po --hardparametrze „ ”) powinien być identyfikatorem każdego zatwierdzenia, dla którego chcesz zresetować gałąź.
Michael Dautermann

1
Ładnie przepisałem historię ... każdy, kto mógł wyciągnąć zmiany, upewniłem się, że zrobili to git reset --hard [commit_id], żebyśmy nie zadzierali z kontinuum czasoprzestrzennym.
Alien Life Form

9
Do czego służy znak „w git push origin + alpha-0.3.0”?
jpierson

1
@jpierson +zmusza do wypychania, podobnie jak -f(ale nieco inaczej: stackoverflow.com/a/25937833/1757149 ). Bez niej, jeśli spróbujesz git push origin alpha-0.3.0push zawiedzie: Updates were rejected because the tip of your current branch is behind.
A__

106

git revert jest mniej niebezpieczny niż niektóre z sugerowanych tutaj podejść:

prompt> git revert 35f6af6f77f116ef922e3d75bc80a4a466f92650
[master 71738a9] Revert "Issue #482 - Fixed bug."
 4 files changed, 30 insertions(+), 42 deletions(-)
prompt> git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)
prompt>

Zastąp 35f6af6f77f116ef922e3d75bc80a4a466f92650 własnym zatwierdzeniem.


2
Jak wymyślić identyfikator 35f6af6f77f116ef922e3d75bc80a4a466f92650? Ta odpowiedź byłaby lepsza, gdybyś mógł to wyjaśnić.
Volomike

2
@Volomike (i twórcy Googlinga z przyszłości), to pytanie opisuje wiele sposobów jego uzyskania: kontrola wersji i pytanie o skrót w SO
Jaime

To jest prawidłowa odpowiedź, ponieważ przy „git reset” nie powinieneś być w stanie wypychać (Aktualizacje zostały odrzucone, ponieważ wierzchołek twojej gałęzi znajduje się za jego zdalnym odpowiednikiem) lub musisz wymusić ściąganie, które nie jest tak naprawdę czyste.
Thomas Decaux,

To działało dla mnie. Należy jednak zachować ostrożność, ponieważ przywracanie spowoduje cofnięcie wszystkich zmian w plikach lokalnych.
user1941537

Zdecydowałem się na tym podejściu wiele razy, ale też używam git rebase -i <-przed-last-dobry-commit id> zrobić interaktywną rebase i czystej historii jako sugerowane tu stackoverflow.com/questions/5189560/... .
Ernesto Allely

35

Przyjęte rozwiązanie (z @charles bailey) jest bardzo niebezpieczne, jeśli pracujesz we wspólnym repozytorium.

Najlepszą praktyką jest to, że wszystkie zatwierdzenia przekazane do zdalnego repozytorium, które są współużytkowane, należy uznać za „niezmienne”. Zamiast tego użyj „git revert”: http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#fixing-mistakes

https://git-scm.com/book/be/v2/Git-Basics-Undoing-Things


Jakie dokładnie są instrukcje, które przepisujesz? Wygląda na to, że masz tylko stare linki.
jww

32

Sposób na zrobienie tego bez utraty pożądanych zmian:

git reset cc4b63b 
git stash
git push -f origin alpha-0.3.0
git stash pop

Następnie możesz wybrać pliki, które chcesz przesłać


19

Inny sposób to zrobić:

  1. utwórz kolejny oddział
  2. pobranie poprzedniego zatwierdzenia w tym oddziale za pomocą „git checkout”
  3. pchnij nowy oddział.
  4. usuń starą gałąź i naciśnij usuń (użyj git push origin --delete <branch_name> )
  5. zmień nazwę nowej gałęzi na starą
  6. pchnij ponownie.

2
To wygląda na prawdziwe rozwiązanie, gdy już popełniłeś błąd w repo
Illarion Kovalchuk


11

Cofnij wielokrotne zatwierdzenia git reset - twardy 0ad5a7a6 (Wystarczy podać skrót SHA1 zatwierdzenia)

Cofnij ostatnie zatwierdzenie

git reset - hard HEAD ~ 1 (zmiany do ostatniego zatwierdzenia zostaną usunięte) git reset --soft HEAD ~ 1 (zmiany do ostatniego zatwierdzenia będą dostępne jako niezatwierdzone modyfikacje lokalne)


9

Scenariusz 1 : Jeśli chcesz cofnąć ostatnie zatwierdzenie, powiedz 8123b7e04b3, poniżej znajduje się polecenie (to zadziałało dla mnie):

git push origin +8123b7e04b3^:<branch_name>

Dane wyjściowe wyglądają jak poniżej:

Total 0 (delta 0), reused 0 (delta 0)
To https://testlocation/code.git
 + 8123b7e...92bc500 8123b7e04b3^ -> master (forced update)

Informacje dodatkowe: Scenariusz 2 : W niektórych sytuacjach może być konieczne przywrócenie cofniętego cofnięcia (w zasadzie cofnięcie cofnięcia) za pomocą poprzedniego polecenia, a następnie użycie poniższego polecenia:

git reset --hard 8123b7e04b3

Wynik:

HEAD is now at cc6206c Comment_that_was_entered_for_commit

Więcej informacji tutaj: https://github.com/blog/2019-how-to-undo-almost-anything-with-git


Scenariusz 1 powinien zawierać zaakceptowaną odpowiedź, ponieważ w pytaniu nie określono, który zatwierdzić do usunięcia. Zaakceptowana odpowiedź usuwa tylko ostatnie zatwierdzenie. Ta odpowiedź usuwa wszelkie zatwierdzenia.
Dominic Cerisano,

0

Istniejące odpowiedzi są dobre i poprawne, jednak co zrobić, jeśli trzeba cofnąć, pushale:

  1. Chcesz zachować zatwierdzenia lokalnie lub chcesz zachować niezatwierdzone zmiany
  2. Nie wiesz, ile zatwierdzeń właśnie popchnąłeś

Użyj tego polecenia, aby przywrócić zmianę do odwołania:

git push -f origin refs/remotes/origin/<branch>@{1}:<branch>

-2

Jeśli chcesz zignorować ostatnie zatwierdzenie, które właśnie wrzuciłeś do zdalnej gałęzi: to nie usunie zatwierdzenia, ale po prostu zignoruje go, przesuwając wskaźnik git do zatwierdzenia wcześniej, o którym mowa HEAD ^ lub HEAD ^ 1

git push origin +HEAD^:branch

Ale jeśli już wypchnąłeś to zatwierdzenie, a inni wyciągnęli gałąź. W takim przypadku przepisywanie historii twojego oddziału jest niepożądane i powinieneś zamiast tego cofnąć to zatwierdzenie:

git revert <SHA-1>
git push origin branch

1
tak! działało to jak urok podczas pracy z githubem. dzięki.
cukabeka

Pytanie dotyczy „wypychania”, to dotyczy oddziału zdalnego. Nie, aby przesunąć HEAD o jeden zatwierdzenie, co oznacza zignoruj ​​naciśnięcie ostatniego zatwierdzenia, po prostu zrób to: git push origin + HEAD ^: your_branch
mkebri 20.04.18
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.