Posso eseguire un ripristino parziale in GIT


156

È possibile ripristinare solo un singolo file o determinate modifiche in un file con commit multi-file?

Storia completa Ho impegnato un mucchio di file. Un certo numero di commit in seguito qualcuno che rimarrà senza nome (JACK !!!) ha copiato un file nel suo repository e ha eseguito il commit di diversi file, sovrascrivendo alcune delle modifiche che ho fatto. Voglio ripristinare l'unico file che è stato ostruito o meglio ancora, andare e ripristinare due modifiche in quel file. Questo dovrà essere un commit di ripristino separato poiché è stato eseguito il pull e il push.


Brian mi ha portato sulla strada giusta. Ho finito con git add --patch e poi usando la funzione di modifica all'interno della patch per ottenere quello che volevo.
Frizione

2
Sono abbastanza in ritardo al gioco, ma credo di aver trovato la risposta "giusta" .
ntc2,

@ ntc2 Stranamente, la risposta accettata ha funzionato per me molto meglio di quella che hai collegato: ha creato conflitti di unione per me da risolvere, invece di non riuscire ad applicare le patch.
Iiridayn

@liridayn Hai letto tutta la mia risposta? Nella sezione "varianti" sostengo che l'aggiunta --3wayrisultati in conflitti di unione invece di mancata applicazione patch.
ntc2,

Risposte:


204

Puoi ripristinare il commit senza crearne uno nuovo aggiungendo l'opzione '--no-commit'. Ciò lascia tutti i file ripristinati nell'area di gestione temporanea. Da lì, eseguivo un ripristino software e aggiungevo le modifiche che desideravo davvero. Per un flusso di lavoro di esempio:

git revert <sha-of-bad-commit> --no-commit
git reset   // This gets them out of the staging area
<edit bad file to look like it should, if necessary>
git add <bad-file>
git checkout . // This wipes all the undesired reverts still hanging around in the working copy
git commit

42
Dopo il ripristino software, è anche possibile git add -pavviare una sessione interattiva che consente di aggiungere selettivamente blocchi di file anziché interi file. (C'è anche git reset -pda cambiare selettivamente sul palco. Buono a sapersi, ma probabilmente non è quello che vuoi in questo scenario.)
Stéphan Kochen

1
Era esattamente quello che cercavo: ripristina la copia di lavoro, seleziona gli hunk in modo interattivo, esegui il commit. Ti meriti un grande
bacio

Un'altra soluzione ispirata a questo sarebbe quello di revert, reset, stash -p(stash "annulla che io non voglio actualy make"), addil resto,commit
Cyril CHAPON

82

Puoi applicare interattivamente la vecchia versione di un file usando il checkoutcomando

Ad esempio, se si conosce la posizione in COMMITcui è stato rimosso il codice da aggiungere, è possibile eseguire il comando seguente:

git checkout -p COMMIT^ -- FILE_TO_REVERT

Git ti chiederà di aggiungere nuovamente gli hunk mancanti dalla versione corrente del file. È possibile utilizzare eper creare una patch della modifica prima di applicarla nuovamente.


Molto utile se si desidera ripristinare solo una parte del file! Fondamentalmente, per ottenere pezzi dalla testa,git checkout -p path/to/file
falstaff

40

Puoi semplicemente controllare manualmente i vecchi, buoni contenuti dei file che desideri ripristinare git checkout. Ad esempio, se si desidera ripristinare my-important-filela versione che era nella versione abc123, è possibile farlo

git checkout abc123 -- my-important-file

Ora hai i vecchi contenuti di my-important-fileback, e puoi anche modificarli se vuoi, e impegnarti come al solito a fare un commit che annullerà le modifiche che ha fatto. Se ci sono solo alcune parti del suo commit che vuoi ripristinare, usa git add -pper selezionare solo alcuni hunk dalla patch che stai commettendo.


19
Questo non è un revert, stai solo riprendendo una vecchia versione del file. Un vero reverte proprio rimuoverà le modifiche di commit errate all'interno del file, anche se è stato modificato più volte da quel commit errato e non si desidera perdere tali modifiche.
Totor

2
Totor, vedi la mia risposta. Puoi usare '-p' per salvare le modifiche. La risposta è molto vicina a questa in realtà.
cmcginty,

1
Oppure puoi combinare questo in git checkout -p.
Léo Lam,

31

Ho trovato un modo per farlo sulla mailing list di Git:

git show <commit> -- <path> | git apply --reverse

Fonte: http://git.661346.n2.nabble.com/Revert-a-single-commit-in-a-single-file-td6064050.html#a6064406

variazioni

Quel comando fallisce (non provoca cambiamenti) se la patch non si applica in modo pulito, ma con --3wayte invece ottieni conflitti che puoi quindi risolvere manualmente (in questo caso la risposta di Casey potrebbe essere più pratica):

git show <commit> -- <path> | git apply --reverse --3way

Puoi anche utilizzarlo per ripristinare parzialmente più commit, ad esempio:

git log -S<string> --patch | git apply --reverse

per ripristinare i file con le modifiche corrispondenti <string>in qualsiasi commit. Questo è esattamente ciò di cui avevo bisogno nel mio caso d'uso (alcuni commit separati hanno introdotto modifiche simili a file diversi, insieme a modifiche di altri file in modi non correlati che non volevo ripristinare).

Se hai diff.noprefix=trueimpostato il tuo ~/.gitconfigallora devi aggiungere -p0al git applycomando, ad es

git show <commit> -- <path> | git apply -p0 --reverse

Questa risposta è molto migliore di quella accettata: "meglio ancora, entra e annulla due modifiche in quel file".
riscritto il

Volevo ripristinare solo una parte di un commit, quindi ho fatto: (1) git show ... > foo.txt (2) modifica foo.txtper rimuovere le differenze Non volevo ripristinare (3) git apply --reverse foo.txt per ripristinare le differenze ancora elencate foo.txt.
Cxw

L'aggiunta di --binary --full-index alla parte show di git potrebbe anche essere una variazione utile
Laurynas Biveinis,
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.