Search code examples
gitgitattributes

GitAttributes -[attribute]=[value]: why apply "-" and assign a value?


I understand most of the gitattributes options, after reading up on them over the past couple days. However, there's one configuration type in the gitattributes to solve all your problems GitHub gist (GistHub?) that I can't quite figure out. A couple of lines in the 3rd set of attributes have something like

*.vb -text=auto

I understand most of the parts of this line by themselves, but together I'm not sure what it means. The *.vb is saying "use this setting for files with a .vb extension". Meanwhile, the -text means "unset the text attribute, or set it to false, for files with the extension .vb" and the =auto means "set the attribute -text to the value auto for files with the .vb extension".

This is where my confusion lies: how can you unset something at the same time that you set it? How can you set something to two values (here, false and auto) at the same time? Is this some secret ninja method to supercharge your gitattributes?


Solution

  • This is the bit of git source code that actually parses attribute lines:

                if (*cp == '-' || *cp == '!') {
                        e->setto = (*cp == '-') ? ATTR__FALSE : ATTR__UNSET;
                        cp++;
                        len--;
                }
                else if (!equals)
                        e->setto = ATTR__TRUE;
                else {
                        e->setto = xmemdupz(equals + 1, ep - equals - 1);
                }
                e->attr = git_attr_internal(cp, len);
    

    (from attr.c in git 2.1.0). In this case, *cp is the character at the start of the attribute, e.g., the - in -text or the t in text; equals is the position of the = character, if any; and e is the internal data structure being set up.

    What this means is that:

    -text=anything
    

    "means" the same thing as just plain -text, because the test on *cp occurs before (and then excludes entirely) the test for =. Similarly, !text=foo just "means" !text: everything after the = winds up quietly ignored.

    It seems unwise to depend on this behavior, and probably git should emit a warning. But the answer is (apparently) that this is just really -text.