Come annullare "git commit --amend" fatto anziché "git commit"


1295

Ho modificato per errore il mio precedente commit. Il commit avrebbe dovuto essere separato per mantenere la cronologia delle modifiche apportate a un determinato file.

C'è un modo per annullare l'ultimo commit? Se faccio qualcosa del genere git reset --hard HEAD^, anche il primo commit è annullato.

(Non ho ancora inviato alcuna directory remota)

Risposte:


2291

Quello che devi fare è creare un nuovo commit con gli stessi dettagli del HEADcommit corrente , ma con il genitore come la versione precedente di HEAD. git reset --softsposta il puntatore del ramo in modo che il prossimo commit avvenga in cima a un commit diverso da quello in cui si trova ora la testa del ramo corrente.

# Move the current head so that it's pointing at the old commit
# Leave the index intact for redoing the commit.
# HEAD@{1} gives you "the commit that HEAD pointed at before 
# it was moved to where it currently points at". Note that this is
# different from HEAD~1, which gives you "the commit that is the
# parent node of the commit that HEAD is currently pointing to."
git reset --soft HEAD@{1}

# commit the current tree using the commit details of the previous
# HEAD commit. (Note that HEAD@{1} is pointing somewhere different from the
# previous command. It's now pointing at the erroneously amended commit.)
git commit -C HEAD@{1}

33
Molto bello, +1. L'ho fatto anche con la seconda vista dell'ultima modifica git reflogper trovare il numero corretto, ad es {2}.
JJD,

179
Giusto per essere chiari, il primo comando è un vero "annullamento". Produce HEAD, directory di lavoro (invariato) e stato dell'indice prima di git commit --amend. Il secondo è una "ripetizione" in un nuovo commit. Questi funzionano per qualsiasi git commit, non solo --amend.
cdunn2001,

60
Quindi, se non hai modificato con un nuovo messaggio di commit che devi salvare, la seconda parte può essere solo un normale git commit.
Matt Montag,

18
Per qualche motivo, mi è stato sempre un errore durante l'esecuzione git reset --soft HEAD@{1}: fatal: ambiguous argument 'HEAD@1': unknown revision or path not in the working tree. Use '--' to separate paths from revisions. Quando ho sostituito HEAD@{1}con l'hash di commit equivalente mostrato in git reflog(grazie JJD!), Questa risposta ha funzionato meravigliosamente!
Tim Camber,

20
@TimArnold a seconda della shell, potrebbe essere necessario mettere tra virgolette singole o doppie HEAD@{1}. Se corro echo HEAD@{1}in tcsh per esempio, l'output è HEAD@1perché le parentesi graffe sono state interpretate da tcsh. Se uso virgolette singole, le parentesi graffe vengono conservate.
Kelvin,

136

usa il ref-log :

git branch fixing-things HEAD@{1}
git reset fixing-things

dovresti quindi avere tutte le modifiche precedentemente modificate solo nella tua copia di lavoro e puoi eseguire nuovamente il commit

per visualizzare un elenco completo del tipo di indici precedente git reflog


7
Anche questo cancella l'indice - ancora utile, ma va oltre un semplice "annulla".
cdunn2001,

3
c'è qualche differenza tra HEAD@{1}e HEAD~1?
neaumusica il

15
@neaumusic: si! HEAD~1è esattamente lo stesso HEAD^e identifica il genitore del commit corrente. HEAD@{1}d'altra parte si riferisce al commit che HEAD ha indicato prima di questo, ovvero significano commit diversi quando si verifica un ramo diverso o si modifica un commit.
Knittl,

@knittl ah non c'è da stupirsi che non pensassi che ciò fosse possibile prima, grazie ancora, buone informazioni
neaumusic

9
il primo passo è ridondante. Semplice git reset HEAD@{1}è abbastanza
Dwelle,

79

Trova i tuoi commit modificati da:

git log --reflog

Nota: è possibile aggiungere --patchper vedere il corpo delle commit per chiarezza. Uguale agit reflog .

quindi resetta HEAD a qualsiasi commit precedente nel punto in cui andava bene:

git reset SHA1 --hard

Nota: sostituisci SHA1 con il tuo hash di commit reale. Si noti inoltre che questo comando perderà tutte le modifiche non confermate, quindi è possibile nasconderle prima. In alternativa, utilizzare --softinvece per conservare le ultime modifiche e quindi eseguirne il commit.

Quindi seleziona l'altro commit di cui hai bisogno sopra:

git cherry-pick SHA1

26
In tal caso git reset SHA1 --soft, è possibile conservare le ultime modifiche e quindi impegnarle.
pravj,

24

Puoi sempre dividere un commit, dal manuale

  • Inizia un rebase interattivo con git rebase -i commit ^, dove commit è il commit che vuoi dividere. In effetti, qualsiasi intervallo di commit lo farà, purché contenga quel commit.
  • Contrassegna il commit che desideri dividere con l'azione "modifica".
  • Quando si tratta di modificare quel commit, eseguire git reset HEAD ^. L'effetto è che HEAD viene riavvolto di uno e l'indice segue l'esempio. Tuttavia, l'albero di lavoro rimane lo stesso.
  • Ora aggiungi le modifiche all'indice che vuoi avere nel primo commit. Puoi usare git add (possibilmente in modo interattivo) o git-gui (o entrambi) per farlo.
  • Effettua il commit dell'indice attuale con qualunque messaggio di commit sia appropriato ora.
  • Ripeti gli ultimi due passaggi fino a quando l'albero di lavoro non è pulito.
  • Continua il rebase con git rebase --continua.

26
troppo complicato. git reflogè tutto ciò che serve
Knittl

2
Molti passaggi sì, ma ogni passaggio è semplice e facile da fare. Questo ha funzionato per me e ottiene il mio voto.
OzBandit,

5
inoltre, questa risposta ti consente di scegliere in modo selettivo le modifiche che hai "modificato" accidentalmente, per fornire un valore aggiuntivo all'approccio git reset --soft HEAD @ {1} (che ha risolto il mio problema BTW)
Wiebe Tijsma,

2
Puoi anche selezionare selettivamente le modifiche con il metodo reflog. Fai git resetinvece invece di git reset --soft, poi fallo git add --patch.
geekofalltrades,

1
Ciò riscrive ancora la storia e richiede una spinta forzata. A seconda della situazione che potrebbe essere o meno un problema.
Pajn,

20

Forse vale la pena notare che se sei ancora nel tuo editor con il messaggio di commit, puoi eliminare il messaggio di commit e interromperà il git commit --amendcomando.


Questo è quello.
Atilkan,

Ho salvato il mio ma ^^
engineercoding il

14

Forse posso usare git reflog per ottenere due commit prima di modificare e dopo modificare.

Quindi utilizzare git diff before_commit_id after_commit_id > d.diff per ottenere le differenze tra prima e dopo la modifica.

Prossimo utilizzo git checkout before_commit_id per tornare a prima del commit

E ultimo utilizzo git apply d.diff per applicare il vero cambiamento che hai fatto.

Questo risolve il mio problema.


11

Se hai eseguito il push del commit su remoto e poi modificato erroneamente le modifiche a quel commit, questo risolverà il tuo problema. Emettere a git logper trovare lo SHA prima del commit. (questo presuppone che il nome remoto sia chiamato origine). Ora emetti questi comandi usando quel SHA.

git reset --soft <SHA BEFORE THE AMMEND>
#you now see all the changes in the commit and the amend undone

#save ALL the changes to the stash
git stash

git pull origin <your-branch> --ff-only
#if you issue git log you can see that you have the commit you didn't want to amend

git stash pop
#git status reveals only the changes you incorrectly amended

#now you can create your new unamended commit

3
Questo è un caso speciale della domanda più generale, ma ha coperto esattamente il mio bisogno immediato.
dmckee --- ex gattino moderatore

8

Puoi fare di seguito per annullare il tuo git commit —amend

  1. git reset --soft HEAD^
  2. git checkout files_from_old_commit_on_branch
  3. git pull origin your_branch_name

====================================

Ora le tue modifiche sono come in precedenza. Quindi hai finito con l'annullamento digit commit —amend

Ora puoi fare git push origin <your_branch_name>, per spingere al ramo.


3

Quasi 9 anni di ritardo, ma non ho visto questa variazione menzionata realizzare la stessa cosa (è una specie di combinazione di alcuni di questi, simile alla risposta migliore ( https://stackoverflow.com/a/1459264/4642530 ) .

Cerca tutte le teste distaccate sul ramo

git reflog show origin/BRANCH_NAME --date=relative

Quindi trova l'hash SHA1

Ripristina al vecchio SHA1

git reset --hard SHA1

Quindi spingerlo indietro.

git push origin BRANCH_NAME

Fatto.

Questo ti riporterà completamente al vecchio commit.

(Inclusa la data del precedente commit di commit distaccato sovrascritto)


Sì, ma in genere desidero ripristinare --softper mantenere le mie modifiche. Voglio solo impegnarlo separatamente
Juan Mendes,

2
  1. Acquista alla filiale temporanea con l'ultimo commit

    git branch temp HEAD@{1}

  2. Ripristina ultimo commit

    git reset temp

  3. Ora avrai tutti i file del tuo commit e il commit precedente. Controlla lo stato di tutti i file.

    git status

  4. Ripristina i tuoi file di commit da git stage.

    git reset myfile1.js (presto)

  5. Ricollegare questo commit

    git commit -C HEAD@{1}

  6. Aggiungi e esegui il commit dei tuoi file con il nuovo commit.

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.