Git reset --hard und Push zum Remote Repository

199

Ich hatte ein Repository mit einigen schlechten Commits (D, E und F für dieses Beispiel).

ABCDEF-Master und Herkunft / Master

Ich habe das lokale Repository speziell mit a geändert git reset --hard. Ich habe vor dem Zurücksetzen einen Zweig genommen, also habe ich jetzt ein Repo, das aussieht wie:

A-B-C master  
     \ D-E-F old_master

A-B-C-D-E-F origin/master

Jetzt brauchte ich einige Teile dieser schlechten Commits, also wählte ich die benötigten Teile aus und machte einige neue Commits, sodass ich jetzt vor Ort Folgendes habe:

A-B-C-G-H master
     \ D-E-F old_master

Jetzt möchte ich diesen Zustand auf das Remote-Repo übertragen. Wenn ich jedoch versuche, einen git pushGit zu machen, gibt mir das höflich die Bürste ab:

$ git push origin +master:master --force  
Total 0 (delta 0), reused 0 (delta 0)  
error: denying non-fast forward refs/heads/master (you should pull first)  
To [email protected]:myrepo.git  
! [remote rejected] master -> master (non-fast forward)  
error: failed to push some refs to '[email protected]:myrepo.git'  

Wie kann ich das Remote-Repo dazu bringen, den aktuellen Status des lokalen Repos zu erfassen?

Robertpostill
quelle
2
Das ist ein 'fast' Duplikat von mehreren "Wie drücke
CB Bailey
2
Das stimmt und ich hatte StackOverflow vor dem Posten nach einer Antwort durchsucht. Meine Suche hatte jedoch nur Antworten ergeben, bei denen ein Git Push - Force das Problem behoben hatte. Vielen Dank für den
Link
2
Sie werden bald (git1.8.5, Q4 2013) in der Lage sein, dies git push -forcesorgfältiger zu tun .
VonC

Antworten:

286

Wenn das Erzwingen eines Pushs nicht hilft (" git push --force origin" oder " git push --force origin master" sollte ausreichen), kann dies bedeuten, dass der Remote-Server Pushs ohne schnellen Vorlauf entweder über die Konfigurationsvariable receive.denyNonFastForwards ablehnt ( Beschreibung siehe git config manpage) oder über Update / Pre-Receive Hook.

Mit älterem Git können Sie diese Einschränkung umgehen, indem Sie " git push origin :master" (siehe ':' vor dem Zweignamen) löschen und dann den git push origin masterangegebenen Zweig " " neu erstellen .

Wenn Sie dies nicht ändern können, dann wäre die einzige Lösung sein , anstatt die Geschichte neu zu schreiben , um ein COMMIT zu erstellen Zurücksetzen Änderungen in DEF :

ABCDEF - [(DEF) ^ - 1] Master

ABCDEF Herkunft / Master
Jakub Narębski
quelle
2
@ JakubNarębski, danke. get revert HEAD~Ngeholfen. Nist die Anzahl der Commits. Wenn ich beispielsweise das vorherige Commit benötige, verwende ichgit revert HEAD~1
Maksim Dmitriev
1
Und seien Sie sich bewusst, dass Sie auf diese Weise alle anderen lokalen Meister brechen werden.
Tom Brito
24

Um Jakubs Antwort zu ergänzen: Wenn Sie in ssh Zugriff auf den Remote-Git-Server haben, können Sie in das Git-Remote-Verzeichnis gehen und Folgendes festlegen:

user@remote$ git config receive.denyNonFastforwards false

Kehren Sie dann zu Ihrem lokalen Repo zurück und versuchen Sie erneut, Ihr Commit durchzuführen mit --force:

user@local$ git push origin +master:master --force

Und schließlich die Servereinstellung auf den ursprünglichen geschützten Zustand zurücksetzen:

user@remote$ git config receive.denyNonFastforwards true
Jealie
quelle
Siehe auch pete.akeo.ie/2011/02/denying-non-fast-forward-and.html für maßgeschneiderte Informationen zu sourceforge.
Hlovdal
Detaillierte Anweisungen zum Deaktivieren von DenyNonFastForwards mit vifinden Sie in diesem SO-Beitrag: stackoverflow.com/a/43721579/2073804
ron190
2

Anstatt Ihren "Master" -Zweig zu reparieren, ist es viel einfacher, ihn durch Umbenennen der Zweige mit Ihrem "gewünschten Master" zu tauschen. Siehe https://stackoverflow.com/a/2862606/2321594 . Auf diese Weise würden Sie nicht einmal eine Spur von mehreren Wiederherstellungsprotokollen hinterlassen.

Hilfe bei der
quelle
1

Das ganze Geschäft mit dem Zurücksetzen von Gittern schien für mich sehr kompliziert zu sein.

Also habe ich etwas in dieser Richtung getan, um meinen src-Ordner in den Zustand zu bringen, den ich vor ein paar Commits hatte

# reset the local state
git reset <somecommit> --hard 
# copy the relevant part e.g. src (exclude is only needed if you specify .)
tar cvfz /tmp/current.tgz --exclude .git  src
# get the current state of git
git pull
# remove what you don't like anymore
rm -rf src
# restore from the tar file
tar xvfz /tmp/current.tgz
# commit everything back to git
git commit -a
# now you can properly push
git push

Auf diese Weise wird der Status in der src in einer tar-Datei gespeichert und git wird gezwungen, diesen Status zu akzeptieren, ohne zu viel herumzuspielen. Im Grunde wird das src-Verzeichnis durch den Status ersetzt, den es vor einigen Commits hatte.

Wolfgang Fahl
quelle
0

Für Benutzer von GitHub hat dies bei mir funktioniert:

  1. Stellen Sie in allen Zweigschutzregeln, in denen Sie die Änderung vornehmen möchten, sicher, dass Force Pushs zulassen aktiviert ist
  2. git reset --hard <full_hash_of_commit_to_reset_to>
  3. git push --force

Dadurch wird der Zweigverlauf auf Ihrem lokalen Computer und dem GitHub-Server "korrigiert". Jeder, der diesen Zweig seit dem fehlerhaften Commit mit dem Server synchronisiert hat, hat den Verlauf auf seinem lokalen Computer. Wenn sie die Berechtigung haben, direkt in den Zweig zu pushen, werden diese Commits bei der Synchronisierung sofort wieder angezeigt.

Alles, was alle anderen tun müssen, ist der git resetBefehl von oben, den Zweig auf ihrem lokalen Computer zu "korrigieren". Natürlich müssten sie sich vor lokalen Verpflichtungen für diesen Zweig nach dem Ziel-Hash hüten. Cherry wählt / sichert diese und wendet sie nach Bedarf erneut an. Wenn Sie sich jedoch in einem geschützten Zweig befinden, ist die Anzahl der Personen, die sich direkt darauf festlegen können, wahrscheinlich begrenzt.

Jason Faulkner
quelle