Annuler une partie des modifications non organisées dans git

158

Comment puis-je annuler des parties de mes modifications non organisées dans git, mais garder le reste tel quel? La façon dont j'ai compris est:

git commit --interactive
# Choose the parts I want to delete
# Commit the changes
git stash
git rebase -i master # (I am an ancestor of master)
# Delete the line of the most recent commit
git stash apply

Cela fonctionne, mais ce serait bien s'il y avait quelque chose comme git commit --interactiveuniquement pour annuler les modifications. De meilleures méthodes?

asmeureur
la source

Réponses:

265

Vous pouvez utiliser git checkout -p, qui vous permet de choisir des morceaux individuels de la différence entre votre copie de travail et l'index pour revenir. De même, git add -pvous permet de choisir des morceaux à ajouter à l'index et git reset -pvous permet de choisir des morceaux individuels de la différence entre l'index et HEAD pour sortir de l'index.

$ git checkout -p file/to/partially/revert
# or ...
$ git checkout -p .

Si vous souhaitez créer un instantané de votre dépôt git au préalable pour conserver ces modifications avant de les annuler, j'aime faire:

$ git stash; git stash apply

Si vous l'utilisez souvent, vous voudrez peut-être lui attribuer un alias:

[alias]
    checkpoint = !git stash; git stash apply

La restauration de morceaux ou de lignes individuelles peut être encore plus facile si vous utilisez un bon mode éditeur ou un bon plugin, qui peut fournir un support pour sélectionner directement les lignes à inverser, ce qui -ppeut parfois être un peu maladroit à utiliser. J'utilise Magit , un mode Emacs très utile pour travailler avec Git. Dans Magit, vous pouvez exécuter magit-status, trouver les différences pour les modifications que vous souhaitez annuler, sélectionner les lignes que vous souhaitez annuler (ou simplement placer le curseur sur les morceaux que vous souhaitez inverser si vous voulez revenir un morceau à la fois au lieu de ligne à la fois) et appuyez sur kpour inverser ces lignes spécifiques. Je recommande vivement Magit si vous utilisez Emacs.

Brian Campbell
la source
Je pense que c'est à peu près aussi complexe que la solution que j'ai initialement proposée, mais je pense que ma solution originale a l'avantage de sauvegarder les lignes supprimées pendant 30 jours car elles sont validées. Je pense que ce serait peut-être bien d'avoir un script shell écrit autour de lui, cependant.
asmeurer
1
Désolé, je viens de réaliser qu'il git checkouty a aussi un -pdrapeau, qui fait exactement ce que vous demandiez en une seule commande. Toutes mes excuses pour l’ensemble complexe d’étapes précédentes; vous pouvez simplement utiliser git checkout -p. En ce qui concerne la sauvegarde de choses, avant de faire quelque chose de potentiellement destructeur, je fais souvent un git stash; git stash apply(ou crée un alias qui fait cela comme git checkpointou quelque chose) pour enregistrer l'arbre actuel dans une réserve afin que je puisse y revenir si quelque chose ne va pas.
Brian Campbell
Voilà, c'est la solution! En ce qui concerne l'alias, je pense que quelque chose comme ça git commit -a -m "Backup Commit" --edit; git reset HEAD^ serait mieux, car cela ne salirait pas mon état de cache, que j'utilise peut-être pour autre chose. Ensuite, tant que vous avez le SHA1, vous pouvez le choisir dans les 30 prochains jours. Le --edit vous permet d'ajouter des informations au message de validation pour vous aider à trouver le SHA1 plus tard si vous le souhaitez. D'un autre côté, cela salirait le git reflog, donc je suppose que c'est un compromis basé sur ce que vous faites.
asmeurer
L'alias de point de contrôle ne fonctionne pas pour moi: seule la première commande est exécutée, pas la seconde. C'est triste, car j'aurais aimé ça. J'utilise la version 1.7.10.4 de git.
Fabien
Existe-t-il un moyen de ne git checkout -ppas appliquer les correctifs à l'index mais de les mettre en scène uniquement?
Geremia
28
git diff > patchfile

Ensuite, éditez le fichier patch et supprimez les parties que vous ne voulez pas annuler, puis:

patch -R < patchfile
octoberblu3
la source
6
Cependant, cette réponse est particulièrement admirable dans sa simplicité et sa facilité d'utilisation. +1
tholy
Le produit a patchfilefière allure dans vim et cela aide vraiment!
Bily
Parfait. Peut confirmer qu'il fonctionne également sous Windows avec Cygwin et Ubuntu bash pour Windows.
Checo R
1
Notez que vous pouvez également utiliser à la git apply -Rplace de patch(juste pour rester dans les domaines de git, ou dans l'événement différent qui patchn'est pas disponible)
user1556435
patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
HappyFace
5

Vous pourriez faire

git checkout master -- path/to/file

Pour chaque fichier que vous souhaitez réinitialiser.

Drew Hoskins
la source
Ou utilisez HEAD à la place du maître si vous travaillez sur une branche. Comme il est dit dans le rapport 'git status' (au moins dans les versions récentes).
Jonathan Leffler le
1

Que diriez-vous

  1. Sauvegardez les fichiers concernés avec les modifications de l'index
  2. utilisez git add -ppour ajouter uniquement les modifications souhaitées à l'index.
Abizern
la source
1

Quand j'exécute 'git status', il dit:

$ git status
# On branch fr/fr.002
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   makefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$

Donc, pour annuler les modifications non organisées, il me dit d'exécuter:

git checkout -- makefile
Jonathan Leffler
la source
3
Je pense qu'il se demandait comment rétablir des morceaux individuels, pas un fichier entier à la fois. C'est, bien sûr, la solution si vous avez juste besoin d'annuler toutes les modifications d'un fichier.
Brian Campbell
Ouais - je suppose que vous avez raison. Les options 'git checkout -p' et 'git add -p' semblent probablement être ce que l'on souhaite - comme vous l'avez dit.
Jonathan Leffler
1

La réponse de Brian Campbell plante mon git, version 1.9.2.msysgit.0, pour des raisons inconnues, donc mon approche est de mettre en scène les morceaux que je veux conserver, d'annuler les modifications dans la copie de travail, puis de désinstaller.

$ git add -p
   ... select the hunks to keep
$ git checkout -- .
$ git reset HEAD .
G-Wiz
la source
1
Il y a aussi git stash -p. Vous pourriez faire git stash -p; git reset --hard; git stash pop. C'est effectivement la même chose que ce que vous faites sauf que vous n'avez pas à écrire un message de validation.
asmeurer
@asmeurer applaudit. Le mien ne nécessite pas de message de validation, mais il est probablement plus logique d'utiliser le stash que l'index pour cela.
G-Wiz
0

vous pouvez faire git checkoutet lui donner le nom des parties que vous souhaitez annuler.

Andrew
la source