# Bug in .gitignore handling

7 messages from 2008-03-26 to 2008-03-26. Participants: Tommy Thorn, Junio C Hamano, Linus Torvalds.
Thread: https://gitlist.dev/t/12880

## Tommy Thorn, 2008-03-26 20:01

Subject: Bug in .gitignore handling
Message-ID: <47EAABB6.30803@thorn.ws>
URL: https://gitlist.dev/e/47EAABB6.30803%40thorn.ws

```
For reasons too upsetting to explain, I have to keep a collection of 
symlinks inside my tree but outside of git's control, such as

mydir/foo -> ../otherdir/foo

To stop git clean from removing it, I added "foo" to .gitignore

The problem is that I foo appears in build paths inside the tree that I 
would like git clean to pick up, however the pattern "foo" is applied 
generally and matches stuff like

mydir/mousetrap/foo/objs

According to the man page, I should be able to change .gitignore to 
"foo/" to stop it from looking recursively, but that doesn't work, as 
now git clean -n -f -d wants to remove mydir/foo but not mydir/foo/objs

My desperate attempts "./foo" and "^foo" also didn't work. Please note 
that this is a vastly simplified version of the real problem, so I can't 
just use "!mousetrap/foo".

It seems "foo/" _should_ work even though foo isn't a directory.

Thanks
Tommy

```

## Junio C Hamano, 2008-03-26 20:20

Subject: Re: Bug in .gitignore handling
Message-ID: <7vhcetck5m.fsf@gitster.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vhcetck5m.fsf%40gitster.siamese.dyndns.org
In-Reply-To: <47EAABB6.30803@thorn.ws>

```
Tommy Thorn <tommy-git@thorn.ws> writes:

> According to the man page, I should be able to change .gitignore to
> "foo/" to stop it from looking recursively, but that doesn't work, as
> now git clean -n -f -d wants to remove mydir/foo but not mydir/foo/objs
>
> My desperate attempts "./foo" and "^foo" also didn't work. Please note
> that this is a vastly simplified version of the real problem, so I
> can't just use "!mousetrap/foo".
>
> It seems "foo/" _should_ work even though foo isn't a directory.

Are you talking about d6b8fc3 (gitignore(5): Allow "foo/" in ignore list
to match directory "foo", 2008-01-31), specifically this part of the
manual?

    diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
    index 08373f5..e847b3b 100644
    --- a/Documentation/gitignore.txt
    +++ b/Documentation/gitignore.txt
    @@ -57,6 +57,13 @@ Patterns have the following format:
        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 without leading directories.

Incidentally I notice that the above patch did not include new tests to
see if "git clean" honors the corrected pattern matching rule.  If your
"real problem" is too complex to describe, perhaps an additional test that
exercises "git clean" with test_expect_failure would help motivated
parties to triage and fix the problem.

"git clean" has always been an ugly and unreliable stepchild, and I would
not be surprised at all if it is ridden with corner case bugs, especially
around the area to skip untracked directories; but in this case you are
not dealing with a directory but a symlink, and it should not get confused
by the fact that the symlink happens to point at a directory.

```

## Tommy Thorn, 2008-03-26 20:26

Subject: Re: Bug in .gitignore handling
Message-ID: <47EAB187.4070009@thorn.ws>
URL: https://gitlist.dev/e/47EAB187.4070009%40thorn.ws
In-Reply-To: <7vhcetck5m.fsf@gitster.siamese.dyndns.org>

```
Junio C Hamano wrote:
> Are you talking about d6b8fc3 (gitignore(5): Allow "foo/" in ignore list
> to match directory "foo", 2008-01-31), specifically this part of the
> manual?
>   

Yes, thanks.

> "git clean" has always been an ugly and unreliable stepchild, and I would
> not be surprised at all if it is ridden with corner case bugs, especially
> around the area to skip untracked directories; but in this case you are
> not dealing with a directory but a symlink, and it should not get confused
> by the fact that the symlink happens to point at a directory.
>   


Thanks, but first step is in ensuring that my understanding is correct. 
Here's the gist of the test case:

mkdir mydir
cd mydir
git init
mkdir mousetrap
touch mousetrap/nonempty
git add mousetrap/nonempty
git commit -m "initial"
ln -s ../otherdir/foo .
echo "foo/" > .gitignore
echo ".gitignore" >> .gitignore
git clean -n -f -d

I expect the last command to report "Would remove mousetrap/foo/", but
I currently get "Would remove foo".

Thanks,
Tommy

```

## Linus Torvalds, 2008-03-26 20:27

Subject: Re: Bug in .gitignore handling
Message-ID: <alpine.LFD.1.00.0803261324380.2775@woody.linux-foundation.org>
URL: https://gitlist.dev/e/alpine.LFD.1.00.0803261324380.2775%40woody.linux-foundation.org
In-Reply-To: <47EAABB6.30803@thorn.ws>

```


On Wed, 26 Mar 2008, Tommy Thorn wrote:
> 
> My desperate attempts "./foo" and "^foo" also didn't work. Please note that
> this is a vastly simplified version of the real problem, so I can't just use
> "!mousetrap/foo".
> 
> It seems "foo/" _should_ work even though foo isn't a directory.

Close but no cigar.

Use "/foo" and it should be ok.

Basically, a path with a slash in it is considered absolute, but if the 
slash is at the end it will only match a directory. A slash at the 
*beginning* will match the root of the git repository, though.

			Linus

```

## Linus Torvalds, 2008-03-26 20:32

Subject: Re: Bug in .gitignore handling
Message-ID: <alpine.LFD.1.00.0803261330280.2775@woody.linux-foundation.org>
URL: https://gitlist.dev/e/alpine.LFD.1.00.0803261330280.2775%40woody.linux-foundation.org
In-Reply-To: <alpine.LFD.1.00.0803261324380.2775@woody.linux-foundation.org>

```


On Wed, 26 Mar 2008, Linus Torvalds wrote:
> 
> Basically, a path with a slash in it is considered absolute, but if the 
> slash is at the end it will only match a directory.

Actually, to clarify: a path with a slash in it *anywhere*else* than at 
the end will be considered absolute. At the end it means "only match 
directories".

So 

	foo

will match any file or directory anywhere in the tree, while

	foo/

will match a directory called "foo" anywhere in the tree, and

	/foo

will match either a file or directory called "foo", but only at the root 
of the repository.

And no, I didn't test it, but that's how it should work, afaik.

		Linus

```

## Tommy Thorn, 2008-03-26 20:35

Subject: Re: Bug in .gitignore handling
Message-ID: <47EAB3AD.5070507@thorn.ws>
URL: https://gitlist.dev/e/47EAB3AD.5070507%40thorn.ws
In-Reply-To: <alpine.LFD.1.00.0803261324380.2775@woody.linux-foundation.org>

```
Linus Torvalds wrote:
> On Wed, 26 Mar 2008, Tommy Thorn wrote:
>   
>> My desperate attempts "./foo" and "^foo" also didn't work. Please note that
>> this is a vastly simplified version of the real problem, so I can't just use
>> "!mousetrap/foo".
>>
>> It seems "foo/" _should_ work even though foo isn't a directory.
>>     
>
> Close but no cigar.
>
> Use "/foo" and it should be ok.
>
> Basically, a path with a slash in it is considered absolute, but if the 
> slash is at the end it will only match a directory. A slash at the 
> *beginning* will match the root of the git repository, though.

D'oh, of course that works. I double check the documentation and it 
actually isn't obvious that that is allowed, so I propose this patch.

Tommy


 From c0a003e995e325d5d9e056137b4b02c370c9dc03 Mon Sep 17 00:00:00 2001
From: Tommy Thorn <tommy-git@thorn.ws>
Date: Wed, 26 Mar 2008 13:34:34 -0700
Subject: [PATCH] Documentation/gitginore.txt: Be explicit about the /foo 
form

Signed-off-by: Tommy Thorn <tommy-git@thorn.ws>
---
 Documentation/gitignore.txt |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index e847b3b..941a8a4 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -57,6 +57,9 @@ Patterns have the following format:
    included again.  If a negated pattern matches, this will
    override lower precedence patterns sources.
 
+ - If the pattern begins with a slash '/', the pattern will only
+   match in the current directory.
+
  - 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
-- 
1.5.5.rc1

```

## Junio C Hamano, 2008-03-26 20:49

Subject: Re: Bug in .gitignore handling
Message-ID: <7vd4phcit1.fsf@gitster.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vd4phcit1.fsf%40gitster.siamese.dyndns.org
In-Reply-To: <47EAB3AD.5070507@thorn.ws>

```
Tommy Thorn <tommy-git@thorn.ws> writes:

> Linus Torvalds wrote:
>> On Wed, 26 Mar 2008, Tommy Thorn wrote:
> ...
>> Use "/foo" and it should be ok.
>>
>> Basically, a path with a slash in it is considered absolute, but if
>> the slash is at the end it will only match a directory. A slash at
>> the *beginning* will match the root of the git repository, though.
>
> D'oh, of course that works. I double check the documentation and it
> actually isn't obvious that that is allowed, so I propose this patch.
>
> diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
> index e847b3b..941a8a4 100644
> --- a/Documentation/gitignore.txt
> +++ b/Documentation/gitignore.txt
> @@ -57,6 +57,9 @@ Patterns have the following format:
>    included again.  If a negated pattern matches, this will
>    override lower precedence patterns sources.
>
> + - If the pattern begins with a slash '/', the pattern will only
> +   match in the current directory.
> +

Did you fully read the existing description and Linus's resopnse?

The above is just a special case of a pattern that contains a slash '/'
(iow, that falls into "Otherwise" rule that follows "If the pattern does
not contain a slash '/'").


 

```
