Le fichier est dans .gitignore mais Git le suit toujours ? Vous avez
commité un secret ? Votre repo fait des centaines de Mo à cause d'un
binaire ? Ce guide couvre les trois problèmes de nettoyage les plus
fréquents : arrêter de suivre un fichier, purger des données sensibles
de tout l'historique, et réduire la taille d'un dépôt.
Prérequis : Enregistrer des modifications et Réécrire l'historique.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Arrêter de suivre un fichier sans le supprimer du disque
- Supprimer un fichier sensible de tout l'historique avec
git filter-repo - Appliquer le bon workflow selon que le secret est local ou déjà poussé
- Déboguer
.gitignorequand un fichier continue d'être tracké malgré la règle
Diagnostic rapide : quel est votre problème ?
Section intitulée « Diagnostic rapide : quel est votre problème ? »Les deux premières lignes se traitent en local, en quelques secondes, sans conséquence pour personne. Les deux dernières impliquent de réécrire l'historique et donc de coordonner toute l'équipe. Identifiez votre symptôme ici avant d'aller plus loin : appliquer la solution des lignes 3 et 4 à un problème des lignes 1 et 2 force vos collègues à recloner pour rien.
| Symptôme | Cause | Section |
|---|---|---|
Fichier dans .gitignore mais suivi par Git | Ajouté avant le .gitignore | « Arrêter de suivre un fichier » |
.gitignore ne semble pas fonctionner | Erreur de syntaxe ou de priorité | « Débugger un .gitignore » |
| Secret/mot de passe commité par erreur | Visibles dans l'historique | « Supprimer un secret de l'historique » |
| Dépôt volumineux (> 100 Mo) | Fichier binaire dans l'historique | « Réduire la taille du dépôt » |
Arrêter de suivre un fichier
Section intitulée « Arrêter de suivre un fichier »Vous avez ajouté config/local.json au repo avant de mettre la règle
dans .gitignore. Le fichier est ignoré pour les futures modifications,
mais Git le suit toujours car il est dans l'index.
git rm --cached config/local.json--cached retire le fichier de l'index (Git arrête de le suivre) sans
le supprimer du disque. Le fichier reste dans votre répertoire de
travail.
Commitez le changement :
git commit -m "chore: arrêter de suivre config/local.json"Vérification :
git status# config/local.json ne doit plus apparaîtrePour un dossier entier :
git rm -r --cached node_modules/git commit -m "chore: arrêter de suivre node_modules"Débugger un .gitignore
Section intitulée « Débugger un .gitignore »Le .gitignore ne fonctionne pas comme attendu ? Utilisez
git check-ignore pour comprendre pourquoi. L'écriture des motifs et les trois
sources de règles sont traitées dans
ignorer des fichiers avec .gitignore ;
cette section se concentre sur le diagnostic dans un dépôt déjà pollué.
Vérifier si un fichier est ignoré
Section intitulée « Vérifier si un fichier est ignoré »Plutôt que de relire le .gitignore à l'oeil, demandez à Git lui-même quelle
règle s'applique. L'option -v est indispensable : sans elle, la commande se
contente d'afficher le chemin, alors qu'avec elle vous obtenez le fichier
source, le numéro de ligne et le motif responsables. Git consulte plusieurs
fichiers d'exclusion (.gitignore de chaque répertoire, .git/info/exclude,
configuration globale), et c'est souvent celui auquel vous ne pensez pas qui
agit.
git check-ignore -v config/local.jsonSortie si le fichier est ignoré :
.gitignore:3:config/*.json config/local.jsonCela indique quelle règle (fichier, ligne) cause l'ignorance. Si aucune sortie, le fichier n'est pas ignoré.
Règles de priorité du .gitignore
Section intitulée « Règles de priorité du .gitignore »Quand plusieurs règles s'appliquent, la dernière règle gagne. L'ordre des
lignes est donc porteur de sens : une exception écrite avant la règle qu'elle
doit contredire n'a aucun effet. Le tableau qui suit détaille les cinq motifs
qui couvrent la quasi-totalité des cas, en particulier la différence entre
logs/*.log et logs/**/*.log, source classique de fichiers oubliés dans les
sous-dossiers.
# Ignorer tous les logs*.log
# MAIS garder error.log!error.log| Règle | Signification |
|---|---|
*.log | Ignore tous les fichiers .log |
!error.log | Négation, force le suivi de error.log |
logs/ | Ignore le dossier logs et tout son contenu |
logs/*.log | Ignore les .log dans logs/ (pas les sous-dossiers) |
logs/**/*.log | Ignore les .log dans logs/ et tous ses sous-dossiers |
Erreurs fréquentes
Section intitulée « Erreurs fréquentes »Deux situations produisent le même ressenti, « mon .gitignore est ignoré »,
alors que les causes n'ont rien à voir. La première tient au fait que
.gitignore ne s'applique qu'aux fichiers non encore suivis : un fichier
déjà dans l'index continue d'être versionné quoi que vous écriviez.
# Ne fonctionne pas : le fichier est déjà suivi par Gitsecret.env
# Solution : git rm --cached secret.env, puis conserver cette règleLa seconde tient à une optimisation de Git : quand un répertoire entier est exclu, Git n'en parcourt pas le contenu, donc aucune exception à l'intérieur ne peut être évaluée. Il faut exclure le contenu et non le répertoire lui-même.
# Ne fonctionne pas : la négation est inatteignablebuild/!build/important.js
# Solution : exclure le contenu, pas le répertoirebuild/*!build/important.jsLister tous les fichiers ignorés
Section intitulée « Lister tous les fichiers ignorés »Avant de conclure qu'une règle ne marche pas, regardez ce que Git exclut
réellement. --ignored ajoute à la sortie de git status une section listant
les fichiers écartés, ce qui permet de repérer une règle trop large qui masque
un fichier que vous vouliez versionner.
git status --ignoredSupprimer un secret de tout l'historique
Section intitulée « Supprimer un secret de tout l'historique »Un mot de passe, une clé API ou un token a été commité. Même si vous le supprimez dans un nouveau commit, il reste visible dans l'historique. Voici le workflow complet.
-
Installez git-filter-repo
git-filter-reporemplace l'ancienfilter-branch(plus sûr, plus rapide). Préférez le paquet de votre distribution : sur les systèmes récents,pip installdans l'environnement Python global échoue avecexternally-managed-environment.Fenêtre de terminal # Debian / Ubuntusudo apt install git-filter-repo# macOSbrew install git-filter-repo# Sinon, dans un environnement Python isolépipx install git-filter-repoVérification :
Fenêtre de terminal git filter-repo --version -
Sauvegardez votre repo (par sécurité)
Fenêtre de terminal cp -r mon-projet mon-projet-backup -
Supprimez le fichier de tout l'historique
Fenêtre de terminal git filter-repo --path .env --invert-paths--invert-pathssignifie : « supprime tout ce qui correspond au path donné ». Le fichier.envdisparaît de tous les commits. -
Vérifiez que le fichier n'apparaît plus
Fenêtre de terminal git log --all --full-history -- .env# Aucun résultat = le fichier est purgé -
Ajoutez le fichier au .gitignore
Fenêtre de terminal echo ".env" >> .gitignoregit add .gitignoregit commit -m "chore: ajouter .env au gitignore" -
Force push vers le remote
Fenêtre de terminal git push --force --allgit push --force --tags -
Prévenez votre équipe
Tous les collègues doivent re-cloner ou exécuter :
Fenêtre de terminal git fetch --allgit reset --hard origin/main
Supprimer un texte spécifique (pas un fichier entier)
Section intitulée « Supprimer un texte spécifique (pas un fichier entier) »Si le secret est une ligne à l'intérieur d'un fichier (pas le fichier entier) :
git filter-repo --replace-text <(echo 'MON_SECRET_123==>***REDACTED***')Cela remplace toutes les occurrences de MON_SECRET_123 par
***REDACTED*** dans tous les fichiers de tout l'historique.
Réduire la taille du dépôt
Section intitulée « Réduire la taille du dépôt »Un fichier binaire volumineux (dump SQL, vidéo, archive) a été commité et gonfle le repo :
Identifier les gros fichiers
Section intitulée « Identifier les gros fichiers »Le poids d'un dépôt vient rarement de son état actuel : il vient des blobs conservés dans l'historique, y compris ceux de fichiers supprimés depuis longtemps. La commande ci-dessous parcourt tous les objets de toutes les références, ne garde que les blobs, et les trie par taille décroissante. La première colonne est la taille en octets, la seconde le chemin. Un binaire de plusieurs dizaines de mégaoctets en tête de liste explique à lui seul la lenteur des clones.
git rev-list --objects --all \ | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \ | awk '/^blob/ {print $3, $4}' \ | sort -rn \ | head -20Sortie :
52428800 data/dump.sql10485760 assets/video-demo.mp4Supprimer les gros fichiers de l'historique
Section intitulée « Supprimer les gros fichiers de l'historique »La commande est la même que pour un secret, seul le chemin change. Attention
toutefois : la taille du dossier .git ne diminue pas immédiatement. Les
anciens objets restent référencés par le reflog jusqu'à ce que le ramasse-miettes
passe, ce que la section dépannage plus bas détaille.
git filter-repo --path data/dump.sql --invert-pathsPrévenir avec Git LFS
Section intitulée « Prévenir avec Git LFS »Pour éviter que cela ne se reproduise, utilisez Git LFS (Large File Storage) pour les fichiers volumineux :
git lfs installgit lfs track "*.sql"git lfs track "*.mp4"git add .gitattributesgit commit -m "chore: configurer Git LFS pour SQL et vidéos"Dépannage : problèmes courants
Section intitulée « Dépannage : problèmes courants »Ces cinq entrées couvrent l'essentiel des blocages rencontrés après un
nettoyage. La troisième mérite une explication : filter-repo a bien retiré les
objets de l'historique, mais Git les conserve tant que le reflog y fait
référence. Tant que vous n'avez pas expiré le reflog et lancé git gc, la taille
du dossier .git ne bouge pas, ce qui donne l'impression que l'opération a
échoué.
| Symptôme | Cause probable | Solution |
|---|---|---|
.gitignore ne fonctionne pas | Fichier déjà suivi (dans l'index) | git rm --cached fichier d'abord |
filter-repo refuse de s'exécuter | Repo pas « fresh clone » | Ajoutez --force ou reclonez |
Le repo est toujours gros après filter-repo | Objets non collectés | git reflog expire --expire=now --all && git gc --prune=now --aggressive |
| Les collègues ont des erreurs après le force push | Historiques divergents | Ils doivent re-cloner ou git fetch --all && git reset --hard origin/main |
La négation !fichier dans .gitignore ne marche pas | Le dossier parent est ignoré avec / | Ignorer le contenu dossier/* au lieu du dossier dossier/ |
À retenir
Section intitulée « À retenir »git rm --cachedarrête de suivre un fichier sans le supprimer du disque.gitignorene s'applique qu'aux fichiers non encore suivis, d'abordrm --cached, puis.gitignoregit check-ignore -vest l'outil de debug du.gitignore- Secret commité = secret compromis, changez-le immédiatement, avant le nettoyage Git
git filter-reposupprime un fichier de tout l'historique (remplacefilter-branch)- Après un
filter-repo, il faut force push et prévenir l'équipe - Git LFS prévient le problème des gros fichiers en les stockant séparément