Come posso forzare correttamente una spinta Git?


1274

Ho impostato un repository "principale" remoto non nudo e l'ho clonato sul mio computer. Ho apportato alcune modifiche locali, aggiornato il mio repository locale e inviato le modifiche al mio repository remoto. Le cose andarono bene fino a quel punto.

Ora, ho dovuto cambiare qualcosa nel repository remoto. Quindi ho cambiato qualcosa nel mio repository locale. Mi sono reso conto che la modifica al repository remoto non era necessaria. Quindi ho provato a farlo git pushdal mio repository locale al mio repository remoto, ma ho ricevuto un errore del tipo:

Per evitare di perdere la cronologia, gli aggiornamenti non rapidi sono stati rifiutati. Unisci le modifiche remote prima di premere nuovamente. Per i dettagli, consultare la sezione "Nota sugli avanzamenti rapidi" di git push --help.

Ho pensato che probabilmente a

git push --force

forzerei la mia copia locale a inviare modifiche a quella remota e a renderla uguale. Impone l'aggiornamento , ma quando torno al repository remoto ed eseguo un commit, noto che i file contengono modifiche obsolete (quelle che in precedenza avevano il repository remoto principale).

Come ho detto nei commenti a una delle risposte :

[I] ho provato a forzare, ma quando torno al server principale per salvare le modifiche, ottengo una stadiazione obsoleta. Pertanto, quando commetto i repository non sono gli stessi. E quando provo ad usare di nuovo git push, ottengo lo stesso errore.

Come posso risolvere questo problema?


4
Presto (git1.8.5, Q4 2013) sarai in grado di fare git push -forcepiù attentamente .
VonC,


6
Come ho dettagliato nella mia risposta , git push --forceè davvero un altro modo valido per forzare la spinta, e spingerà i rami così come git push origin master --forcecon il default di Git push.default config settings, anche se quali rami vengono spinti in modo diverso differisce tra le versioni di Git precedenti alla 2.0 rispetto alla 2.0.

2
git push --forcefunziona bene in questi giorni, FWIW ...
rogerdpack

git push --force-with-leasefunziona ancora meglio :), rifiuterà di aggiornare un ramo a meno che non sia lo stato che ti aspetti. (vedi developer.atlassian.com/blog/2015/04/force-with-lease )
spoorcc

Risposte:


2309

Basta fare:

git push origin <your_branch_name> --force

o se si dispone di un repository specifico:

git push https://git.... --force

Questo eliminerà i tuoi precedenti commit e spingerà quelli attuali.

Potrebbe non essere corretto, ma se qualcuno si imbatte in questa pagina, ha pensato di voler una soluzione semplice ...

Bandiera corta

Si noti inoltre che -fè l'abbreviazione di --force, quindi

git push origin <your_branch_name> -f

funzionerà anche.


58
È possibile utilizzare git push origin +masterinvece, che consente di inviare più refspec senza forzarli tutti.
Nickgrim,

5
Tieni presente che, se lo fai accidentalmente git push --force, potresti finire per incasinare il tuo ramo principale (a seconda del tuo comportamento push predefinito) .. Che potrebbe succhiare .. un po '..: D
Jeewes

9
@Jeewes a partire da Git versione 2.0, il comportamento predefinito di git push --forceè fondamentalmente quello di forzare il push del ramo attualmente estratto nella sua parte di contatore remoto, quindi se hai il ramo principale estratto, allora è identico a git push origin master --force. Sarà diverso se stai usando l' matchingimpostazione per push.default, che è l'impostazione predefinita per le versioni Git precedenti alla 2.0. matchingspinge tutte le filiali locali a quelle remote che hanno lo stesso nome, quindi forzare la spinta quindi potrebbe sicuramente non essere quello che vuoi fare ...

@Jeewes Ma con Git 2.0, il valore predefinito è più sicuro, o almeno non è più pericoloso di quello che git push origin master --forceè.

2
push -f è buono ma non consigliato per master poiché la maggior parte dei repository aziendali ha disabilitato -f per master. ha merge -s oursfunzionato per me
mihai

247

E se push --forcenon funziona puoi farlo push --delete. Guarda la seconda riga su questa istanza:

git reset --hard HEAD~3  # reset current branch to 3 commits ago
git push origin master --delete  # do a very very bad bad thing
git push origin master  # regular push

Ma attenzione ...

Non tornare mai più su una storia di git pubblica!

In altre parole:

  • Non forcespingere mai su un repository pubblico.
  • Non fare questo o qualcosa che possa rompere qualcuno pull.
  • Mai reseto la rewritestoria in un repository che qualcuno potrebbe aver già estratto.

Naturalmente ci sono eccezioni eccezionalmente rare anche a questa regola, ma nella maggior parte dei casi non è necessario farlo e genererà problemi a tutti gli altri.

Esegui invece un ripristino.

E fai sempre attenzione a ciò che invii a un repository pubblico . Ripristino:

git revert -n HEAD~3..HEAD  # prepare a new commit reverting last 3 commits
git commit -m "sorry - revert last 3 commits because I was not careful"
git push origin master  # regular push

In effetti, entrambe le HEAD di origine (dal ripristino e dal ripristino del male ) conterranno gli stessi file.


modifica per aggiungere informazioni aggiornate e altri argomenti in giro push --force

Considera di spingere la forza con un leasing anziché di spingere, ma preferisci comunque tornare

Un altro problema push --forcepuò portare quando qualcuno spinge qualcosa prima di te, ma dopo che hai già recuperato. Se spingi con forza la tua versione rinnovata ora sostituirai il lavoro dagli altri .

git push --force-with-leaseintrodotto in git 1.8.5 ( grazie al commento @VonC sulla domanda) cerca di affrontare questo specifico problema. Fondamentalmente, porterà un errore e non spingerà se il telecomando è stato modificato dall'ultimo recupero.

Questo è utile se sei davvero sicuro di averne push --forcebisogno, ma vuoi comunque prevenire ulteriori problemi. Andrei fino a dire che dovrebbe essere il push --forcecomportamento predefinito . Ma è ancora lungi dall'essere una scusa per forzare a push. Le persone che hanno recuperato prima del tuo rebase avranno ancora molti problemi, che potrebbero essere facilmente evitati se tu fossi invece tornato .

E dal momento che stiamo parlando di git --pushcasi ...

Perché qualcuno dovrebbe voler forzare la spinta?

@linquize ha portato un buon esempio di forza di spinta sui commenti: dati sensibili . Hai trapelato dati erroneamente che non dovrebbero essere inviati. Se sei abbastanza veloce, puoi "ripararlo"* forzando una spinta in alto.

*I dati rimarranno comunque sul telecomando a meno che non si esegua anche una garbage collection o si pulisca in qualche modo . C'è anche l'ovvio potenziale che possa essere diffuso da altri che l'hanno già preso , ma hai capito.


1
Il problema, @rogerdpack, non è se è fattibile. È. Ma può riassumere in un grande disastro. Più qualcuno lo fa (forza push) e meno spesso aggiorni (tira) dal repository pubblico, maggiore è il disastro. Può smantellare il mondo come lo conosci !!! 111 Almeno il mondo che comprende quel particolare repository.
Cregox,

3
Se si dispone di dati sensibili, forzare push
linquize

3
@Cawas: Penso che significhi che se stai cercando di rimuovere i dati sensibili dal repository, allora vuoi riscrivere la cronologia. Se ripristini, i dati sensibili sono ancora presenti nel commit precedente. Detto questo, se qualcun altro ha già estratto dal repository, la riscrittura della cronologia non ti aiuterà a impedire loro di accedere ai dati sensibili - è già troppo tardi a quel punto.
Stuart Golodetz,

3
git push origin master --delete # do a very very bad bad thing git push origin master # regular pushquesto in realtà ha risolto perfettamente il mio problema (su un repository con solo io e il mio amico). forse è sbagliato per i repository pubblici ma per uno privato questo è un salvavita.
Can Poyrazoğlu, il

1
questo accade automaticamente con alcuni gestori di pronti contro termine, ovvero auto-squash ecc., la forza che spinge dopo aver terminato un ramo di funzionalità per ridurre i commit è comune e prevista.
FlavorScape

18

Prima di tutto, non vorrei apportare alcuna modifica direttamente nel repository "principale". Se vuoi davvero avere un repository "principale", allora dovresti solo spingerlo, non cambiarlo mai direttamente.

Per quanto riguarda l'errore che stai riscontrando, hai provato git pulldal tuo repository locale e quindi git pushal repository principale? Quello che stai facendo attualmente (se ho capito bene) è forzare la spinta e quindi perdere le modifiche nel repository "principale". È necessario prima unire le modifiche localmente.


Sì, ho provato a tirare, ma sto perdendo la perdita di dati a causa di quel pull. Voglio fare i miei repository principali come sono i miei locali, senza prima aggiornarli da quelli principali.
Spyros

1
In tal caso git push -f, utilizzare , ma se si modifica nuovamente il repository principale, è necessario tornare al repository locale e git pull, in modo che si sincronizzi con le ultime modifiche. Quindi puoi fare il tuo lavoro e spingere di nuovo. Se segui questo flusso di lavoro "push-pull", non otterrai il tipo di errore di cui ti lamentavi.
ubik,

si, capisco che è stata colpa mia: / ci proverò e torno tra poco grazie
Spyros

1
ho provato a forzare, ma quando torno al server principale per salvare le modifiche, ottengo una stadiazione obsoleta. Pertanto, quando commetto i repository non sono gli stessi. E quando provo ad usare di nuovo git push, ottengo lo stesso errore.
Spyros,

17

Se mi trovo sul mio ramo locale A e voglio forzare il push del ramo locale B sul ramo di origine CI può utilizzare la sintassi seguente:

git push --force origin B:C

2
Ho scoperto che anche se sono nella mia filiale B locale, devo ancora farlo git push --force origin B:C. Nel mio caso, sembra che git push --force origin Cpasserà solo dal master locale al ramo C remoto, indipendentemente dal ramo in cui mi trovo attualmente. git version 2.3.8 (Apple Git-58)
Weishi Zeng,

12

utilizzare questo comando seguente:

git push -f origin master

1
Forse dare qualche spiegazione in più sul perché questa risposta è preferibile alle altre e cosa la rende diversa.
Adam,

oh, scusa per l'inconveniente, stavo avendo lo stesso problema e questo comando lo ha risolto, ho pensato che avrei dovuto condividerlo.
mustafa Elsayed

12
È uguale agli altri, hai appena cambiato la posizione della -fbandiera ...
svelandiag

11

Consiglio vivamente di:

  • spingere solo al repository principale

  • assicurarsi che il repository principale sia un repository nudo , al fine di non avere mai problemi con l'albero di lavoro del repository principale non sincronizzato con la sua .gitbase. Vedi " Come spingere un repository git locale su un altro computer? "

  • Se è necessario apportare modifiche al repository principale (non elaborato), clonarlo (sul server principale), apportare le modifiche e riprovare ad esso

In altre parole, mantenere un repository nudo accessibile sia dal server principale che dal computer locale, al fine di avere un repository upstream singolo da / verso il quale eseguire il pull / pull.


5

Questa era la nostra soluzione per sostituire master in un repository gitHub aziendale mantenendo la cronologia.

push -fla padronanza dei repository aziendali è spesso disabilitata per mantenere la cronologia delle filiali. Questa soluzione ha funzionato per noi.

git fetch desiredOrigin
git checkout -b master desiredOrigin/master // get origin master

git checkout currentBranch  // move to target branch
git merge -s ours master  // merge using ours over master
// vim will open for the commit message
git checkout master  // move to master
git merge currentBranch  // merge resolved changes into master

spingi il tuo ramo verso desiredOrigine crea un PR


3

Ho avuto la stessa domanda ma alla fine l'ho capito. Quello che molto probabilmente dovrai fare è eseguire i seguenti due comandi git (sostituendo l'hash con il numero di revisione del commit git):

git checkout <hash>
git push -f HEAD:master
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.