Aller au contenu
Développement medium

Le fichier .gitignore : ignorer des fichiers et vérifier ce que Git prend en compte

16 min de lecture

Un dépôt Git ne doit contenir que ce que vous écrivez. Les dépendances installées, les artefacts de build, les journaux et les fichiers de configuration locale n'ont rien à y faire : ils alourdissent le dépôt, polluent les revues de code et exposent parfois des secrets.

Le fichier .gitignore répond à ce besoin. Il contient des motifs, un par ligne, et Git écarte les fichiers qui leur correspondent. Une règle détermine tout le reste : .gitignore ne filtre que les fichiers que Git ne suit pas encore. Un fichier déjà commité continue d'être suivi, quelle que soit la règle ajoutée ensuite. C'est l'origine de la quasi-totalité des « mon .gitignore ne fonctionne pas ».

Ce guide couvre l'écriture des règles, mais surtout la vérification : savoir quelle règle s'applique à un fichier donné, lister ce que Git écarte, et distinguer un fichier réellement ignoré d'un fichier simplement non modifié.

  • Écrire des règles : jokers, ancrage à la racine, dossiers, négation
  • git check-ignore -v : savoir quelle ligne de quel fichier ignore un chemin
  • Deux pièges de vérification qui font croire à une règle inopérante
  • Lister ce que Git ignore, et ce qu'il suit réellement
  • Réparer le cas du fichier déjà suivi
  • Les trois sources de règles : partagée, locale, globale

Git classe chaque fichier du répertoire de travail dans l'une de trois catégories : suivi (il est dans l'index, Git surveille ses modifications), non suivi (Git le voit mais ne le surveille pas), ou ignoré (Git le voit et a reçu l'ordre de ne pas le proposer).

.gitignore n'agit que sur la frontière entre les deux dernières. Il retire du bruit un fichier non suivi pour qu'il n'apparaisse plus dans git status et qu'un git add . ne l'attrape pas. Il n'a aucun effet sur un fichier déjà suivi, et il ne supprime rien du disque ni de l'historique.

Voici un projet Node.js avant toute règle :

Fenêtre de terminal
git status --short
?? README.md
?? debug.log
?? dist/
?? erreurs.log
?? node_modules/
?? src/

Les fichiers utiles se noient parmi les dépendances et les artefacts. Un .gitignore placé à la racine du dépôt règle le problème :

Fenêtre de terminal
cat > .gitignore <<'EOF'
# Dependances installees par npm
node_modules/
# Artefacts de build
dist/
# Journaux, sauf celui qu'on veut versionner
*.log
!erreurs.log
# Secrets
.env
EOF
Fenêtre de terminal
git status --short
?? .gitignore
?? README.md
?? erreurs.log
?? src/

Le .gitignore apparaît lui-même dans la liste, et c'est voulu : il doit être versionné pour que toute l'équipe partage les mêmes exclusions.

Écrire une règle est facile, savoir si elle s'applique l'est moins. Trois questions reviennent : pourquoi ce fichier est-il ignoré, qu'est-ce que Git écarte au total, et qu'est-ce qu'il suit réellement. Chacune a sa commande dédiée.

git check-ignore -v prend un chemin et répond en désignant la règle exacte qui le concerne, au format fichier:ligne:motif suivi du chemin testé.

Fenêtre de terminal
git check-ignore -v debug.log
.gitignore:8:*.log debug.log

La réponse se lit : la ligne 8 du fichier .gitignore, qui contient le motif *.log, s'applique à debug.log. C'est bien plus utile qu'un simple oui ou non, surtout dans un projet qui empile plusieurs .gitignore.

Fenêtre de terminal
git check-ignore -v dist/bundle.js
.gitignore:5:dist/ dist/bundle.js

Piège 1 : une négation s'affiche comme une correspondance

Section intitulée « Piège 1 : une négation s'affiche comme une correspondance »

L'option -v affiche tout motif qui correspond, y compris un motif de négation. Or un motif commençant par ! signifie exactement l'inverse : le fichier n'est pas ignoré.

Fenêtre de terminal
git check-ignore -v erreurs.log
.gitignore:9:!erreurs.log erreurs.log

La documentation officielle le formule ainsi : « Matching an exclude pattern usually means the path is excluded, but if the pattern begins with ! then it is a negated pattern and matching it means the path is NOT excluded ». Une sortie non vide ne veut donc pas dire « ignoré » : il faut regarder si le motif commence par !.

Le code de retour n'aide pas davantage en mode -v : il vaut 0 ici, alors que le fichier n'est pas ignoré. Sans -v, en revanche, la réponse est nette, car la commande ne liste plus que les chemins réellement écartés :

Fenêtre de terminal
git check-ignore erreurs.log
[aucune sortie, code de retour 1]

C'est cette forme qu'il faut utiliser dans un script : code 0 signifie ignoré, code 1 signifie conservé.

Pour la vue d'ensemble, git status --ignored ajoute les fichiers ignorés au rapport habituel, préfixés de !! :

Fenêtre de terminal
git status --ignored --short
?? .gitignore
?? README.md
?? erreurs.log
?? src/
!! debug.log
!! dist/
!! node_modules/

Cette sortie regroupe les dossiers entiers. Pour obtenir la liste fichier par fichier, ce qui est nécessaire avant de vérifier qu'aucun fichier utile ne s'est fait attraper par une règle trop large :

Fenêtre de terminal
git ls-files --others --ignored --exclude-standard
debug.log
dist/bundle.js
node_modules/express/index.js

Les trois options se lisent ensemble : --others sélectionne les fichiers non suivis, --ignored restreint aux ignorés, et --exclude-standard applique les règles habituelles au lieu d'exiger qu'on les fournisse à la main.

La commande symétrique répond à la question la plus importante avant un push :

Fenêtre de terminal
git ls-files

Elle liste le contenu de l'index, donc tout ce que Git surveille. Un fichier qui apparaît ici est suivi, quelles que soient vos règles d'exclusion. C'est le contrôle à faire quand vous soupçonnez qu'un fichier sensible est entré dans le dépôt.

Voici le scénario le plus fréquent. Un fichier .env a été commité par inadvertance, puis la règle .env a été ajoutée au .gitignore. La règle semble sans effet, et la vérification donne un résultat déroutant :

Fenêtre de terminal
git check-ignore -v .env
[aucune sortie, code de retour 1]

check-ignore affirme qu'aucune règle ne s'applique, alors que la ligne existe bel et bien. L'explication tient en une phrase de la documentation : « tracked files are not shown at all since they are not subject to exclude rules ». Un fichier suivi n'est pas soumis aux règles d'exclusion, la commande n'a donc rien à en dire.

L'option --no-index demande d'ignorer l'index et de ne consulter que les règles. Elle a été ajoutée à Git pour exactement ce diagnostic :

Fenêtre de terminal
git check-ignore -v --no-index .env
.gitignore:12:.env .env

La règle était donc correcte depuis le début. Le problème n'est pas le motif, c'est l'index. La preuve tient en une commande :

Fenêtre de terminal
git ls-files
.env

La réparation consiste à retirer le fichier de l'index sans le supprimer du disque, ce que fait git rm --cached :

Fenêtre de terminal
git rm --cached .env
git status --short
D .env
?? .gitignore
?? README.md
?? erreurs.log
?? src/

Le D signale que la suppression est indexée : le prochain commit retirera le fichier du dépôt. Sur le disque, il est toujours là, et il est désormais bien ignoré :

Fenêtre de terminal
git check-ignore -v .env
.gitignore:12:.env .env

.gitignore n'est pas la seule source. Git en consulte trois, qui répondent à des besoins différents.

FichierPortéeVersionnéUsage
.gitignoreLe dépôt, pour toute l'équipeOuiRègles du projet : dépendances, artefacts, secrets
.git/info/excludeVotre copie locale du dépôtNonVos fichiers de travail, sans imposer la règle aux autres
core.excludesFileToutes vos machines et tous vos dépôtsNonFichiers de votre éditeur ou de votre système

Le fichier local sert quand une exclusion ne concerne que vous. Elle n'a pas à polluer le .gitignore partagé :

Fenêtre de terminal
echo 'notes-perso.md' >> .git/info/exclude
git check-ignore -v notes-perso.md
.git/info/exclude:7:notes-perso.md notes-perso.md

La règle globale s'applique à tous vos dépôts. C'est la bonne place pour les fichiers de votre outillage personnel, que vos collègues n'ont aucune raison de subir dans le fichier partagé :

Fenêtre de terminal
git config --global core.excludesFile ~/.gitignore_global
echo '*.bak' >> ~/.gitignore_global
git check-ignore -v serveur.js.bak
/home/dev/.gitignore_global:1:*.bak serveur.js.bak

L'intérêt de check-ignore -v apparaît pleinement ici : il nomme le fichier source, donc vous savez immédiatement laquelle des trois est en cause.

Un motif se lit de gauche à droite, et quatre mécanismes suffisent à couvrir la quasi-totalité des besoins.

Le joker * remplace n'importe quelle suite de caractères dans un nom : *.log attrape debug.log comme application.log. La barre oblique finale restreint la règle aux dossiers : dist/ ignore le dossier et tout son contenu, là où dist attraperait aussi un fichier nommé dist.

La barre oblique initiale ancre la règle à la racine du dépôt. Sans elle, un motif s'applique à n'importe quelle profondeur, ce qui surprend souvent :

Fenêtre de terminal
git check-ignore -v config.json
.gitignore:13:/config.json config.json
Fenêtre de terminal
git check-ignore -v src/config.json
[aucune sortie, code de retour 1]

Le fichier de la racine est ignoré, celui de src/ ne l'est pas. Sans le / initial, les deux l'auraient été.

Le point d'exclamation réintègre un fichier qu'une règle précédente excluait. L'ordre compte : une exception doit venir après la règle qu'elle contredit, puisque c'est le dernier motif correspondant qui l'emporte.

Git refuse d'indexer un fichier ignoré, et le dit clairement :

Fenêtre de terminal
git add debug.log
The following paths are ignored by one of your .gitignore files:
debug.log
hint: Use -f if you really want to add them.

L'option -f passe outre. Elle se justifie pour un artefact qu'il faut exceptionnellement versionner, par exemple un fichier de build de référence servant de point de comparaison :

Fenêtre de terminal
git add -f debug.log
git status --short debug.log
A debug.log

Ce contournement crée précisément la situation décrite plus haut : le fichier devient suivi, et la règle qui l'exclut n'a plus prise sur lui. Préférez donc une négation explicite dans le .gitignore, qui reste lisible pour l'équipe, plutôt qu'un -f dont personne ne gardera la trace.

GitHub maintient une collection de modèles .gitignore par langage et par outil, sur github.com/github/gitignore. Partir de ces modèles évite d'oublier les fichiers propres à un écosystème, comme __pycache__/ en Python ou .terraform/ en Terraform.

Ces modèles restent un point de départ. Vérifiez toujours le résultat avec git status --ignored, car un modèle générique peut écarter un fichier que votre projet doit versionner.

Les symptômes se ressemblent tous, mais la cause diffère selon que le fichier est déjà suivi, qu'une négation le réintègre, ou que le motif ne correspond pas à ce que vous croyez. La colonne du milieu donne la commande qui tranche entre les trois.

SymptômeComment trancherSolution
Le fichier apparaît encore dans git statusgit ls-files <fichier> le retourneIl est suivi : git rm --cached <fichier>
check-ignore ne trouve aucune règle, pourtant elle existegit check-ignore -v --no-index <fichier> la montreLe fichier est suivi, même solution
check-ignore -v affiche une règle mais le fichier n'est pas ignoréLe motif affiché commence par !Une négation le réintègre, revoyez l'ordre des lignes
Une négation reste sans effetLa règle affichée est un dossier avec / finalRéintégrez d'abord le dossier parent
Une règle attrape trop de fichiersgit ls-files --others --ignored --exclude-standardAncrez le motif avec un / initial
git add refuse le fichierMessage paths are ignoredgit add -f, ou ajoutez une négation
La règle ne vient pas du .gitignore du projetLa sortie de check-ignore -v nomme le fichier sourceRegardez .git/info/exclude et core.excludesFile
  1. .gitignore ne filtre que les fichiers non suivis : un fichier déjà commité échappe à toute règle ajoutée après coup.
  2. git check-ignore -v <fichier> désigne la règle exacte, au format fichier:ligne:motif.
  3. Un motif affiché commençant par ! signifie que le fichier n'est PAS ignoré, malgré un code de retour 0.
  4. Sans -v, le code de retour est fiable : 0 pour ignoré, 1 pour conservé. C'est la forme à scripter.
  5. --no-index révèle la règle qui s'applique à un fichier suivi, et prouve que le motif est correct.
  6. git rm --cached arrête le suivi sans supprimer le fichier du disque, mais ne nettoie pas l'historique.
  7. git ls-files liste ce que Git suit réellement : le contrôle à faire avant de pousser.
  8. Trois sources de règles : .gitignore partagé, .git/info/exclude local, core.excludesFile global.

Les questions ci-dessous portent sur les situations où le comportement observé contredit ce que la règle laisse attendre. Chaque réponse indique la commande de vérification qui permet de trancher sur votre propre dépôt.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn