Hard reset di un singolo file


1006

Al momento ho tre file modificati nella mia directory di lavoro. Tuttavia, desidero che uno di essi venga ripristinato allo stato HEAD.

In SVN, userei svn revert <filename>(seguito da svn update <filename>se necessario) ma in Git dovrei usare git reset --hard. Tuttavia, questo comando non può operare su un singolo file.

Esiste un modo in Git per annullare le modifiche in un singolo file e sovrascriverlo con una nuova copia HEAD?


3
git checkoutdi seguito è la risposta. In git, "ripristina" è qualcosa che fai per un commit. "Ripristina" riproduce il contrario di un commit storico nella directory di lavoro, quindi è possibile effettuare un nuovo commit che "annulla" il commit ripristinato. Trovo che questo sia un frequente punto di confusione per le persone che vengono a git da svn.
Dan Ray,


Se siete interessati perché non si può fare hard reset con percorsi, controllare la mia risposta .
utente

Questa domanda presuppone che si sappia cos'è un Hard reset.

Risposte:


1811

Puoi usare il seguente comando:

git checkout HEAD -- my-file.txt

... che aggiornerà sia la copia di lavoro my-file.txtche il suo stato nell'indice con quello di HEAD.

--in pratica significa: trattare ogni argomento dopo questo punto come un nome di file . Maggiori dettagli in questa risposta . Grazie a VonC per averlo segnalato.


58
Risposta più completa. +1;) Per il '-', puoi anche stackoverflow.com/questions/6561142/... (e, più in generale, stackoverflow.com/questions/1192180/... )
VonC

8
Inoltre, non dimenticare che puoi fare riferimento a un commit precedente HEAD~1per indicare il penultimo commit.
Ryanmt,

14
Puoi tralasciare HEADse sei a capo dell'attuale ramo - vedi norbauer.com/rails-consulting/notes/…
cxw

4
Qualche idea sul perché il resetcomando (come dice) "non può eseguire un hard reset con percorsi", e quindi perché il checkoutcomando non è (non può essere?) Utilizzato per ripristinare a fondo l'intero set? (Voglio dire perché è stato progettato così.)
Sz.

1
@cxw Sfortunatamente, questo non è del tutto vero. Dalla pagina man di git checkout: "Sovrascrivi i percorsi nell'albero di lavoro sostituendoli con i contenuti dell'indice o nel <tree-ish>". Vale a dire se <tree-ish>viene omesso, qualunque contenuto nell'indice verrà utilizzato per aggiornare l'albero di lavoro. Ciò può differire o meno da HEAD.
tuntap

137

Ripristina a testa:

Per ripristinare a fondo un singolo file su HEAD:

git checkout @ -- myfile.ext

Si noti che @è l'abbreviazione di HEAD. Una versione precedente di git potrebbe non supportare la forma abbreviata.

Ripristina per indicizzare:

Per reimpostare in modo rigido un singolo file sull'indice , supponendo che l'indice non sia vuoto, altrimenti su HEAD:

git checkout -- myfile.ext

Il punto è che, per sicurezza, non si vuole uscire da @o HEADdal comando a meno che non si intende specificamente ripristinare sull'indice .


1
Che succede con il "-" prima di myfile.ext?
Lance Kind

3
@LanceKind Come ho capito, è usato per delimitare un elenco di nomi di file che lo seguono. Senza di essa, ci sono casi in cui git interpreta gli argomenti in modo errato.
Acumenus,

2
Non solo nomi di file. La convenzione ampiamente utilizzata separa le opzioni dagli argomenti posizionali in molte utility. Vedi man bashpagina Citato
boweeb

1
Convenzionalmente, --viene usato per dire al programma I've finished specifying "options", and from here on, everything will be a positional argument.. Convenzionalmente, le "opzioni" sono i token come quelli --recursiveche possono apparire in qualsiasi ordine o addirittura essere combinati insieme nella loro forma abbreviata, come con rm -rf. Al contrario, gli "argomenti posizionali" sono molto più simili agli argomenti passati a una funzione in un linguaggio di programmazione: la loro posizione nell'elenco dei token definisce cosa esattamente il programma farà con loro (questi sono spesso nomi di file). --rimuove l'ambiguità su quale sia quale.
iono,

42

Per ripristinare l'upstream / master, procedi come segue:

git checkout upstream/master -- myfile.txt

19

Da Git 2.23 (agosto 2019) è possibile utilizzare restore( ulteriori informazioni ):

git restore pathTo/MyFile

Quanto sopra verrà ripristinato MyFilesu HEAD(l'ultimo commit) sul ramo corrente.

Se si desidera ottenere le modifiche da altri commit, è possibile tornare indietro nella cronologia dei commit. Il comando seguente otterrà MyFiledue commit precedenti all'ultimo. Ora hai bisogno dell'opzione -s( --source) poiché ora usi master~2e non master(l'impostazione predefinita) mentre ripristini l'origine:

git restore -s master~2 pathTo/MyFile

Puoi anche ottenere il file da un altro ramo!

git restore -s my-feature-branch pathTo/MyFile

1
Il modo più semplice finora. Purtroppo questa risposta non sta ottenendo abbastanza attenzione.
singrium,


4

è possibile utilizzare il comando seguente per ripristinare il singolo file

git checkout HEAD -- path_to_file/file_name

Elenca tutti i file modificati per ottenere path_to_file/filenamecon il comando seguente

git status

1

Puoi usare il seguente comando:

git reset -- my-file.txt

che aggiornerà sia la copia di lavoro di my-file.txtquando aggiunto.


Non cambia il contenuto del file modificato, come richiesto.
Rafael,

Quando hai aggiunto allo stash Hai modificato il file?
ADDYQU,

1
Questo non è specificamente il punto @ADDQU. La domanda è come "resettare" un file, non rimuoverlo dall'elenco graduale.
Rafael,

@Rafael Hai ragione, ma voglio farti sapere che esiste anche un modo.
ADDYQU,

0

Puoi usare il seguente comando:

git checkout filename

Se hai un ramo con lo stesso nome file devi usare questo comando:

git checkout -- filename

1
Questo non "ripristinerà" il file, ma copia solo lo stato dell'indice nell'albero di lavoro. Un "hard reset" ripristinerebbe prima l'indice.
AH

-21

Un modo semplice, pratico e pratico per farti uscire dall'acqua calda, soprattutto se non ti senti a tuo agio con Git:

  1. Visualizza il registro del tuo file

    git log myFile.js

    commit 1023057173029091u23f01w276931f7f42595f84f Autore: kmiklas Data: mar 7 ago 09:29:34 2018 -0400

    JIRA-12345 - Refactor con nuova architettura.

  2. Nota l'hash del file:

    1023057173029091u23f01w276931f7f42595f84f

  3. Mostra il file usando l'hash. Assicurati che sia quello che vuoi:

    git show 1023057173029091u23f01w276931f7f42595f84f: ./ myFile.js

  4. Reindirizzare il file su una copia locale

    git show 1023057173029091u23f01w276931f7f42595f84f: ./ myFile.js> myFile.07aug2018.js

  5. Eseguire il backup del file corrente.

    cp myFile.js myFile.bak.js

  6. Apri entrambi i file nel tuo editor di testo preferito.

    vim myFile.js
    vim myFile.07aug2018.js

  7. Copia n 'incolla codice da myFile.07aug2018.js in myFile.js e salva.

  8. Esegui il commit e invia myFile.js

  9. Ancora una volta visualizzare il registro e confermare che il file sia correttamente inserito.

  10. Di 'ai tuoi clienti di estrarre l'ultimo, felicemente vederlo funzionare con la vecchia versione in atto.

Non è la soluzione più sexy o più git-centric, e sicuramente un reset / inversione "manuale", ma funziona. Richiede una conoscenza minima di Git e non disturba la cronologia di commit.


2
Questa risposta è molto più complessa e soggetta a errori rispetto a qualsiasi soluzione che la precede da anni.
Artif3x

2
Perché qualcuno dovrebbe usare questa soluzione !? la vera risposta è solo un semplice comando.
Milad Rahimi,

1
Questa è la soluzione ottimale per determinate circostanze. Ha merito per chi è in difficoltà, dove git non funziona correttamente e per chi ha bisogno di una soluzione.
kmiklas,
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.