Supprimer un fichier d'un référentiel Git sans le supprimer du système de fichiers local

3048

Mon commit initial contenait des fichiers journaux. J'ai ajouté *logà mon .gitignore, et maintenant je veux supprimer les fichiers journaux de mon référentiel.

git rm mylogfile.log

supprimera un fichier du référentiel, mais le supprimera également du système de fichiers local.

Comment puis-je supprimer ce fichier du référentiel sans supprimer ma copie locale du fichier?

mveerman
la source
14
Il convient de noter que la réponse la plus votée est dangereuse pour certains. Si vous utilisez un dépôt à distance que lorsque vous poussez votre local, puis tirez ailleurs les fichiers que vous avez supprimés de git uniquement SERONT SUPPRIMÉS . Ceci est mentionné dans l'une des réponses mais n'est pas commenté.
RichieHH

Réponses:

4357

Depuis le fichier man :

Quand --cached est donné, le contenu intermédiaire doit correspondre à la pointe de la branche ou au fichier sur le disque, ce qui permet de supprimer le fichier uniquement de l'index.

Donc, pour un seul fichier:

git rm --cached mylogfile.log

et pour un seul répertoire:

git rm --cached -r mydirectory
bdonlan
la source
151
Facile à manquer car il n'est pas aussi explicite que svn rm --keep-local.
Martin
114
Mais comment conserver les fichiers sur des serveurs distants? Cela conserve mon local, mais si je pousse et tire depuis un autre serveur, le fichier est supprimé. J'ai également ajouté un .gitignore pour le fichier, mais il est toujours supprimé
spankmaster79
6
Cela supprime toujours les fichiers sur git pull si vous êtes derrière le commit aprèsgit rm
Petr Peller
9
Il convient de noter que, après avoir exécuté la commande dans la réponse, vous devez utiliser git commit -m "Commit message"et git push. Si vous avez d'autres modifications par étapes (vérifiez avec git status), elles seront également validées à ce moment.
Sinjai
9
Puisque c'est la réponse la plus acceptée et ne fait pas, ce qui est demandé, je vais dire ce que je fais. J'utilise la commande git rm --cached mylogfile.loget supprime le fichier du référentiel. Pour éviter de perdre le fichier sur un système productif, je fais une sauvegarde du fichier et je tire après cela. Le fichier est supprimé comme mentionné précédemment et doit être copié à partir de votre sauvegarde. C'est assez pénible, mais je n'ai trouvé aucune meilleure solution à ce problème.
Marcel Grolms
275

Pour supprimer un dossier entier du référentiel (comme les fichiers Resharper), procédez comme suit:

git rm -r --cached folderName

J'avais commis des fichiers de resharper et je ne voulais pas qu'ils persistent pour les autres utilisateurs du projet.

Sam Tyson
la source
13
Juste une note supplémentaire pour les futurs visiteurs: n'utilisez pas d'interface graphique pour «synchroniser» le commit avec le dépôt. Cela ramènera les fichiers dans votre référentiel local. Vous devez faire un Git Push repo branchpour supprimer les fichiers de la télécommande.
RubberDuck
211

Vous pouvez également supprimer des fichiers du référentiel en fonction de votre .gitignore sans les supprimer du système de fichiers local:

git rm --cached `git ls-files -i -X .gitignore`

Ou, alternativement, sur Windows Powershell:

git rm --cached $(git ls-files -i -X .gitignore)
nul
la source
7
Ne fonctionne pas sous Windows. git ls-files -i -X ​​.gitignore fonctionne, mais je ne sais pas comment envoyer les fichiers à 'git rm'. Savez-vous comment le faire?
Erik Z
17
Fonctionne sur Windows si vous utilisez Git Bash au lieu de cmd-console
Andreas Zita
17
Aime ça. A fonctionné, sauf que j'avais des fichiers qui ont fini par avoir des espaces dans le nom de fichier. Je solution ici modifié à ceci: git ls-files -i -X .gitignore | xargs -I{} git rm --cached "{}". Veuillez envisager de modifier ou d'ajouter cette solution à la réponse ici, car c'est un excellent outil pour avoir ...
mpettis
Je n'ai pas essayé, mais il devrait être testé, il supprimera également les fichiers comme celui .gitkeepqui préserve un dossier vide dans le référentiel. Par exemple. .gitignorecontient le dossier uploadset le dépôt est obligé de garder une trace de .gitkeep. En supprimant tout du repo sous, uploadsil sera également supprimé .gitkeep.
Vladimir Vukanac
Cette suggestion fonctionnait parfaitement dans PowerShell: git rm --cached $ (git ls-files -i -X ​​.gitignore)
geekandglitter
89

Selon ma réponse ici: /programming/6313126/how-to-remove-a-directory-in-my-github-repository

Pour supprimer un dossier / répertoire ou un fichier uniquement du référentiel git et non du local, essayez 3 étapes simples.


Étapes pour supprimer le répertoire

git rm -r --cached File-or-FolderName
git commit -m "Removed folder from repository"
git push origin master

Étapes pour ignorer ce dossier dans les prochains validations

Pour ignorer ce dossier à partir des validations suivantes, créez un fichier à la racine nommé .gitignore et mettez-y le nom de ce dossier. Vous pouvez en mettre autant que vous le souhaitez

Le fichier .gitignore ressemblera à ceci

/FolderName

supprimer le répertoire

eirenaios
la source
@gaurav heureux d'avoir aidé!
eirenaios
69

De plus, si vous avez validé des données sensibles (par exemple un fichier contenant des mots de passe), vous devez les supprimer complètement de l'historique du référentiel. Voici un guide expliquant comment procéder: http://help.github.com/remove-sensitive-data/

BoD
la source
13
Cette réponse doit inclure les commandes requises pour effectuer cette tâche au lieu de créer un lien vers un autre site Web.
Florian Lemaitre
1
Je voudrais également noter que j'ai trouvé l'utilisation de l' outil de nettoyage git bfg repo plus facile et plus rapide.
Lubed Up Slug le
64

Une solution plus générique:

  1. Modifier le .gitignorefichier.

    ECHO mylogfile.log >> .gitignore

  2. Supprimez tous les éléments de l'index.

    git rm -r -f --cached .

  3. Reconstruire l'index.

    git add .

  4. Faire un nouveau commit

    git commit -m "Removed mylogfile.log"

mAsT3RpEE
la source
2
Cela supprimera-t-il réellement le fichier?
Mr_and_Mrs_D
6
De GitHub? NON. Si vous avez déjà poussé vers github, il ne le supprimera pas du site. Mais cela mettra à jour votre référentiel git local.
mAsT3RpEE
5
Le commentaire que vous avez supprimé a été plus éliminé en fait :) Le problème avec la solution rm --cashedest qu'il supprimera finalement le fichier lorsque l'on tire - non? Et ce n'est pas ce que les gens veulent quand ils disent "Supprimer un fichier du référentiel sans le supprimer du système de fichiers local ". Maintenant, pourquoi la solution ci-dessus acceptée me dépasse-t-elle probablement que le PO fonctionnait seul et n'a jamais été retiré? Je ne sais pas. Je comprends le problème de github "une fois poussé toujours là" ofc
Mr_and_Mrs_D
Je ne pense pas qu'il existe une solution à 100% à moins que vous ne demandiez à github lui-même. Pour l'instant, respectez-le. Copier le fichier, ajouter à gitignore, faire git rm -r réel, valider, pousser, restaurer le fichier. Avez-vous réussi à trouver une autre solution?
mAsT3RpEE
9
Mon problème n'est pas github - c'est que le fichier sera réellement supprimé des collègues lorsqu'ils tireront . Je ne veux pas que le fichier soit supprimé. Cela m'a causé d'énormes problèmes dans le passé. Je me demandais donc s'il existe vraiment une solution qui ne supprime vraiment pas le fichier. Voir aussi le commentaire dans la réponse acceptée: stackoverflow.com/questions/1143796/…
Mr_and_Mrs_D
24

Git vous permet d'ignorer ces fichiers en supposant qu'ils sont inchangés. Pour ce faire, exécutez la git update-index --assume-unchanged path/to/file.txtcommande. Une fois un fichier marqué comme tel, git ignorera complètement toutes les modifications sur ce fichier; ils n'apparaîtront pas lors de l'exécution de git status ou git diff, et ils ne seront jamais validés.

(Sur https://help.github.com/articles/ignoring-files )

Par conséquent, ne le supprimez pas, mais ignorez pour toujours les modifications apportées. Je pense que cela ne fonctionne que localement, donc les collègues peuvent toujours voir des modifications à moins qu'ils exécutent la même commande que ci-dessus. (Il faut quand même vérifier cela.)

Remarque: Cela ne répond pas directement à la question, mais est basé sur des questions de suivi dans les commentaires des autres réponses.

Rystraum
la source
2
Hm, je fais cela mais je vois que le fichier peut être écrasé si quelqu'un d'autre le modifie sur le dépôt.
AlxVallejo
17

Si vous souhaitez simplement décompresser un fichier et ne pas le supprimer du référentiel local et distant, utilisez cette commande:

git update-index --assume-unchanged  file_name_with_path
Afraz Ahmad
la source
2
Bien que ce soit une bonne réponse, il est important de noter que cela ne "décompresse pas" un fichier dans le sens où les gens utilisent généralement ce mot avec Git, où un fichier non suivi est un fichier qui ne figure pas dans l'historique du référentiel et qui n'a jamais été . Cette réponse permet de conserver le fichier dans le référentiel mais d'empêcher Git de remarquer que des modifications y ont été apportées. Cela présente des différences importantes - le plus important, le fichier est toujours présent pour les autres, et si quelqu'un d'autre y apporte des modifications et que vous tirez, votre copie locale peut être écrasée sans confirmation.
Soren Bjornstad
8

Les réponses ci-dessus n'ont pas fonctionné pour moi. j'ai utiliséfilter-branch pour supprimer tous les fichiers validés.

Supprimez un fichier d'un référentiel git avec:

git filter-branch --tree-filter 'rm  file'

Supprimez un dossier d'un référentiel git avec:

git filter-branch --tree-filter 'rm -rf directory'

Cela supprime le répertoire ou le fichier de toutes les validations.

Vous pouvez spécifier un commit en utilisant:

git filter-branch --tree-filter 'rm -rf directory' HEAD

Ou une gamme:

git filter-branch --tree-filter 'rm -rf vendor/gems' t49dse..HEAD

Pour tout pousser à distance, vous pouvez faire:

git push origin master --force
Martijn Mellens
la source
2
Ceci est combiné avec git rm -r --cached NAMEl'astuce pour le supprimer de votre dépôt git local et l'empêcher d'affecter toute personne qui tire plus tard (en supprimant l'historique du fichier ou du répertoire de git.)
notbad.jpeg
1
Cela réécrit l'histoire de git et vous auriez besoin de pousser - force après, c'est un peu hors de portée avec la question je suppose. Sur un dépôt public célèbre, vous ne pouvez pas simplement changer la ligne de l'historique comme ça, car tout le monde ayant déjà cloné le dépôt aurait des problèmes lors du tirage.
Guillaume Perrot
0

Ignorez les fichiers, supprimez les fichiers de git, mettez à jour git (pour la suppression).

Remarque: cela ne concerne pas l'historique des informations sensibles.

Ce processus nécessite définitivement une compréhension de ce qui se passe avec git. Au fil du temps, ayant acquis cela, j'ai appris à faire des processus tels que:

1) Ignorez les fichiers

  • Ajouter ou mettre à jour le projet .gitignore pour les ignorer - dans de nombreux cas comme le vôtre, le répertoire parent, par exemplelog/ sera l'expression régulière à utiliser.
  • engager et pousser .gitignore changement de fichier (je ne sais pas si push a besoin de vous, pas de mal si c'est fait).

2) Supprimez les fichiers de git (uniquement).

  • Maintenant, supprimez les fichiers de git (uniquement) avec git remove --cached some_dir/
  • Vérifiez qu'ils restent toujours localement (ils devraient!).

3) Ajoutez et validez ce changement (il s'agit essentiellement d'un changement pour "ajouter" en supprimant des éléments, malgré la commande "ajouter" autrement déroutante!)

  • git add .
  • git commit -m"removal"
Michael Durrant
la source