karan / joe

:running: A .gitignore magician in your command line
http://karan.github.io/joe/
MIT License
2.88k stars 210 forks source link

github/gitignore files are not composable #63

Closed DavidJFelix closed 6 years ago

DavidJFelix commented 8 years ago

So I've had some issues with tools like this in the past, namely gitignore.io. They all source from github's repository of gitignores.

Here's the issue. The rules contained within a gitignore are not communative, they're read in an overwrite (final rule wins) fashion. So if you have a project that uses multiple technologies, the order of lines in a gitignore declaration is often important. Here's an example:

If you use java.gitignore then gradle.gitignore You'll have the following order of rules:

...
*.jar
...
!gradle-wrapper.jar
...

This is the correct way to declare it. You have a general rule and you have very acute exceptions after it. Gradle wants to include gradle-wrapper.jar, java wants to exclude the average jar. The problem arises when you use the gitignores in the opposite order. If you use gradle.gitignore then java.gitignore your rules will be ordered as such:

...
!gradle-wrapper.jar
...
*.jar
...

which means that all jars will be ignored, including gradle-wrapper.jar, despite the fact that you called it out to not be ignored.

So joe java gradle and joe gradle java are not the same command.

But, back to the key of this issue. github gitignores repo is not designed in a way to check that rules work together. Each file is its own standalone entity and if you're combining them, in-depth work needs to be taken to ensure your rules are correct - right now this is a manual process. I'd be exceptionally impressed if gitignores were tested in every possible combination. The issue is that any tool wanting to combine them needs to consider the actual values of each line in order to properly compose them, which may be difficult.

In the example above, there was a correct order... it might be easy to say "well just get the order right". But suppose there isn't a correct order. Say we have foo.gitignore which says:

lib/
!/bin/utility

and we have bar.gitignore which says:

bin/
!/lib/include/

Most people reading these two files could understand that the correct solution is to merge the two and probably do something like this:

bin/
lib/
!/bin/utility
!/lib/include

But simply composing the files by placing one after another will result in incorrect behavior however you do it. The other issue is that while I said that this is the correct way to compose them, can you really know that without knowing what the files are? I can promise you there are edge cases where this isn't the right way, despite it being the most reasonable assumption from the given problem.

awarrenlove commented 8 years ago

Wouldn't the way to merge these rules always be from most general to most specific? Effectively this means the rules are ordered by ascending directory depth, with directories at depth n immediately preceding files at depth n.