Priorité des règles gitignore et motifs de négation (!)
Pourquoi la dernière règle l'emporte, la priorité entre .gitignore, info/exclude et la configuration globale, et pourquoi ! ne peut pas réinclure un fichier quand son répertoire parent est exclu.
Quand une règle gitignore ne se comporte pas comme prévu, la cause tient presque toujours à l'ordre et au répertoire parent. Cet article résume quelle règle git suit lorsque plusieurs s'appliquent.
Dans un même fichier : la dernière règle correspondante l'emporte
Dans un .gitignore, git lit de haut en bas et c'est le dernier motif correspondant qui décide. Si ce motif commence par !, le fichier n'est pas ignoré ; sinon, il l'est.
*.log
!important.log
important.log correspond aux deux lignes, mais la dernière est une négation : il est donc suivi. Inversez l'ordre et le résultat s'inverse aussi.
!important.log
*.log
La dernière correspondance de important.log est maintenant *.log : il est ignoré. C'est pourquoi, quand vous combinez plusieurs modèles dans le générateur, l'ordre de sélection devient l'ordre des règles. Par exemple, si vous utilisez *.jar du modèle Java avec !gradle-wrapper.jar du modèle Gradle, Gradle doit venir après.
Priorité entre plusieurs fichiers
git lit des règles à quatre endroits. Plus une source est haut dans la liste, plus sa priorité est élevée.
- Motifs passés en ligne de commande (certaines commandes comme
git ls-files --exclude) .gitignoredans le même répertoire que le chemin ou dans un répertoire parent — les fichiers plus profonds priment sur ceux du dessus$GIT_DIR/info/exclude(généralement.git/info/exclude)- Le fichier désigné par le réglage
core.excludesFile(gitignore global)
Par exemple, si le .gitignore racine contient *.tmp et sub/.gitignore contient !*.tmp, sub/y.tmp est suivi grâce à la négation du fichier plus profond. En revanche, écrire !x dans .git/info/exclude ne sert à rien : le x du .gitignore est prioritaire et x reste ignoré.
$ git check-ignore -v x y.tmp sub/y.tmp
.gitignore:1:x x
.gitignore:2:*.tmp y.tmp
sub/.gitignore:1:!*.tmp sub/y.tmp
L'exception la plus importante : parent exclu, réinclusion impossible
La documentation de git le dit ainsi : il n'est pas possible de réinclure un fichier si l'un de ses répertoires parents est exclu. Pour des raisons de performance, git n'entre même pas dans un répertoire exclu, si bien que les règles ! visant des fichiers à l'intérieur ne sont jamais lues.
logs/
!logs/keep.txt
Avec ces règles, logs/keep.txt reste ignoré. git check-ignore -v affiche logs/ comme règle décisive.
La solution consiste à exclure le contenu du répertoire plutôt que le répertoire.
logs/*
!logs/keep.txt
logs/* ne correspond pas au répertoire logs lui-même : git y entre donc et applique la négation à keep.txt. Le /log/* + !/log/.keep du modèle Rails et le .vscode/* + !.vscode/settings.json du modèle VS Code reposent sur le même principe.
Pour réinclure un chemin plus profond, il faut réinclure chaque répertoire intermédiaire.
config/*
!config/app/
config/app/*
!config/app/defaults.yml
Motif de liste blanche (allowlist)
Le même principe s'applique quand vous voulez lister seulement ce qu'il faut suivre plutôt que ce qu'il faut ignorer.
# ignorer tout à la racine
/*
# puis réinclure le nécessaire
!/.gitignore
!/src/
!/README.md
/* correspond à chaque élément de la racine sans exclure la racine elle-même, donc !/src/ fonctionne. Dans ce schéma, le .gitignore lui-même tombe aussi sous /* : n'oubliez pas !/.gitignore. D'ailleurs, sans cette ligne, git status --ignored fait apparaître .gitignore parmi les éléments ignorés.
Règles en double et ordre
Si une même règle apparaît plusieurs fois, les occurrences précédentes n'influent pas sur le résultat, car la même règle plus bas correspond toujours plus tard. En revanche, supprimer un doublon situé plus bas peut changer le résultat s'il y a une négation entre les deux.
*.log
!debug.log
*.log
Ici, supprimer le dernier *.log fait passer debug.log à l'état suivi. Le générateur de ce site détecte ce cas : il ne supprime les doublons situés plus bas que s'il n'y a aucune règle de négation entre eux, et conserve les autres.
Références
- Documentation officielle de gitignore : PATTERN FORMAT, NOTES
- Documentation officielle de git-check-ignore
- Vérifié le : 2026-09-23 (exemples contrôlés avec git 2.50.1)