Wie kann ich ein geändertes Commit an das Remote-Git-Repository senden?

662

Wenn ich ein bisschen mit meinem Quellcode gearbeitet habe, habe ich mein übliches Commit ausgeführt und dann in ein Remote-Repository verschoben. Aber dann bemerkte ich, dass ich vergessen hatte, meine Importe im Quellcode zu organisieren. Also mache ich den Änderungsbefehl, um das vorherige Commit zu ersetzen:

> git commit --amend

Leider kann das Commit nicht zurück in das Repository verschoben werden. Es wird folgendermaßen abgelehnt:

> git push origin
To //my.remote.repo.com/stuff.git/
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to '//my.remote.repo.com/stuff.git/'

Was sollte ich tun? (Ich kann auf das Remote-Repository zugreifen.)

Spoike
quelle
Was wäre, wenn meine --amend nur die Commit-Nachricht ändern würde? Gibt es eine Möglichkeit, die letzte Festschreibungsnachricht alleine zu bearbeiten, wenn sie bereits auf Remote übertragen wurde? Ich habe das auf Github gemacht und die gleiche Nachricht über nicht schnellen Vorlauf erhalten. Dann habe ich unten eine Lösung angewendet, aber durch die Zusammenführung wurden oben nur weitere
7
@faB: Ich denke das ist eine FAQ. Eine Commit-Nachricht wird zusammen mit dem Commit gehasht. Wenn Sie sie ändern , ändert sich die Revid (Hash). Wenn es nicht klar ist: Nein, kannst du nicht. IIRC kann Out-of-Band-Informationen in Notizen speichern (so können Sie vorhandene Commits mit Anmerkungen versehen, ohne sie zu ändern). Verwenden Sie Tags, um bestimmte Commits zu kennzeichnen
siehe
1
Sie werden bald (git1.8.5, Q4 2013) in der Lage sein, dies git push -forcesorgfältiger zu tun .
VonC
3
Hier ist der Cowboy-Stil. Lernen Sie nicht weiter und suchen Sie nicht nach Möglichkeiten, um die vorherige Git-Änderung rückgängig zu machen. Fügen Sie einfach einen Platzhaltercode hinzu, ich meine, fügen Sie einen Kommentar hinzu, bereinigen Sie ein bisschen Code oder fügen Sie einfach ein paar Striche hinzu. Machen Sie jetzt ein echtes Commit und schieben Sie es auf die Fernbedienung. Erledigt !
Nehem
@ user58777 Wenn Ihre Änderung nur die Festschreibungsnachricht ändern sollte und Sie seitdem keine zusätzlichen lokalen Festschreibungen mehr vorgenommen haben, können Sie Ihren lokalen Zweig auf die Remote-Festschreibung zurücksetzen, die Sie vor dem Ändern der Festschreibungsnachricht gepusht haben.
Scott Ahten

Antworten:

504

Ich habe tatsächlich einmal mit --forceund .gitRepository gepusht und wurde von Linus BIG TIME beschimpft . Im Allgemeinen wird dies viele Probleme für andere Menschen verursachen. Eine einfache Antwort lautet "Tu es nicht".

Ich sehe, dass andere sowieso das Rezept dafür gegeben haben, deshalb werde ich sie hier nicht wiederholen. Aber hier ist ein Tipp, um sich von der Situation zu erholen, nachdem Sie das geänderte Commit mit --force (oder + master) veröffentlicht haben.

  1. Verwenden git reflogSie diese Option, um das alte Commit zu finden, das Sie geändert haben (rufen Sie es auf old, und wir rufen das neue Commit auf, das Sie durch Ändern erstellt haben new).
  2. Erstellen Sie eine Zusammenführung zwischen oldund new, indem Sie den Baum von new, like aufzeichnen git checkout new && git merge -s ours old.
  3. Verbinde das mit deinem Meister mit git merge master
  4. Aktualisieren Sie Ihren Master mit dem Ergebnis mit git push . HEAD:master
  5. Schieben Sie das Ergebnis heraus.

Dann werden die Menschen , die unglücklich genug waren, haben sich für ihre Arbeit auf dem Festschreiben Sie ausgelöscht durch eine Änderung und zwingt einen Push wird das resultierende merge sehen werden sehen , dass Sie bevorzugen newüber old. Bei ihren späteren Zusammenschlüssen werden die Konflikte zwischen oldund newdie aus Ihrer Änderung resultierenden Konflikte nicht sichtbar, sodass sie nicht leiden müssen.

João Pimentel Ferreira
quelle
17
Ich bin mir sehr wohl bewusst, was passiert, wenn Sie einen geänderten Commit erzwingen (indem Sie die Geschichte zerstören). Zum Glück war ich der einzige Entwickler im Projekt, bei dem sich das Remote-Repo auf einem Netzwerklaufwerk befand. Es war also keine so große Sache. Ich habe nie darüber nachgedacht, ein Änderungs-Commit zusammenzuführen, daher werde ich dies positiv bewerten.
Spoike
61
In unserem Unternehmen drängen wir ziemlich regelmäßig auf von Einzelpersonen entwickelte Feature-Zweige.
Ondra Žižka
2
Die Schelte von Linus war, weil Sie die Geschichte mit der Force-Option gelöscht haben, nicht weil Sie es nicht tun sollten. Die Lösung von GabrielleV funktioniert einwandfrei, da sie den Verlauf nicht verändert.
user411279
2
Bitte, da der Autor (Gitster) dieser Antwort nicht mehr zu existieren scheint, könnte jemand helfen, die Artikelnummer 1 zu klären: Finden Sie das alte Commit. Wenn Sie kein Backup haben, wo würden Sie es finden? Amend and Force Push hätte es nicht zerstört? Vielleicht bezieht er sich darauf, es von einem Freund / Mitarbeiter zu bekommen, der es noch im Baum hat?
Dr. Beco
2
Dr. Breco können Sie verwenden git reflog, um es zu finden
Simon Zyx
269

Sie sehen eine Git-Sicherheitsfunktion. Git weigert sich, den Remote-Zweig mit Ihrem Zweig zu aktualisieren, da das Head-Commit Ihres Zweigs nicht direkt vom aktuellen Head-Commit des Zweigs abhängt, auf den Sie pushen.

Wenn dies nicht der Fall wäre, würden zwei Personen, die ungefähr zur gleichen Zeit in dasselbe Repository pushen, nicht wissen, dass zur gleichen Zeit ein neues Commit eingeht, und wer zuletzt pusht, würde die Arbeit des vorherigen Drückers ohne eines von beiden verlieren sie erkennen dies.

Wenn Sie wissen, dass Sie die einzige Person sind, die Druck ausübt, und Sie ein geändertes Commit oder ein Commit, das den Zweig zurückspult, senden möchten, können Sie Git zwingen, den Remote-Zweig mithilfe des -fSchalters zu aktualisieren .

git push -f origin master

Auch dies funktioniert möglicherweise nicht, da Git es Remote-Repositorys ermöglicht, nicht schnell vorwärts gerichtete Pushs am anderen Ende mithilfe der Konfigurationsvariablen abzulehnen receive.denynonfastforwards. In diesem Fall sieht der Ablehnungsgrund folgendermaßen aus (beachten Sie den Teil "Remote abgelehnt"):

 ! [remote rejected] master -> master (non-fast forward)

Um dies zu umgehen, müssen Sie entweder die Konfiguration des Remote-Repositorys ändern oder als Dirty-Hack den Zweig folgendermaßen löschen und neu erstellen:

git push origin :master
git push origin master

Im Allgemeinen verwendet der letzte Parameter git pushdas Format <local_ref>:<remote_ref>, wobei local_refder Name des Zweigs im lokalen Repository und remote_refder Name des Zweigs im Remote-Repository ist. Dieses Befehlspaar verwendet zwei Abkürzungen. :masterhat eine null local_ref, was bedeutet, dass eine Nullverzweigung auf die entfernte Seite verschoben wird master, dh die entfernte Verzweigung gelöscht wird. Ein Zweigstellenname ohne :Mittel schiebt den lokalen Zweig mit dem angegebenen Namen an den Remote-Zweig mit demselben Namen. masterin dieser Situation ist kurz für master:master.

CB Bailey
quelle
2
Dies funktionierte nicht mit Github, es gab mir die folgende Nachricht: [Remote abgelehnt] Master (Löschen des aktuellen Zweigs verboten)
Vedang
Ich wollte keinen Push erzwingen (von dem ich wusste, dass es das Problem lösen würde), aber jetzt habe ich wohl keine andere Wahl.
Vedang
1
Dies ist die einzige Lösung, die für mein mit assembla gehostetes Repo funktioniert hat.
Justin
1
Durch Löschen des Remote-Master-Zweigs wird der Speicherplatz im Remote-Repo freigegeben.
Mr_and_Mrs_D
1
@Mr_and_Mrs_D: Nicht sofort, aber nach git gcAblauf der Reflogs werden alte Objekte beschnitten. Niemand, der das Repository klont, erhält Objekte, die nicht mehr erreichbar sind, sobald der Zweig aktualisiert wurde.
CB Bailey
211

Schneller Scherz: Die Tatsache, dass hier niemand die einfache Antwort gepostet hat, zeigt die verzweifelte Benutzerfeindlichkeit der Git-CLI.

Wie auch immer, der "offensichtliche" Weg, dies zu tun, vorausgesetzt, Sie haben nicht versucht, den Druck zu erzwingen, besteht darin, zuerst zu ziehen. Dadurch wird die Änderung, die Sie geändert haben (und daher nicht mehr haben), abgerufen, sodass Sie sie wieder haben.

Sobald Sie Konflikte gelöst haben, können Sie erneut pushen.

Damit:

git pull

Wenn beim Ziehen Fehler auftreten, stimmt möglicherweise etwas in Ihrer lokalen Repository-Konfiguration nicht (ich hatte eine falsche Referenz im Zweigabschnitt .git / config).

Und danach

git push

Vielleicht bekommen Sie ein zusätzliches Commit mit dem Thema, das von einer "Trivial Merge" erzählt.

GabrieleV
quelle
2
Ja, ich habe darüber geschrieben, siehe stackoverflow.com/questions/253055/… ;)
Spoike
10
Das funktioniert nicht wirklich so, wie ich es erwartet hatte. Es werden zwei neue Commits erstellt. Eine, die eine Nachbildung der alten ist, aber mit den geänderten Änderungen. Und ein Merge Commit mit einem leeren Diff. Das alte Commit bleibt unverändert und enthüllt möglicherweise sensible Daten, die ich ändern wollte. Ich glaube git push -foder git resetist der einzige Weg hierher.
Knie
40
Während das Problem technisch beantwortet wird, wird das Problem nicht wirklich behoben. Wie Sie sagten, wird ein zusätzliches Commit generiert, aber der Hauptgrund, warum Benutzer ein Commit ändern, besteht darin, das Erstellen eines neuen Commits zu vermeiden. Wenn das Poster also Ihren Anweisungen folgen würde, würde er nicht das gewünschte Ergebnis erzielen. Genauso sinnvoll wäre es, das Commit überhaupt nicht zu ändern.
Dan Jones
102

Kurze Antwort: Schieben Sie geänderte Commits nicht auf ein öffentliches Repo.

Lange Antwort: Einige Git-Befehle wie git commit --amendund git rebaseschreiben das Verlaufsdiagramm tatsächlich neu. Dies ist in Ordnung, solange Sie Ihre Änderungen nicht veröffentlicht haben, aber wenn Sie dies einmal getan haben, sollten Sie sich wirklich nicht mit dem Verlauf beschäftigen, denn wenn jemand Ihre Änderungen bereits erhalten hat, kann dies fehlschlagen, wenn er erneut versucht, sie zu ziehen . Anstatt ein Commit zu ändern, sollten Sie nur ein neues Commit mit den Änderungen vornehmen.

Wenn Sie jedoch wirklich, wirklich ein geändertes Commit vorantreiben möchten, können Sie dies folgendermaßen tun:

$ git push origin +master:master

Das führende +Zeichen erzwingt das Drücken des Pushs, auch wenn dies nicht zu einem "Fast-Forward" -Commit führt. (Ein Fast-Forward-Commit tritt auf, wenn die Änderungen, die Sie vornehmen, direkt von den Änderungen abhängen, die bereits im öffentlichen Repo enthalten sind.)

Mipadi
quelle
5
Wie ist das anders (besser oder schlechter) als git push -f? Vielen Dank!
Bentford
11
@entford: Es ist im Grunde das gleiche wie git push -f.
Mipadi
54

Hier ist eine sehr einfache und saubere Möglichkeit, Ihre Änderungen zu verschieben, nachdem Sie bereits Folgendes vorgenommen haben commit --amend:

git reset --soft HEAD^
git stash
git push -f origin master
git stash pop
git commit -a
git push origin master

Welches macht das Folgende:

  • Setzen Sie den Verzweigungskopf auf das übergeordnete Commit zurück.
  • Verstecke dieses letzte Commit.
  • Druck auf Fernbedienung erzwingen. Die Fernbedienung hat jetzt nicht das letzte Commit.
  • Pop dein Versteck.
  • Sauber verpflichten.
  • Zur Fernbedienung drücken.

Denken Sie daran, "Ursprung" und "Master" zu ändern, wenn Sie dies auf einen anderen Zweig oder eine andere Fernbedienung anwenden.

Faiza
quelle
3
2 Anmerkungen: - Stellen Sie sicher, dass Sie den Namen des Zweigs ändern, wenn Sie an einem anderen arbeiten. - Ich musste ihn git addvor meinem Commit verwenden, um die Änderungen aufzunehmen.
SylvainB
1
In Windows CMD sollte der erste Befehl maskiert werden : git reset --soft "HEAD^". Der Rest funktioniert gut.
MrMister
2
"ein sehr einfacher und sauberer Weg .." cit. Dieses Verfahren umfasst erzwungenes Drücken. Angesichts aller Kritikpunkte in den obigen Antworten bin ich mir nicht sicher, ob dieses Verfahren tatsächlich sauber ist.
Na13-c
24

Ich habe es gelöst, indem ich mein lokales geändertes Commit verworfen und die neuen Änderungen oben hinzugefügt habe:

# Rewind to commit before conflicting
git reset --soft HEAD~1

# Pull the remote version
git pull

# Add the new commit on top
git add ...
git commit
git push
bara
quelle
2
Dies ist die einfachste Version!
Mknaf
Das Hinzufügen eines weiteren Änderungs-Commits ist besser als das Umschreiben des Verlaufs. Ich bin mit @mknaf
sdkks
8

Ich hatte das gleiche Problem.

  • Das letzte Commit, das bereits verschoben wurde, wurde versehentlich geändert
  • Viele Änderungen vor Ort vorgenommen, etwa fünf Mal festgeschrieben
  • Versucht zu pushen, bekam einen Fehler, geriet in Panik, führte Remote zusammen, bekam viele Nicht-meine-Dateien, pushe, schlug fehl usw.

Als Git-Neuling dachte ich, es sei komplett FUBAR .

Lösung: Etwas wie von @bara vorgeschlagen + einen lokalen Sicherungszweig erstellt

# Rewind to commit just before the pushed-and-amended one.
# Replace <hash> with the needed hash.
# --soft means: leave all the changes there, so nothing is lost.
git reset --soft <hash>

# Create new branch, just for a backup, still having all changes in it.
# The branch was feature/1234, new one - feature/1234-gone-bad
git checkout -b feature/1234-gone-bad

# Commit all the changes (all the mess) not to lose it & not to carry around
git commit -a -m "feature/1234 backup"

# Switch back to the original branch
git checkout feature/1234

# Pull the from remote (named 'origin'), thus 'repairing' our main problem
git pull origin/feature/1234

# Now you have a clean-and-non-diverged branch and a backup of the local changes.
# Check the needed files from the backup branch
git checkout feature/1234-gone-bad -- the/path/to/file.php

Vielleicht ist es keine schnelle und saubere Lösung, und ich habe meine Historie verloren (1 Commit statt 5), aber es hat einen Tag Arbeit gespart.

Davisca
quelle
6

Wenn Sie den Code nicht in Ihren Remote-Zweig (GitHub / Bitbucket) übertragen haben, können Sie die Commit-Nachricht in der Befehlszeile wie folgt ändern.

 git commit --amend -m "Your new message"

Wenn Sie an einem bestimmten Zweig arbeiten, gehen Sie folgendermaßen vor:

git commit --amend -m "BRANCH-NAME: new message"

Wenn Sie den Code bereits mit einer falschen Nachricht gepusht haben, müssen Sie beim Ändern der Nachricht vorsichtig sein. Wenn Sie also die Festschreibungsnachricht ändern und erneut versuchen, sie zu übertragen, treten Probleme auf. Befolgen Sie die folgenden Schritte, um den Vorgang zu vereinfachen.

Bitte lesen Sie die gesamte Antwort, bevor Sie dies tun

git commit --amend -m "BRANCH-NAME : your new message"

git push -f origin BRANCH-NAME                # Not a best practice. Read below why?

Wichtiger Hinweis: Wenn Sie den Force Push direkt verwenden, können Codeprobleme auftreten, an denen andere Entwickler in demselben Zweig arbeiten. Um diese Konflikte zu vermeiden, müssen Sie den Code aus Ihrem Zweig ziehen, bevor Sie den Force-Push ausführen :

 git commit --amend -m "BRANCH-NAME : your new message"
 git pull origin BRANCH-NAME
 git push -f origin BRANCH-NAME

Dies ist die beste Vorgehensweise beim Ändern der Festschreibungsnachricht, wenn diese bereits übertragen wurde.

Prabhakar Undurthi
quelle
1
Wenn Sie das Commit in Ihrem letzten Beispiel erfolgreich zurückgezogen haben, warum müssen Sie Push erzwingen? Würde ein Standard-Push nicht ausreichen? Vielen Dank
Thomas
Die von Thomas gestellte Frage ist in der Tat sehr gültig. Ich selbst musste den Druck nach dem Ziehen nicht erzwingen.
Na13-c
Bitte nennen Sie es nicht "die beste Vorgehensweise", da es eine Möglichkeit gibt, dies zu umgehen --force. Siehe die akzeptierte Antwort
Farid,
5

Wenn Sie wissen, dass niemand Ihr nicht geändertes Commit gezogen hat, verwenden Sie die --force-with-leaseOptiongit push .

In TortoiseGit können Sie dasselbe unter den Optionen "Push ...", "Force: May verwirft" und "Bekannte Änderungen" überprüfen.

Mit Force (möglicherweise bekannte Änderungen verwerfen) kann das Remote-Repository einen sichereren Push ohne schnellen Vorlauf akzeptieren. Dies kann dazu führen, dass das Remote-Repository Commits verliert. Verwenden Sie es mit Vorsicht. Dies kann verhindern, dass unbekannte Änderungen von anderen Personen auf der Fernbedienung verloren gehen. Es wird geprüft, ob der Serverzweig auf dasselbe Commit wie der Remote-Tracking-Zweig verweist (bekannte Änderungen). Wenn ja, wird ein Kraftstoß ausgeführt. Andernfalls wird es abgelehnt. Da git keine Remote-Tracking-Tags hat, können Tags mit dieser Option nicht überschrieben werden.

ShawnFeatherly
quelle
4

Sie erhalten diesen Fehler, weil die Git-Fernbedienung bereits über diese Festschreibungsdateien verfügt. Sie müssen den Zweig zwingen, damit dies funktioniert:

git push -f origin branch_name

Stellen Sie außerdem sicher, dass Sie den Code von der Fernbedienung abrufen, da möglicherweise eine andere Person in Ihrem Team in denselben Zweig verschoben hat.

git pull origin branch_name

Dies ist einer der Fälle, in denen wir das Commit auf Remote erzwingen müssen.

Praveen Dhawan
quelle
Warum berücksichtigt diese Antwort nicht die wichtigsten Kommentare, die in früheren Antworten geäußert wurden?
Na13-c
2

Hier ist eine sehr einfache und saubere Möglichkeit, Ihre Änderungen zu verschieben, nachdem Sie bereits ein git add "your files"und vorgenommen haben git commit --amend:

git push origin master -f

oder:

git push origin master --force
Craken
quelle
Ich höre, dass das schlecht ist, und ich bin mir sicher, dass es so ist. Es gibt einen (guten) Grund, warum Git standardmäßig fehlschlägt (und --force erfordert), da bin ich mir sicher.
Rolf
1

Ich musste dieses Problem beheben, indem ich aus dem Remote-Repo zog und mich mit den entstandenen Zusammenführungskonflikten befasste, festschrieb und dann pushe. Aber ich habe das Gefühl, dass es einen besseren Weg gibt.

Spoike
quelle
Nicht wirklich. Das Problem könnte sein, dass Sie Ihre lokale Kopie vom Remote-Repo nicht aktualisiert haben. Git wird nicht darauf drängen, da Sie möglicherweise manuell Zusammenführungen durchführen müssen. In meiner anderen Antwort habe ich einen Befehl (und eine Erklärung), der einen Push erzwingt - aber Vorsicht, möglicherweise werden Änderungen in der Fernbedienung gelöscht.
Mipadi
1

Ich habe einfach weiter gemacht, was Git mir gesagt hat. Damit:

  • Kann wegen geänderten Commits nicht pushen.
  • Ich ziehe wie vorgeschlagen.
  • Zusammenführung schlägt fehl. also behebe ich es manuell.
  • Erstellen Sie ein neues Commit (mit der Bezeichnung "Merge") und drücken Sie es.
  • Es scheint zu funktionieren!

Hinweis: Das geänderte Commit war das neueste.

Rolf
quelle
1
Ich würde abstimmen, wenn ich mehr Reputationspunkte hätte, also werde ich hier nur höflich fragen, wer warst du von den Leidenden? Derjenige, der geändert hat? Derjenige, der mit geändertem Commit an einem Zweig gezogen und gearbeitet hat? Vor der Änderung oder danach? Ich habe gerade jede meiner Modifikationen gelöscht, weil ich dich missverstanden habe ... Zum Glück gab es nicht viel ...
Bartis Áron
1

Folgendes hat für mich funktioniert, als ich den Autor und Committer eines Commits geändert habe.

git push -f origin master

Git war klug genug, um herauszufinden, dass es sich um Commits identischer Deltas handelte, die sich nur im Abschnitt mit den Metainformationen unterschieden.

Sowohl die lokalen als auch die entfernten Köpfe wiesen auf die fraglichen Commits hin.

MadPhysicist
quelle
0

Hier ist, wie ich eine Bearbeitung in einem vorherigen Commit behoben habe:

  1. Speichern Sie Ihre Arbeit bisher.
  2. Bewahren Sie Ihre Änderungen vorerst auf, wenn sie vorgenommen wurden: git stashJetzt ist Ihre Arbeitskopie im Status Ihres letzten Commits sauber.
  3. Nehmen Sie die Änderungen und Korrekturen vor.
  4. Übernehmen Sie die Änderungen im Modus " Ändern " :git commit --all --amend
  5. Ihr Editor fragt nach einer Protokollnachricht (standardmäßig die alte Protokollnachricht). Speichern Sie den Editor und beenden Sie ihn, wenn Sie damit zufrieden sind.

    Die neuen Änderungen werden dem alten Commit hinzugefügt. Überzeugen Sie sich selbst mit git logundgit diff HEAD^

  6. Wenden Sie Ihre versteckten Änderungen erneut an, falls sie vorgenommen wurden: git stash apply

Harshal Wani
quelle