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?

Jamis Charles
źródło
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
2
Możliwy duplikat zatwierdzeń usuwania z oddziału w Git
wjandrea,
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.
VonC
źródło
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.

eckes
źródło
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!

Kannan S.
źródło
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)

sahilabrar
źródło
3

W przypadku komputerów z systemem Windows użyj:

git reset HEAD~1  #Remove Commit Locally
Anvesh Yalamarthy
źródło
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
Schwern
źródło
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> 
Ibrohim Ermatov
źródło
0

Jeśli masz bezpośredni dostęp do zdalnego repozytorium, zawsze możesz użyć:

git reset --soft HEAD^

Działa to, ponieważ nie ma próby modyfikacji nieistniejącego katalogu roboczego. Aby uzyskać więcej informacji, zobacz oryginalną odpowiedź:

Jak mogę anulować ostatnie zatwierdzenie w repozytorium git bare?

Hazok
źródło
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 
minhas23
źródło
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)
ravi.zombie
źródło
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!

Bhuszan
źródło
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?

iBug
źródło
0

dla mnie działa to dwa polecenia:

git checkout commit_id
git push origin +name_of_branch
Yahor M.
źródło
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
A-Sharabiani
źródło