Ripristina le modifiche a un file in un commit


Risposte:


222

Il modo più pulito che ho visto per farlo è descritto qui

git show some_commit_sha1 -- some_file.c | git apply -R

Simile alla risposta di VonC ma utilizzando git showe git apply.


10
Ben fatto. La soluzione dello script è eccessiva per questo. Perché non può esserci solo git revert sha-1 filename?
Mark Edington

16
Funziona sul mio Mac, ma su Windows (sotto Cygwin) mi dà:fatal: unrecognized input
Kedar Mhaswade

1
@MerhawiFissehaye: Penso che il checkout di git annullerà nuovamente le modifiche per tornare allo stato in cui si trovava il commit. Ho aggiunto 'git filename; git commit --amend 'per rimuovere il file dal commit.
ViFI

3
Solo un suggerimento, devo quasi sempre aggiungere il -3flag a git apply per l'unione a tre vie quando la patch fallisce, poiché di solito correggo una modifica un po 'indietro nel tempo.
angularsen

2
Forse ovvio per la maggior parte, ma assicurati di some_file.cincludere il percorso del file se ce n'è uno, altrimenti non
aggiusterai

35

Supponendo che sia corretto modificare la cronologia del commit, ecco un flusso di lavoro per annullare le modifiche in un singolo file in un commit precedente:

Ad esempio, vuoi annullare le modifiche in 1 file ( badfile.txt) nel commit aaa222:

aaa333 Good commit
aaa222 Problem commit containing badfile.txt
aaa111 Base commit

Ripeti il ​​commit di base, modifica il commit del problema e continua.

1) Avvia rebase interattivo:

git rebase -i aaa111

2) Contrassegna il commit del problema per la modifica nell'editor cambiando pickin e(per la modifica):

e aaa222
pick aaa333

3) Ripristina le modifiche al file danneggiato:

git show -- badfile.txt | git apply -R

4) Aggiungi le modifiche e modifica il commit:

git add badfile.txt
git commit --amend

5) Termina il rebase:

git rebase --continue

Voglio solo sottolineare che questo presuppone che tu possa modificare la cronologia di git. Alcune risposte sopra creano un nuovo commit che inverte il particolare cambiamento senza modificare la cronologia, il che non è sempre possibile / consentito.
angularsen

Fantastico. Questo era esattamente quello che stavo cercando. Avevo già questa idea, ma mi sono confuso durante il rebase interattivo che i file durante l'esecuzione editnon venivano visualizzati come modificati. Ma ha git show -- badfile.txt | git apply -Rdato la risposta di cui avevo bisogno <3
mraxus

se capisco questo git apply -R rimuove il commit su quel file riportandolo allo stato originale modificato?
DaImTo

19

git revert è per tutti i contenuti dei file all'interno di un commit.

Per un singolo file, puoi scrivere uno script :

#!/bin/bash

function output_help {
    echo "usage: git-revert-single-file <sha1> <file>"
}

sha1=$1
file=$2

if [[ $sha1 ]]; then
git diff $sha1..$sha1^ -- $file | patch -p1
else
output_help
fi

(Dalle utilità git-shell-scripts di smtlaissezfaire )


Nota:

un altro modo è descritto qui se non è ancora stato eseguito il commit della modifica corrente.

git checkout -- filename

git checkout ha alcune opzioni per un file, modificando il file da HEAD, sovrascrivendo la modifica.


Dropped.on.Caprica menziona nei commenti :

Puoi aggiungere un alias a git in modo da poter fare git revert-file <hash> <file-loc>e ripristinare quel file specifico.
Vedi questo succo .

[alias]
  revert-file = !sh /home/some-user/git-file-revert.sh

Solo per aggiungere alla discussione qui, puoi aggiungere un alias a git in modo da poter fare git revert-file <hash> <file-loc>e ripristinare quel file specifico. Ho sollevato da questa risposta (anche se ho dovuto apportare un paio di modifiche per funzionare correttamente). Puoi trovare una copia del mio .gitconfigscript modificato qui: gist.github.com/droppedoncaprica/5b67ec0021371a0ad438
AlbertEngelB

@ Dropped.on.Caprica buon punto. L'ho incluso nella risposta per una maggiore visibilità.
VonC

12

Vorrei semplicemente utilizzare l' --no-commitopzione git-reverte quindi rimuovere i file che non si desidera vengano ripristinati dall'indice prima di eseguirne il commit. Ecco un esempio che mostra come ripristinare facilmente solo le modifiche a foo.c nel secondo commit più recente:

$ git revert --no-commit HEAD~1
$ git reset HEAD
$ git add foo.c
$ git commit -m "Reverting recent change to foo.c"
$ git reset --hard HEAD

Il primo git-reset"rimuove lo stage" da tutti i file, in modo che possiamo quindi aggiungere nuovamente solo un file che vogliamo ripristinare. Il finale git-reset --hardelimina i restanti file ripristinati che non vogliamo mantenere.


9

Molto più semplice:

git reset HEAD^ path/to/file/to/revert

poi

git commit --amend   

e poi

git push -f

il file è andato e il commit di hash, messaggio, ecc. è lo stesso.


Per completezza, serve un git checkout -- path/to/file/to/revertpassaggio? Inoltre, non è vero che l'hash è lo stesso dopo, giusto? L'ultima frase potrebbe essere migliore come qualcosa del tipo: "Il risultato è che l'ultimo commit viene sostituito da uno nuovo che differisce solo per il fatto che non contiene le modifiche al file ripristinato."
Kevin

@ Kevin probabilmente hai ragione. Dovrò ricontrollare l'ultima riga, ma ripensando a questo di un paio di anni fa sarei sorpreso se l'hash del commit è invariato.
Forrest

6
git reset HEAD^ path/to/file/to/revert/in/commit

Il comando precedente toglierà il file dal commit, ma si rifletterà in git status.

git checkout path/to/file/to/revert/in/commit

Il comando precedente annullerà le modifiche (di conseguenza otterrai il file uguale a HEAD).

git commit

(Passare --amendper modificare il commit.)

git push

Con questo, il file che è già nel commit viene rimosso e ripristinato.

I passaggi precedenti dovrebbero essere seguiti dal ramo in cui viene effettuato il commit.


5

Puoi seguire questa procedura:

  1. git revert -n <*commit*>( -nannulla tutte le modifiche ma non le impegna)
  2. git add <*filename*> (nome del / dei file che vuoi ripristinare e salvare)
  3. git commit -m 'reverted message' (aggiungi un messaggio per il ripristino)
  4. dopo aver eseguito il commit, elimina le altre modifiche ai file in modo che i file rimangano aggiornati con le modifiche apportate prima del ripristino

1

Se desideri ripristinare le modifiche su un file dal tuo ultimo commit, questo è quello che sto usando di solito. Penso che questa sia la soluzione più semplice.

Si noti che il file verrà aggiunto all'area di staging.

git checkout <prev_commit_hash> -- <path_to_your_file>

Spero che sia d'aiuto :)

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.