Annuler les modifications de copie de travail d'un fichier dans Git?

1634

Après le dernier commit, j'ai modifié un tas de fichiers dans ma copie de travail, mais je veux annuler les modifications apportées à l'un de ces fichiers, comme pour le réinitialiser au même état que le commit le plus récent.

Cependant, je veux seulement annuler les modifications de copie de travail de ce seul fichier, rien d'autre avec lui.

Comment je fais ça?

hasen
la source

Réponses:

2215

Vous pouvez utiliser

git checkout -- file

Vous pouvez le faire sans --(comme suggéré par nimrodm), mais si le nom de fichier ressemble à une branche ou à une balise (ou à un autre identifiant de révision), il peut devenir confus, il --est donc préférable d' utiliser .

Vous pouvez également consulter une version particulière d'un fichier:

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
Brian Campbell
la source
34
quelle est la différence entre HEAD et HEAD ^?
Hasen
62
HEAD est le commit le plus récent sur la branche courante, et HEAD ^ est le commit précédent sur la branche courante. Pour la situation que vous décrivez, vous pouvez utiliser git checkout HEAD - filename.
Paul
16
En bref "git checkout sha-reference - filename" où la sha-reference est une référence au sha d'un commit, sous n'importe quelle forme (branche, tag, parent, etc.)
Lakshman Prasad
29
REMARQUE: si le fichier est déjà intermédiaire, vous devez d'abord le réinitialiser. git reset HEAD <filename> ; git checkout -- <filename>
Olie
14
@gwho Oui, vous pouvez le faire HEAD^^pour 2 validations à partir de la plus récente, ou HEAD^^^pour 3 validations de retour. Vous pouvez également utiliser HEAD~2, ou HEAD~3, ce qui devient plus pratique si vous souhaitez revenir en arrière, tandis que HEAD^2signifie "le deuxième parent de cette validation"; en raison des validations de fusion, une validation peut avoir plusieurs validations précédentes, donc avec HEAD^un nombre sélectionne lequel de ces parents, tandis qu'avec HEAD~un nombre sélectionne toujours le premier parent mais ce nombre de validations revient. Voir git help rev-parsepour plus de détails.
Brian Campbell,
139

Utilisez simplement

git checkout filename

Cela remplacera le nom de fichier par la dernière version de la branche actuelle.

AVERTISSEMENT: vos modifications seront annulées - aucune sauvegarde n'est conservée.

nimrodm
la source
22
@duckx, c'est pour lever l'ambiguïté des noms de branche des noms de fichiers. si vous dites git checkout xet x se trouve être un nom de branche ainsi qu'un nom de fichier, je ne sais pas quel est le comportement par défaut mais je pense que git supposera que vous voulez passer à la branche x. Lorsque vous utilisez, --vous dites que ce qui suit est un ou plusieurs noms de fichier.
hasen
1
ic merci d'avoir clarifié cela. tout le monde suppose que vous savez quoi - signifie quand ils vous montrent des exemples. et ce n'est pas quelque chose que vous pouvez google facilement aussi.
Patoshi パ ト シ
1
On dirait que la réponse a été modifiée pour en supprimer le --. Bien que toujours correct, comme le souligne @hasen, s'il y a une ambiguïté entre le nom de fichier et les noms de branche, vous pouvez vous retrouver avec un comportement très indésirable ici!
BrainSlugs83
2
Je l'aime tel qu'il est, sans --, agréable et facile. Lorsque vous nommez des branches en utilisant des noms de fichiers, il doit y avoir une mauvaise pensée quelque part ...
Marco Faustinelli
133
git checkout <commit> <filename>

Je l'ai utilisé aujourd'hui car j'ai réalisé que mon favicon avait été écrasé il y a quelques commits il y a quelques temps lorsque je suis passé à la version drupal 6.10, j'ai donc dû le récupérer. Voici ce que j'ai fait:

git checkout 088ecd favicon.ico
neoneye
la source
1
Comment puis-je obtenir la validation (d'un fichier précédemment supprimé) à l'exception du défilement de tonnes de sortie "git log --stat"?
Alex
4
OMI, c'est un peu difficile via la ligne de commande de parcourir le journal des gits et de trouver le bon fichier. Il est beaucoup plus facile avec une application GUI, comme sourcetreeapp.com
neoneye
6
git log --oneline <filename>vous donnera un journal plus compact et n'inclura que les modifications apportées au fichier spécifique
rjmunro
1
alternativement, vous pouvez utilisergit reflog <filename>
ygesher
70

Si votre fichier est déjà mis en scène (se produit lorsque vous effectuez un ajout de git, etc. après la modification du fichier) pour annuler les modifications.

Utilisation

git reset HEAD <file>

alors

git checkout <file>

Si ce n'est déjà fait, utilisez simplement

git checkout <file>
thanikkal
la source
2
Cela a été plus utile que le haha ​​accepté. Il est facile d'oublier les modifications qui ont été mises en place et celles qui ne l'ont pas été. Bien que j'aie également essayé "git reset --hard" auparavant, il n'a pas fait ce que "git reset HEAD" a fait. Je me demande pourquoi?
Arman Bimatov
20

Si vous souhaitez simplement annuler les modifications du commit précédent sur ce fichier, vous pouvez essayer ceci:

git checkout branchname^ filename

Cela extraira le fichier tel qu'il était avant le dernier commit. Si vous souhaitez revenir en arrière quelques fois, utilisez la branchname~nnotation.

sykora
la source
Cela ne supprimera pas les modifications de la validation, il appliquera simplement le diff à la version sur la HEAD.
FernandoEscher
2
Bien que cela soit vrai, l'affiche originale voulait juste annuler ses modifications de copie de travail (je pense), pas annuler les modifications du dernier commit. La question de l'affiche originale n'était pas claire, donc je peux comprendre la confusion.
peut-être pas l'utilisation d'OP, mais je cherchais comment écraser ma branche avec la copie du maître - cela fonctionne très bien lors du remplacementbranchname^
Alex
15

J'ai fait via git bash:

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

  1. Statut Git. [Nous avons donc vu un fichier modifié.]
  2. git checkout - index.html [j'ai changé dans le fichier index.html:
  3. git status [maintenant ces modifications ont été supprimées]

entrez la description de l'image ici

Shiva
la source
8

Je suis toujours confus avec cela, voici donc un cas de test de rappel; disons que nous avons ce bashscript à tester 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

À ce stade, la modification n'est pas mise en scène dans le cache, tout git statuscomme:

$ 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")

Si à partir de ce point, nous le faisons git checkout, le résultat est le suivant:

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

Si au contraire nous le faisons git reset, le résultat est:

$ 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")

Donc, dans ce cas - si les modifications ne sont pas échelonnées, git resetcela ne fait aucune différence, tout en git checkoutécrasant les modifications.


Maintenant, disons que le dernier changement par rapport au script ci-dessus est mis en scène / mis en cache, c'est-à-dire que nous l'avons également fait git add b.txtà la fin.

Dans ce cas, git statusà ce stade est:

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

    modified:   b.txt

Si à partir de ce point, nous le faisons git checkout, le résultat est le suivant:

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

Si au contraire nous le faisons git reset, le résultat est:

$ 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")

Donc, dans ce cas - si les modifications sont échelonnées, elles git resetferont essentiellement des changements échelonnés en changements non échelonnés - alors qu'elles git checkoutécraseront complètement les changements.

sdaau
la source
7

Cette réponse concerne la commande nécessaire pour annuler les modifications locales qui se trouvent dans plusieurs fichiers spécifiques dans le même ou plusieurs dossiers (ou répertoires). Cette réponse répond spécifiquement à la question où un utilisateur a plus d'un fichier mais l'utilisateur ne veut pas annuler toutes les modifications locales:

si vous avez un ou plusieurs fichiers, vous pouvez appliquer la même commande ( git checkout -- file) à chacun de ces fichiers en répertoriant chacun de leur emplacement séparé par un espace comme dans:

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

attention à l'espace ci-dessus entre nom1 / nom2 / fileOne.ext nomA / subFolder / fileTwo.ext

Pour plusieurs fichiers dans le même dossier:

Si vous devez annuler les modifications de tous les fichiers d'un certain répertoire, utilisez la vérification git comme suit:

git checkout -- name1/name2/*

L'astérisque ci-dessus fait l'affaire de l'annulation de tous les fichiers à cet emplacement sous nom1 / nom2.

De même, les éléments suivants peuvent annuler les modifications dans tous les fichiers pour plusieurs dossiers:

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

attention encore à l'espace entre nom1 / nom2 / * nomA / sous-dossier / * dans ce qui précède.

Remarque: nom1, nom2, nomA, sous-dossier - tous ces exemples de noms de dossier indiquent le dossier ou le package dans lequel le ou les fichiers en question peuvent résider.

Nirmal
la source
5

Je restaure mes fichiers en utilisant l'identifiant SHA, ce que je fais est git checkout <sha hash id> <file name>

Être à
la source
3

Pour moi, seul celui-ci a fonctionné

git checkout -p filename

entrez la description de l'image ici

Ramesh Bhupathi
la source
2

Si vous n'avez pas encore poussé ou partagé votre commit:

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

S'il est déjà validé, vous pouvez annuler la modification du fichier et valider à nouveau, puis écraser la nouvelle validation avec la dernière validation.

Gina
la source
1
L'ajout de commandes spécifiques à utiliser aiderait l'affiche originale et les futurs visiteurs.
Adrian
0

Je ne sais pas pourquoi mais quand j'essaye d'entrer mon code, il apparaît comme une image.

entrez la description de l'image ici

Gène
la source