web-dev-qa-db-fra.com

Comment faire en sorte que Git "oublie" un fichier qui a été suivi mais qui est maintenant dans.

Il y a un fichier qui a été suivi par git, mais il se trouve maintenant dans la liste .gitignore.

Cependant, ce fichier continue à apparaître dans git status après avoir été modifié. Comment forcer git à l'oublier complètement?

4132
Ivan

.gitignore empêchera l'ajout de fichiers non suivis (sans add -f) à l'ensemble des fichiers suivis par git, mais git continuera à suivre tous les fichiers déjà suivis.

Pour arrêter de suivre un fichier, vous devez le supprimer de l'index. Ceci peut être réalisé avec cette commande.

git rm --cached <file>

La suppression du fichier de la révision principale aura lieu lors de la prochaine validation.

AVERTISSEMENT: Bien que cela ne supprime pas le fichier physique de votre répertoire local, il supprimera les fichiers des ordinateurs des autres développeurs lors du prochain git pull

4420
CB Bailey

La série de commandes ci-dessous supprimera tous les éléments de l'index Git (et non du répertoire de travail ou du référentiel local), puis mettra à jour l'index Git, tout en respectant git ignore. PS. Index = Cache

Premier:

git rm -r --cached . 
git add .

Ensuite:

git commit -am "Remove ignored files"
2233
Matt Frear

git update-index fait le travail pour moi:

git update-index --assume-unchanged <file>

Remarque: Cette solution est en réalité indépendante sur .gitignore car gitignore ne concerne que les fichiers non suivis.

edit: Depuis que cette réponse a été postée, une nouvelle option a été créée et devrait être préférée. Vous devez utiliser --skip-worktree, qui concerne les fichiers suivis modifiés que l'utilisateur ne veut plus valider, et conservez --assume-unchanged pour éviter que git ne vérifie le statut des gros fichiers suivis. Voir https://stackoverflow.com/a/13631525/717372 pour plus de détails ... 

git update-index --skip-worktree <file>
861
Konstantin
git ls-files --ignored --exclude-standard -z | xargs -0 git rm --cached
git commit -am "Remove ignored files"

Cela prend la liste des fichiers ignorés et les supprime de l'index, puis valide les modifications.

241
thSoft

J'utilise toujours cette commande pour supprimer ces fichiers non suivis. Une ligne, style Unix, sortie nette:

git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached

Il répertorie tous vos fichiers ignorés, remplace chaque ligne de sortie par une ligne entre guillemets pour gérer les chemins contenant des espaces, et passe tout à git rm -r --cached pour supprimer les chemins/fichiers/répertoires de l'index.

64
David Hernandez

Si vous ne pouvez pas git rm un fichier suivi parce que d'autres personnes peuvent en avoir besoin (avertissement, même si vousgit rm --cached, lorsqu'une autre personne obtient cette modification, leurs fichiers seront supprimés dans leur système de fichiers). Celles-ci sont souvent effectuées en raison de substitutions de fichiers de configuration, d'informations d'authentification, etc. Veuillez consulter https://Gist.github.com/1423106 pour connaître les méthodes utilisées par les gens pour résoudre ce problème.

Résumer:

  • Demandez à votre application de rechercher un fichier ignoré config-overide.ini et utilisez-la sur le fichier validé config.ini (ou recherchez ~/.config/myapp.ini ou $ MYCONFIGFILE).
  • Validez le fichier config-sample.ini et ignorez le fichier config.ini. Demandez à un script ou à une copie similaire de copier le fichier si nécessaire.
  • Essayez d'utiliser gitattributes clean/smudge magic pour appliquer et supprimer les modifications à votre place, par exemple masquer le fichier de configuration en tant qu'extraction depuis une autre branche et nettoyer le fichier de configuration en tant qu'extraction depuis HEAD. C'est un truc délicat, je ne le recommande pas pour l'utilisateur novice.
  • Conservez le fichier de configuration sur une branche de déploiement qui lui est dédiée et qui n’est jamais fusionné avec le maître. Lorsque vous souhaitez déployer/compiler/tester, vous fusionnez avec cette branche et récupérez ce fichier. Il s'agit essentiellement d'une approche de nettoyage/nettoyage, sauf l'utilisation de stratégies de fusion humaine et de modules extra-git.
  • Anti-recommandation: Ne pas utiliser supposer-inchangé, cela se terminera en larmes (parce que mentir à soi-même provoquera de mauvaises choses, comme si votre changement était perdu à jamais).
53
Seth Robertson

déplacez-le, engagez-vous, puis réinstallez-le. Cela a fonctionné pour moi dans le passé. Il existe probablement un moyen plus "gittier" d'y parvenir.

50
Joel Hooks

Utilisez ceci quand:

1. Vous voulez extraire beaucoup de fichiers, ou

2. Vous avez mis à jour votre fichier gitignore

Lien source:http://www.codeblocq.com/2016/01/Untrack-files-already-added-to-git-repository-based-on-gitignore/

Supposons que vous avez déjà ajouté/validé des fichiers dans votre référentiel git et que vous les ajoutez ensuite à votre .gitignore; ces fichiers seront toujours présents dans votre index de référentiel. Nous verrons dans cet article comment nous en débarrasser.

Étape 1: Validez toutes vos modifications.

Avant de continuer, assurez-vous que toutes vos modifications sont validées, y compris votre fichier .gitignore.

Étape 2: Supprimer tout du référentiel

Pour effacer votre repo, utilisez:

git rm -r --cached .
  • rm est la commande remove
  • -r permettra un retrait récursif
  • –Cached supprimera uniquement les fichiers de l'index. Vos fichiers seront toujours là.

La commande rm peut être impitoyable. Si vous souhaitez essayer au préalable, ajoutez le drapeau -n ou --dry-run pour tester le résultat.

Étape 3: Re-tout ajouter

git add .

Étape 4: S'engager

git commit -m ".gitignore fix"

Votre dépôt est propre :)

Poussez les modifications sur votre télécommande pour voir les modifications effectives également.

44
Dheeraj Bhaskar

Ce qui n'a pas fonctionné pour moi

(Sous Linux), je voulais utiliser les messages ici suggérant l’approche ls-files --ignored --exclude-standard | xargs git rm -r --cached. Cependant, (certains des) fichiers à supprimer avaient une nouvelle ligne/LF/\n incorporée dans leurs noms. Aucune des solutions:

git ls-files --ignored --exclude-standard | xargs -d"\n" git rm --cached
git ls-files --ignored --exclude-standard | sed 's/.*/"&"/' | xargs git rm -r --cached

faire face à cette situation (obtenir des erreurs sur les fichiers non trouvés).

Alors j'offre

git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached

Ceci utilise l'argument -z de ls-files , et l'argument -0 de xargs pour prendre en charge correctement/correctement les caractères "méchants" dans les noms de fichiers.

Dans la page de manuel git-ls-files (1) , vous indiquez:

Lorsque l'option -z n'est pas utilisée, les caractères TAB, LF et antislash dans Les chemins d'accès sont représentés respectivement par\t,\n et \\.

je pense donc que ma solution est nécessaire si les noms de fichiers contiennent l'un de ces caractères.

EDIT: On m'a demandé d'ajouter que --- comme toute commande git rm --- ceci doit être suivi d'un commit pour rendre les suppressions permanentes, par exemple. git commit -am "Remove ignored files".

38
JonBrave

J'ai accompli cela en utilisant git filter-branch . La commande exacte que j'ai utilisée provient de la page de manuel:

WARNING: cela supprimera le fichier de votre historique

git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD

Cette commande recréera l’intégralité de l’historique des validations, en exécutant git rm avant chaque validation, et supprimera le fichier spécifié. N'oubliez pas de le sauvegarder avant d'exécuter la commande car elle sera perdue.

36
drrlvn
  1. Mettez à jour votre fichier .gitignore - par exemple, ajoutez un dossier que vous ne souhaitez pas suivre sur .gitignore.

  2. git rm -r --cached . - Supprime tous les fichiers suivis, y compris les fichiers recherchés et indésirables. Votre code sera en sécurité tant que vous aurez sauvegardé localement.

  3. git add . - Tous les fichiers seront rajoutés, à l'exception de ceux dans .gitignore.


Merci du chapeau à @AkiraYamamoto pour nous avoir indiqué la bonne direction.

18
Chen_Wayne

Je pense que peut-être que git ne peut pas totalement oublier un fichier à cause de sa conception ( section "Snapshots, Not Differences" ).

Ce problème est absent, par exemple, lors de l'utilisation de CVS. CVS stocke les informations sous forme de liste de modifications basées sur des fichiers. Les informations pour CVS sont un ensemble de fichiers et les modifications apportées à chaque fichier au fil du temps.

Mais dans Git, chaque fois que vous validez ou enregistrez l’état de votre projet, il prend essentiellement une photo de ce à quoi ressemble tous vos fichiers et stocke une référence à cet instantané. Donc, si vous avez ajouté un fichier une fois, il sera toujours présent dans cet instantané.

Ces 2 articles m'ont été utiles:

git suppose-inchangé vs skip-worktree et Comment ignorer les modifications dans les fichiers suivis avec Git

En me basant sur cela, je fais ce qui suit, si le fichier est déjà suivi:

git update-index --skip-worktree <file>

À partir de ce moment, toutes les modifications locales dans ce fichier seront ignorées et ne seront pas transférées à distance. Si le fichier est modifié à distance, un conflit surviendra lorsque git pull. Stash ne fonctionnera pas. Pour le résoudre, copiez le contenu du fichier dans le lieu sûr et procédez comme suit:

git update-index --no-skip-worktree <file>
git stash
git pull 

Le contenu du fichier sera remplacé par le contenu distant. Collez vos modifications d'un endroit sûr à un fichier et effectuez à nouveau:

git update-index --skip-worktree <file>

Si tout le monde travaillant avec le projet exécute git update-index --skip-worktree <file>, les problèmes avec pull doivent être absents. Cette solution convient aux fichiers de configuration, lorsque chaque développeur a sa propre configuration de projet.

Ce n'est pas très pratique de le faire à chaque fois, lorsque le fichier a été modifié à distance, mais vous pouvez le protéger contre le remplacement par du contenu distant.

13
Boolean_Type

Faites les étapes suivantes en série, tout ira bien.

1 .remove les fichiers ajoutés par erreur du répertoire/storage. Vous pouvez utiliser la commande "rm -r" (pour linux) ou les supprimer en parcourant les répertoires. Ou déplacez-les vers un autre emplacement de votre PC. [Vous devrez peut-être fermer le IDE si vous exécutez pour déplacer/supprimer]

2.ajoutez maintenant les fichiers/répertoires au fichier gitignore et enregistrez-le.

3. maintenant supprimer les de git cache en utilisant ces commandes (s'il y a plusieurs répertoires, supprimez-les un à un en lançant de manière répétée cette commande)

git rm -r --cached path-to-those-files

4. maintenant do a commit et Push, utilisez ces commandes. Ceci supprimera ces fichiers de git remote et fera en sorte que git arrête de suivre ces fichiers.

git add .
git commit -m "removed unnecessary files from git"
git Push Origin
5

La réponse copier/coller est git rm --cached -r .; git add .; git status

Cette commande ignorera les fichiers déjà validés dans un référentiel Git mais nous les avons maintenant ajoutés à .gitignore.

5
youhans

La réponse de Matt Fear était l'IMHO le plus efficace. Voici un script PowerShell permettant aux utilisateurs de Windows de ne supprimer que les fichiers de leur dépôt Git qui correspondent à leur liste d'exclusion.

# Get files matching exclusionsfrom .gitignore
# Excluding comments and empty lines
$ignoreFiles =  gc .gitignore | ?{$_ -notmatch  "#"} |  ?{$_ -match  "\S"} | % {
                    $ignore = "*" + $_ + "*"
                    (gci -r -i $ignore).FullName
                }
$ignoreFiles = $ignoreFiles| ?{$_ -match  "\S"}

# Remove each of these file from Git 
$ignoreFiles | % { git rm $_}

git add .
5
Ameer Deen

Déplacez ou copiez le fichier dans un emplacement sûr pour ne pas le perdre. Puis, récupérez le fichier et validez. Le fichier sera toujours affiché si vous revenez à l'un de ces commits précédents ou à une autre branche où il n'a pas été supprimé. Cependant, dans tous les commits futurs, vous ne verrez plus le fichier. Si le fichier se trouve dans git ignore, vous pouvez le déplacer dans le dossier, et git ne le verra pas.

5
Apreche

Le BFG est spécialement conçu pour supprimer les données indésirables telles que les gros fichiers ou les mots de passe des dépôts Git. Il comporte donc un simple indicateur qui supprimera tous les fichiers historiques volumineux (pas dans la validation actuelle): ' --strip-blobs-plus-que '

$ Java -jar bfg.jar --strip-blobs-bigger-than 100M

Si vous souhaitez spécifier les fichiers par nom, vous pouvez également le faire:

$ Java -jar bfg.jar --delete-files *.mp4

Le format BFG est 10-1000 fois plus rapide que git filter-branch et est généralement beaucoup plus facile à utiliser - consultez le les instructions d'utilisation complètes et exemples pour plus de détails.

Source: https://confluence.atlassian.com/bitbucket/reduce-repository-size-321848262.html

3
Meir Gerenstadt

Si vous ne souhaitez pas utiliser l'interface de ligne de commande et travaillez sous Windows, une solution très simple consiste à utiliser TortoiseGit , il comporte l'action "Supprimer (garder local)" dans le menu qui fonctionne correctement.

2
Pedi T.

J'ai aimé la réponse de JonBrave mais j'ai des répertoires de travail assez confus qui engagent -a me fait peur, alors voici ce que j'ai fait:

git config --global alias.exclude-ignored '! git fichiers-ls -z --ignored --exclude-standard | xargs -0 git rm -r --cached && git ls-files -z --ignored --exclude-standard | xargs -0 git stage && git stage .gitignore && git commit -m "nouveau gitignore et supprime les fichiers ignorés de l'index" '

le décomposer:

git ls-files -z --ignored --exclude-standard | xargs -0 git rm -r --cached 
git ls-files -z --ignored --exclude-standard | xargs -0 git stage 
git stage .gitignore 
git commit -m "new gitignore and remove ignored files from index"
  • supprimer les fichiers ignorés de l'index
  • stage .gitignore et les fichiers que vous venez de supprimer
  • commettre
2
Jay Irvine

Ce problème ne concerne plus le dernier git (v2.17.1 au moment de la rédaction).

Le .gitignore ignore enfin les fichiers suivis mais supprimés. Vous pouvez le tester vous-même en exécutant le script suivant. La déclaration finale git status doit indiquer "rien à commettre".

# Create empty repo
mkdir gitignore-test
cd gitignore-test
git init

# Create a file and commit it
echo "hello" > file
git add file
git commit -m initial

# Add the file to gitignore and commit
echo "file" > .gitignore
git add .gitignore
git commit -m gitignore

# Remove the file and commit
git rm file
git commit -m "removed file"

# Reintroduce the file and check status.
# .gitignore is now respected - status reports "nothing to commit".
echo "hello" > file
git status
1
Lloyd

Surtout pour les fichiers basés sur IDE, j'utilise ceci:

Par exemple, le slnx.sqlite, je viens de le supprimer complètement comme suit:

git rm {PATH_OF_THE_FILE}/slnx.sqlite -f
git commit -m "remove slnx.sqlite"

N'oubliez pas que certains de ces fichiers stockent certains paramètres utilisateur et préférences pour les projets (tels que les fichiers que vous avez ouverts). Ainsi, chaque fois que vous naviguez ou apportez des modifications à votre IDE, ce fichier est modifié. Il est donc vérifié et affiché en tant que modifications non validées.

1
curiousBoy

L'utilisation de la commande git rm --cached ne répond pas à la question d'origine:

Comment forcer git à oublier complètement [un fichier]?

En fait, cette solution fera en sorte que le fichier soit supprimé dans toutes les autres instances du référentiel lors de l’exécution de git pull!

La bonne façon de forcer git à oublier un fichier est documentée par GitHub here .

Je recommande de lire la documentation, mais en gros:

git fetch --all
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch full/path/to/file' --Prune-empty --tag-name-filter cat -- --all
git Push Origin --force --all
git Push Origin --force --tags
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --Prune=now

remplacez simplement full/path/to/file par le chemin complet du fichier. Assurez-vous que vous avez ajouté le fichier à votre .gitignore.

Vous devrez également (temporairement) autoriser les transferts non rapides vers votre référentiel , puisque vous modifiez votre historique git.

1
Skeets

Si commis DS_Store déjà engagé:

find . -name .DS_Store -print0 | xargs -0 git rm --ignore-unmatch

Ignorez-les par:

echo ".DS_Store" >> ~/.gitignore_global
echo "._.DS_Store" >> ~/.gitignore_global
echo "**/.DS_Store" >> ~/.gitignore_global
echo "**/._.DS_Store" >> ~/.gitignore_global
git config --global core.excludesfile ~/.gitignore_global

Enfin, engagez-vous!

0
user7718859

Cette méthode fait que git oublie complètement les fichiers ignorés ( passés /présents/futurs ), mais ne supprime rien du répertoire de travail (même si elle est extraite de nouveau de la télécommande).

Cette méthode nécessite l’utilisation de /.git/info/exclude (préféré) OU a préexistant .gitignore dans tous les validations dont les fichiers doivent être ignorés/oubliés. 1

Toutes les méthodes pour forcer git à ignorer les comportements après coup réécrivent effectivement l’historique et ont donc ramifications significatives pour toutes les pensions publiques/partagées/collaboratives qui pourraient être retirées après ce processus. 2

Conseil général: commencez par un dépôt propre - tout est mis en oeuvre, rien n’est en attente dans le répertoire de travail ou l’index, et effectuez une sauvegarde !

De plus, les commentaires/ historique de révision de cette réponse ( et l'historique de révision de cette question ) peuvent être utiles/éclairant.

#commit up-to-date .gitignore (if not already existing)
#this command must be run on each branch

git add .gitignore
git commit -m "Create .gitignore"

#apply standard git ignore behavior only to current index, not working directory (--cached)
#if this command returns nothing, ensure /.git/info/exclude AND/OR .gitignore exist
#this command must be run on each branch

git ls-files -z --ignored --exclude-standard | xargs -0 git rm --cached

#Commit to prevent working directory data loss!
#this commit will be automatically deleted by the --Prune-empty flag in the following command
#this command must be run on each branch

git commit -m "ignored index"

#Apply standard git ignore behavior RETROACTIVELY to all commits from all branches (--all)
#This step WILL delete ignored files from working directory UNLESS they have been dereferenced from the index by the commit above
#This step will also delete any "empty" commits.  If deliberate "empty" commits should be kept, remove --Prune-empty and instead run git reset HEAD^ immediately after this command

git filter-branch --tree-filter 'git ls-files -z --ignored --exclude-standard | xargs -0 git rm -f --ignore-unmatch' --Prune-empty --tag-name-filter cat -- --all

#List all still-existing files that are now ignored properly
#if this command returns nothing, it's time to restore from backup and start over
#this command must be run on each branch

git ls-files --other --ignored --exclude-standard

Enfin, suivez le reste de ce guide GitHub (à partir de l’étape 6) , qui contient des avertissements importants/des informations sur les commandes ci-dessous .

git Push Origin --force --all
git Push Origin --force --tags
git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --Prune=now

Les autres développeurs tirés du référentiel distant maintenant modifié doivent effectuer une sauvegarde, puis:

#fetch modified remote

git fetch --all

#"Pull" changes WITHOUT deleting newly-ignored files from working directory
#This will overwrite local tracked files with remote - ensure any local modifications are backed-up/stashed
#Switching branches after this procedure WILL LOOSE all newly-gitignored files in working directory because they are no longer tracked when switching branches

git reset FETCH_HEAD

Notes de bas de page

1 Étant donné que /.git/info/exclude peut être appliqué à toutes les validations historiques à l'aide des instructions ci-dessus, peut-être des détails sur l'obtention d'un fichier .gitignore dans la ou les validations historiques qui ont besoin c'est au-delà de la portée de cette réponse. Je voulais qu'un .gitignore correct soit dans le commit racine, comme si c'était la première chose que je faisais. D'autres peuvent ne pas s'en soucier puisque /.git/info/exclude peut accomplir la même chose, peu importe où le .gitignore existe dans l'historique de validation, et l'historique de réécriture est clairement un très sujet délicat, même conscient des ramifications .

FWIW, les méthodes potentielles peuvent inclure git rebase ou un git filter-branch qui copie un external .gitignore dans chaque commit, comme les réponses à cette question

2 L'application du comportement d'ignorage après coup en validant les résultats d'une commande autonome git rm --cached risque d'entraîner la suppression ultérieure du fichier tire de la télécommande poussée par force. L'indicateur --Prune-empty de la commande git filter-branch suivante permet d'éviter ce problème en supprimant automatiquement la précédente validation avec suppression de tous les fichiers ignorés. La réécriture de l’historique git entraîne également des modifications des hachages, ce qui fera des dégâts lors des futures retraits des pensions publiques/partagées/collaboratives. S'il vous plaît comprendre les ramifications complètement avant de faire cela à un tel repo. Ce guide GitHub spécifie ce qui suit:

Dites à vos collaborateurs de rebase , de ne pas fusionner, toutes les branches qu'ils ont créées à partir de votre ancien historique de référentiel (corrompu). Un commit de fusion pourrait réintroduire tout ou partie de l’histoire corrompue que vous venez de prendre la peine de purger.

Les solutions alternatives qui n’affectent pas le référentiel distant sont git update-index --assume-unchanged </path/file> ou git update-index --skip-worktree <file>, dont on peut trouver des exemples ici .

0
goofology