Come posso "annullare il ripristino" di un commit Git ripristinato?


487

Data una modifica che è stata impegnata utilizzando commite quindi ripristinata utilizzando revert, qual è il modo migliore per annullare tale ripristino?

Idealmente, questo dovrebbe essere fatto con un nuovo commit, in modo da non riscrivere la cronologia.



@phuclv un commento per un possibile duplicato lì, punti qui. Uno deve essere contrassegnato come originale e uno deve essere contrassegnato come dupliate
John Demetriou

@JohnDemetriou no la domanda che ha una migliore serie di risposte dovrebbe essere tenuta aperta. Il tempo non è rilevante qui Come devono essere gestite le domande duplicate?
phuclv,

Non ho detto del tempo. Mi è capitato di commentare uno dei due sull'argomento
John Demetriou

Risposte:


385

Se non hai ancora inviato questa modifica, git reset --hard HEAD^

Altrimenti, ripristinare il ripristino va perfettamente bene.

Un altro modo è quello di git checkout HEAD^^ -- .e poi git add -A && git commit.


8
Si noti che se si desidera annullare il ripristino senza applicare immediatamente le modifiche originali al ramo principale, è possibile (1) ripristinare il ramo originale se eliminato, (2) fare clic su "ripristina" sul ramo di ripristino come notato da Adam, quindi ( 3) fai clic su "modifica" nell'intestazione del PR risultante e cambia il ramo target nel ramo originale invece che nel master. Ora il tuo ramo originale può essere ricongiunto per effettuare le modifiche precedentemente annullate.
pauljm,

1
Si noti che ciò rimuoverà tutte le modifiche nella struttura e nell'indice di lavoro. Usa git stash per salvare le modifiche che non vuoi perdere.
zpon,

3
Qual è il vantaggio del metodo checkout && commit? Sembra che nel caso generale git cherry-picko in alternativa git revertsiano i modi più semplici per ripristinare un ripristino.
Robert Jack Will

5
Penso che sarebbe utile mostrare come:, Otherwise, reverting the revert is perfectly fine.e poi anche spiegare cosa git checkout HEAD^^ -- .sta facendo.
Todd

3
Buon Dio, non usare git add -A... a meno che tu non voglia aggiungere tutti i file al controllo della versione, che molto probabilmente non è quello che vuoi.
Kaitain,

474

git cherry-pick <original commit sha>
Farà una copia del commit originale, essenzialmente riapplicando il commit

Il ripristino del ripristino farà la stessa cosa, con un messaggio di commit più difficile:
git revert <commit sha of the revert>

Ognuno di questi modi ti consentirà di git pushnon sovrascrivere la cronologia, perché crea un nuovo commit dopo il ripristino.
Quando si digita il commit sha, in genere sono necessari solo i primi 5 o 6 caratteri:
git cherry-pick 6bfabc


61
Questa è facilmente la soluzione più elegante e completa alla domanda dei PO. Molto meglio della risposta accettata con le sue ipotesi in merito al fatto che il commit di ripristino si trovi nella TESTA dell'albero di commit. L'op ha anche specificamente richiesto una soluzione che non riscriva la storia, quindi la soluzione difficile offerta nella risposta accettata è semplicemente sbagliata.
Timo,

6
@Timo Per chiarire, la risposta accettata contiene la soluzione che ho usato ("ripristinare il ripristino"), ed è stata pubblicata entro poche ore dalla mia domanda, 3 anni prima di questa risposta. Quindi, il segno di spunta.
JimmidyJoo,

6
@JimmidyJoo So che ero in ritardo di 3 anni, volevo solo che le persone venissero qui da una ricerca su Google per vedere una risposta migliore
Stephan

2
@Stephan Yep, ma ancora una volta, per chiarire: è una risposta migliore, non quella che ho usato per risolvere il mio problema. Stavo semplicemente commentando il motivo per cui il segno di spunta è dove si trova. Domanda a tutti: la convenzione SO stabilisce che dovrei "mantenere" le mie domande passate e riassegnare i segni di spunta quando arrivano nuove risposte?
JimmidyJoo,

3
@JimmidyJoo Non ho idea della convenzione SO. Ma come ricercatore di Google, preferisco davvero vedere la risposta migliore selezionata. E apprezzerei gli sforzi di chiunque per mantenere le domande passate.
Paiman Roointan,

30

Un commit di ripristino è proprio come qualsiasi altro commit in git. Significato, puoi ripristinarlo, come in:

git revert 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746

Ciò ovviamente ha senso solo una volta che le modifiche sono state inviate, e specialmente quando non puoi forzare la spinta sul ramo di destinazione (che è una buona idea per il tuo ramo principale ). Se la modifica non è stata inviata, fai semplicemente cherry-pick, ripristina o semplicemente rimuovi il commit di ripristino come da altri post.

Nel nostro team, abbiamo una regola per utilizzare un ripristino sui commit di ripristino che sono stati impegnati nel ramo principale, principalmente per mantenere pulita la cronologia, in modo da poter vedere quale commit ripristina cosa:

      7963f4b2a9d   Revert "Revert "OD-9033 parallel reporting configuration"
      "This reverts commit a0e5e86d3b66cf206ae98a9c989f649eeba7965f.
                    ...
     a0e5e86d3b6    Revert "OD-9055 paralel reporting configuration"
     This reverts commit 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746.
                ...
     Merge pull request parallel_reporting_dbs to master* commit 
    '648d7d808bc1bca6dbf72d93bf3da7c65a9bd746'

In questo modo, puoi tracciare la storia e capire l'intera storia, e anche quelli senza la conoscenza dell'eredità potrebbero risolverli da soli. Considerando che, se scegli la ciliegia o rinnova le cose, queste informazioni preziose andranno perse (a meno che non le includa nel commento).

Ovviamente, se un commit è stato ripristinato e ripristinato più di una volta, questo diventa piuttosto disordinato.


15

Ripristinare il ripristino farà il trucco

Per esempio,

Se abcdefè il tuo commit ed ghijklè il commit che hai quando hai ripristinato il commit abcdef, esegui:

git revert ghijkl

Questo ripristinerà il ripristino


4

È stupido per me. Ma ero stato nella stessa situazione e sono tornato per impegni ripristinati. Ho fatto i ripristini numerici, quindi ho dovuto eseguire il ripristino per ogni "ripristino di ripristino".

Ora la mia storia di commit sembra un po 'strana.

storia strana

È un progetto per animali domestici quindi è OK. Ma per il progetto della vita reale darei la preferenza per andare all'ultimo commit prima di ripristinare tutti i codici ripristinati insieme in un commit e un commento più ragionevole.


4
Si può essere interessati nelle risposte ad un'altra mia domanda: stackoverflow.com/questions/10415565/...
JimmidyJoo

2
È possibile evitare il commit automatico e scegliere il messaggio di commit utilizzando il flag --no-commit durante il ripristino e quindi il commit con il messaggio pertinente
David Barda,

Inoltre puoi specificare più ID di commit quando usi git revert (penso che debbano essere nel giusto ordine).
Aalex Gabi,

Posso farlo dal desktop di Github?
Guillaume F.,

4

Ecco come l'ho fatto:
se il ramo è my_branchnamestato incluso in un'unione che è stata ripristinata. E volevo ripristinare my_branchname:

Io prima faccio una git checkout -b my_new_branchnameda my_branchname.
Poi faccio un git reset --soft $COMMIT_HASHin cui $COMMIT_HASHè l'hash del commit destra commit prima che il primo commit di my_branchname(vedi git log)
Poi faccio un nuovo commit git commit -m "Add back reverted changes"
Poi spingere verso l'alto la nuova filiale git push origin new_branchname
Poi ho fatto una richiesta di pull per la nuova filiale.


Ben fatto quando ci sono troppe "selezioni di ciliegie" da fare. Non capisco perché questa risposta abbia così pochi voti
Fundhor

2

Oppure potresti git checkout -b <new-branch>e git cherry-pick <commit>il precedente al e git rebaseal drop drop revertcommit. invia richiesta pull come prima.


1

Se non ti piace l'idea di "ripristinare un ripristino" (specialmente quando ciò significa perdere informazioni sulla cronologia per molti commit), puoi sempre andare alla documentazione di git su "Ripristinare una fusione difettosa" .

Data la seguente situazione iniziale

 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E   <-- fixed-up topic branch

(W è il ripristino iniziale della fusione M; D ed E sono correzioni al ramo / commit della funzione inizialmente rotto)

Ora puoi semplicemente riprodurre di nuovo i commit da A a E, in modo che nessuno di essi "appartenga" all'unione ripristinata:

$ git checkout E
$ git rebase --no-ff P

La nuova copia del tuo ramo ora può essere masternuovamente unita :

   A'---B'---C'------------D'---E'  <-- recreated topic branch
  /
 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E

Buona idea e grazie per il collegamento doc. Di solito rifacciamo con master prima di ricollegarci, ma git sembra riconoscere che A ', B', C 'sono gli stessi di quelli precedenti, e ora ho D, E dopo W ( pastebin ). Suggerimenti su come risolverlo?
Kristoffer Bakkejord,

0

Per recuperare le modifiche non messe in scena e messe in scena che sono state ripristinate dopo un commit:

git reset HEAD@{1}

Per ripristinare tutte le eliminazioni non messe in scena:

git ls-files -d | xargs git checkout --
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.