threads / bug / 12880

Bug in .gitignore handling

Subject: Bug in .gitignore handling

## tl;dr

7 messages between Mar 26, 2008 and Mar 26, 2008.

replies: 6people: 3as markdown or json

Tommy Thorn· Mar 26, 2008, 20:01 UTC · lore

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· Mar 26, 2008, 20:20 UTC · re: Tommy Thorn · lore

Re: Bug in .gitignore handling

Tommy Thorn <tommy-git@thorn.ws> writes:
Show 9 quoted lines
> 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· Mar 26, 2008, 20:26 UTC · re: Junio C Hamano · lore

Re: Bug in .gitignore handling

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.
Show 6 quoted lines
> "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· Mar 26, 2008, 20:27 UTC · re: Tommy Thorn · lore

Re: Bug in .gitignore handling

On Wed, 26 Mar 2008, Tommy Thorn wrote:
Show 6 quoted lines
> 
> 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· Mar 26, 2008, 20:32 UTC · re: Linus Torvalds · lore

Re: Bug in .gitignore handling

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· Mar 26, 2008, 20:35 UTC · re: Linus Torvalds · lore

Re: Bug in .gitignore handling

Linus Torvalds wrote:
Show 16 quoted lines
> 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· Mar 26, 2008, 20:49 UTC · re: Tommy Thorn · lore

Re: Bug in .gitignore handling

Tommy Thorn <tommy-git@thorn.ws> writes:
Show 23 quoted lines
> 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 '/'").

 

← back to recent threads