Skip to content

Honor gitignore negation patterns for directories - #1564

Open
cryo2010 wants to merge 1 commit into
ggreer:masterfrom
cryo2010:fix/1563-gitignore-negation-directories
Open

Honor gitignore negation patterns for directories#1564
cryo2010 wants to merge 1 commit into
ggreer:masterfrom
cryo2010:fix/1563-gitignore-negation-directories

Conversation

@cryo2010

Copy link
Copy Markdown

Fixes #1563

Problem

The common .gitignore idiom for ignoring extensionless files (POSIX binaries):

*
!*.*
!*/

caused ag to skip essentially the entire repo. Git interprets it as "ignore everything, then un-ignore anything with a dot and all directories," but ag matched directories against ignore patterns by plain name first, so * ignored them before the trailing-slash form that !*/ can match was ever consulted. Negation matches also could not take precedence: path_ignore_search returned the same 0 for "invert pattern matched" and "nothing matched."

Fix

  • path_ignore_search now returns a tri-state: 1 (ignored), -1 (explicitly un-ignored by an invert pattern), 0 (no match). Invert patterns are checked before the other pattern classes at the same level, and the ackmate filter result is normalized to 0/1 so it does not collide with the new -1.
  • filename_filter evaluates a directory's plain and trailing-slash forms together, so an invert match on either form wins. An explicit un-ignore stops the walk up the parent ignore chain, matching git's deepest-match precedence.

Testing

  • New cram test tests/ignore_invert_dir.t covering the idiom above; it fails on master and passes with this change.
  • Full test suite passes (44 tests, 1 skipped).
  • Manually verified against git status --porcelain --ignored on a test repo with nested directories and extensionless files at multiple depths: ag's results now match git's ignore semantics exactly.

The gitignore idiom for ignoring extensionless files:

    *
    !*.*
    !*/

caused ag to skip the entire repo. Directories were matched against
ignore patterns by plain name first, so * ignored them before the
trailing-slash form that !*/ can match was ever consulted.

Make path_ignore_search return a tri-state: 1 (ignored), -1 (explicitly
un-ignored by an invert pattern), 0 (no match). Invert patterns are now
checked before all other pattern classes at the same level, and an
explicit un-ignore stops the walk up the parent ignore chain, matching
git's deepest-match precedence. filename_filter evaluates a directory's
plain and trailing-slash forms together, letting an invert match on
either form win.

Fixes ggreer#1563
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant