DEV Community

Devanshu Biswas
Devanshu Biswas

Posted on

Zero of Ten Ignore Patterns Mean the Same Thing in git, rsync, a Shell Glob and Docker

*.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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode

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)