Git Force Push: Was es ist und wann Sie ihn sicher einsetzen

Programmierung

Sie haben einen Branch per git rebase umgeschrieben, den letzten Commit mit --amend korrigiert oder mehrere Commits zusammengefasst – und plötzlich weigert sich git push mit ! [rejected] ... (non-fast-forward). Genau hier kommt der Force Push ins Spiel. Er umgeht die Ablehnung bewusst – nützlich und riskant zugleich. Der Reihe nach: was der Befehl technisch tut, warum --force-with-lease fast immer die bessere Wahl ist, wie Sie in vier Schritten sicher pushen und wie Sie überschriebene Commits per Reflog zurückholen.

Was git push --force technisch bedeutet

Ein normaler Push ist nur erlaubt, wenn er ein sogenannter Fast-Forward ist: Der Remote-Branch zeigt auf einen Commit, der in Ihrer lokalen Historie enthalten ist. Git kann den Zeiger dann einfach nach vorne schieben, ohne dass etwas verloren geht. (Mehr dazu im Beitrag Was ist Git Fast-Forward?.)

Sobald sich Ihre lokale Historie und die Remote-Historie auseinanderentwickelt haben – etwa weil Sie Commits umgeschrieben haben – ist kein Fast-Forward mehr möglich. Git lehnt den Push ab, um keine Commits zu verlieren.

git push --force (kurz: git push -f) hebt genau diese Schutzsperre auf. Der Befehl weist den Remote an, den Branch-Zeiger bedingungslos auf Ihren lokalen Stand zu setzen – egal, was vorher dort stand. Commits, die auf dem Remote lagen und nicht in Ihrer neuen Historie enthalten sind, werden vom Branch gelöst und irgendwann von der Garbage Collection entfernt.

Wichtig: Ein Force Push überschreibt keine Dateien im klassischen Sinn. Er verschiebt nur den Branch-Zeiger. Die alten Commits bleiben serverseitig oft noch eine Weile über ihren Hash erreichbar – GitHub etwa hält nicht mehr referenzierte Commits eine Zeit lang vor, bevor die Garbage Collection sie entfernt. Verlassen sollten Sie sich darauf aber nicht.

Wann Sie einen Force Push wirklich brauchen

Ein Force Push ist immer dann nötig, wenn Sie bereits gepushte Historie verändert haben. Typische Fälle:

  • Nach git rebase – Sie haben Commits auf eine neue Basis gesetzt; ihre Hashes haben sich geändert.
  • Nach git commit --amend – Sie haben den letzten (schon gepushten) Commit korrigiert, etwa die Commit-Message oder eine vergessene Datei.
  • Nach einem interaktiven Rebase (git rebase -i) – Sie haben Commits zusammengefasst (squash), umsortiert oder gelöscht.
  • Nach git reset --hard <älterer-commit> – Sie wollen den Remote-Branch auf einen früheren Stand zurücksetzen.

Das verbindende Muster: Sobald ein Commit-Hash sich ändert, betrachtet Git das als komplett neue Historie – und ein normaler Push scheitert.

Die sichere Variante: --force-with-lease

Das eigentliche Risiko am nackten --force ist nicht, dass Sie Ihre eigene Arbeit überschreiben, sondern dass Sie die Arbeit anderer wegwerfen. Wenn eine Kollegin nach Ihrem letzten Fetch etwas auf denselben Branch gepusht hat, löscht --force deren Commit kommentarlos.

git push --force-with-lease verhindert das:

git push --force-with-lease

Der Befehl vergleicht vor dem Push, ob der Remote-Branch noch genau auf dem Commit steht, den Sie zuletzt gesehen haben (Ihr Remote-Tracking-Ref, z. B. origin/feature). Nur wenn das übereinstimmt, wird gepusht. Hat jemand zwischenzeitlich etwas hochgeladen, bricht Git mit stale info ab, statt zu überschreiben.

--force-with-lease gibt es seit Git 1.8.5. Machen Sie es sich zur Gewohnheit – als Alias:

git config --global alias.pushf "push --force-with-lease"

Die Lücke, die --force-if-includes schließt

--force-with-lease hat einen Haken: Es prüft gegen Ihr Remote-Tracking-Ref. Läuft im Hintergrund ein git fetch (viele IDEs und Editoren tun das automatisch), wird dieser Ref aktualisiert – und die „Versicherung“ schützt nicht mehr, obwohl Sie die neuen Commits nie gesehen haben.

Seit Git 2.30 (Ende 2020) gibt es dafür --force-if-includes:

git push --force-with-lease --force-if-includes

Diese Option verlangt zusätzlich, dass die aktuelle Remote-Spitze tatsächlich in Ihre lokale Historie integriert wurde. Für sicherheitsbewusstes Arbeiten ist die Kombination aus beiden Flags der beste Kompromiss zwischen „geht durch“ und „zerstört nichts“.

Schritt für Schritt: sicher force-pushen

  1. Fetchen und prüfen, was auf dem Remote liegt:
    git fetch origin
    git log --oneline origin/feature -5
  2. Sicherstellen, dass niemand sonst am Branch arbeitet – kurz im Team nachfragen, wenn es kein rein persönlicher Branch ist.
  3. Optional ein Backup des aktuellen Stands als lokalen Branch anlegen, falls Sie doch zurückmüssen:
    git branch backup/feature-vor-rebase
  4. Mit Lease pushen:
    git push --force-with-lease --force-if-includes origin feature

Schritt 3 kostet zwei Sekunden und erspart im Zweifel viel Ärger.

Typische Fehler und ihre Lösung

! [rejected] ... (non-fast-forward) – Der Klassiker nach einem Rebase. Solange Sie sicher sind, dass die Umschreibung gewollt war, ist genau hier ein --force-with-lease die richtige Antwort. War die Divergenz nicht gewollt, integrieren Sie stattdessen mit git pull --rebase.

stale info / Push mit Lease abgelehnt – Jemand hat gepusht, seit Sie zuletzt gefetcht haben. Nicht einfach auf --force ausweichen. Erst git fetch, die neuen Commits ansehen (git log origin/feature), einarbeiten, dann erneut pushen.

protected branch hook declined / refusing to allow ... force push – Auf dem Server (GitHub, GitLab) ist eine Branch-Protection-Regel aktiv, die Force Pushes blockiert. Das ist bei main/master gewollt. Wie man die Regel bei Bedarf gezielt lockert, steht in Wie aktiviert man Force Push in GitHub?.

Versehentlich fremde Commits überschrieben – Der teuerste Fehler, und der Grund, --force zu meiden. Die Rettung läuft über das Reflog (siehe unten).

Wenn es doch schiefging: Rettung über das Reflog

Solange ein Commit einmal in Ihrem lokalen Repository existierte, ist er meist noch erreichbar – auch wenn kein Branch mehr auf ihn zeigt. Das Reflog protokolliert jede Bewegung der Branch-Zeiger:

git reflog

Sie sehen eine Liste wie a1b2c3d HEAD@{2}: commit: .... Suchen Sie den letzten guten Stand, dann stellen Sie ihn wieder her:

git reset --hard a1b2c3d

Danach den korrekten Stand erneut pushen. Auch überschriebene fremde Commits lassen sich oft retten – aber nur, wenn die betroffene Person deren Hash noch kennt oder ihn lokal hat. Ihr eigenes Reflog kennt fremde Commits nur, wenn sie durch Ihr Repository gelaufen sind.

Was Sie niemals force-pushen sollten

Force Push gehört auf eigene, kurzlebige Feature-Branches. Tabu ist er auf geteilten Branches, an denen mehrere arbeiten, und auf main/develop. Wer dort die Historie umschreibt, zwingt alle anderen zu manuellem git reset und riskiert verlorene Arbeit. Sichern Sie solche Branches serverseitig per Branch-Protection ab, statt auf Disziplin zu vertrauen.

FAQ

Was ist der Unterschied zwischen --force und --force-with-lease? --force überschreibt den Remote-Branch bedingungslos. --force-with-lease überschreibt nur, wenn der Remote noch genau auf dem Commit steht, den Sie zuletzt gesehen haben – hat jemand anders gepusht, bricht Git ab. In fast allen Fällen ist --force-with-lease die richtige Wahl.

Kann ich nach einem Force Push verlorene Commits zurückholen? Lokal ja: git reflog zeigt frühere Stände, git reset --hard <hash> stellt sie wieder her. Verlassen sollten Sie sich darauf nicht – legen Sie vor riskanten Aktionen lieber einen Backup-Branch an. Verwandtes Thema: einen Git-Branch lokal und remote löschen.

Warum wird mein Force Push auf main abgelehnt? Sehr wahrscheinlich schützt eine Branch-Protection-Regel den Branch. Das ist Absicht. Ändern Sie die Regel nur, wenn Sie genau wissen, was Sie tun – auf Standard-Branches ist ein Force Push praktisch nie nötig.