Git non-fast-forward rifiutato


88

Mi sembra che questa domanda sia stata posta molte volte, ma la soluzione è tipicamente "Ho cancellato la directory e ho rifatto il lavoro con una nuova cassa". Ho eseguito un commit e un push, ma mi sono reso conto di aver fatto riferimento al numero di ticket sbagliato nel messaggio di commit. Quindi ho cercato SO per una soluzione rapida e ho finito per digitare quanto segue nel terminale:

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

L'unico problema è che ricevo il seguente messaggio di errore:

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.

Sto usando il modello git-flow e sto lavorando al ramo di sviluppo. Come posso unire di nuovo le cose per rendere di nuovo felice git?


Risposte:


52

Forza git push:

git push origin +develop

24
Questa è una soluzione, ma leggi il commento di Brian Campbell in modo da capire cosa stai facendo prima di usarlo.
Thelem

5
git push origin + master
Aniket Thakur

Si veda anche la nota su receive.denyNonFastForwardsdi risposta di Brian Campbell : +o --forcenon può essere sufficientemente forte, a seconda di come-chiunque essi siano, hanno configurato il loro repository Git.
torek

174

Se si preme un commit al server, e poi riscrivere quella commit a livello locale (con git reset, git rebase,git filter-branch o qualsiasi altra manipolazione della storia), e poi spinto che impegnano riscritto il backup al server, si rovinare chiunque altro che aveva tirato. Ecco un esempio; diciamo di aver eseguito il commit di A e di averlo inviato al server.

- * - * - A <- maestro

- * - * - A <- origine / maestro

Ora decidi di riscrivere A, nel modo che hai menzionato, resettando e reimpegnando. Nota che questo lascia un commit penzolante, A, che alla fine verrà raccolto in modo spazzatura in quanto non è raggiungibile.

-*-*-UN
    \
     Un '<- maestro

- * - * - A <- origine / maestro

Se qualcun altro, diciamo Fred, tira giù master dal server mentre stai facendo questo, avrà un riferimento ad A, da cui potrebbe iniziare a lavorare:

- * - * - A '<- master

- * - * - A <- origine / maestro

- * - * - AB <- fred / master

Ora, se tu fossi in grado di spingere la tua A 'su origin / master, il che creerebbe un avanzamento non veloce, non avrebbe A nella sua cronologia. Quindi, se Fred avesse provato a tirare di nuovo, avrebbe dovuto improvvisamente unire e reintrodurre il commit A:

- * - * - A '<- master

- * - * - A <- origine / maestro

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

Se Fred se ne accorge, allora potrebbe fare un rebase, che impedirebbe la ricomparsa del commit A. Ma avrebbe dovuto notarlo e ricordarsi di farlo; e se hai più di una persona che ha tirato giù A, dovrebbero tutte ribasare per evitare di ottenere il commit A extra nell'albero.

Quindi, in genere non è una buona idea cambiare la storia su un repo da cui attingono altre persone. Se, tuttavia, ti capita di sapere che nessun altro sta estraendo da quel repository (ad esempio, è il tuo repository privato o hai solo un altro sviluppatore che lavora al progetto con cui puoi coordinarti facilmente), allora puoi forzatamente aggiornare eseguendo:

git push -f

o

git push origin +master

Entrambi ignoreranno il controllo per un push non fast-forward e aggiorneranno ciò che è sul server alla tua nuova revisione A ', abbandonando la revisione A in modo che alla fine venga raccolta dalla spazzatura.

È possibile che i push push siano completamente disabilitati con l' receive.denyNonFastForwardsopzione di configurazione. Questa opzione è abilitata per impostazione predefinita nei repository condivisi. In tal caso, se vuoi davvero forzare un push, l'opzione migliore è eliminare il ramo e ricrearlo, con git push origin :master; git push origin master:master. in ogni caso, ildenyNonFastForwards opzione è abilitata per un motivo, descritto sopra; su un repository condiviso, significa che ora tutti coloro che lo utilizzano devono assicurarsi di rifarsi alla nuova storia.

In un repository condiviso, in genere è meglio inserire solo nuovi commit che risolvono qualsiasi problema tu abbia; è possibile utilizzare git revertper generare commit che annulleranno le modifiche dei commit precedenti.


ottima educazione, e alla fine hai ricevuto il comando, ma il mio ramo si chiamava sviluppo (basato su git-flow), e l'altro ragazzo ha messo il +developsuo comando, quindi il controllo va a lui. Hai comunque un numero di punti astronomico: P
rynmrtn

8
Oppure usa il meno cripticogit push --force
Bennett McElwee

3
@Panique Stai cercando di consentire a più persone di lavorare contemporaneamente su una base di codice ampia e complessa, senza bloccarsi a vicenda (consentendo a una sola persona alla volta di lavorarci) e senza che le modifiche si sovrascrivano a vicenda. È necessario che ogni persona sia in grado di apportare modifiche in modo indipendente e unire tali modifiche. La fusione (sia manuale che automatica) può introdurre problemi imprevisti; quindi vuoi conservare quante più informazioni possibile per poter capire cosa è successo se è andato storto. Questo è intrinsecamente complesso; non è sporco, solo un problema difficile.
Brian Campbell

Ho provato entrambe le opzioni -f e + per riscrivere la cronologia del repository remoto. In entrambe le opzioni, mi sono imbattuto in un problema di non avanzamento rapido. [17:05] $ git push -f origin local_A: remote_A Conteggio oggetti: 35, fatto. Compressione delta utilizzando fino a 2 thread. Comprimere oggetti: 100% (18/18), fatto. Scrittura di oggetti: 100% (21/21), 7,41 KiB, fatto. Totale 21 (delta 9), riutilizzato 0 (delta 0) remoto: per evitare di perdere la cronologia, gli aggiornamenti non rapidi sono stati rifiutati. Unisci le modifiche remote (es. "Git pull") prima di premere di nuovo. Vedere la sezione "Nota sull'avanzamento rapido" di "git push --help" per i dettagli.
Srikanth

4
@Srikanth È possibile disabilitare completamente i push forzati con l' receive.denyNonFastForwardsopzione di configurazione. Questa opzione è abilitata per impostazione predefinita nei repository condivisi. In tal caso, se vuoi davvero forzare un push, l'opzione migliore è eliminare il ramo e ricrearlo, con git push origin :remote_A; git push origin local_A:remote_A. Ma leggi quello che ho scritto sopra sul perché è una cattiva idea fare questo tipo di flusso di lavoro su un repository condiviso. Dovresti provare a farlo solo se hai qualcosa che causa seri problemi nel commit che stai cercando di eliminare o riscrivere.
Brian Campbell

14

Potresti dover fare un git pull, che MAGGIO unire automaticamente le cose per te. Quindi puoi impegnarti di nuovo. In caso di conflitti, ti verrà chiesto di risolverli.

Tieni presente che devi specificare da quale ramo eseguire il pull se non hai aggiornato il tuo gitconfig per specificare ...

Per esempio:

git pull origin develop:develop

Ancora pazzo per il non avanzamento veloce. Qualche idea su come forzare la fusione? ! [rejected] develop -> develop (non-fast-forward)
rynmrtn

Penso che l'interruttore sia -f ma potrei sbagliarmi. kernel.org/pub/software/scm/git/docs/git-pull.html
Tony

Questo funziona parzialmente. Non vedo gli aggiornamenti su GitHub, però (mostra il commit precedente come l'ultimo anche con una git push origin develop)
rynmrtn

7

Stavo usando EGit e ho affrontato anche questo problema. Ho appena provato al rebaseramo corrente e ha funzionato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.