threads / discuss / 28571

Git attributes ignored for root directory

Subject: Git attributes ignored for root directory

## tl;dr

13 messages between Oct 4, 2011 and Oct 13, 2011.

replies: 12people: 4as markdown or json

Gioele Barabucci· Oct 4, 2011, 18:52 UTC · lore
Hello,

I just updated to git v1.7.7 using the Ubuntu Lucid PPA and I found that `git check-attr` is broken now.

I have this attribute in my `$HOME/.gitattributes` file:
     /. show_in_prompt=no
Now, if I go to `$HOME` and run
     git check-attr show_in_prompt -- .
With git v1.7.6 this is the answer I got:
     .: show_in_prompt: no
With the newer v1.7.7 I get this, instead:
     .: show_in_prompt: unspecified

Also, if I use the `--all` option, `check-attr` does not show any attribute at all.

I see in the release notes of 1.7.7-rc1 that `check-attr` has been changed to allow relative paths to be specified. Maybe this error is related to that change.

Best,
-- 
Gioele Barabucci <gioele@svario.it>
Michael Haggerty· Oct 5, 2011, 12:05 UTC · re: Gioele Barabucci · lore

Re: Git attributes ignored for root directory

On 10/04/2011 08:52 PM, Gioele Barabucci wrote:
Show 25 quoted lines
> I just updated to git v1.7.7 using the Ubuntu Lucid PPA and I found that
> `git check-attr` is broken now.
> 
> I have this attribute in my `$HOME/.gitattributes` file:
> 
>     /. show_in_prompt=no
> 
> Now, if I go to `$HOME` and run
> 
>     git check-attr show_in_prompt -- .
> 
> With git v1.7.6 this is the answer I got:
> 
>     .: show_in_prompt: no
> 
> With the newer v1.7.7 I get this, instead:
> 
>     .: show_in_prompt: unspecified
> 
> Also, if I use the `--all` option, `check-attr` does not show any
> attribute at all.
> 
> I see in the release notes of 1.7.7-rc1 that `check-attr` has been
> changed to allow relative paths to be specified. Maybe this error is
> related to that change.
Indeed, your use case is broken by
f5114a40c0d0276ce6ff215a3dc51eb19da5b420

In fact the support for gitattributes using patterns involving "." was pretty spotty in v1.7.6 too. For example,

------------------------------------------- echo ". foo" >./.gitattributes git check-attr foo -- . ./ ./. x x/ ./x x/. .: foo: set ./: foo: unspecified WRONG ./.: foo: set x: foo: unspecified WRONG? x/: foo: unspecified WRONG? ./x: foo: unspecified WRONG? x/.: foo: set RIGHT?

------------------------------------------- echo "/. foo" >./.gitattributes git check-attr foo -- . ./ ./. x x/ ./x x/. .: foo: set ./: foo: unspecified WRONG ./.: foo: set x: foo: unspecified x/: foo: unspecified ./x: foo: unspecified x/.: foo: unspecified

------------------------------------------- echo ". foo" >x/.gitattributes git check-attr foo -- . ./ ./. x x/ ./x x/. .: foo: unspecified ./: foo: unspecified ./.: foo: unspecified x: foo: unspecified WRONG? x/: foo: unspecified WRONG? ./x: foo: unspecified WRONG? x/.: foo: set RIGHT?

------------------------------------------- echo "/. foo" >x/.gitattributes git check-attr foo -- . ./ ./. x x/ ./x x/. .: foo: unspecified ./: foo: unspecified ./.: foo: unspecified x: foo: unspecified WRONG x/: foo: unspecified WRONG ./x: foo: unspecified WRONG x/.: foo: set

-------------------------------------------

I conclude that this functionality was never really defined correctly, and you were pretty lucky that your case worked at all :-)

It's not to hard to fix your particular use case. But for a real fix, we would need to decide what is the correct behavior in all of the lines above marked "?"; specifically, should "." match every subdirectory under a given directory, does it match only the directory containing the .gitattributes file, or is this construct illegal?

Michael
-- 
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/
Gioele Barabucci· Oct 5, 2011, 14:47 UTC · re: Michael Haggerty · lore

Re: Git attributes ignored for root directory

On 05/10/2011 14:05, Michael Haggerty wrote:
Show 12 quoted lines
> On 10/04/2011 08:52 PM, Gioele Barabucci wrote:
>> With the newer v1.7.7 I get this, instead:
>>
>>      .: show_in_prompt: unspecified
>>
>> I see in the release notes of 1.7.7-rc1 that `check-attr` has been
>> changed to allow relative paths to be specified. Maybe this error is
>> related to that change.
>
> Indeed, your use case is broken by
>
> f5114a40c0d0276ce6ff215a3dc51eb19da5b420
Wow, debug-by-changelog :)
> In fact the support for gitattributes using patterns involving "." was
> pretty spotty in v1.7.6 too.  For example,
[...]
Show 5 quoted lines
> It's not to hard to fix your particular use case.  But for a real fix,
> we would need to decide what is the correct behavior in all of the lines
> above marked "?"; specifically, should "." match every subdirectory
> under a given directory, does it match only the directory containing the
> .gitattributes file, or is this construct illegal?
I do not know what the correct behavior should be, but here is my use case.

I use git to version almost all my $HOME dir. In addition to my usual files there are also separate project repositories under $HOME. I enjoy using a git-enabled prompt in those projects' dirs but not in my $HOME dir.

So I have this code somewhere in my `~/.bashrc`:
     local show_status="$(git check-attr show_in_prompt -- .)"
     local show_pattern='^\.: show_in_prompt: (.*)$'
     # add the following line to .gitattributes
     #
     #     /. show_in_prompt=no
     local show_in_prompt='yes'
     if [[ ${show_status} =~ ${show_pattern} ]]; then
            show_in_prompt="${BASH_REMATCH[1]}"
     fi
     if [ "${show_in_prompt}" == 'no' ]; then
             return
     fi

As you see in my the line of this code, I exploit the fact that "." refers to the root git dir, not to the current dir, to simplify the code. Otherwise I would had to discover what is the path of the current dir relative to its root git dir, something that I'd like to avoid as this code runs every time the prompt is shown.

This is just my personal use case. On the other hand, the first time I looked at check-attr I found it strange that paths were meant as relative to the root git dir ("." in "/foo" = "/") and not expanded from the current dir ("." in "/foo" = "/foo").

Bye,
-- 
Gioele Barabucci <gioele@svario.it>
Junio C Hamano· Oct 5, 2011, 17:38 UTC · re: Michael Haggerty · lore

Re: Git attributes ignored for root directory

Michael Haggerty <mhagger@alum.mit.edu> writes:
Show 9 quoted lines
> Indeed, your use case is broken by
>
> f5114a40c0d0276ce6ff215a3dc51eb19da5b420
>
> In fact the support for gitattributes using patterns involving "." was
> pretty spotty in v1.7.6 too.  For example,
> ...
> I conclude that this functionality was never really defined correctly,
> and you were pretty lucky that your case worked at all :-)

The attribute patterns (or exclude patterns for that matter) were never designed to name "the current directory". The way to name "everything *in* this directory" has always been to say "*" (the "* text=auto" example in the documentation says it shows how to set the attribute "for all files"). Admittedly the pattern may miss ".*" files.

I have to agree that things like "./" and "." were outside the scope of the design; in some cases undefined behaviour given to such patterns may have made sense but that was mere accident.

If we were to give some defined behaviour to these patterns, updating the "Pattern Format" section of Documentation/gitignore.txt is the first thing to do. The text currently reads like this:

PATTERN FORMAT --------------

 - A blank line matches no files, so it can serve as a separator
   for readability.
 - A line starting with # serves as a comment.
 - An optional prefix '!' which negates the pattern; any
   matching file excluded by a previous pattern will become
   included again.  If a negated pattern matches, this will
   override lower precedence patterns sources.
 - If the pattern ends with a slash, it is removed for the
   purpose of the following description, but it would only find
   a match with a directory.  In other words, `foo/` will match a
   directory `foo` and paths underneath it, but will not match a
   regular file or a symbolic link `foo` (this is consistent
   with the way how pathspec works in general in git).
 - If the pattern does not contain a slash '/', git treats it as
   a shell glob pattern and checks for a match against the
   pathname relative to the location of the `.gitignore` file
   (relative to the toplevel of the work tree if not from a
   `.gitignore` file).
 - Otherwise, git treats the pattern as a shell glob suitable
   for consumption by fnmatch(3) with the FNM_PATHNAME flag:
   wildcards in the pattern will not match a / in the pathname.
   For example, "Documentation/{asterisk}.html" matches
   "Documentation/git.html" but not "Documentation/ppc/ppc.html"
   or "tools/perf/Documentation/perf.html".
 - A leading slash matches the beginning of the pathname.
   For example, "/{asterisk}.c" matches "cat-file.c" but not
   "mozilla-sha1/sha1.c".

I think adding the following before the 5th rule ("If the pattern does not contain a slash") would be sufficient:

 - If the pattern is a single dot and nothing else, it matches everything
   in the current directory.

So "./" in .gitignore or .gitattributes at the toplevel would match all the top-level directories and files but does not apply to the paths contained in the matched directories. "." in .gitignore or .gitattributes at the toplevel would match everything under the sun.

Personally I do not think it is an improvement. You can certainly say "we have one less undefined case and are more consistent", but the downside of that consistency is that it is very confusing and error prone for the end users. Would it be sensible to assume that users would not be surprised if ". text=auto" meant that the attribute applies to every file in the worktree?

Gioele Barabucci· Oct 5, 2011, 17:56 UTC · re: Junio C Hamano · lore

Re: Git attributes ignored for root directory

On 05/10/2011 19:38, Junio C Hamano wrote:
Show 8 quoted lines
>> In fact the support for gitattributes using patterns involving "." was
>> pretty spotty in v1.7.6 too.  For example,
>
> The attribute patterns (or exclude patterns for that matter) were never
> designed to name "the current directory". The way to name "everything *in*
> this directory" has always been to say "*" (the "* text=auto" example in
> the documentation says it shows how to set the attribute "for all
> files"). Admittedly the pattern may miss ".*" files.

What if I do not want to say things about the "content" of the directory but about the directory itself? This is exactly my case.

> I have to agree that things like "./" and "."  were outside the scope of
> the design; in some cases undefined behaviour given to such patterns may
> have made sense but that was mere accident.
Actually what I have in my `~/.gitattributes` is
     /. show_in_prompt=no
Anyway, I see a conflict between
>   - A leading slash matches the beginning of the pathname.
>     For example, "/{asterisk}.c" matches "cat-file.c" but not
>     "mozilla-sha1/sha1.c".
and
>   - If the pattern is a single dot and nothing else, it matches everything
>     in the current directory.

in the first case `.` is treated as a "glob dot", while in the second case it is treated as a "regexp dot". I would find this confusing.

Patterns can match directories using `/foo`. Why don't you just say that `.` is equivalent to `./` and `/foo/.` is equivalent to `/foo`?

> So "./" in .gitignore or .gitattributes at the toplevel would match all
> the top-level directories and files but does not apply to the paths
> contained in the matched directories. "." in .gitignore or .gitattributes
> at the toplevel would match everything under the sun.

In the case of `.gitignore`, `/foo/.` and `/foo/` would have the same effect and they look sane to me.

> Would it be sensible to assume that users would not be surprised if
> ". text=auto" meant that the attribute applies to every file in the
> worktree?

I would be surprised as I expect `.` to be a "glob dot". But maybe it is just me and my prejudices :)

Bye,
-- 
Gioele Barabucci <gioele@svario.it>
Junio C Hamano· Oct 5, 2011, 18:35 UTC · re: Gioele Barabucci · lore

Re: Git attributes ignored for root directory

Gioele Barabucci <gioele@svario.it> writes:
Show 12 quoted lines
> On 05/10/2011 19:38, Junio C Hamano wrote:
>>> In fact the support for gitattributes using patterns involving "." was
>>> pretty spotty in v1.7.6 too.  For example,
>>
>> The attribute patterns (or exclude patterns for that matter) were never
>> designed to name "the current directory". The way to name "everything *in*
>> this directory" has always been to say "*" (the "* text=auto" example in
>> the documentation says it shows how to set the attribute "for all
>> files"). Admittedly the pattern may miss ".*" files.
>
> What if I do not want to say things about the "content" of the
> directory but about the directory itself? This is exactly my case.

Oh, that is totally different. We do not store directories, and they do not have attributes, period.

Gioele Barabucci· Oct 5, 2011, 20:17 UTC · re: Junio C Hamano · lore

Re: Git attributes ignored for root directory

On 05/10/2011 20:35, Junio C Hamano wrote:
Show 5 quoted lines
>> What if I do not want to say things about the "content" of the
>> directory but about the directory itself? This is exactly my case.
>
> Oh, that is totally different. We do not store directories, and they do
> not have attributes, period.

While that is true (yet many beg git to natively support empty dirs…), `.gitignore` does deal with directories. As you quoted,

 > If the pattern ends with a slash, it is removed for the purpose
 > of the following description, but it would only find a match with
 > a directory. In other words, foo/ will match a directory foo and
 > paths underneath it

Isn't applying the same logic to `.gitattributes` be the most straightforward solution? Also code-wise, I suppose.

Bye,
-- 
Gioele Barabucci <gioele@svario.it>
Junio C Hamano· Oct 5, 2011, 20:25 UTC · re: Gioele Barabucci · lore

Re: Git attributes ignored for root directory

Gioele Barabucci <gioele@svario.it> writes:
Show 6 quoted lines
> ...  As you quoted,
>
>> If the pattern ends with a slash, it is removed for the purpose
>> of the following description, but it would only find a match with
>> a directory. In other words, foo/ will match a directory foo and
>> paths underneath it

But the "will match a directory foo and" part in that description, while makes it easier to read, is technically unnecessary and even misleading.

The ignore patterns ultimately decides which paths are not to be added to the index. Colloquially we could say "foo directory is ignored", but such a statement is just a short-hand for "everything in foo is ignored"; technically "foo directory is ignored" is not necessary because we never add the directory itself to the index.

Michael Haggerty· Oct 12, 2011, 22:35 UTC · re: Junio C Hamano · lore

Re: Git attributes ignored for root directory

On 10/05/2011 07:38 PM, Junio C Hamano wrote:
>  - If the pattern is a single dot and nothing else, it matches everything
>    in the current directory.

This disagrees with shell usage, where "." represents a directory itself, not the files within a directory. By the trailing slash rule that you quoted, "./" should also represent the containing directory.

Given that git currently tries to ignore directories and only think about files, the consistent thing to do would be to declare "." and "./" as undefined. Because someday git *may* want to get a bit smarter about directories, and at that time it would be a shame not to have "." and/or "./" available to represent the containing directory. (But implementing it will require some special-casing within the attr module, which is currently pretty stupid.)

Michael
-- 
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/
Junio C Hamano· Oct 12, 2011, 23:12 UTC · re: Michael Haggerty · lore

Re: Git attributes ignored for root directory

Michael Haggerty <mhagger@alum.mit.edu> writes:
Show 6 quoted lines
> On 10/05/2011 07:38 PM, Junio C Hamano wrote:
>>  - If the pattern is a single dot and nothing else, it matches everything
>>    in the current directory.
>
> This disagrees with shell usage, where "." represents a directory
> itself, not the files within a directory.
Either you misread me, or what I wrote was fuzzy, or perhaps both.

The suggested update to the list of rules very much wants a '.' to mean the directory itself. The problem I was solving, which turned out to be something different from the original issue in the thread was this.

Suppose you have a directory "foo" and want to say "I want to ignore everything in that directory". You would say "foo/" in .gitignore in the higher level and you are happy.

How would you say the same thing if the directory to be ignored weren't "foo" but at the top-level of the working tree? There is no such level higher than the top-level where you can say "<the name of your project>/" in its .gitignore file.

The best you could do is to say "./" in the .gitignore file at the top-level directory, and the update rule you quoted is specifically designed to address it.

Of course, you could list both ".*" and "*" in the .gitignore file at the top-level directory for the same effect, but that works only because you do not have to give values to the entry in .gitignore mechanism. It would be cumbersome to duplicate two entries in .gitattributes file like that as a workaround.

Gioele Barabucci· Oct 13, 2011, 10:49 UTC · re: Junio C Hamano · lore

Re: Git attributes ignored for root directory

On 13/10/2011 00:12, Junio C Hamano wrote:
Show 8 quoted lines
> Suppose you have a directory "foo" and want to say "I want to ignore
> everything in that directory". You would say "foo/" in .gitignore in the
> higher level and you are happy.
>
> How would you say the same thing if the directory to be ignored weren't
> "foo" but at the top-level of the working tree? There is no such level
> higher than the top-level where you can say "<the name of your project>/"
> in its .gitignore file.
Shouldn't `/.` or `/./` work?

I see that `/*/` in `.gitignores` successfully ignores all the non-hidden directories in the root project directory. Another accidental success? :)

-- 
Gioele Barabucci <gioele@svario.it>
Johannes Sixt· Oct 13, 2011, 13:16 UTC · re: Gioele Barabucci · lore

Re: Git attributes ignored for root directory

Am 10/13/2011 12:49, schrieb Gioele Barabucci:
> I see that `/*/` in `.gitignores` successfully ignores all the non-hidden
> directories in the root project directory. Another accidental success? :)

No, that's by design. The first slash means "apply only in this directory, not any subdirectories", and the slash at the end means "match only if the name is a directory".

-- Hannes
Junio C Hamano· Oct 13, 2011, 17:38 UTC · re: Gioele Barabucci · lore

Re: Git attributes ignored for root directory

Gioele Barabucci <gioele@svario.it> writes:
Show 12 quoted lines
> On 13/10/2011 00:12, Junio C Hamano wrote:
> ...
>> How would you say the same thing if the directory to be ignored weren't
>> "foo" but at the top-level of the working tree? There is no such level
>> higher than the top-level where you can say "<the name of your project>/"
>> in its .gitignore file.
>
> Shouldn't `/.` or `/./` work?
>
> I see that `/*/` in `.gitignores` successfully ignores all the
> non-hidden directories in the root project directory. Another
> accidental success? :)

Hannes correctly explained how /*/ works already; armed with that knowledge, we can understand that:

        /.      would mean "what matches dot only in this directory."
        /./     would mean "what matches dot only in this directory
                but the thing that matches must be a directory."
        ./      would mean "what matches dot in this directory and its
                subdirectories, but the thing that matches must be a
                directory."

Given that "." does _not_ match the directory that has the .gitignore or the .gitattribute file with the current system, none of the above patterns can be used to match everything in the top level directory in a way similar to how you can say "foo/" to match everything in "foo" directory from the top-level directory.

The answer to your question is no, it shouldn't work.

Without adding a rule to the "Pattern Format" section as I suggested in my message that Michael quoted in his question, that is.

← back to recent threads