11103 votes

Comment annuler 'git add' avant le commit ?

J'ai ajouté par erreur des fichiers à Git en utilisant la commande :

git add myfile.txt

Je n'ai pas encore exécuté git commit. Comment puis-je annuler cela pour que ces modifications ne soient pas incluses dans le commit ?

50 votes

À partir de Git v1.8.4, toutes les réponses ci-dessous qui utilisent HEAD ou head peuvent désormais utiliser @ à la place de HEAD. Consultez cette réponse (dernière section) pour comprendre pourquoi vous pouvez faire cela.

5 votes

J'ai fait un petit résumé qui montre toutes les façons de retirer un fichier de la mise en scène : stackoverflow.com/questions/6919121/…

6 votes

Pourquoi ne pas git checkout?

13206voto

genehack Points 26851

Pour annuler la mise en scène d'un fichier spécifique

git reset 

Cela supprimera le fichier de l'index actuel (la liste "sur le point d'être commis") sans rien changer d'autre.

Pour annuler la mise en scène de tous les fichiers du jeu de changements actuel :

git reset

Dans les anciennes versions de Git, les commandes ci-dessus sont équivalentes à git reset HEAD et git reset HEAD respectivement, et échoueront si HEAD est indéfini (parce que vous n'avez pas encore effectué de commits dans votre dépôt) ou ambigu (parce que vous avez créé une branche appelée HEAD, ce qui est une chose stupide que vous ne devriez pas faire). Cela a été changé dans Git 1.8.2, cependant, donc dans les versions modernes de Git vous pouvez utiliser les commandes ci-dessus même avant d'effectuer votre premier commit:

"git reset" (sans options ni paramètres) avait l'habitude de renvoyer une erreur lorsque vous n'avez aucun commit dans votre historique, mais il vous donne maintenant un index vide (pour correspondre à un commit inexistant sur lequel vous n'êtes même pas).

Documentation : git reset

152 votes

Bien sûr, ce n'est pas un véritable annulation, car si la mauvaise commande git add a écrasé une version précédemment mise en cache non validée, nous ne pouvons pas la récupérer. J'ai essayé de clarifier cela dans ma réponse ci-dessous.

12 votes

git reset HEAD *.extext sont les fichiers de l'extension donnée que vous voulez désindexer. Pour moi, c'était *.bmp & *.zip

1 votes

Git reset a dit qu'il avait annulé les modifications mais lorsque j'ai procédé à un autre git status, elles étaient toujours affichées comme modifiées

2426voto

Rhubarb Points 16453

Vous voulez :

git rm --cached 

Raisonnement :

Quand j'étais nouveau dans ce domaine, j'ai d'abord essayé

git reset .

(pour annuler tout ce que j'avais ajouté initialement), seulement pour obtenir ce message (pas si) utile :

fatal: Impossible de résoudre 'HEAD' en tant que référence valide.

Il s'avère que c'est parce que la référence HEAD (branche ?) n'existe pas avant le premier commit. Autrement dit, vous rencontrerez le même problème de débutant que moi si votre méthode de travail était similaire à la mienne :

  1. cd vers mon super nouveau répertoire de projet pour essayer Git, la nouvelle tendance

  2. git init

  3. git add .

  4. git status

    ... plein de choses apparaissent...

    \=> Zut, je ne voulais pas ajouter tout ça.

  5. chercher "annuler git add" sur Google

    \=> trouver Stack Overflow - super

  6. git reset .

    \=> fatal: Impossible de résoudre 'HEAD' en tant que référence valide.

Il s'avère également qu'il y a un bug signalé concernant l'inutilité de cela dans la liste de diffusion.

Et la solution correcte était justement là dans la sortie de statut de Git (que j'avais négligée comme étant une "chose")

...
# Modifications à valider :
#   (utilisez "git rm --cached ..." pour annuler l'étape)
...

Et la solution est en effet d'utiliser git rm --cached FICHIER.

Remarquez les avertissements ailleurs ici - git rm supprime votre copie locale du fichier de travail, mais pas si vous utilisez --cached. Voici le résultat de git help rm :

--cached Utilisez cette option pour enlever des chemins de stage et de l'index seulement. Les fichiers de l'arborescence de travail, modifiés ou non, seront laissés.

Je continue en utilisant

git rm --cached .

pour tout enlever et recommencer. Ça n'a pas fonctionné cependant, car tandis que add . est récursif, il s'avère que rm a besoin de -r pour être récursif. Soupir.

git rm -r --cached .

D'accord, maintenant je suis de retour au point de départ. La prochaine fois, je vais utiliser -n pour faire une simulation et voir ce qui sera ajouté :

git add -n .

J'ai sauvegardé tout dans un endroit sûr avant de faire confiance à git help rm concernant le --cached qui ne détruit rien (et qu'arriverait-il si je l'avais mal orthographié).

0 votes

Ne faites pas simplement "git reset" sans .c'est ce que vous voulez, ou ai-je manqué quelque chose?

27 votes

Hah. J'ai suivi le même processus. Sauf que j'ai abandonné et dit rm -rf .git, git init parce que je ne faisais pas confiance à git rm --cached pour garder ma copie de travail. Cela montre à quel point git reste encore trop complexe par endroits. git unstage devrait simplement être une commande standard, je ne m'en soucie pas si je peux l'ajouter en tant qu'alias.

3 votes

A-t-il fait cela et a supprimé tous mes autres fichiers existants - inchangé - à partir de la sauvegarde git. Les réajouter rend tout plus grand et détruit l'historique correct. Git est vraiment un projet inachevé.

622voto

Paul Beckingham Points 7460

Si vous tapez :

git status

Git vous dira ce qui est mis en scène, etc., y compris des instructions sur la façon de démettre en scène :

utilisez "git reset HEAD ..." pour démettre en scène

Je trouve que Git fait un assez bon travail pour me pousser à faire ce qu'il faut dans des situations comme celle-ci.

Note : Les versions récentes de Git (1.8.4.x) ont changé ce message :

(utilisez "git rm --cached ..." pour démettre en scène)

28 votes

Le message sera différent en fonction que le fichier add ait été déjà suivi (le add a uniquement enregistré une nouvelle version dans le cache - ici il affichera votre message). Sinon, si le fichier n'était pas préalablement mis en scène, il affichera utilisez "git rm --cached ..." pour annuler la mise en scène

0 votes

Super ! Le git reset HEAD est le seul qui fonctionnera si vous souhaitez annuler la suppression d'un fichier

3 votes

Ma version de git 2.14.3 dit git reset HEAD pour annuler la mise en staging.

305voto

takeshin Points 16579

Pour clarifier: git add déplace les modifications du répertoire de travail actuel vers la zone de staging (index).

Ce processus est appelé staging. Ainsi, la commande la plus naturelle pour stager les modifications (fichiers modifiés) est la plus évidente :

git stage

git add est simplement un alias plus facile à taper pour git stage

Dommage qu'il n'y ait pas de commandes git unstage ni git unadd. Celle pertinente est plus difficile à deviner ou à retenir, mais elle est assez évidente :

git reset HEAD --

Nous pouvons facilement créer un alias pour ceci :

git config --global alias.unadd 'reset HEAD --'
git config --global alias.unstage 'reset HEAD --'

Et enfin, nous avons de nouvelles commandes :

git add file1
git stage file2
git unadd file2
git unstage file1

Personnellement, j'utilise des alias encore plus courts :

git a # Pour le staging
git u # Pour le unstaging

7 votes

"mouvements"? Cela indiquerait qu'il est passé du répertoire de travail. Ce n'est pas le cas.

4 votes

Pourquoi est-ce évident ?

0 votes

En réalité, git stage est l'alias de git add, qui est la commande historique, à la fois sur Git et sur d'autres SCM. Elle a été ajoutée en décembre 2008 avec le commit 11920d28da dans le "dépôt git de Git", si je puis dire.

215voto

leonbloy Points 27119

Un complément à la réponse acceptée, si votre fichier ajouté par erreur était énorme, vous remarquerez probablement que, même après l'avoir retiré de l'index avec 'git reset', il semble toujours occuper de l'espace dans le répertoire .git.

Il n'y a pas lieu de s'inquiéter; le fichier est en effet toujours dans le dépôt, mais seulement sous forme d'"objet lâche". Il ne sera pas copié vers d'autres dépôts (via clone, push), et l'espace sera éventuellement récupéré - bien que peut-être pas tout de suite. Si vous êtes anxieux, vous pouvez exécuter :

git gc --prune=now

Mise à jour (ce qui suit est ma tentative pour dissiper quelques confusions qui peuvent découler des réponses les plus plébiscitées) :

Alors, quel est le véritable annuler de git add ?

git reset HEAD ?

ou

git rm --cached ?

Strictement parlant, et si je ne me trompe pas : aucun.

git add ne peut pas être annulé - en toute sécurité, en général.

Rappelons d'abord ce que fait effectivement git add :

  1. Si n'était pas suivi auparavant, git add l'ajoute au cache, avec son contenu actuel.

  2. Si était déjà suivi, git add enregistre le contenu actuel (un instantané, une version) dans le cache. Dans Git, cette action est encore appelée add, (pas seulement mettre à jour), car deux versions (instantanés) différents d'un fichier sont considérées comme deux éléments distincts : donc, nous ajoutons effectivement un nouvel élément au cache, à commettre ultérieurement.

À la lumière de ceci, la question est légèrement ambiguë :

J'ai ajouté par erreur des fichiers en utilisant la commande...

Le scénario de l'auteur du post semble être le premier (fichier non suivi), nous voulons que l'"annulation" supprime le fichier (pas uniquement le contenu actuel) des éléments suivis. Si tel est le cas, alors il est bon d'exécuter git rm --cached .

Et nous pourrions également exécuter git reset HEAD . C'est généralement préférable, car cela fonctionne dans les deux scénarios : cela annule également lorsque nous avons ajouté par erreur une version d'un élément déjà suivi.

Mais il y a deux mises en garde.

Premièrement : Il y a (comme indiqué dans la réponse) un seul scénario où git reset HEAD ne fonctionne pas, mais git rm --cached le fait : un nouveau dépôt (sans commits). Mais, vraiment, c'est un cas pratiquement négligeable.

Deuxièmement : Soyez conscient que git reset HEAD ne peut pas récupérer magiquement le contenu du fichier mis en cache précédemment, il le resynchronise simplement depuis le HEAD. Si notre git add égaré a écrasé une version mise en cache précédemment non committée, nous ne pouvons pas la récupérer. C'est pourquoi, strictement parlant, nous ne pouvons pas annuler [*].

Exemple :

$ git init
$ echo "version 1" > file.txt
$ git add file.txt   # Premier ajout de file.txt
$ git commit -m 'premier commit'
$ echo "version 2" > file.txt
$ git add  file.txt   # Mettre en stage (ne pas committer) "version 2" de file.txt
$ git diff --cached file.txt
-version 1
+version 2
$ echo "version 3" > file.txt
$ git diff  file.txt
-version 2
+version 3
$ git add  file.txt    # Oops, ce n'est pas ce que nous voulions
$ git reset HEAD file.txt  # Annuler ?
$ git diff --cached file.txt  # Aucune différence, bien sûr. stage = HEAD
$ git diff file.txt   # Nous avons irrémédiablement perdu "version 2"
-version 1
+version 3

Bien sûr, cela n'est pas très critique si nous suivons simplement le flux de travail habituel de ne faire 'git add' que pour ajouter de nouveaux fichiers (cas 1), et de mettre à jour les nouveaux contenus via la commande de commit, git commit -a.


* (Edit : ce qui précède est pratiquement correct, mais il peut toujours y avoir quelques moyens légèrement bricolés/complexes pour récupérer des modifications qui ont été mises en stage, mais pas committées et ensuite écrasées - voir les commentaires de Johannes Matokic et iolsmit)

6 votes

Strictement parlant, il y a un moyen de récupérer un fichier déjà mis en scène qui a été remplacé avec git add. Comme vous le mentionnez git add crée un objet git pour ce fichier qui deviendra un objet lâche non seulement lors de la suppression complète du fichier, mais aussi lorsqu'il est écrasé avec un nouveau contenu. Mais il n'y a pas de commande pour le récupérer automatiquement. Au lieu de cela, le fichier doit être identifié et extrait manuellement ou avec des outils écrits uniquement pour ce cas (libgit2 permettra cela). Mais cela ne vaudra la peine que si le fichier est très important et volumineux et ne peut pas être reconstruit en éditant la version précédente.

4 votes

Pour me corriger : Une fois que le fichier d'objet perdu est trouvé (utilisez des métadonnées comme la date/heure de création) git cat-file pourrait être utilisé pour récupérer son contenu.

8 votes

Une autre façon de récupérer des changements qui ont été mis en scène mais pas encore commis et qui ont ensuite été écrasés par exemple par un autre git add est via git fsck --inaccessible qui listera tous les objets inaccessibles, que vous pouvez ensuite inspecter avec git show SHA-1_ID ou git fsck --lost-found qui va écrire des objets flagrants dans .git/lost-found/commit/ ou .git/lost-found/other/, en fonction du type. Voir aussi git fsck --help

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X