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?
.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
.
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"
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>
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.
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.
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:
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.
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.
Avant de continuer, assurez-vous que toutes vos modifications sont validées, y compris votre fichier .gitignore.
Pour effacer votre repo, utilisez:
git rm -r --cached .
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.
git add .
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.
(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).
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"
.
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.
Mettez à jour votre fichier .gitignore
- par exemple, ajoutez un dossier que vous ne souhaitez pas suivre sur .gitignore
.
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.
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.
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.
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
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
.
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 .
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.
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
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.
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"
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
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.
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.
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!
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. 1Toutes 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
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 .