Rétablir ou extraire de manière sélective les modifications apportées à un fichier dans Git?

88

Existe-t-il une commande qui vous permet d'annuler partiellement les modifications d'un fichier (ou de fichiers) dans le répertoire de travail?

Supposons que vous ayez beaucoup modifié un fichier mais que vous vous rendiez compte que vous souhaitez annuler certaines des modifications à l'état validé, mais pas les autres modifications.

J'envisage une option pour git checkoutqui fonctionne beaucoup comme git add -p, c'est-à-dire qu'il passe par le fichier morceau par morceau et vous demande si vous voulez le garder ou non.

1800 INFORMATIONS
la source

Réponses:

85

Vous pourriez utiliser

git add -p <path>

pour mettre en scène les morceaux que vous souhaitez conserver dans un fichier particulier, puis

git checkout -- <path>

pour annuler les modifications de l'arborescence de travail que vous ne vouliez pas conserver, en récupérant la version intermédiaire du fichier.

Enfin, vous pouvez utiliser

git reset -- <path>

pour rétablir la version intermédiaire du fichier vers la version validée la plus récente du fichier pour vous laisser avec vos modifications sans étape.

CB Bailey
la source
Pour ce cas d'utilisation simple, que tout autre système de contrôle de version appelle simplement "revert", pourquoi la commande Git est-elle si obscure?
Jan Hettich
5
@Jan La commande des autres systèmes de contrôle de version revertvous permet-elle de sélectionner les modifications d'un fichier qui seront annulées? Vraiment demander, car je n'ai de l'expérience qu'avec CVS ​​et Git. Dans Git, il git checkout -- path/to/filey a une seule commande qui annule toutes les modifications de ce fichier, mais ce n'est pas la même chose que ci-dessus.
michiakig
3
Il y a aussi git checkout --patchet git reset --patchqui fonctionnent comme git add --patchdans le dernier git.
Matt Connolly
2
@Rudie, le --indique généralement la fin de l'analyse des options, et que tous les arguments qui suivent doivent être interprétés littéralement. Cela signifie que vous n'aurez pas à ajouter ./avant tout nom de fichier commençant par un signe moins, si le nom de fichier vient après --.
zrajm
lorsque j'utilise git checkout --patchle diff semble être à l'envers. Les symboles moins ajoutent du texte à ma copie de travail et les symboles plus suppriment des lignes de ma copie de travail.
Felipe Alvarez
115

Avec la version git> = 1.7.1 je peux

git checkout -p

Je ne sais pas quand cette fonctionnalité a été introduite.

thisgeek
la source
11
Il est à noter que vous pouvez également faire git reset -ppour annuler de manière sélective les modifications de la zone de préparation / index. Je ne sais pas non plus dans quelle version de Git cela a été introduit.
C'est la bonne réponse, pourquoi elle n'a pas été acceptée.
wukong
1
@wukong car cette réponse a été publiée 2 ans après la question. À ce moment (2009), la réponse de Charles était la meilleure solution
pomeh
8

git checkout $filerétablit l'état du fichier $fileau dernier état validé. Je pense que vous pouvez utiliser git checkout SHA-1 -- $filepour restaurer le fichier au commit identifié par SHA-1.

Koraktor
la source
1
ouais, pas exactement ce que je veux, puisque je veux conserver certaines des modifications que j'ai apportées au fichier et annuler les autres
1800 INFORMATION
1

De combien de commits avez-vous besoin pour revenir en arrière et sélectionner? S'il ne s'agit que d'un seul, prenez peut-être une branche juste avant, extrayez le fichier que vous avez validé et utilisez-le git add -ppour l'ajouter comme vous le souhaitez. Ensuite, vous pouvez revenir à l'endroit où vous étiez et extraire le fichier de votre branche temporaire.

C'est:

git checkout -b temp troublesome-commit^
git checkout troublesome-commit -- path/to/file
git add -p path/to/file
git commit -c troublesome-commit
git checkout @{-1}
git checkout temp -- path/to/file
git commit path/to/file
git branch -D temp

D'autres alternatives incluent revenir en arrière et éditer le commit avec git rebase -i(marquer le commit comme edit, puis faire un git reset HEAD^et refaire le commit lorsqu'il est replacé dans le shell).

Si les modifications que vous devez sélectionner sont réparties sur une série de validations, il peut être préférable de les extraire sous forme de patchs (ou d'un patch les couvrant tous) et d'éditer manuellement le patch, en supprimant les modifications que vous souhaitez conserver, et introduire le résidu dans git apply --reverse.

araqnid
la source
Je ne veux pas vraiment annuler quoi que ce soit qui est commis, je veux annuler les modifications qui ne sont que dans ma copie de travail
1800 INFORMATIONS