Comment décompresser un grand nombre de fichiers sans supprimer le contenu

454

J'ai accidentellement ajouté beaucoup de fichiers temporaires en utilisant git add -A

J'ai réussi à décompresser les fichiers en utilisant les commandes suivantes et j'ai réussi à supprimer l'index sale.

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

Les commandes ci-dessus sont répertoriées dans le git help rm. Mais malheureusement, mes fichiers ont également été supprimés lors de l'exécution, même si j'avais donné l'option de cache. Comment effacer l'index sans perdre le contenu?

Il serait également utile que quelqu'un explique le fonctionnement de cette opération de canalisation.

Sarat
la source
8
rm -fn'est pas une commande git et n'a pas d' --cachedoption. Vos fichiers locaux ont été supprimés avant votre exécution, git rmdonc je ne pense pas que vous puissiez légitimement blâmer git rmquoi que ce soit.
CB Bailey
8
@sarat, veuillez envisager de remplacer la bonne réponse par la réponse très appréciée de Ian Maddox , car la réponsegit reset --hard n'est pas correcte et supprimera en fait le contenu. Cela va dérouter les utilisateurs - comme cela m'a fait.
Marco Pashkov
2
@sarat comme le dit Marco, continuez. Cette page reçoit beaucoup de trafic.
Ross
@MarcoPashkov & Ross remercie les gars. Terminé.
sarat

Réponses:

986

git reset

Si tout ce que vous voulez, c'est d'annuler une exécution "git add" trop zélée:

git reset

Vos modifications ne seront pas mises en scène et seront prêtes à être ajoutées à votre guise.


NE COUREZ PAS git reset --hard.

Il non seulement mettra en scène vos fichiers ajoutés, mais annulera toutes les modifications que vous avez apportées dans votre répertoire de travail. Si vous avez créé de nouveaux fichiers dans le répertoire de travail, il ne les supprimera cependant pas.

Ian Maddox
la source
15
Je te dois une pinte Ian
DasBooten
1
Je trouve souvent que je dois git checkout -- *aussi jouer
Den-Jason
1
Vous avez économisé beaucoup d'efforts. Merci l'homme
RajnikantDixit
35

Si vous avez un dépôt vierge (ou si HEAD n'est pas défini) [1], vous pouvez simplement

rm .git/index

Bien sûr, cela vous obligera à ajouter à nouveau les fichiers que vous avez voulez ajouter.


[1] Remarque (comme expliqué dans les commentaires), cela ne se produira généralement que lorsque le dépôt est neuf ("vierge") ou si aucun engagement n'a été fait. Plus techniquement, chaque fois qu'il n'y a pas de caisse ou d'arbre de travail.

Juste pour être plus clair :)

sehe
la source
Oui, cela ressemble plus à la suppression de l'index créé lui-même. Heureusement, je n'ai pas besoin de réinitialiser git. Merci!
Sarat
Êtes-vous sûr que c'est une opération sûre? Je viens de le faire (en fait, l'index a été déplacé) et j'ai mis tous les autres fichiers en attente de suppression.
inger
@inger "Si vous avez un dépôt vierge". Vous n'aviez clairement pas cela.
sehe
En fait, je me demandais ce que vous vouliez dire par "repo vierge" (je ne me sens pas chanceux avec google non plus). Donc vous vouliez dire un repo vide en fait?
inger
1
@inger D'accord. Je devais supposer que le PO avait eu cette situation exacte - il ne le précise pas, mais sa description laisse la possibilité. Quoi qu'il en soit, je partage juste des informations et ne peux pas influencer le vote :(. J'ai ajouté un mot d'avertissement au texte de la réponse, au cas où cela aiderait les autres à l'avenir.
Voir
15

Utilisez git reset HEADpour réinitialiser l'index sans supprimer les fichiers. (Si vous souhaitez uniquement réinitialiser un fichier particulier dans l'index, vous pouvez le git reset HEAD -- /path/to/filefaire.)

L'opérateur de tuyaux, dans une coquille, prend le stdoutprocessus à gauche et le transmet stdinau processus à droite. C'est essentiellement l'équivalent de:

$ proc1 > proc1.out
$ proc2 < proc1.out
$ rm proc1.out

mais au lieu de cela $ proc1 | proc2, le deuxième processus peut commencer à obtenir des données avant que le premier ne soit sorti, et aucun fichier réel n'est impliqué.

ambre
la source
mais comment l'utiliser avec plusieurs fichiers. Je n'ai jamais validé ces fichiers auparavant.
Sarat
3
Tapez simplement git reset HEADsans spécifier quoi que ce soit d'autre, et cela réinitialisera l'index entier. Vous pouvez ensuite simplement ajouter à nouveau uniquement les fichiers que vous souhaitez.
Amber
J'ai eu l'erreur suivante. Je n'ai jamais commis ces articles auparavant. $ git reset HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions
Sarat
1
Essayez juste git resetalors, sans le HEAD.
Amber
J'ai déjà essayé de me retrouver avec l'erreur suivante. $ git reset fatal: Failed to resolve 'HEAD' as a valid ref.
Sarat
9
git stash && git stash pop
Bijan
la source
2
Je ferais 'git stash && git stash pop' pour que la cachette soit également supprimée. «appliquer» laisserait la cachette dans la liste de cachettes.
chitti
8

Si HEAD n'est pas défini (c.-à-d., Vous n'avez pas encore de commit, mais vous ne voulez pas simplement souffler .gitparce que vous avez déjà configuré une autre configuration de dépôt que vous souhaitez conserver), vous pouvez également faire

git rm -rf --cached .

pour tout déchaîner. C'est en fait la même chose que la solution de sehe, mais évite de nettoyer avec les composants internes de Git.

jjlin
la source
cela indique en fait à Git de supprimer tout dans la zone mise en cache.
Visionary Software Solutions
1
Le cache est également connu comme la zone de transit, donc je ne sais pas où vous en êtes.
jjlin
De sehe, rm .git / index est très dangereux - assurez-vous de lire la NOTE qu'il a sur un tout nouveau dépôt! C'est beaucoup plus sûr pour les autres 99,999% du temps. Je n'ai pas lu attentivement et j'ai dû souffler ma copie de travail et re-cloner après avoir fait rm .git / index sur ma copie de travail.
phpguru
N'UTILISEZ PAS cette commande! Il changera TOUS les projets à l'état non suivi (y compris ceux qui n'ont pas été organisés). Ce n'est pas une solution à la question d'origine. La bonne solution à l'aide de la commande «git rm» consiste à spécifier UNIQUEMENT les fichiers que vous souhaitez supprimer: git rm -rf --cached <fichiers que vous souhaitez supprimer>.
Monte Creasor
Vous ne devez utiliser cette commande que si vous avez un nouveau référentiel sans aucune validation (c'est ce que signifie "HEAD not set"), mais vous ne voulez pas simplement souffler .gitparce que vous avez configuré une autre configuration de référentiel vouloir garder. J'ai édité pour clarifier cela.
jjlin
5

Attention: n'utilisez la commande suivante que si vous voulez perdre du travail non engagé!

L'utilisation git reseta été expliquée, mais vous avez également demandé une explication des commandes canalisées, alors voici:

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

La commande git ls-filesrépertorie tous les fichiers connus de git. L'option leur -zimpose un format spécifique, le format attendu par xargs -0, qui les invoque rm -fensuite, ce qui signifie de les supprimer sans vérifier votre approbation.

En d'autres termes, "listez tous les fichiers que git connaît et supprimez votre copie locale".

Ensuite, nous arrivons à git diff, qui montre les changements entre les différentes versions des éléments que git connaît. Il peut s'agir de changements entre différentes arborescences, de différences entre les copies locales et les copies distantes, etc.
Tel qu'utilisé ici, il montre les changements non programmés; les fichiers que vous avez modifiés mais que vous n'avez pas encore validés. L'option --name-onlysignifie que vous voulez uniquement les noms de fichiers (complets) et --diff-filter=Dque vous êtes intéressé par les fichiers supprimés uniquement. (Hé, n'avons-nous pas simplement supprimé un tas de choses?) Cela est ensuite canalisé dans le fichier que xargs -0nous avons vu auparavant, qui les invoque git rm --cached, ce qui signifie qu'elles sont supprimées du cache, tandis que l'arborescence de travail doit être laissée seule - sauf que vous venez de supprimer tous les fichiers de votre arborescence de travail. Maintenant, ils sont également supprimés de votre index.

En d'autres termes, toutes les modifications, échelonnées ou non, ont disparu et votre arborescence de travail est vide. Ayez un cri, extrayez vos fichiers frais d'origine ou à distance et refaites votre travail. Maudissez le sadique qui a écrit ces lignes infernales; Je ne sais absolument pas pourquoi quelqu'un voudrait faire ça.


TL; DR: vous venez de tout arroser; recommencer et utiliser à git resetpartir de maintenant.

SQB
la source
2

Je crains que la première de ces lignes de commande ne supprime inconditionnellement de la copie de travail tous les fichiers qui se trouvent dans la zone de transit de git. Le second a mis en scène tous les fichiers qui ont été suivis mais ont maintenant été supprimés. Malheureusement, cela signifie que vous aurez perdu toutes les modifications non validées de ces fichiers.

Si vous souhaitez récupérer votre copie de travail et votre index comme ils étaient lors du dernier commit , vous pouvez ( avec précaution ) utiliser la commande suivante:

git reset --hard

Je dis "soigneusement" car git reset --hard cela effacera les changements non validés dans votre copie de travail et votre index. Cependant, dans cette situation, il semble que vous vouliez simplement revenir à l'état lors de votre dernier commit, et les modifications non validées ont quand même été perdues.

Mise à jour: il ressort de vos commentaires sur la réponse d'Amber que vous n'avez pas encore créé de commits (car HEAD ne peut pas être résolu), donc cela n'aidera pas, je le crains.

Quant à la façon dont ces canaux fonctionnent: git ls-files -zet les git diff --name-only --diff-filter=D -zdeux produisent une liste de noms de fichiers séparés par l'octet 0. (Ceci est utile, car, contrairement aux nouvelles lignes, les 0octets sont garantis de ne pas se produire dans les noms de fichiers sur les systèmes de type Unix.) Le programme xargsconstruit essentiellement des lignes de commande à partir de son entrée standard, par défaut en prenant des lignes de l'entrée standard et en les ajoutant à la fin de la ligne de commande. L' -0option dit de s'attendre à ce que l'entrée standard soit séparée par des 0octets. xargspeut invoquer la commande plusieurs fois pour utiliser tous les paramètres de l'entrée standard, en s'assurant que la ligne de commande ne devient jamais trop longue.

À titre d'exemple simple, si vous avez un fichier appelé test.txt, avec le contenu suivant:

hello
goodbye
hello again

... alors la commande xargs echo whatever < test.txtinvoquera la commande:

echo whatever hello goodbye hello again
Mark Longair
la source
Je n'ai jamais fait de commits donc ça dira que je ne peux pas résoudre HEAD. Ce que nous faisons dans de telles situations. Merci beaucoup d'avoir expliqué le tuyau en détail.
Sarat
8
Si vous venez de changer votre git ignore et avez ajouté git --all pour inclure un grand nombre de fichiers, N'exécutez PAS git reset --hard pour les supprimer. ILS SERONT SUPPRIMÉS !!
Ajoy
5
Uwaaahh !! Vous devrez peut-être mettre en évidence le mot "soigneusement" . Je viens de voir ces trois mots "git reset --hard" et tous mes fichiers non mis en scène sont ... fufff !! disparu!!!!!
Vineeth Chitteti
1

Si vous souhaitez annuler toutes les modifications, utilisez la commande ci-dessous,

git reset --soft HEAD

Dans le cas où vous souhaitez annuler les modifications et les annuler à partir du répertoire de travail,

git reset --hard HEAD
027
la source