Git: annulla i commit spinti


609

Ho un progetto in un repository remoto, sincronizzato con un repository locale (sviluppo) e un server (prod). Ho apportato alcune modifiche impegnate già inviate a remoto ed estratte dal server. Ora voglio annullare quei cambiamenti. Quindi potrei semplicemente git checkouteseguire il commit prima delle modifiche e impegnare le nuove modifiche, ma suppongo che ci saranno problemi a spingerle di nuovo in remoto. Qualche suggerimento su come devo procedere?


Risposte:


735

Puoi ripristinare singoli commit con:

git revert <commit_hash>

Ciò creerà un nuovo commit che ripristina le modifiche del commit specificato. Nota che ripristina solo quel commit specifico e non lo fa dopo. Se desideri ripristinare una serie di commit, puoi farlo in questo modo:

git revert <oldest_commit_hash>..<latest_commit_hash>

Ripristina i commit tra e inclusi i commit specificati.

Guarda la pagina man di git-revert per maggiori informazioni sul git revertcomando. Guarda anche questa risposta per ulteriori informazioni sul ripristino degli commit.


22
In altre parole, ritorna al <oldest_commit_hash>;)
David

7
@mr_jigsaw Usegit log
gitaarik

2
Nella documentazione di Git, dice che il comando di ripristino ripristina i commit tra il primo e l'ultimo commit (sia il primo che l'ultimo incluso). Vedi documentazione
Onur Demir,

4
@aod è corretto, questa risposta deve essere aggiornata. l'attuale API git per il ripristino è <oldest_commit_hash>stata inclusa nell'elenco dei ripristini
JHixson

4
con git 2.17.2 ripristina <old> .. <nuovo> non include vecchio ma include <nuovo>
chingis

353

Una soluzione che non lascia tracce di "annulla".

NOTA: non farlo se qualcuno ha già ritirato la modifica (la utilizzerei solo sul mio repository personale)

fare:

git reset <previous label or sha1>

questo ricontrollerà tutti gli aggiornamenti localmente (quindi lo stato git elencherà tutti i file aggiornati)

quindi "fai il tuo lavoro" e impegni nuovamente le modifiche (Nota: questo passaggio è facoltativo)

git commit -am "blabla"

In questo momento il tuo albero locale differisce dal telecomando

git push -f <remote-name> <branch-name>

spingerà e forzerà il telecomando a considerare questo push e rimuoverà quello precedente (specificare il nome remoto e il nome del ramo non è obbligatorio ma è raccomandato per evitare di aggiornare tutti i rami con il flag di aggiornamento).

!! attenzione alcuni tag potrebbero ancora puntare rimossi commit !! how-to-delete-a-remote-tag


4
-a tutti i file tracciati verranno sottoposti a commit -m segue il messaggio di commit
jo_

3
Esattamente quello che ho cercato. Qualcuno ha commesso un errore e ha spinto e ripristinato di nuovo in seguito. Non è stato possibile unire i rami per questo motivo e volevo che il repository fosse nuovamente nello stato corretto (e rimuovendo il commit dalla cronologia poiché erano comunque difettosi)
esegui il

1
Quale "etichetta precedente o sha1" dovrei usare? Devo inserire l'ultimo "corretto" o quello precedente e ripetere tutte le modifiche apportate dall'ultimo corretto?
elysch,

3
quello appena prima dell'eroso impegno
jo_Mar

1
Esattamente quello di cui ho bisogno. Ho spinto un ramo a dominare per errore. E di conseguenza ho avuto molti rifiuti nella storia. Ho appena eseguito l' git push -fultimo commit corretto e ripulito la cronologia remota! Grazie!
Anton Rybalko,

193

Quello che faccio in questi casi è:

  • Nel server, spostare il cursore indietro sull'ultimo commit valido noto:

    git push -f origin <last_known_good_commit>:<branch_name>
    
  • A livello locale, fai lo stesso:

    git reset --hard <last_known_good_commit>
    #         ^^^^^^
    #         optional
    



Vedi un esempio completo su un ramo my_new_branchche ho creato per questo scopo:

$ git branch
my_new_branch

Questa è la storia recente dopo aver aggiunto alcune cose a myfile.py:

$ git log
commit 80143bcaaca77963a47c211a9cbe664d5448d546
Author: me
Date:   Wed Mar 23 12:48:03 2016 +0100

    Adding new stuff in myfile.py

commit b4zad078237fa48746a4feb6517fa409f6bf238e
Author: me
Date:   Tue Mar 18 12:46:59 2016 +0100

    Initial commit

Voglio liberarmi dell'ultimo commit, che era già stato spinto, quindi corro:

$ git push -f origin b4zad078237fa48746a4feb6517fa409f6bf238e:my_new_branch
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:me/myrepo.git
 + 80143bc...b4zad07 b4zad078237fa48746a4feb6517fa409f6bf238e -> my_new_branch (forced update)

Bello! Ora vedo il file che è stato modificato su quel commit ( myfile.py) mostra in "non messo in scena per commit":

$ git status
On branch my_new_branch
Your branch is up-to-date with 'origin/my_new_branch'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   myfile.py

no changes added to commit (use "git add" and/or "git commit -a")

Dal momento che non desidero queste modifiche, sposto anche il cursore indietro localmente:

$ git reset --hard b4zad078237fa48746a4feb6517fa409f6bf238e
HEAD is now at b4zad07 Initial commit

Quindi ora HEAD è nel commit precedente, sia in locale che in remoto:

$ git log
commit b4zad078237fa48746a4feb6517fa409f6bf238e
Author: me
Date:   Tue Mar 18 12:46:59 2016 +0100

    Initial commit

10
Questa è la risposta corretta! questo è esattamente ciò che era necessario fare nel mio caso grazie ho imparato qualcosa di nuovo oggi :)
Egli Becerra

2
Questa è la risposta corretta! Riguarda gli commit push (!)!
powtac,

3
Se vuoi veramente ripristinare le modifiche (come se non le avessi mai spinte), questa è la risposta corretta.
Jacob

1
Risposta perfetta Ha funzionato bene come previsto!
RafiAlhamd,

2
Qualcuno compra a quest'uomo una birra!
Jay Nebhwani,

72

Puoi INVIARE (o puoi anche chiamarlo ELIMINA ) Git Commit ENTRAMBI A livello locale e remoto se segui i passaggi indicati di seguito tramite la riga di comando git.

Eseguire il comando seguente per visualizzare l'id di commit che si desidera ripristinare

git log --oneline --decorate --graph

Avrai come uno screenshot seguente inserisci qui la descrizione dell'immagine

Se controlli anche il telecomando (tramite l'interfaccia Web) , puoi vedere che sarebbe lo stesso mostrato di seguito

inserisci qui la descrizione dell'immagine

Come per lo screenshot, al momento sei su commit id e110322 ma vuoi tornare a 030bbf6 SIA LOCALMENTE che REMOTO .

Effettuare le seguenti operazioni per ELIMINARE / REVERT Commettere localmente + in remoto


Primo ripristino locale per il commit dell'ID 030bbf6

git reset --hard 030bbf6

seguito da

git clean -f -d

Questi due comandi puliscono la reimpostazione della forza per eseguire il commit della fase 030bbf6 come mostrato di seguito nell'istantanea

inserisci qui la descrizione dell'immagine

ora se esegui git status, vedrai che sei DUE commit DIETRO dal ramo remoto come mostrato di seguito inserisci qui la descrizione dell'immagine

Eseguire la procedura seguente per aggiornare gli indici (se sono presenti aggiornamenti). Si consiglia di chiedere a tutti gli sviluppatori di non accettare richieste pull sul ramo remoto principale.

git fetch --all

Una volta terminato, ti viene richiesto di spingere questo commit con forza usando il simbolo + davanti al ramo come mostrato di seguito. Ho usato qui come ramo principale , è possibile sostituirlo con qualsiasi

inserisci qui la descrizione dell'immagine Codice

git push -u origin +master

ora se vedi l'interfaccia web di remoto allora commetti dovrebbe essere ripristinato pure.

inserisci qui la descrizione dell'immagine


61

Questo rimuoverà i tuoi commit push

git reset --hard 'xxxxx'

git clean -f -d

git push -f

7
Questo metodo riscrive correttamente la cronologia per eliminare il commit. Fantastico
Jesse Reza Khorasanee il

2
questa risposta è el magnifeco!
truthadjustr,

3
Adoro la risposta, grazie :)
Dzenis H.

1
Per essere chiari (non ero sicuro): il commit sarà il commit corrente dopo l'operazione. Non l'ultimo da eliminare.
Maik639,

21
git revert HEAD -m 1

Nella riga di codice sopra. "L'ultimo argomento rappresenta"

  • 1 - ripristina un commit.

  • 2 - ripristina gli ultimi due commit.

  • n - ripristina gli ultimi n commit.

È necessario premere dopo questo comando per attivare l'effetto sul telecomando. Hai altre opzioni come specificare l'intervallo di commit da ripristinare. Questa è una delle opzioni.


Successivamente utilizzare git commit -am "COMMIT_MESSAGE" quindi git pushogit push -f


8
Questo non è vero - il parametro -m specifica il numero del genitore su cui ripristinare (in genere 1 se si desidera ripristinare le modifiche "loro" in entrata, anziché 2 per le modifiche unite, "nostre" - per l'unione 2 commit). Non ha nulla a che fare con il numero di commit ripristinati - se si desidera ripristinare un intervallo di commit, utilizzaregit revert ref1..ref2
Riferimento null

1
Non ha avuto l'effetto desiderato
Sam Tuke,

4

2020 Modo semplice:

git reset <commit_hash>

(L'hash dell'ultimo commit che vuoi mantenere).

Manterrai localmente le modifiche ora senza commit.

Se vuoi spingere di nuovo, devi fare:

git push -f

0

Ecco la mia strada:

Diciamo che il nome del ramo è develop.

# Create a new temp branch based on one history commit
git checkout <last_known_good_commit_hash>
git checkout -b develop-temp

# Delete the original develop branch and 
# create a new branch with the same name based on the develop-temp branch
git branch -D develop
git checkout -b develop

# Force update this new branch
git push -f origin develop

# Remove the temp branch
git branch -D develop-temp

0

Puoi fare qualcosa del genere

git push origin +<short_commit_sha>^:<branch_name>
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.