Annullare le modifiche alla copia di lavoro di un file in Git?


1634

Dopo l'ultimo commit, ho modificato un sacco di file nella mia copia di lavoro, ma voglio annullare le modifiche a uno di quei file, come nel ripristinarlo allo stesso stato del commit più recente.

Tuttavia, voglio solo annullare le modifiche alla copia di lavoro di un solo file, nient'altro.

Come lo faccio?

Risposte:


2215

Puoi usare

git checkout -- file

Puoi farlo senza il --(come suggerito da nimrodm), ma se il nome del file sembra un ramo o un tag (o un altro identificatore di revisione), può essere confuso, quindi usare --è meglio.

Puoi anche controllare una versione particolare di un file:

git checkout v1.2.3 -- file         # tag v1.2.3
git checkout stable -- file         # stable branch
git checkout origin/master -- file  # upstream master
git checkout HEAD -- file           # the version from the most recent commit
git checkout HEAD^ -- file          # the version before the most recent commit

34
qual è la differenza tra HEAD e HEAD ^?
hasen,

62
HEAD è il commit più recente sul ramo corrente e HEAD ^ è il commit prima di quello sul ramo corrente. Per la situazione che descrivi, puoi usare git checkout HEAD - nome file.
Paul,

16
In breve "git checkout sha-reference - nomefile" in cui il riferimento sha è un riferimento allo sha di un commit, in qualsiasi forma (ramo, tag, parent, ecc.)
Lakshman Prasad

29
NOTA: se il file è già in scena, è necessario prima ripristinarlo. git reset HEAD <filename> ; git checkout -- <filename>
Olie,

14
@gwho Sì, puoi fare HEAD^^per 2 commit dalla più recente o HEAD^^^per 3 commit indietro. Puoi anche usare HEAD~2, o HEAD~3, che diventa più conveniente se vuoi tornare più commit, mentre HEAD^2significa "il secondo genitore di questo commit"; a causa dei commit di merge, un commit può avere più di un commit precedente, quindi con HEAD^un numero seleziona quale di questi genitori, mentre con HEAD~un numero seleziona sempre il primo genitore ma quel numero di commit. Vedi git help rev-parseper maggiori dettagli.
Brian Campbell,

139

Basta usare

git checkout filename

Ciò sostituirà il nome file con l'ultima versione del ramo corrente.

ATTENZIONE: le modifiche verranno eliminate - non viene conservato alcun backup.


22
@duckx serve per chiarire i nomi dei rami dai nomi dei file. se dici git checkout xche x sembra essere un nome di ramo e un nome di file, non sono sicuro di quale sia il comportamento predefinito ma penso che git supporrà che tu voglia passare al ramo x. Quando usi --stai dicendo che ciò che segue sono i nomi dei file.
hasen

1
ic grazie per averlo chiarito. tutti presumono che tu sappia cosa - significa quando ti mostrano esempi. e non è qualcosa che puoi anche google facilmente.
Patoshi パ ト シ

1
Sembra che la risposta sia stata modificata per rimuoverla --. Sebbene sia ancora corretto, come sottolinea @hasen, se c'è un'ambiguità tra il nome del file e i nomi dei rami, potresti finire con un comportamento molto indesiderato qui!
BrainSlugs83

2
Mi piace così com'è, senza --, bello e facile. Quando dai un nome ai rami usando nomi di file, devi pensare male da qualche parte ...
Marco Faustinelli,

133
git checkout <commit> <filename>

L'ho usato oggi perché mi sono reso conto che la mia favicon era stata sovrascritta alcuni commit fa quando ho eseguito l'upgrade a drupal 6.10, quindi ho dovuto recuperarlo. Ecco cosa ho fatto:

git checkout 088ecd favicon.ico

1
Come posso ottenere il commit (di un file precedentemente cancellato) tranne che per lo scrolling di tonnellate di output "git log --stat"?
Alex

4
IMO è un po 'difficile tramite la riga di comando scansionare il registro di Gits e trovare il file giusto. È molto più facile con un'app GUI, come sourcetreeapp.com
neoneye

6
git log --oneline <filename>ti darà un registro più compatto e includerà solo le modifiche al file specifico
rjmunro

1
in alternativa, puoi usaregit reflog <filename>
ygesher il

70

Se il tuo file è già in scena (succede quando fai un git add etc dopo che il file è stato modificato) per mettere in scena le tue modifiche.

Uso

git reset HEAD <file>

Poi

git checkout <file>

Se non è già in scena, basta usare

git checkout <file>

2
Questo è stato più utile di quello accettato haha. È facile dimenticare quali cambiamenti sono stati messi in scena e quali no, quindi il ripristino ha aiutato. Anche se ho già provato "git reset --hard" prima, non ha fatto quello che ha fatto "git reset HEAD". Mi chiedo perché?
Arman Bimatov,

20

Se vuoi semplicemente annullare le modifiche del commit precedente in quel file, puoi provare questo:

git checkout branchname^ filename

Questo verificherà il file com'era prima dell'ultimo commit. Se vuoi tornare indietro qualche altro commit, usa la branchname~nnotazione.


Questo non rimuoverà le modifiche dal commit, applicherà solo il diff alla versione su HEAD.
FernandoEscher,

2
Sebbene sia vero, il poster originale voleva solo ripristinare le modifiche della sua copia di lavoro (penso), non annullare le modifiche dall'ultimo commit. La domanda del poster originale era un po 'poco chiara, quindi posso capire la confusione.

forse non l'uso di OP, ma stavo cercando come sovrascrivere il mio ramo con la copia del master - funziona abbastanza bene quando lo sostituiscobranchname^
Alex

15

Ho fatto tramite git bash:

(use "git checkout -- <file>..." to discard changes in working directory)

  1. Stato Git. [Quindi abbiamo visto un file modificato.]
  2. git checkout - index.html [ho cambiato nel file index.html:
  3. stato git [ora quelle modifiche sono state rimosse]

inserisci qui la descrizione dell'immagine


8

Mi confondo sempre con questo, quindi ecco un caso di promemoria; diciamo che abbiamo questo bashscript da testare git:

set -x
rm -rf test
mkdir test
cd test
git init
git config user.name test
git config user.email test@test.com
echo 1 > a.txt
echo 1 > b.txt
git add *
git commit -m "initial commit"
echo 2 >> b.txt
git add b.txt
git commit -m "second commit"
echo 3 >> b.txt

A questo punto, la modifica non viene gestita nella cache, quindi git statusè:

$ git status
On branch master
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:   b.txt

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

Se da questo punto, lo facciamo git checkout, il risultato è questo:

$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean

Se invece lo facciamo git reset, il risultato è:

$ git reset HEAD -- b.txt
Unstaged changes after reset:
M   b.txt
$ git status
On branch master
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:   b.txt

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

Quindi, in questo caso - se le modifiche non vengono messe in scena, git resetnon fa alcuna differenza, mentre le git checkoutsovrascrive.


Ora, supponiamo che l'ultimo cambiamento dallo script sopra sia messo in scena / memorizzato nella cache, vale a dire anche git add b.txtalla fine.

In questo caso, git statusa questo punto è:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   b.txt

Se da questo punto, lo facciamo git checkout, il risultato è questo:

$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean

Se invece lo facciamo git reset, il risultato è:

$ git reset HEAD -- b.txt
Unstaged changes after reset:
M   b.txt
$ git status
On branch master
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:   b.txt

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

Quindi, in questo caso - se le modifiche vengono messe in scena, git resetsostanzialmente trasformeranno le modifiche in fasi in modifiche non messe in scena - mentre git checkoutverranno sovrascritte completamente.


7

Questa risposta è per il comando necessario per annullare le modifiche locali che si trovano in più file specifici nella stessa o più cartelle (o directory). Ciò risponde in modo specifico alla domanda in cui un utente ha più di un file ma l'utente non vuole annullare tutte le modifiche locali:

se hai uno o più file puoi applicare lo stesso comando ( git checkout -- file) a ciascuno di quei file elencando ciascuno della loro posizione separata dallo spazio come in:

git checkout -- name1/name2/fileOne.ext nameA/subFolder/fileTwo.ext

fai attenzione allo spazio sopra tra name1 / name2 / fileOne.ext nameA / subFolder / fileTwo.ext

Per più file nella stessa cartella:

Se ti capita di dover annullare le modifiche per tutti i file in una determinata directory, usa git checkout come segue:

git checkout -- name1/name2/*

L'asterisco di cui sopra fa il trucco di annullare tutti i file in quella posizione sotto name1 / name2.

Allo stesso modo, quanto segue può annullare le modifiche in tutti i file per più cartelle:

git checkout -- name1/name2/* nameA/subFolder/*

di nuovo attenzione allo spazio tra name1 / name2 / * nameA / subFolder / * in quanto sopra.

Nota: nome1, nome2, nomeA, sottocartella: tutti questi nomi di cartelle di esempio indicano la cartella o il pacchetto in cui risiedono i file in questione.


5

Ripristino i miei file utilizzando l'id SHA, quello che faccio è git checkout <sha hash id> <file name>



2

Se non hai ancora inviato o condiviso in altro modo il tuo commit:

git diff --stat HEAD^...HEAD | \
fgrep filename_snippet_to_revert | cut -d' ' -f2 | xargs git checkout HEAD^ --
git commit -a --amend

0

Se è già stato eseguito il commit, è possibile ripristinare la modifica per il file e ripetere il commit, quindi annullare il nuovo commit con l'ultimo commit.


1
L'aggiunta di comandi specifici da utilizzare aiuterebbe il poster originale e i futuri visitatori.
Adrian,

0

Non so perché, ma quando provo a inserire il mio codice, viene visualizzato come immagine.

inserisci qui la descrizione dell'immagine

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.