Langue:Français
OUTIL DEV

Gitignore Debugger

Découvrez exactement pourquoi Git n'ignore pas votre fichier.

Collez un chemin de fichier et vos règles .gitignore. Nous vous montrons quelle règle correspond, et pourquoi.

Tout s'exécute dans votre navigateur. Vos fichiers ne sont jamais envoyés.

Qu'est-ce qu'un fichier .gitignore ?

Un fichier .gitignore est un fichier texte qui indique à Git quels fichiers laisser hors du contrôle de version. Chaque ligne est un motif — *.log, node_modules/, .env — et tout chemin non suivi correspondant à un motif disparaît de git status, est sauté par git add . et n'est jamais commité.

Le mot non suivi porte l'essentiel du sens de cette phrase, et il explique à lui seul plus de cas de gitignore qui ne fonctionne pas que tous les bugs de motif réunis. Git ne consulte .gitignore que pour les fichiers qu'il ne suit pas déjà. Dès qu'un fichier a été commité, Git continue de le suivre indéfiniment, quoi que vous ajoutiez ensuite à .gitignore.

Ce que fait le Gitignore Debugger

Collez un chemin de fichier et le contenu de votre .gitignore : ce débogueur .gitignore rend le même verdict que Git — ignoré ou non ignoré — accompagné de la règle précise et du numéro de ligne responsables. Il liste ensuite toutes les règles qui correspondent au chemin, dans l'ordre où Git les évalue, et signale celle qui a réellement tranché.

C'est cette dernière partie qu'un simple vérificateur de gitignore laisse de côté. Savoir qu'un fichier est ignoré est rarement le plus difficile. Savoir laquelle de vos quarante règles l'a fait — et pourquoi celle que vous attendiez a perdu — l'est. Cela fonctionne dans les deux sens : pourquoi Git ignore votre fichier alors que vous voulez le commiter, et pourquoi il n'ignore pas celui dont vous voulez vous débarrasser.

Le moteur réimplémente les règles de motif de Git : motifs par nom de base ou ancrés, * qui ne franchit jamais un /, les trois formes de **, les suffixes / réservés aux répertoires, les classes de caractères, les espaces finaux échappés. Son comportement est vérifié contre la sortie réelle de git check-ignore, pas supposé.

Comment l'utiliser

  1. Saisissez le chemin tel qu'il apparaît dans votre dépôt, relatif à la racine — src/config/local.json, pas C:\projects\app\src\config\local.json. Utilisez des barres obliques ; les antislashs Windows sont convertis pour vous.
  2. Collez tout votre .gitignore. Ne le réduisez pas à la seule règle que vous suspectez — la préséance entre les règles est généralement le vrai bug, et couper le fichier jette cette information.
  3. Lisez le verdict, puis la chaîne de règles en dessous. C'est là qu'une règle gitignore qui ne fonctionne pas cesse d'être un mystère.

Pour tester des règles gitignore sur un répertoire plutôt que sur un fichier, terminez le chemin par une barre oblique — build/. La distinction compte, car une règle terminée par / ne correspond qu'à des répertoires.

Pourquoi les règles gitignore ne fonctionnent parfois pas

À peu près dans l'ordre de fréquence des coupables :

Préséance des règles gitignore : la dernière correspondance gagne

C'est celle qui surprend. Au sein d'un même .gitignore, c'est le dernier motif qui correspond à un chemin qui décide de son sort — pas le premier. Ces deux fichiers contiennent des règles identiques et donnent des résultats opposés pour important.log :

*.log
!important.log        → important.log est versionné
!important.log
*.log                 → important.log est ignoré

Placez donc les règles larges d'abord et les exceptions ensuite. D'un fichier à l'autre, un .gitignore situé dans un sous-répertoire l'emporte sur un autre plus haut pour les chemins situés en dessous. Git lit aussi .git/info/exclude, propre au dépôt et jamais commité, ainsi que votre core.excludesFile global. Une règle introuvable dans le moindre .gitignore se cache souvent dans l'un de ces deux endroits — git check-ignore -v affiche le fichier et la ligne qui ont tranché.

Les règles de négation, et pourquoi ! échoue souvent

Préfixer un motif par ! réinclut ce qu'une règle antérieure avait ignoré. Cela a deux limites, et la seconde explique la quasi-totalité des cas de négation gitignore qui ne fonctionne pas.

D'abord, quelque chose en amont doit avoir ignoré le chemin. !important.log tout seul ne fait rien, parce qu'il n'y a jamais rien eu à écraser.

Ensuite, et c'est bien plus surprenant : vous ne pouvez pas réinclure un fichier situé dans un répertoire ignoré. Ceci ne fonctionne pas, et aucun réordonnancement n'y changera quoi que ce soit :

build/
!build/keep.txt

Quand build/ est ignoré, Git n'y descend jamais. Il n'examine pas build/keep.txt, il n'atteint donc jamais la ligne 2. Ignorez plutôt le contenu du répertoire, ce qui laisse le répertoire lui-même parcourable :

build/*
!build/keep.txt

Pour sauver quelque chose de plus profond, chaque répertoire intermédiaire doit lui aussi rester accessible — build/*, puis !build/assets/, puis !build/assets/logo.svg.

Répertoires parents ignorés

Le parcours de répertoires de Git s'arrête au premier répertoire ignoré qu'il rencontre, et tout ce qui se trouve en dessous hérite du verdict sans être examiné. C'est pourquoi un parent ignoré l'emporte sur n'importe quelle règle écrite pour le fichier lui-même, aussi précise qu'elle paraisse.

Dans ce cas, le débogueur nomme le parent qui a bloqué le parcours au lieu de dire simplement que le fichier est ignoré, et il affiche tout de même les règles de négation que vous avez écrites pour le fichier — marquées comme inatteignables, parce que Git n'est jamais allé assez loin pour les considérer. Corrigez d'abord le répertoire et les règles en dessous se remettent à fonctionner d'elles-mêmes.

Erreurs .gitignore courantes

Quelques exemples concrets

Le chemin src/logs/debug.log face à ces règles n'est pas ignoré. La négation est la dernière correspondance et aucun répertoire parent ne bloque le parcours : elle est donc atteinte et elle gagne :

*.log
!src/logs/debug.log

Le chemin build/keep.txt face à ces règles est ignoré, en raison de build/ à la ligne 1 qui correspond au répertoire parent. La ligne 2 ne se déclenche jamais :

build/
!build/keep.txt

Le chemin docs/api/notes.md face à cette règle n'est pas ignoré, parce que le motif est ancré par sa barre oblique et que * ne franchira pas celle de api/notes.md. C'est docs/**/*.md qui était voulu :

docs/*.md

Collez n'importe lequel de ces exemples dans le testeur gitignore ci-dessus pour voir la chaîne de règles complète. De retour dans un terminal, git check-ignore -v path/to/file est l'équivalent intégré — il nomme le fichier source, le numéro de ligne et le motif qui ont tranché, et cela vaut la peine de le connaître.

Questions fréquentes

Pourquoi Git ignore-t-il mon fichier ?

Un motif y correspond, et ce n'est souvent pas celui que vous regardez. Les coupables habituels sont un .gitignore dans un sous-répertoire, un répertoire parent ignoré, ou votre fichier d'exclusion global. Exécutez git check-ignore -v path/to/file : il affiche exactement le fichier source, le numéro de ligne et le motif qui ont tranché. Coller le chemin et les règles dans le débogueur ci-dessus montre la même chose, plus les règles qui correspondaient et ont perdu.

Pourquoi ma règle .gitignore ne fonctionne-t-elle pas ?

Quatre causes couvrent presque tous les cas, à peu près par ordre de fréquence : le fichier est déjà suivi, la règle est donc entièrement sautée ; une règle ultérieure l'a écrasée, parce que la dernière correspondance gagne ; un répertoire parent est ignoré, Git n'a donc jamais atteint la règle ; ou le motif est ancré autrement que vous ne le pensiez — une barre oblique ailleurs qu'à la fin ancre un motif au répertoire qui contient le .gitignore.

Pourquoi ! ne réinclut-il pas mon fichier ?

Soit rien en amont n'avait ignoré le chemin, et la négation n'avait donc rien à écraser, soit — bien plus probablement — le fichier se trouve dans un répertoire ignoré. Git ne descend pas dans les répertoires ignorés : il ne voit donc jamais le fichier et n'évalue jamais votre règle !.

Ignorez le contenu du répertoire plutôt que le répertoire lui-même : remplacez build/ par build/*, gardez !build/keep.txt après, et la négation est atteinte.

Est-ce la dernière règle .gitignore qui gagne ?

Oui. Au sein d'un fichier, c'est le dernier motif qui correspond à un chemin qui décide de son sort — pas le premier, ni le plus spécifique. *.log suivi de !important.log conserve important.log ; inversez ces deux lignes et il est ignoré. Placez les règles larges d'abord et les exceptions ensuite.

Pourquoi un dossier ignoré empêche-t-il une règle de négation de fonctionner ?

Parce que le parcours de répertoires de Git s'arrête au premier répertoire ignoré. Quand build/ correspond, Git marque tout le sous-arbre comme ignoré sans lister ce qu'il contient : !build/keep.txt n'est donc pas écrasé, il n'est simplement jamais atteint. Réordonner n'y change rien ; seul le fait de rendre le répertoire à nouveau parcourable y change quelque chose, et c'est ce que fait build/*.

Comment tester une règle .gitignore ?

Collez le chemin du fichier et vos règles dans le débogueur en haut de cette page. Il donne le verdict, la règle et la ligne décisives, et toutes les règles qui correspondaient en chemin — y compris les négations qui ne pouvaient jamais prendre effet.

Sur un vrai dépôt, git check-ignore -v path/to/file nomme le fichier source, la ligne et le motif responsables, et git status --ignored liste tout ce qui est actuellement ignoré.

.gitignore agit-il sur les fichiers déjà suivis ?

Non. .gitignore ne s'applique qu'aux chemins non suivis. Dès qu'un fichier a été commité, Git continue de le suivre et la règle est sautée — c'est la raison la plus fréquente pour laquelle une règle parfaitement correcte semble ne rien faire. Pour cesser de suivre un fichier sans le supprimer, exécutez git rm --cached path/to/file et commitez ce changement.

Un point qui égare souvent : git check-ignore signalera tout de même une correspondance pour un fichier suivi, parce qu'il teste les motifs sans consulter l'index. Un « oui, ignoré » de cette commande ne signifie pas que Git a cessé de suivre le fichier.

Les règles .gitignore peuvent-elles contenir des espaces ?

Oui, au milieu. my logs/ correspond à un répertoire dont le nom contient une espace, sans aucun échappement. Les espaces finaux sont une autre affaire : Git les supprime, donc *.log suivi d'une espace se comporte exactement comme *.log. Pour correspondre à un nom de fichier qui se termine réellement par une espace, échappez-la — foo\ .

Les espaces en début de ligne sont significatives et ne sont jamais supprimées : une règle indentée par accident ne correspond donc qu'aux chemins qui commencent par cette espace. Si une règle semble inerte sans raison, vérifiez qu'il n'y a pas d'indentation parasite.

Où Git cherche-t-il des règles d'exclusion en dehors de .gitignore ?

À trois autres endroits, consultés dans cet ordre de préséance : les fichiers .gitignore eux-mêmes, le répertoire le plus profond l'emportant ; puis .git/info/exclude, propre au dépôt et jamais commité ; puis ce que désigne core.excludesFile, votre liste d'exclusion globale.

Une règle introuvable où que ce soit dans le dépôt est donc généralement dans l'un des deux derniers. git config --get core.excludesFile révèle le chemin global, et git check-ignore -v nomme le fichier qui a réellement tranché.

Quelle est la différence entre * et ** ?

* correspond à n'importe quelle suite de caractères sauf / : il ne quitte donc jamais un segment de chemin unique. src/*/test.js ne descend que d'un niveau.

** franchit les séparateurs, mais seulement dans les trois positions que Git reconnaît — un **/ en tête pour n'importe quelle profondeur, un /** en fin pour tout ce qui se trouve dans un répertoire, et /**/ au milieu pour zéro répertoire ou plus. Ailleurs, comme dans a**b, les astérisques supplémentaires se comportent comme un simple *.