Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

implausible
Copy link
Contributor

When a directory's contents are ignored, and then a glob negation is made to a nested subdir, other subdirectories are now unignored.

The best example I have is:

/dir/*
!/dir/sub1/sub2/**/*

After the second rule is added, files in /dir/sub1 are now unignored.

implausible and others added 2 commits March 14, 2019 13:06
When a directory's contents are ignored, and then a glob negation is made to a nested subdir, other subdirectories are now unignored
Matching on the prefix of a negated pattern was triggering false
negatives on siblings of that pattern. e.g.

Given the .gitignore:
dir/*
!dir/sub1/sub2/**

The path `dir/a.text` would not be ignored.
@implausible implausible changed the title Implement failing test for gitignore of complex subdirectory negation Negation of subdir ignore causes other subdirs to be unignored Mar 15, 2019
@implausible
Copy link
Contributor Author

implausible commented Mar 15, 2019

@pks-t It seems you were in this area last time, some guidance would be appreciated! We're seeing this problem prop up in GitKraken and wanted to try and get to the bottom of it. Let me know if there's something we're not able to grok, but it seems that the block that sat there is now no longer performing its function adequately. It seems that removal of that block is closer to the gitignore spec than the current iteration is now.

The big question I have is what do you think we broke instead?

@pks-t
Copy link
Member

pks-t commented Mar 15, 2019

The big question I have is what do you think we broke instead?

This is the single most important question when it comes to gitignore code. You know, on the surface the rules look quite easy. But whenever you feel like you've improved the code to more closely match git.git, then nope. Some weird corner case you weren't aware of just broke.

To be honest, by now I don't care for what I think anymore, as I started to trust our gitignore tests a lot more than my own judgement. I'm not able to grok all those intricacies and every time I take a look atthat code I need to re-learn everything from the beginning.

Anyway, let's see where this block comes from. Blame shows f25bc0b (Fix rejection of parent dir of negated ignores, 2014-08-08):

Fix rejection of parent dir of negated ignores

While scanning through a directory hierarchy, this prevents a
positive ignore match on a parent directory from blocking the scan
of a directory when a negative match rule exists for files inside
the directory.

Unfortunately, no test has been added for that. From my guess, this looks like one of the following two scenarios:

/parent/
!/parent/child/file

We do not want to unignore "/parent/child/file" in this case. Second guess:

/parent/
!/parent/file

We do not want to unignore "/parent/child" here either.

So right now libgit2 does the right thing with regards to the above two scenarios, which might be what that commit wanted to fix. After removing the block, we still do the right thing, so it can't be required for them. Either my inferred scenarios are plain wrong or we have modified enough code for it to not be required anymore.

Long story short: your changes look quite sensible to me, at least judging from the spec.

@@ -1213,3 +1213,41 @@ void test_status_ignore__unignored_subdirs(void)
assert_is_ignored("dir/a.test");
refute_is_ignored("dir/subdir/a.test");
}

void test_status_ignore__ignored_subdirfiles_with_subdir_rule(void)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like you should add these two tests to "tests/attr/ignore.c" instead.

"!dir/sub1/sub2/**\n");

assert_is_ignored("dir/a.test");
assert_is_ignored("dir/sub1/a.test");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd definitely want to test that "dir/sub1/sub2/foobar" is ignored, too.

"empty_standard_repo/dir/a.test",
"empty_standard_repo/dir/sub1/sub2/b.test",
NULL
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to create those testfiles in "test/attr/ignore.c". You can just rewrite the gitignore file and then immediately use assert_is_ignored in there.

@emmax86
Copy link
Contributor

emmax86 commented Mar 15, 2019

You are definitely on point with your suggestion that there should be a test case for "dir/sub1/sub2/foobar". Unfortunately, this iteration at the gitignore spec doesn't pass that test case; it is returns unignored, when it should be ignored. However, we were not passing this case in 0.27 or 0.28 either. It would seem this change has increased coverage of the spec without any detectable regressions. I have updated this PR with the failing assertion to demonstrate this.

For comparison, I pushed up test/ignore-0.28.1, test/ignore-0.27.8, and test/ignore-0.27.0. On these branches, I added test cases for each of the assertions in test_status_ignore__ignored_subdirfiles_with_subdir_rule to demonstrate which assertions failed. Here were my results:

0.27.0:
✅ assert_is_ignored("dir/a.test");
✅ assert_is_ignored("dir/sub1/a.test");
❌ assert_is_ignored("dir/sub1/sub2");
❌ assert_is_ignored("dir/sub1/sub2/b.test");

0.27.8
✅ assert_is_ignored("dir/a.test");
❌ assert_is_ignored("dir/sub1/a.test");
❌ assert_is_ignored("dir/sub1/sub2");
❌ assert_is_ignored("dir/sub1/sub2/b.test");

0.28.1
✅ assert_is_ignored("dir/a.test");
❌ assert_is_ignored("dir/sub1/a.test");
❌ assert_is_ignored("dir/sub1/sub2");
❌ assert_is_ignored("dir/sub1/sub2/b.test");

This PR:
✅ assert_is_ignored("dir/a.test");
✅ assert_is_ignored("dir/sub1/a.test");
✅ assert_is_ignored("dir/sub1/sub2");
❌ assert_is_ignored("dir/sub1/sub2/b.test");

@implausible
Copy link
Contributor Author

@pks-t So I think if we look at the recent history of gitignore in libgit2, we're actually in a better position than we were before if this PR were to be merged. One of the selling points on merging this PR without necessarily fixing the negation case as well is that it is a vastly simpler discussion for customers. When their ignore file produces changes in GitKraken that are ignored in the CLI, if the reason is "That rule you added isn't supported in Git and should be removed from your .gitignore", then it's a super quick fix as a support issue.

Right now, the gitignore system as is produces very odd and less fixable behavior. What are your thoughts?

Copy link
Member

@pks-t pks-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry it took me so long to get back. Have been scavenging off in the last few weeks to make my desktop environment workable again :/

I'm happy to merge. It seems to pass everything we'd expect it to, except for the case where we erroneously unignore files in ignored deep directories. And that case didn't work before either, so we may as well handle that in a separate PR.

@pks-t pks-t merged commit 9aa049d into libgit2:master Mar 29, 2019
@implausible implausible deleted the fix/gitignore-negation branch March 29, 2019 14:53
@implausible
Copy link
Contributor Author

Excellent. Appreciate the merge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants