gitignore negation patterns are not honored for directories: * + !*/ ignores the entire repo

Author: cryo2010Created Jul 25, 2026Updated Jul 25, 2026

Summary

ag does not correctly handle the common .gitignore idiom for ignoring extensionless files (POSIX binaries):

.gitignore

*
!*.*
!*/

Git interprets this as "ignore everything, then un-ignore anything with a dot and all directories," so only extensionless files are ignored. ag applies the * pattern to directories before considering the !*/ negation, so every directory is treated as ignored and their contents are never searched. In practice ag returns results only from files with a dot in the repo root and silently skips the rest of the repository.

Steps to reproduce

bash
mkdir agtest && cd agtest
printf '*\n!*.*\n!*/\n' > .gitignore
echo 'needle in text'   > readme.txt
echo 'needle in binary' > mybinary
mkdir src
echo 'needle in source' > src/main.c

ag needle

Expected behavior

Matches git's interpretation (verify with git init -q . && git status --porcelain --ignored, which marks only mybinary as ignored):

bash
readme.txt:1:needle in text
src/main.c:1:needle in source

Actual behavior

bash
readme.txt:1:needle in text

src/main.c is never searched because the src directory is considered ignored. In a real repo this means almost all files are skipped.

Source: ggreer/the_silver_searcher