Tags: #git #ignore
Imagine you have the following tree structure:
.
├── cmd
│ └── fastly
├── fastly
You want to avoid commiting the fastly file in the root, but you’re OK with cmd/fastly being committed.
To achieve this we need to use a specific wildcard glob that at first glance appears unintuitive:
**/fastly
!cmd/fastly
What the first line does is match both ./fastly and ./cmd/fastly, while the second line allows you to negate the ./cmd/fastly.
Originally, the first line was set to fastly but it turns out if you do that, the second line will no longer work because the first line is matched anywhere in the path, and that means gitignore cannot negate files inside an an already ignored directory (which this would do, i.e. fastly isn’t ignoring the root fastly file, it’s ignoring anything that contains fastly).
The reason **/fastly didn’t immediately spring to mind for me is because I read it as matching any subdirectory containing fastly (e.g. it would match cmd/fastly), when in fact the **/ is misleading because it will match either ./ or <some-directory-name>/ and that’s why it works to match ./fastly and ./cmd/fastly and thus we can safely negate the second line of our gitignore, because we’ve not just blanket ignored every possible folder containing fastly, we have this time in fact constrained our match to include the root file.