Re: Change in .gitignore handling: intended or bug?

2 messages, 2 authors, 2016-06-15 · open the first message on its own page

Re: Change in .gitignore handling: intended or bug?

From: Junio C Hamano <hidden>
Date: 2016-06-15 23:08:39

Junio C Hamano [off-list ref] writes:
We need documentation update to settle this one before 2.8 final
ships, as we seem to be seeing more and more end-user confusion on
the list.  I tried to come up with a trimmed-down example, which is
shown below, but I suspect that the code is not exactly working the
way it is described in that (1) dir/file1 is ignored and (3)
!dir/file3 entry makes difference.

Where did my example go wrong?

FYI, if I prefix '/' to all the .gitignore entries in the example, i.e.
making it

    *
    !/dir
    /dir/file2
    !/dir/file3

instead, then dir/file1 and dir/file3 do get shown as unignored.

If it is documented somewhere, then I can update the example and
declare victory (but then the text that accompanies the example
still needs to remind the readers why the leading '/' matters.
I also found that having an extra slash at the end of the
"everything underneath 'dir' directory is included", i.e.

     *
     !/dir/
     /dir/file2
     !/dir/file3

breaks it.  dir/file1 is ignored, dir/file3 isn't but the latter is
only because there is an explicit !/dir/file3.  This is contrary to
this rule in the documentation:

 - 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).

In other words, '!/dir/' does not seem to match the directory dir
and paths underneath it.

Thanks.
quoted hunk
 Documentation/gitignore.txt | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 3ded6fd..b841233 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -150,6 +150,40 @@ excluded, the following conditions must be met:
  - The directory part in the re-include rules must be literal (i.e. no
    wildcards)
 
+A re-inclusion of a directory makes all files in the directory
+unignored.  For example, suppose you have files `.gitignore`,
+`dir/file1`, `dir/file2`, and `dir/file3`, and have the following in
+your `.gitignore`:
+
+----------------
+*
+!dir
+# dir/file1 is not mentioned in .gitignore
+dir/file2
+!dir/file3
+----------------
+
+Then:
+
+ - `.gitignore` gets ignored, because it matches the `*` at the top
+   level;
+
+ - `dir/file1` gets unignored, because `dir` marks everything
+   underneath `dir/` to be unignored unless otherwise specified;
+
+ - `dir/file2` gets ignored, because `dir/file2` is listed to be
+   ignored;
+
+ - `dir/file3` gets unignored, because `dir/file3` is listed to be
+   ignored.  Note that the entry `!dir/file3` is redundant because
+   everything underneath `dir/` is marked to be unignored already.
+
+Some earlier versions of Git treated `!dir` differently in that it
+did not cause the paths under it unignored, but this has been
+corrected to be consistent with `dir` that says "`dir` and everything
+below are ignored."
+
+
 EXAMPLES
 --------
 

Re: Change in .gitignore handling: intended or bug?

From: Duy Nguyen <hidden>
Date: 2016-06-15 23:08:39

On Tue, Mar 8, 2016 at 1:14 PM, Junio C Hamano [off-list ref] wrote:
Junio C Hamano [off-list ref] writes:
quoted
We need documentation update to settle this one before 2.8 final
ships, as we seem to be seeing more and more end-user confusion on
the list.  I tried to come up with a trimmed-down example, which is
shown below, but I suspect that the code is not exactly working the
way it is described in that (1) dir/file1 is ignored and (3)
!dir/file3 entry makes difference.

Where did my example go wrong?

FYI, if I prefix '/' to all the .gitignore entries in the example, i.e.
making it

    *
    !/dir
    /dir/file2
    !/dir/file3

instead, then dir/file1 and dir/file3 do get shown as unignored.
Arghhh.. bug!!!

The difference between "dir" and "/dir" is, the former is basename
matching while the latter is pathname matching. When we check
dir/file1 after we enter "dir", we do try to check rule "!/dir" (or
"!dir") before rule "*". In the pathname matching case, it works
thanks to a60ea8f.

In the basename matching case (i.e. rule "!dir"), the code does not do
the right thing. It blindly checks the base name of dir/file1, which
is "file1", against the pattern "dir". The right thing to do is check
the "dir" in "dir/file1" part against pattern "dir". Failing that, we
fall back to pattern "*" and excludes dir/file1 as well.
quoted
If it is documented somewhere, then I can update the example and
declare victory (but then the text that accompanies the example
still needs to remind the readers why the leading '/' matters.
I also found that having an extra slash at the end of the
"everything underneath 'dir' directory is included", i.e.

     *
     !/dir/
     /dir/file2
     !/dir/file3

breaks it.  dir/file1 is ignored, dir/file3 isn't but the latter is
only because there is an explicit !/dir/file3.  This is contrary to
this rule in the documentation:
This is pretty much the same. But instead basename matching unable to
deal with nested rules, the trailing slash means "check if it is a
directory". Again, the code tries to check if "dir/file1" is a
directory instead of "dir".

I haven't dug back in history, but my impression is it has been so
probably from the beginning of "!" introduction. This has nothing to
do with nd/exclusion-regression-fix, which is more about

    dir
    !dir/file

than

    !dir
    dir/file

Although the first patch in that series happens to fix the pathname
matching case in this example.

I don't know. It seems to me I should fix this anyway, by making both
"NODIR" and "MUSTBEDIR" code work well inside a directory. That should
fix it. I hope I don't have to turn dir.c up side down for that. Last
time I looked, it wasn't easy, which led to hack/avoid it with 57534ee
and that was eventually reverted.
-- 
Duy
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help