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 ?
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 ?
git reset
Cela supprimera le fichier de l'index actuel (la liste "sur le point d'être commis") sans rien changer d'autre.
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
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.
git reset HEAD *.ext
où ext
sont les fichiers de l'extension donnée que vous voulez désindexer. Pour moi, c'était *.bmp
& *.zip
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
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 :
cd vers mon super nouveau répertoire de projet pour essayer Git, la nouvelle tendance
git init
git add .
git status
... plein de choses apparaissent...
\=> Zut, je ne voulais pas ajouter tout ça.
chercher "annuler git add" sur Google
\=> trouver Stack Overflow - super
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é).
Ne faites pas simplement "git reset" sans .c'est ce que vous voulez, ou ai-je manqué quelque chose?
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.
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é.
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)
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
Super ! Le git reset HEAD
est le seul qui fonctionnera si vous souhaitez annuler la suppression d'un fichier
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
"mouvements"? Cela indiquerait qu'il est passé du répertoire de travail. Ce n'est pas le cas.
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.
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
:
Si n'était pas suivi auparavant, git add
l'ajoute au cache, avec son contenu actuel.
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)
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.
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.
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 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.
50 votes
À partir de Git v1.8.4, toutes les réponses ci-dessous qui utilisent
HEAD
ouhead
peuvent désormais utiliser@
à la place deHEAD
. 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?
15 votes
@ErikReppen
git checkout
ne supprime pas les modifications mises en scène de l'index de commit. Il ne fait que revenir en arrière sur les modifications non mises en scène à la dernière révision commitée - ce qui, d'ailleurs, n'est pas ce que je veux non plus, je veux ces modifications, je veux juste les inclure dans un commit ultérieur.8 votes
Si vous utilisez Eclipse, il vous suffit de décocher les fichiers dans la boîte de dialogue de commit.
2 votes
Voici une excellente ressource directement depuis Github : Comment annuler (presque) n'importe quoi avec Git
3 votes
Avant de poster une nouvelle réponse, gardez à l'esprit qu'il y a déjà plus de 25 réponses à cette question. Assurez-vous que votre réponse apporte ce qui n'est pas parmi les réponses existantes.
0 votes
Je voudrais pouvoir voter positivement pour cela à chaque fois que je dois y revenir pour m'y référer
0 votes
Git supprimer myfile.txt
0 votes
Je fais toujours fonctionner cela en exécutant
git reset
. Pour plus d'informations, assurez-vous de jeter un oeil à cet article.0 votes
Si les lecteurs préfèrent utiliser l'interface graphique, vous pouvez cliquer avec le bouton droit sur un fichier et cliquer sur réinitialiser, ou annuler la mise en scène.
0 votes
git rm --cached
déstage et arrête de suivre (marqué pour suppression lors du prochain commit) un fichier donné, tandis quegit reset HEAD
ne fait que déstager le fichier0 votes
Pour les personnes travaillant avec de grands dépôts, vous pouvez également annuler le processus d'ajout git et il reviendra automatiquement en arrière.
0 votes
@jasonleonhard, ce n'est pas un mauvais lien de Github mais le scénario de l'OP n'est pas là!
0 votes
Ces nombreuses réponses, pourtant avec des contradictions et de la complexité, juste pour une chose aussi simple. C'est affreux