git selective annule les modifications locales d'un fichier

149

Dans mon dépôt git qui suit un dépôt svn, j'ai apporté un certain nombre de modifications à un seul fichier.

Maintenant, je veux annuler ces changements (comme svn revert), mais seulement des parties du fichier.

Je veux pouvoir afficher les différences sur le fichier, annuler (annuler) les modifications que je ne veux pas et conserver les modifications que je souhaite.

les

git add -i 

La commande semble avoir une option pour le faire mais je ne veux pas encore la mettre en scène.

Pradeep
la source

Réponses:

91

Vous pouvez le faire directement avec git checkout -p. Voir la réponse de Daniel Stutzbach ci-dessous.


Ancienne réponse (avant l' checkout -pintroduction):

Vous pouvez le faire comme ceci:

git add -i

(sélectionnez les mecs que vous souhaitez conserver)

git commit -m "tmp"

Vous avez maintenant un commit avec uniquement les modifications que vous souhaitez conserver, et le reste n'est pas mis en scène.

git reset --hard HEAD

À ce stade, les modifications non validées ont été ignorées, vous disposez donc d'un répertoire de travail propre, avec les modifications que vous souhaitez conserver en premier.

git reset --mixed HEAD^

Cela supprime le dernier commit ('tmp'), mais conserve les modifications dans votre répertoire de travail, sans étape.

EDIT: remplacé --softpar --mixed, pour nettoyer la zone de préparation.

Paolo Capriotti
la source
cela va valider les changements que je souhaite conserver, n'est-ce pas? Je ne veux pas encore valider ces changements. mm peut-être que je prends les engagements trop au sérieux. Peut-être que je devrais me détendre maintenant car tout est dans un dépôt local. btw que fait git reset --soft HEAD ^?
Pradeep
"git reset --soft HEAD ^" annule un commit en ce sens qu'il garde le répertoire de travail et l'index comme c'était le cas, et déplace la branche actuelle d'un commit en arrière.
Jakub Narębski
Merci Jakub. Paolo, pourquoi une réinitialisation logicielle de la tête - 1 serait-elle nécessaire ici? la validation partielle et la réinitialisation matérielle devraient suffire, n'est-ce pas pour conserver certaines modifications et en supprimer d'autres?
Pradeep
1
La réponse de Daniel ci-dessous est très simple et semble être la bonne façon de le faire.
Umang
309

Je pense que vous pouvez le faire plus simplement avec:

git checkout -p <optional filename(s)>

Depuis la page de manuel:

   −p, −−patch
       Interactively select hunks in the difference between the <tree−ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree−ish> was specified, the index).
       This means that you can use git checkout −p to selectively discard
       edits from your current working tree.
Daniel Stutzbach
la source
1
De plus, si vous ne souhaitez pas le faire de manière sélective, vous pouvez utiliser "git checkout - <file> ..." pour annuler les modifications.
db42
Traite-t-il des répertoires?
bbum
1
Cela semble échouer beaucoup pour moi lors de la suppression des modifications ("erreur: le correctif a échoué <file>", "erreur: <file> le correctif ne s'applique pas"). Curieusement, je recevrai ces erreurs lors de l'utilisation de l' aoption en mode patch pour supprimer un fichier entier, mais git checkout -- <file>fonctionne comme prévu. Quelqu'un sait pourquoi?
chrnola
J'ai eu cette erreur plusieurs fois si le fichier avait déjà été corrigé, et donc le correctif interactif était obsolète avec les correctifs appliqués du fichier actuel. Cela s'est produit lors de l'utilisation d'un outil d'interface graphique comme l'arbre des sources si j'ai jeté un morceau deux fois accidentellement. La deuxième fois produirait cette erreur.
phyatt
3

Vous pouvez exécuter git diffle fichier, enregistrez le diff résultant, le modifier pour supprimer les modifications que vous ne souhaitez enregistrer, puis exécutez - le par patch -Rde défaire les diffs restants.

git diff fichier.txt> patch.tmp
# éditez patch.tmp pour supprimer les morceaux que vous souhaitez conserver
patch -R <patch.tmp
Greg Hewgill
la source
J'avais 2 mecs dans mon fichier de patch et j'en ai supprimé un. Je ne sais pas quelle est la raison, mais le correctif -R continue d'être rejeté avec cela.
Pradeep
2
Vous mentionnez dans un autre commentaire que git diffle fichier entier a été modifié. Cela se produit généralement lorsque vous avez enregistré le fichier en utilisant des fins de ligne différentes de ce qu'il était auparavant. Cela entraînerait également le patchrejet du fichier de correctif. Cela ressemble-t-il à ce qui aurait pu arriver?
Greg Hewgill
vous avez raison. les fins de ligne sont basculées chaque fois que j'utilise la commande patch. Je suis sous windows et j'utilise cream / vim. Besoin de régler ça d'abord, je pense.
Pradeep
Je n'ai pas pu résoudre le problème avec le correctif sous Windows. Bien que je sois sûr que cela fonctionne, je préfère utiliser la recette de Paolo. Pour l'amour de ces commandes interactives pour travailler avec les diffs en utilisant git add -i.
Pradeep
3

On dirait que tu veux

 git revert --no-commit $REVSISON 

Vous pouvez ensuite utiliser

 git diff --cached

pour voir quel changement sera fait avant de s'engager (car le retour est juste un commit dans une direction avant qui réplique l'inverse d'un changement dans le passé)

Si vous étiez avec un dépôt Git pur, vous pourriez éventuellement, en fonction de vos objectifs, utiliser interactif rebase ( git rebase -i) pour revenir au commit que vous n'aimez pas et modifier le commit rétroactivement afin que les changements que vous n'aimez pas ne se produisent jamais , mais ce n'est généralement que si vous SAVEZ que vous ne voudrez plus jamais le revoir.

Kent Fredric
la source
Je suis revenu comme vous l'avez mentionné à une révision précédente (est-ce correct?) Et maintenant git diff montre simplement le fichier entier comme modifié. Il est censé montrer les modifications que j'avais faites?
Pradeep
1

En relisant la question, il semble que vous vouliez annuler les changements qui se trouvent dans votre arbre de travail et non les changements qui ont été précédemment validés, mais certaines des autres réponses donnent l'impression que ma lecture peut être erronée. Pouvez-vous clarifier?

Si les modifications ne se trouvent que dans votre copie de travail, le moyen le plus simple de le faire est de mettre en scène les modifications que vous souhaitez conserver:

git add -i <file>

Jetez ensuite les modifications que vous ne souhaitez pas conserver en vérifiant la version d'index:

git checkout -- <file>

Ensuite, annulez les modifications si vous ne voulez pas encore les mettre en scène:

git reset -- <file>

Cette recette annule uniquement les modifications sélectionnées dans le fichier (ou les fichiers que vous spécifiez) et ne crée pas de validation temporaire qui doit ensuite être annulée.

Si vous souhaitez appliquer de manière sélective uniquement certaines des modifications apportées lors des validations précédentes, vous pouvez d'abord réinitialiser un fichier à un état de validation précédent:

git reset <commit_before_first_unwanted_change> -- <file>

Ensuite, vous pouvez suivre la recette précédente git add -i <file>pour mettre en scène les modifications que vous souhaitez conserver, git checkout -- <file>éliminer les modifications indésirables et git reset -- <file>«annuler» les modifications.

CB Bailey
la source
0

Les options de ligne de commande décrites dans les réponses ici sont pratiques lorsque le fichier se trouve sur un serveur auquel j'accède via un terminal ssh. Cependant, lorsque le fichier est sur ma machine locale, je préfère la méthode suivante:

Ouvrez le fichier dans l'éditeur netbeans (fourni avec le support git). Netbeans place des marques rouges / vertes / bleues sur les numéros de ligne pour indiquer où les éléments ont été supprimés / ajoutés / modifiés (respectivement).

Un clic droit sur l'une de ces marques vous donne la possibilité d'annuler cette modification. De plus, vous pouvez faire un clic droit sur les marques rouges et bleues pour trouver voir l'ancienne version dans une fenêtre contextuelle.

Abhishek Anand
la source