Wycofywanie lokalnego i zdalnego repozytorium git o 1 zatwierdzenie


188

Przeczytałem podobne posty na ten temat i przez całe życie nie mogę wymyślić, jak to zrobić poprawnie.

Zalogowałem około 1000 plików, których nie chcę i wolałbym nie przechodzić przez 1by1 i usuwać je wszystkie z repozytorium.

  • Mam zdalny masteroddział.
  • Mam lokalny masteroddział.

Oba są w tej samej wersji.

Chcę cofnąć mojego pilota o 1 zatwierdzenie.

Powiedz, że moja historia masterjest A--B--C--D--E.
Chcę wycofać mój lokalny do D.
Następnie przesuń go na zdalny, aby mój bieżący skrót był zarówno zdalny, jak i lokalny.

Mam problemy z robieniem tego.
Korzystam z Git Tower, ale czuję się swobodnie z linii poleceń. Jakaś pomoc?

AKTUALIZACJA: Świetne komentarze poniżej. Wydaje się, że korzystanie z resetowania jest częściowo odradzane, zwłaszcza jeśli repozytorium jest udostępniane innym użytkownikom. Jaki jest najlepszy sposób na cofnięcie zmian poprzedniego zatwierdzenia bez twardego resetu ? Czy jest jakiś sposób?


Zaktualizowałem swoją odpowiedź, aby „cofnąć zmiany poprzedniego zatwierdzenia bez twardego resetu”.
VonC

3
Służy git revertdo robienia bez twardego resetu i bez przeszkadzania użytkownikom.
user562374


Odradzanie zdalnego sterowania jest odradzane, ale jeśli to właśnie chcesz zrobić, zrób to. Istnieją setki sposobów, aby to zrobić, ale wynik byłby taki sam po stronie serwera.
FelipeC

Odpowiedzi:


307

Jeśli nikt jeszcze nie wyciągnął twojego zdalnego repo, możesz zmienić oddział HEAD i zmusić go do przekazania do wspomnianego repozytorium:

git reset --hard HEAD^ 
git push -f 

(lub, jeśli masz bezpośredni dostęp do zdalnego repozytorium, możesz zmienić jego odniesienie do HEAD, nawet jeśli jest to repozytorium od samego początku )

Pamiętaj, jak skomentował Alien-Technology w komentarzach poniżej , w systemie Windows (sesja CMD) potrzebujesz ^^:

git reset --hard HEAD^^
git push -f 

Aktualizacja od 2011 roku:
Używanie git push --force-with-lease( które tutaj przedstawiam , wprowadzonego w 2013 roku wraz z Git 1.8.5) jest bezpieczniejsze.

Zobacz Schwern jest odpowiedź na ilustracji.


Co jeśli ktoś już ściągnął repo? Co bym wtedy zrobił?

Następnie zasugerowałbym coś, co nie przepisuje historii:

  • git revert lokalnie twoje ostatnie zatwierdzenie (tworzenie nowego zatwierdzenia, które odwraca to, co zrobiło poprzednie zatwierdzenie)
  • naciśnij „cofnij” wygenerowany przez git revert.

1
Co jeśli ktoś już ściągnął repo? Co bym wtedy zrobił?
Jamis Charles,

1
@gwho tworzy oddział? Nie, to przesuwa GŁOWĘ gałęzi, ale wciąż jesteś w tej samej gałęzi. Ponieważ jednak push nie jest już przewijaniem do przodu, tak, musisz go wymusić.
VonC

1
czy istnieje sposób, aby dowiedzieć się, czy ktoś wyciągnął repo?
Pinkerton,

4
W systemie Windows ^ znak jest używany do linii kontynuacji i uciec charakter, dzięki czemu polecenie: git resetowania --hard HEAD ^^
Alien Technologia

1
@ AlienTechnology Korzystając z PowerShell, w Windows 10 musiałem tylko pisać reset --hard HEAD^i nie reset --hard HEAD^^resetować ostatniego zatwierdzenia.
Gaspacchio

58

Ustaw oddział lokalny o jedną wersję wstecz ( HEAD^oznacza jedną wersję wstecz):

git reset --hard HEAD^

Wciśnij zmiany do źródła:

git push --force

Będziesz musiał wymusić pchanie, ponieważ w przeciwnym razie git rozpoznałby cię za originjednym zatwierdzeniem i nic się nie zmieni.

Robiąc to --forcepoleca gitowi nadpisanie HEADw zdalnym repozytorium bez respektowania jakichkolwiek postępów.


1
Sugerowałbym nie nazywać tego wycofaniem, ponieważ jest to specyficzny termin o zupełnie innym znaczeniu w git.
Cascabel,

@Jefromi: Dzięki za podpowiedź. Edytowane.
eckes

Świetna odpowiedź. Czytałem, że używanie resetowania wydaje się być częściowo odradzane, zwłaszcza jeśli repozytorium jest udostępniane innym użytkownikom. Czy jest na to czystszy sposób, który cofa wszystkie poprzednie zmiany zatwierdzenia?
Jamis Charles,

Bądź ostrożny! Ukryj swoje niezaangażowane zmiany lub je utraciłeś
Nosov Pavel

To super. Czy to oznacza, że ​​kiedy to zrobimy git push origin master, Git jest w stanie utworzyć nowe zatwierdzenie zdalnie, ponieważ lokalny oddział wyprzedza przynajmniej raz zatwierdzenie? Co więcej, ta ostatnia musi zasadniczo różnić się od tego, na co wskazuje szef w zdalnym repo?
MadPhysicist,

18

Jeśli chcesz cofnąć ostatnie zatwierdzenie, słuchaj:

Krok 1:

Sprawdź swoje lokalne zobowiązania za pomocą wiadomości

$ git log

Krok 2:

Usuń ostatni zatwierdzenie bez resetowania zmian z oddziału lokalnego (lub głównego)

$ git reset HEAD^

LUB jeśli nie chcesz, aby pliki ostatnich zatwierdzeń i aktualizacji były nasłuchiwane

$ git reset HEAD^ --hard

Krok 3:

Możemy zaktualizować pliki i kody i ponownie musimy naciskać z siłą, aby usunąć poprzednie zatwierdzenie. Zachowa nowe zatwierdzenie.

$ git push origin branch -f

Otóż ​​to!


To nie przywraca zatwierdzenia, zastępuje jedno. Proszę nie mylić nas z nowicjuszami poprzez niewłaściwe stosowanie konwencjonalnych terminów.
Suncat2000

7

Wpisując poniżej polecenie, możesz zobaczyć historię git commit -

$ git log

Powiedzmy, że twoja historia w tej gałęzi jest podobna do - commit_A, commit_B, commit_C, commit_D. Gdzie, zatwierdzenie_D jest ostatnim zatwierdzeniem i tutaj pozostaje HEAD. Teraz, aby usunąć ostatnie zatwierdzenie z lokalnego i zdalnego, musisz wykonać następujące czynności:

Krok 1: Usuń ostatnie zatwierdzenie lokalnie przez -

$ git reset - hard HEAD ~

Spowoduje to zmianę HEAD zatwierdzenia na commit_C

Krok 2: Wciśnij swoją zmianę dla nowego zatwierdzenia HEAD do zdalnego

$ git push origin + HEAD

To polecenie spowoduje usunięcie ostatniego zatwierdzenia ze zdalnego.

PS to polecenie jest testowane na Mac OSX i powinno działać również na innych systemach operacyjnych (nie twierdząc jednak o innym systemie operacyjnym)



3

Oto zaktualizowana wersja procedury, która jest bezpieczniejsza.

git reset --hard HEAD^ 
git push --force-with-lease

git push -fbezkrytycznie zastąpi zdalne repozytorium własnymi zmianami. Jeśli ktoś wprowadził zmiany, zostaną utracone. git push --force-with-leasewypchnie twój rebase tylko wtedy, gdy repozytorium będzie zgodne z oczekiwaniami. Jeśli ktoś już naciskał, twój push nie powiedzie się.

Zobacz - siła uważana za szkodliwą; zrozumienie git-force-with-leasing .

Polecam aliasing to jako repush = push --force-with-lease.

Co jeśli ktoś już ściągnął repo? Co bym wtedy zrobił?

Powiedz im, aby git pull --rebase=merges. Zamiast a git fetch origini git merge origin/masterbędzie git fetch origini git rebase -r origin/master. Spowoduje to przepisanie wszelkich lokalnych zmian masterna nowe na podstawie zmiany origin/master. -rzachowa wszelkie połączenia, które mogły zostać dokonane.

Polecam ustawienie tego jako domyślnego zachowania podczas ciągnięcia. Jest bezpieczny, poradzi sobie z ponownym bazowaniem na innych i spowoduje mniej niepotrzebnych połączeń.

[pull]
        rebase = merges

1
Zgoda i głosowanie. Dla mojej obrony moja stara odpowiedź z 2011 roku została napisana dwa lata przed wprowadzeniem --force-with-leaseopcji.
VonC

Myślałem, że już to zrobiłem (wczoraj): stackoverflow.com/posts/4647362/revisions
VonC

1

Rozwiązałem problem podobny do twojego za pomocą następujących poleceń:

git reset --hard HEAD^
git push -f <remote> <local branch>:<remote branch> 


0

Chciałem tylko usunąć ostatnie zatwierdzenie ze zdalnej i wyczyścić również historię zatwierdzeń. Poniższe działało jak urok

git reset --hard HEAD^ 
git push -f 

Ale w jaki sposób „następujące” różni się od mojej powyższej odpowiedzi ?
VCC,

0

Sposób zresetowania głowicy i przywrócenia poprzedniego zatwierdzenia jest zakończony

$ git reset HEAD^ --hard
$ git push <branchname> -f

Ale czasami może nie zostać zaakceptowany w zdalnej gałęzi:

To ssh:<git repo>
 ! [rejected]        develop -> develop (non-fast-forward)
error: failed to push some refs to 'ssh:<git repo>'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

to innym sposobem jest

git revert HEAD
git push <remote branch>

To działa dobrze.

UWAGA: pamiętaj, jeśli git push -f <force>nie powiodło się, a następnie spróbuj przywrócić. Zrób to git pullwcześniej, aby zdalne i lokalne były zsynchronizowane, a następnie spróbuj git revert.
Sprawdź, git logaby upewnić się, że zdalny i lokalny są w tym samym punkcie zatwierdzenia z tym samym SHA1 ..

git revert 
A --> B --> C -->D
A--> B --> C --> D --> ^D(taking out the changes and committing reverted diffs)

0

na lokalnym mistrzu

git reflog
-- this will list all last commit
  e.g Head@{0} -- wrong push
      Head@{1} -- correct push  
git checkout Head@{1} .
  -- this will reset your last modified files

git status 
git commit -m "reverted to last best"
git push origin/master

Nie musisz się martwić, czy ktoś pociągnął, czy nie.

Gotowe!


0

Jeśli chcesz tylko usunąć ostatnie zatwierdzenie ze zdalnego repozytorium bez bałaganu w lokalnym repozytorium, oto jedna linijka:

git push origin +origin/master~:master

Używa następującej składni:

git push <remote> <refspec>

Tutaj <remote>jest origini <refspec>ma następującą strukturę:

+origin/master~:master

Szczegóły można znaleźć w git-push(1). Powyższe +oznacza „force push this ref”, a druga część oznacza „od origin/master~do master(zdalnego origin)”. Nietrudno wiedzieć, że origin/master~to ostatnie zatwierdzenie wcześniej origin/master, prawda?


0

dla mnie działa to dwa polecenia:

git checkout commit_id
git push origin +name_of_branch

0

Możesz także to zrobić:

git reset --hard <commit-hash>
git push -f origin master

i niech wszyscy inni, którzy otrzymali najnowsze złe zatwierdzenia, resetują:

git reset --hard origin/master
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.