Odrzucono Git non-fast-forward


88

Wydaje mi się, że to pytanie było zadawane wiele razy, ale zazwyczaj jest to rozwiązanie: „Usunąłem katalog i ponownie wykonałem pracę z nowym wyewidencjonowaniem”. Wykonałem zatwierdzenie i naciśnięcie, ale zdałem sobie sprawę, że odniosłem się do niewłaściwego numeru biletu w komunikacie dotyczącym zatwierdzenia. Poszukałem więc szybkiego rozwiązania w SO i skończyło się na wpisaniu w terminalu:

$ git reset --soft HEAD^
$ git commit -m "... correct message ..."

Jedynym problemem jest to, że otrzymuję następujący komunikat o błędzie:

To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

Używam modelu git-flow i pracuję nad gałęzią deweloperską. Jak mogę ponownie scalić rzeczy, aby ponownie uszczęśliwić gita?


Odpowiedzi:


52

Siła git push:

git push origin +develop

24
To rozwiązanie, ale przeczytaj komentarz Briana Campbella, aby zrozumieć, co robisz, zanim tego użyjesz.
— thelem

5
git push origin + master
— Aniket Thakur

Zobacz także notatkę o receive.denyNonFastForwardsw odpowiedzi Brian Campbell : +albo --forcemoże nie być wystarczająco energiczne, w zależności od sposobu ich kimkolwiek oni są, zostały skonfigurowane swoje repozytorium git.
— torek

174

Jeśli naciśniesz commit do serwera, a następnie przepisać że popełniania lokalnie (z git reset, git rebase, git filter-branchlub jakiejkolwiek innej manipulacji historii), a następnie popchnął że przepisany popełnić powrotem do serwera, można zepsuć nikogo, kto pociągnął. Oto przykład; powiedz, że popełniłeś A i wypchnąłeś go na serwer.

- * - * - A <- master

- * - * - A <- początek / wzorzec

Teraz decydujesz się przepisać A w sposób, o którym wspomniałeś, resetując i ponownie zatwierdzając. Zauważ, że pozostawia to wiszące zatwierdzenie, A, które ostatecznie zostanie zebrane jako śmieci, ponieważ nie jest osiągalne.

-*-*-ZA
    \
     A '<- mistrz

- * - * - A <- początek / wzorzec

Jeśli ktoś inny, powiedzmy Fred, ściągnie masterserwer z serwera, kiedy to robisz, będzie miał odniesienie do A, od którego może zacząć pracę:

- * - * - A '<- master

- * - * - A <- początek / wzorzec

- * - * - AB <- fred / master

Teraz, gdybyś był w stanie popchnąć swoje A 'do początku / końca, co spowodowałoby szybkie przewijanie do przodu, nie miałoby ono A w swojej historii. Więc jeśli Fred spróbuje ponownie pociągnąć, musiałby nagle scalić i ponownie wprowadzić zatwierdzenie A:

- * - * - A '<- master

- * - * - A <- początek / wzorzec

- * - * - AB- \ 
    \ * <- fred / master
     ZA'--/

Jeśli Fred zdarzy się, że to zauważy, może wykonać rebase, co uniemożliwi ponowne pojawienie się zatwierdzenia A. Ale musiałby to zauważyć i pamiętać, żeby to zrobić; a jeśli masz więcej niż jedną osobę, która ściągnęła A, wszyscy musieliby zmienić bazę, aby uniknąć dodatkowego zatwierdzenia A w drzewie.

Więc generalnie nie jest dobrym pomysłem zmienianie historii w repozytorium, z którego korzystają inni ludzie. Jeśli jednak wiesz, że nikt inny nie wyciąga z tego repozytorium (na przykład jest to twoje własne prywatne repozytorium lub masz tylko jednego programistę pracującego nad projektem, z którym możesz łatwo koordynować), możesz wymusić aktualizacja poprzez uruchomienie:

git push -f

lub

git push origin +master

Obaj zignorują sprawdzanie, czy nie ma szybkiego przewijania do przodu, i zaktualizują zawartość serwera do nowej wersji A ', porzucając wersję A, aby ostatecznie została usunięta.

Możliwe, że wymuszenie wypychania jest całkowicie wyłączone za pomocą receive.denyNonFastForwardsopcji konfiguracji. Ta opcja jest domyślnie włączona w repozytoriach współdzielonych. W takim przypadku, jeśli naprawdę chcesz wymusić wypychanie, najlepszą opcją jest usunięcie gałęzi i ponowne utworzenie jej za pomocą git push origin :master; git push origin master:master. Jednak denyNonFastForwardsopcja jest włączona nie bez powodu, który opisano powyżej; na współdzielonym repozytorium oznacza to, że teraz każdy, kto go używa, musi upewnić się, że bazuje na nowej historii.

W repozytorium współużytkowanym generalnie lepiej jest po prostu wypchnąć nowe zatwierdzenia, które naprawią każdy problem; możesz użyć git revertdo wygenerowania zatwierdzeń, które cofną zmiany poprzednich zatwierdzeń.


świetna edukacja, a komendę dostałeś w końcu, ale moja gałąź nazywała się develop (na podstawie git-flow), a drugi facet podał +developkomendę - więc czek trafia do niego. I tak masz astronomiczną liczbę punktów: P
— rynmrtn 14.04.11

7
Lub użyj mniej tajemniczegogit push --force
— Bennett McElwee

3
@Panique Próbujesz pozwolić kilku osobom pracować na dużym, złożonym kodzie w tym samym czasie, bez blokowania się nawzajem (pozwalając tylko jednej osobie na pracę w tym samym czasie) i bez nadpisywania zmian. Każda osoba musi mieć możliwość niezależnego wprowadzania zmian i scalania tych zmian. Scalanie (ręczne lub automatyczne) może spowodować nieoczekiwane problemy; więc chcesz zachować jak najwięcej informacji, aby móc dowiedzieć się, co się stało, gdyby coś poszło nie tak. Jest to z natury złożone; to nie jest brudne, tylko trudny problem.
— Brian Campbell,

Wypróbowałem opcję -f i +, aby przepisać historię zdalnego repozytorium. W obu opcjach napotkałem problem braku przewijania do przodu. [17:05] $ git push -f origin local_A: remote_A Zliczanie obiektów: 35, gotowe. Kompresja delta z wykorzystaniem do 2 wątków. Kompresja obiektów: 100% (18/18), gotowe. Pisanie obiektów: 100% (21/21), 7,41 KiB, gotowe. Łącznie 21 (delta 9), ponownie użyte 0 (delta 0) zdalne: aby zapobiec utracie historii, odrzucono aktualizacje bez szybkiego przewijania do przodu. Scal zdalne zmiany (np. „Git pull”) przed ponownym naciśnięciem. Zobacz sekcję „Note about fast-forward” w „git push --help” po szczegóły.
— Srikanth

4
@Srikanth Można całkowicie wyłączyć wymuszone wypychanie za pomocą receive.denyNonFastForwardsopcji config. Ta opcja jest domyślnie włączona w repozytoriach współdzielonych. W takim przypadku, jeśli naprawdę chcesz wymusić wypychanie, najlepszą opcją jest usunięcie gałęzi i ponowne utworzenie jej za pomocą git push origin :remote_A; git push origin local_A:remote_A. Ale przeczytaj to, co napisałem powyżej, o tym, dlaczego wykonywanie tego rodzaju przepływu pracy we współdzielonym repozytorium jest złym pomysłem. Powinieneś spróbować to zrobić tylko wtedy, gdy masz coś, co powoduje poważne problemy w zatwierdzeniu, którego próbujesz się pozbyć lub przepisać.
— Brian Campbell

14

Być może będziesz musiał zrobić git pull, co MOŻE automatycznie scalić elementy za Ciebie. Następnie możesz ponownie zatwierdzić. Jeśli masz konflikty, wyświetli się monit o ich rozwiązanie.

Pamiętaj, że musisz określić, z której gałęzi chcesz pobierać, jeśli nie zaktualizowałeś gitconfig, aby określić ...

Na przykład:

git pull origin develop:develop

Wciąż szalony o nie przewijaniu do przodu. Jakieś przemyślenia, jak zmusić to do połączenia? ! [rejected] develop -> develop (non-fast-forward)
— rynmrtn

Myślę, że przełącznik to -f, ale mogę się mylić. kernel.org/pub/software/scm/git/docs/git-pull.html
— Tony

To częściowo działa. Nie widzę jednak aktualizacji na githubie (pokazuje poprzednie zatwierdzenie jako najnowsze nawet z a git push origin develop)
— rynmrtn 14.04.11

7

Używałem EGit i napotkałem również ten problem. Właśnie spróbowałem do rebasebieżącej gałęzi i zadziałało.

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.