Jak poprawnie wymusić push Git?

1272

Skonfigurowałem zdalne nie-podstawowe „główne” repozytorium i sklonowałem je na moim komputerze. Wprowadziłem kilka lokalnych zmian, zaktualizowałem moje lokalne repozytorium i przesunąłem je z powrotem do mojego zdalnego repozytorium. Do tego momentu wszystko było w porządku.

Teraz musiałem coś zmienić w zdalnym repozytorium. Potem zmieniłem coś w moim lokalnym repozytorium. Uświadomiłem sobie, że zmiana zdalnego repo nie była potrzebna. Próbowałem więc git pushz lokalnego repozytorium do mojego zdalnego repozytorium, ale wystąpił błąd:

Aby zapobiec utracie historii, aktualizacje nie do szybkiego przewijania zostały odrzucone Scal zdalne zmiany przed ponownym przekazaniem dalej. Aby git push --helpuzyskać szczegółowe informacje, zobacz sekcję „Uwaga na temat szybkiego przewijania” .

Myślałem, że prawdopodobnie a

git push --force

zmusiłbym moją kopię lokalną do wypchnięcia zmian do zdalnej i uczynienia tego samego. Wymusza aktualizację , ale kiedy wracam do zdalnego repozytorium i dokonuję zatwierdzenia, zauważam, że pliki zawierają nieaktualne zmiany (te, które poprzednio miały główne repozytorium).

Jak wspomniałem w komentarzach do jednej z odpowiedzi :

[Próbowałem wymusić, ale wracając do serwera głównego, aby zapisać zmiany, dostaję przestarzałą inscenizację. Kiedy więc zatwierdzam, repozytoria nie są takie same. A kiedy próbuję ponownie użyć git push, pojawia się ten sam błąd.

Jak mogę rozwiązać ten problem?

Spyros
źródło
4
Wkrótce (git1.8.5, IV kwartał 2013 r.) Będziesz mógł robić to git push -forceostrożniej .
VonC
6
Jak szczegółowo opisuję w mojej odpowiedzi , git push --forcejest to rzeczywiście inny prawidłowy sposób wymuszania wypychania i wypychania gałęzi tak samo dobrze, jak git push origin master --forcew przypadku domyślnej wersji Git push.default config settings, chociaż które gałęzie, które są szczególnie wypychane, różnią się między wersjami Git przed 2.0 a po 2.0.
2
git push --forcedziała teraz dobrze, FWIW ...
rogerdpack
git push --force-with-leasedziała jeszcze lepiej :), odmówi aktualizacji oddziału, chyba że jest to stan, którego się spodziewasz. (patrz developer.atlassian.com/blog/2015/04/force-with-lease )
spoorcc

Odpowiedzi:

2305

Po prostu zrób:

git push origin <your_branch_name> --force

lub jeśli masz konkretne repozytorium:

git push https://git.... --force

Spowoduje to usunięcie poprzednich zatwierdzeń i przekazanie bieżącego.

Może to nie być właściwe, ale jeśli ktoś natknie się na tę stronę, pomyślał, że może chcieć prostego rozwiązania ...

Krótka flaga

Zauważ też, że -fto skrót --force, więc

git push origin <your_branch_name> -f

będzie również działać.

Katie
źródło
58
Możesz użyć git push origin +masterzamiast tego, co pozwala wypchnąć wiele referencji bez wymuszania ich wszystkich.
nickgrim
5
Pamiętaj, że jeśli przypadkowo to zrobisz git push --force, możesz zepsuć gałąź master (w zależności od domyślnego zachowania push). Co może być do bani .. trochę ..: D
Jeewes
9
@Jeewes, począwszy od wersji Git 2.0, domyślne zachowanie git push --forcepolega na wymuszeniu wypchnięcia aktualnie wyewidencjonowanej gałęzi do jej części licznika zdalnego, więc jeśli masz gałąź master wyewidencjonowaną, to jest identyczna git push origin master --force. Będzie inaczej, jeśli używasz matchingustawienia push.default, które jest domyślne dla wersji Git wcześniejszych niż 2.0. matchingwypycha wszystkie oddziały miejscowych do zdalnych, które mają tę samą nazwę, więc wymuszone pchanie może zdecydowanie nie być tym, co chcesz zrobić ...
@Jeewes Ale w Git 2.0 ustawienie domyślne jest bezpieczniejsze, a przynajmniej nie jest bardziej niebezpieczne niż git push origin master --forcejest.
2
push -f jest dobry, ale nie jest ponownie wyświetlany dla master, ponieważ większość korporacyjnych repozytoriów ma wyłączoną opcję -f dla master. merge -s ourspracował dla mnie
Mihai
247

A jeśli push --forcenie działa, możesz to zrobić push --delete. Spójrz na 2 nd linii w tym przypadku:

git reset --hard HEAD~3  # reset current branch to 3 commits ago
git push origin master --delete  # do a very very bad bad thing
git push origin master  # regular push

Ale strzeż się...

Nigdy nie wracaj do publicznej historii gitów!

Innymi słowy:

  • Nigdy nie forcepchaj publicznego repozytorium.
  • Nie rób tego ani niczego, co może kogoś uszkodzić pull.
  • Nigdy, resetani rewritehistorii w repozytorium, które ktoś mógł już wyciągnąć.

Oczywiście istnieją wyjątkowo rzadkie wyjątki nawet od tej reguły, ale w większości przypadków nie trzeba tego robić i spowoduje to problemy dla wszystkich innych.

Zamiast tego wykonaj cofnięcie.

I zawsze bądź ostrożny z tym, co popychasz do publicznego repozytorium . Cofanie:

git revert -n HEAD~3..HEAD  # prepare a new commit reverting last 3 commits
git commit -m "sorry - revert last 3 commits because I was not careful"
git push origin master  # regular push

W efekcie oba początkowe HEAD (z przywrócenia i zła resetowania ) będą zawierać te same pliki.


edytuj, aby dodać zaktualizowane informacje i więcej argumentów push --force

Rozważ siłę pchającą z dzierżawą zamiast pchania, ale nadal wolisz wycofać

Innym problemem push --forcemoże być sytuacja, gdy ktoś naciska na coś przed tobą, ale po tym, jak już go pobrałeś. Jeśli przeforsujesz wymuszoną wersję, zastąpisz teraz pracę innych .

git push --force-with-leasewprowadzony w git 1.8.5 ( dzięki komentarzowi @VonC do pytania) próbuje rozwiązać ten konkretny problem. Zasadniczo spowoduje błąd i nie wypchnie, jeśli pilot został zmodyfikowany od czasu ostatniego pobrania.

Jest to dobre, jeśli naprawdę jesteś pewien, że push --forcejest potrzebny, ale nadal chcesz zapobiec kolejnym problemom. Chciałbym powiedzieć, że powinno to być push --forcezachowanie domyślne . Ale wciąż nie jest to wymówka, aby wymusić push. Ludzie, którzy znaleźli się przed twoją bazą , nadal będą mieli wiele problemów, których można łatwo uniknąć, gdybyś zamiast tego cofnął się .

A ponieważ mówimy o git --pushinstancjach ...

Dlaczego ktoś miałby wymuszać nacisk?

@linquize przyniósł dobry przykład siły nacisku na komentarze: wrażliwe dane . Źle wyciekłeś danych, których nie należy wypychać. Jeśli jesteś wystarczająco szybki, możesz go „naprawić”* , wymuszając nacisk na górę.

*Dane nadal będą na pilocie chyba też zrobić śmieci zbierać lub oczyścić go jakoś . Istnieje również oczywisty potencjał, aby rozprzestrzenić go przez innych, którzy już go pobrali , ale masz pomysł.

Cregox
źródło
1
Problem @rogerdpack nie polega na tym, czy jest to wykonalne. To jest. Ale może to podsumować wielką katastrofę. Im więcej ktoś to robi (wymuszanie push) i im rzadziej aktualizujesz (ściągasz) z publicznego repozytorium, tym większa jest katastrofa. Może zdemontować świat taki, jaki znasz !!! 111 Przynajmniej świat składający się z tego konkretnego repozytorium.
cregox 24.09.2013
3
Jeśli masz wrażliwe dane,
wymuś
3
@Cawas: Myślę, że ma na myśli, że jeśli próbujesz usunąć poufne dane z repozytorium, to chcesz przepisać historię. Jeśli cofniesz, poufne dane będą nadal obecne we wcześniejszym zatwierdzeniu. To powiedziawszy, jeśli ktoś inny wyciągnął już z repozytorium, wówczas przepisywanie historii nie pomoże ci uniemożliwić mu dostęp do poufnych danych - w tym momencie jest już za późno.
Stuart Golodetz,
3
git push origin master --delete # do a very very bad bad thing git push origin master # regular pushto faktycznie rozwiązało mój problem idealnie (na repozytorium tylko ze mną i moim przyjacielem). może jest to złe dla publicznych repozytoriów, ale dla prywatnych jest to ratowanie życia.
Can Poyrazoğlu
1
dzieje się to automatycznie w przypadku niektórych menedżerów repozytoriów, czyli automatycznych squashów itp. Wymuszanie wypychania po zakończeniu gałęzi funkcji w celu zmniejszenia liczby zatwierdzeń jest powszechne i oczekiwane.
FlavorScape
18

Przede wszystkim nie wprowadzałbym żadnych zmian bezpośrednio w repozytorium „głównym”. Jeśli naprawdę chcesz mieć „główne” repozytorium, powinieneś je tylko naciskać, nigdy nie zmieniaj bezpośrednio.

Jeśli chodzi o występujący błąd, czy próbowałeś git pullz lokalnego repozytorium, a następnie git pushz repozytorium głównego? To, co obecnie robisz (jeśli dobrze to rozumiem), wymusza push, a następnie utratę zmian w „głównym” repozytorium. Najpierw powinieneś scalić zmiany lokalnie.

ubik
źródło
tak, próbowałem wyciągnąć, ale tracę dane z tego powodu. Chcę tworzyć moje główne repozytoria tak, jak moje lokalne, bez wcześniejszej aktualizacji z głównego.
Spyros,
1
W takim przypadku skorzystaj git push -f, ale jeśli ponownie zmienisz główne repozytorium, musisz wrócić do repozytorium lokalnego i git pull, aby zsynchronizowało się ono z najnowszymi zmianami. Następnie możesz wykonać swoją pracę i naciskać ponownie. Jeśli zastosujesz się do tego przepływu pracy „push-pull”, nie dostaniesz błędu, na który narzekałeś.
ubik
tak, rozumiem, że to była moja wina: / Spróbuję i wrócę za chwilę dzięki
Spyros
1
Próbowałem wymusić, ale wracając do serwera głównego, aby zapisać zmiany, dostaję przestarzałą wersję. Kiedy więc zatwierdzam, repozytoria nie są takie same. A kiedy próbuję ponownie użyć git push, pojawia się ten sam błąd.
Spyros,
17

Jeśli jestem w mojej gałęzi lokalnej A i chcę wymusić wypchnięcie gałęzi lokalnej B do gałęzi źródłowej CI, można użyć następującej składni:

git push --force origin B:C
IcedDante
źródło
2
Dowiedziałem się, że nawet jestem w moim lokalnym oddziale B, wciąż muszę to zrobić git push --force origin B:C. W moim przypadku wydaje się, że git push --force origin Cbędzie przekazywał tylko z lokalnego mastera do zdalnej gałęzi C, niezależnie od tego, w której gałęzi aktualnie się znajduję. git version 2.3.8 (Apple Git-58)
Weishi Zeng,
12

użyj następującego polecenia:

git push -f origin master
mustafa Elsayed
źródło
1
Może podaj jakieś wyjaśnienie, dlaczego ta odpowiedź jest lepsza od innych i co ją wyróżnia.
Adam
och, przepraszam za niedogodności, miałem ten sam problem i to polecenie go rozwiązało, pomyślałem, że powinienem go udostępnić.
mustafa Elsayed
12
To jest tak samo jak inne, właśnie zmieniłeś pozycję -fflagi ...
svelandiag
11

Naprawdę polecam:

  • push tylko do głównego repozytorium

  • upewnij się, że repozytorium główne jest repozytorium , aby nigdy nie mieć problemu z tym, że drzewo robocze repozytorium głównego nie jest zsynchronizowane z .gitbazą. Zobacz „ Jak przekazać lokalne repozytorium git na inny komputer?

  • Jeśli musisz dokonać modyfikacji w głównym (nagim) repozytorium, sklonuj go (na głównym serwerze), dokonaj modyfikacji i odepchnij się do niego

Innymi słowy, utrzymuj dostęp do repozytorium zarówno z głównego serwera, jak i komputera lokalnego, aby mieć jedno repozytorium z / do którego można pobrać / pobrać.

VonC
źródło
5

To było nasze rozwiązanie do zastępowania wzorca w korporacyjnym repozytorium gitHub przy zachowaniu historii.

push -fopanowanie repozytoriów korporacyjnych jest często wyłączone, aby zachować historię oddziałów. To rozwiązanie działało dla nas.

git fetch desiredOrigin
git checkout -b master desiredOrigin/master // get origin master

git checkout currentBranch  // move to target branch
git merge -s ours master  // merge using ours over master
// vim will open for the commit message
git checkout master  // move to master
git merge currentBranch  // merge resolved changes into master

popchnij swój oddział desiredOrigini utwórz PR

Mihai
źródło
3

Miałem to samo pytanie, ale w końcu je zrozumiałem. Najprawdopodobniej musisz wykonać następujące dwa polecenia git (zamieniając skrót na numer wersji git commit):

git checkout <hash>
git push -f HEAD:master
Brian M.
źródło