Git reset --hard e invia al repository remoto


200

Avevo un repository che aveva dei brutti commit (D, E e F per questo esempio).

Master ABCDEF e origine / master

Ho modificato il repository locale specificatamente con a git reset --hard. Ho preso un ramo prima del reset, quindi ora ho un repository che assomiglia a:

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

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

Ora avevo bisogno di alcune parti di quei commit errati, quindi ho scelto i pezzi di cui avevo bisogno e ho fatto alcuni nuovi commit, quindi ora ho i seguenti localmente:

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

Ora voglio spingere questo stato di cose al repository remoto. Tuttavia, quando provo a fare un git pushGit educatamente mi dà il pennello:

$ 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 git@git.example.com:myrepo.git  
! [remote rejected] master -> master (non-fast forward)  
error: failed to push some refs to 'git@git.example.com:myrepo.git'  

Come posso ottenere il repository remoto per prendere lo stato corrente del repository locale?


2
Si tratta di un "quasi" duplicato di diversi "come posso inviare domande sulla storia modificata", ad esempio vedere la risposta qui stackoverflow.com/questions/253055/…
CB Bailey

2
È vero e avevo cercato StackOverflow per una risposta prima di pubblicare. Tuttavia, la mia ricerca ha prodotto solo risposte in cui un git push - force ha risolto il problema. Grazie per il collegamento al tuo post :)
robertpostill

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

Risposte:


287

Se forzare un push non aiuta (" git push --force origin" o " git push --force origin master" dovrebbe essere sufficiente), potrebbe significare che il server remoto sta rifiutando push non di avanzamento rapido tramite la variabile di configurazione rece.denyNonFastForwards (vedere la manpage git config per la descrizione), oppure tramite hook di aggiornamento / pre-ricezione.

Con Git più vecchio puoi aggirare quella limitazione eliminando " git push origin :master" (vedi ':' prima del nome del ramo) e quindi ricreando " git push origin master" un determinato ramo.

Se non è possibile modificarlo, l'unica soluzione sarebbe invece di riscrivere la cronologia per creare un commit che ripristini le modifiche in DEF :

ABCDEF - [(DEF) ^ - 1] master

Origine / master ABCDEF

2
@ JakubNarębski, grazie. get revert HEAD~Naiutato. Nè il numero di commit. Ad esempio, se ho bisogno del commit precedente, userògit revert HEAD~1
Maksim Dmitriev il

1
E sappi che distruggerai tutti gli altri maestri locali facendo questo.
Tom Brito,

24

Per completare la risposta di Jakub, se hai accesso al server remoto git in ssh, puoi andare nella directory git remote e impostare:

user@remote$ git config receive.denyNonFastforwards false

Quindi tornare al repository locale, riprovare a eseguire il commit con --force:

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

E infine ripristinare le impostazioni del server nello stato originale protetto:

user@remote$ git config receive.denyNonFastforwards true

Vedi anche pete.akeo.ie/2011/02/denying-non-fast-forward-and.html per informazioni su sourceforge su misura al riguardo.
hlovdal

Le istruzioni dettagliate su come disabilitare denyNonFastForwards utilizzando visono fornite su questo post SO:
stackoverflow.com/a/43721579/2073804


1

Tutta la faccenda del ripristino del git sembrava complicarmi molto.

Quindi ho fatto qualcosa del genere per ottenere la mia cartella src nello stato che avevo fatto qualche commit fa

# 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

In questo modo lo stato delle cose in src è tenuto in un file tar e git è costretto ad accettare questo stato senza troppe complicazioni, in sostanza la directory src viene sostituita con lo stato che aveva commesso diverse volte fa.


0

Per gli utenti di GitHub, questo ha funzionato per me:

  1. In tutte le regole di protezione delle filiali in cui si desidera apportare la modifica, assicurarsi che Consenti push forzati sia abilitato
  2. git reset --hard <full_hash_of_commit_to_reset_to>
  3. git push --force

Questo "correggerà" la cronologia delle filiali sul tuo computer locale e sul server GitHub, ma chiunque abbia sincronizzato questo ramo con il server dal momento del commit errato avrà la cronologia sul proprio computer locale. Se hanno il permesso di inviare direttamente alla filiale, questi commit mostreranno il backup quando si sincronizzano.

Tutto quello che tutti gli altri devono fare è il git resetcomando dall'alto per "correggere" il ramo sul proprio computer locale. Naturalmente avrebbero bisogno di diffidare di tutti gli impegni locali effettuati in questo ramo dopo l'hash del bersaglio. Cherry seleziona / esegue il backup e riapplica quelli necessari, ma se ti trovi in ​​un ramo protetto, è probabile che il numero di persone che possono impegnarsi direttamente in esso sia limitato.

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.