threads / discuss / 38481

Relative paths don't work in .gitignore as would be expected.

Subject: Relative paths don't work in .gitignore as would be expected.

## tl;dr

5 messages between Feb 1, 2015 and Feb 3, 2015.

replies: 4people: 3as markdown or json

/#!/JoePea· Feb 1, 2015, 22:51 UTC · lore
I have this in my .gitignore:
  ./*.js

I would expect that to cause git to ignore .js files in the same folder as .gitignore, but it doesn't do anything. However, this works:

  /*.js

I'm not sure what this actually means because a leading slash is the root of some filesystem, and we're not in the root, nor do gitignore files always exist in the root of a git repo. Being able to have

  ./*.js
in .gitignore would make much sense.
/#!/JoePea
Stefan Beller· Feb 2, 2015, 05:57 UTC · re: /#!/JoePea · lore

Re: Relative paths don't work in .gitignore as would be expected.

On 01.02.2015 14:51, /#!/JoePea wrote:
Show 11 quoted lines
> I have this in my .gitignore:
> 
>   ./*.js
> 
> I would expect that to cause git to ignore .js files in the same
> folder as .gitignore, but it doesn't do anything. However, this works:
> 
>   /*.js
> 
> I'm not sure what this actually means because a leading slash is the
> root of some filesystem, 

That's true, though you'd never (barely?) git version control an entire file system?

A trailing "/**" matches everything inside. For example, "abc/**" matches all files inside directory "abc", relative to the location of the .gitignore file, with infinite depth. (from man gitignore, though reading that and not finding a './' it may need improvement

Junio C Hamano· Feb 2, 2015, 19:15 UTC · re: Stefan Beller · lore

Re: Relative paths don't work in .gitignore as would be expected.

Stefan Beller <stefanbeller@gmail.com> writes:
Show 12 quoted lines
> On 01.02.2015 14:51, /#!/JoePea wrote:
>> I have this in my .gitignore:
>> 
>>   ./*.js
>> 
>> I would expect that to cause git to ignore .js files in the same
>> folder as .gitignore, but it doesn't do anything. However, this works:
>> 
>>   /*.js
>> 
>> I'm not sure what this actually means because a leading slash is the
>> root of some filesystem, 
Isn't gitignore(5) documentation reasonably clear?
 - 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).
 - A leading slash matches the beginning of the pathname. For
   example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
> That's true, though you'd never (barely?) git version control an entire
> file system?

When you have the entire file system under /.git, "/var/" still would be the right way to spell a pattern to match only a directory (because of the trailing '/') whose name matches 'var' and lives in the root level of the filesystem (because of the leading '/' anchors the pattern to the same level as the file the pattern appears in, i.e. /.gitignore) and no other place.

> (from man gitignore, though reading that and not finding a './' it may
> need improvement
We do not allow relative pathname traversal with "." or "..", do we?

I would be very hesitant to special case "./*.js" to mean "*.js files in the same directory as .gitignore appears", as I think it risks intelligent readers to infer "../foo/*.js" or "../*.js" would take effect, when placed in "bar/.gitignore". A design that spreads an incorrect assumption/expectation is not a good one, I would have to say.

Stefan Beller· Feb 3, 2015, 02:18 UTC · re: Junio C Hamano · lore

Re: Relative paths don't work in .gitignore as would be expected.

2015-02-02 11:15 GMT-08:00 Junio C Hamano <gitster@pobox.com>:
Show 41 quoted lines
> Stefan Beller <stefanbeller@gmail.com> writes:
>
>> On 01.02.2015 14:51, /#!/JoePea wrote:
>>> I have this in my .gitignore:
>>>
>>>   ./*.js
>>>
>>> I would expect that to cause git to ignore .js files in the same
>>> folder as .gitignore, but it doesn't do anything. However, this works:
>>>
>>>   /*.js
>>>
>>> I'm not sure what this actually means because a leading slash is the
>>> root of some filesystem,
>
> Isn't gitignore(5) documentation reasonably clear?
>
>  - 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).
>
>  - A leading slash matches the beginning of the pathname. For
>    example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
>
>> That's true, though you'd never (barely?) git version control an entire
>> file system?
>
> When you have the entire file system under /.git, "/var/" still
> would be the right way to spell a pattern to match only a directory
> (because of the trailing '/') whose name matches 'var' and lives in
> the root level of the filesystem (because of the leading '/' anchors
> the pattern to the same level as the file the pattern appears in,
> i.e. /.gitignore) and no other place.

Ok, that's true. So when I started diving into the wonderful world of unix like operating system, one of the first things I was taught is "/" starts an absolute path, while "./foo" or just "foo" starts a relative path. And this stuck with me. Now I realize git treats the repository root literally as the root and hence absolute paths starting with "/" make totally sense inside git as the world stops for git outside its work directory.

Show 5 quoted lines
>
>> (from man gitignore, though reading that and not finding a './' it may
>> need improvement
>
> We do not allow relative pathname traversal with "." or "..", do we?

Because we don't have to. It's always relative to the .gitignore file (foo/.gitignore can talk about bar/ and still mean foo/bar), so we don't need to express the relativity in any special way.

Show 8 quoted lines
>
> I would be very hesitant to special case "./*.js" to mean "*.js
> files in the same directory as .gitignore appears", as I think it
> risks intelligent readers to infer "../foo/*.js" or "../*.js" would
> take effect, when placed in "bar/.gitignore".  A design that spreads
> an incorrect assumption/expectation is not a good one, I would have
> to say.
>

I did not say I'd change the behavior of the ignore rules. I rather meant to say the documentation could be filled with examples for common patterns.

That way you'd not be required to read all the rules and *think* about them, but rather can just copy/paste and hope it works. ;)

Sorry if this sounded otherwise.
Junio C Hamano· Feb 3, 2015, 20:11 UTC · re: Stefan Beller · lore

Re: Relative paths don't work in .gitignore as would be expected.

Stefan Beller <stefanbeller@gmail.com> writes:
Show 21 quoted lines
> 2015-02-02 11:15 GMT-08:00 Junio C Hamano <gitster@pobox.com>:
>
>> Isn't gitignore(5) documentation reasonably clear?
>> ...
>>  - A leading slash matches the beginning of the pathname. For
>>    example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
>>
>>> That's true, though you'd never (barely?) git version control an entire
>>> file system?
>>
>> When you have the entire file system under /.git, "/var/" still
>> would be the right way to spell a pattern to match ...
>> ... and lives in the root level of the filesystem (because of the
>> leading '/' anchors
>> the pattern to the same level as the file the pattern appears in,
>> i.e. /.gitignore) and no other place.
>
> ... Now I realize git treats the repository
> root literally as the root and hence absolute paths starting with "/"
> make totally sense inside git as the world stops for git outside its
> work directory.

Only when the pattern appears in .gitignore at the top-level of the project, you can say: "/*.js" matches files with ".js" suffix at the root level of the project because '/' means 'root'.

But that explanation breaks down for "t/.gitignore" that has entries like "/.prove". It is not excluding ".prove" at the top-level of the project. It is excluding those that appear at the same level as that ignore file in question lives in, i.e. the "t/" directory. It excludes "t/.prove", it excludes neither ".prove" at the top-level nor "t/tt/ttt/.prove".

In hindsight, using '/' prefix as a way to anchor the patter to the same directory the .gitignore file appears in was suboptimal, exactly because it would invite the above reaction. But I do not know if using "./" as the prefix to denote the same thing would have been better.

← back to recent threads