*.log, build/, !keep.log, **/tmp. The same handful of characters goes into a .gitignore, an rsync --exclude, a shell glob and a .dockerignore.
This implements all four from their own rules over one shared glob matcher, so the same pattern is read four ways and the answers sit side by side — and a difference in the table is a difference in the rules, not in four separate parsers.
Try any pattern: https://dev48.infy.uk/solve/day78-gitignore-glob-matcher.html
Not one pattern survives all four
10 patterns × 24 paths is an enumerated 240-cell grid. The four tools agree on 212 cells — 88.33%, which reads as reassuring until you notice zero of the ten patterns is read identically by all four on every path.
The disagreements are concentrated in the patterns people actually write.
The anchoring rule produces most of it
git treats a pattern with no slash as a basename pattern and matches it at any depth. Docker anchors everything at the context root.
pattern: *.log
git rsync shell docker
app.log ign ign ign ign
src/app.log ign ign kept kept
src/deep/app.log ign ign kept kept
Both are correct, documented behaviour. Neither file format announces which one it is.
| pair | cells that differ |
|---|---|
shell glob ↔ .dockerignore
|
3 |
| git ↔ rsync | 4 |
| git ↔ shell glob | 28 |
The intuition that "ignore syntax is ignore syntax" is right within a family — both root-anchored, or both basename-matching — and wrong across them.
The negation that does nothing, silently
This is the one that costs an afternoon:
test/ <- excludes the directory itself
!test/fixtures/keep.log <- never gets a chance to apply
The file stays ignored. git does not descend into an excluded directory, so the re-inclusion never runs. No error, no warning, nothing in git status to suggest the second line did nothing.
And the obvious repair does not work either — adding !test/fixtures/ changes nothing, because test itself is still excluded. The line that works is:
test/* <- exclude the CONTENTS, not the directory
!test/fixtures/
One character. Nothing in the file, the tool, or the output tells you which of the two you wrote.
70 verifier asserts, 21 in-page checks, 0 failures.
Top comments (0)