# [PATCH] make slash-rules more readable

4 messages from 2019-05-18 to 2019-05-29. Participants: Dr. Adam Nielsen, Philip Oakley.
Thread: https://gitlist.dev/t/51121

## Dr. Adam Nielsen, 2019-05-18 14:07

Subject: [PATCH] make slash-rules more readable
Message-ID: <20190518140759.14500-1-admin@in-ici.net>
URL: https://gitlist.dev/e/20190518140759.14500-1-admin%40in-ici.net

```
gitignore.txt: make slash-rules more readable

Make all paragraphs valid, even if they are not read
in strict order. Make paragraph better understandable
for pattern without slash. Add sentece and example
for pattern with slash. Be precise whenever a trailing 
slashe would make a difference. Add some examples.

Signed-off-by: Dr. Adam Nielsen <admin@in-ici.net>

---
 Documentation/gitignore.txt | 58 +++++++++++++++++++++++--------------
 1 file changed, 37 insertions(+), 21 deletions(-)

diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index b5bc9dbff0..584c82c7df 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -89,28 +89,44 @@ PATTERN FORMAT
    Put a backslash ("`\`") in front of the first "`!`" for patterns
    that begin with a literal "`!`", for example, "`\!important!.txt`".
 
- - If the pattern ends with a slash, it is removed for the
-   purpose of the following description, but it would only find
+ - A slash `/` is used as a directory separator. A leading and trailing 
+   slash have special meaning and are explained in the following.
+
+ - If the pattern ends with a slash, 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).
-
- - Otherwise, Git treats the pattern as a shell glob: "`*`" matches
-   anything except "`/`", "`?`" matches any one character except "`/`"
-   and "`[]`" matches one character in a selected range. See
-   fnmatch(3) and the FNM_PATHNAME flag for a more detailed
-   description.
-
- - A leading slash matches the beginning of the pathname.
-   For example, "/{asterisk}.c" matches "cat-file.c" but not
-   "mozilla-sha1/sha1.c".
+   directory `foo`, 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 end with a slash, it would find a match
+   with a file or directory.
+
+ - If the pattern contains no slash or only a trailing slash,
+   the pattern is matched against all files and folders (recursively)
+   from the location of the `.gitignore` file.
+   For example, `frotz/` matches `frotz` and `a/frotz` that
+   is a directory (relative from the `.gitignore` file).
+   Otherwise the pattern is matched relative to the 
+   location of the `.gitignore` file. 
+   For example, `doc/frotz/` matches `doc/frotz` directory, but not
+   `a/doc/frotz` (relative from the `.gitignore` file). 
+
+ - The above pargraph also includes the case of a leading slash.
+   For example, the pattern `/bar` only matches the file or 
+   folder `bar` that is at the same location as the `gitignore` 
+   file. Whereas the pattern `bar` would also match in folders 
+   below the `gitignore`  file. Note that the pattern `doc/frotz` 
+   and `/doc/frotz` have the same effect in any `.gitignore` file. 
+
+ - An asterisk "`*`" matches anything except a slash.
+   A pattern "foo/*", for example, matches "foo/test.json"
+   (a regular file), "foo/bar" (a diretory), but it does not match
+   "foo/bar/hello.c" (a regular file), as the asterisk in the
+   patter does not match "bar/hello.c" which has a slash in it.
+   The character "`?`" matches any one character except "`/`".
+   The range notation, e.g. `[a-zA-Z]`, can be used to match
+   one of the characters in a range. See fnmatch(3) and the
+   FNM_PATHNAME flag for a more detailed description.
 
 Two consecutive asterisks ("`**`") in patterns matched against
 full pathname may have special meaning:
-- 
2.17.1


```

## Philip Oakley, 2019-05-18 19:34

Subject: Re: [PATCH] make slash-rules more readable
Message-ID: <7b062fd1-c793-b8b9-c997-90f53f958e2c@iee.org>
URL: https://gitlist.dev/e/7b062fd1-c793-b8b9-c997-90f53f958e2c%40iee.org
In-Reply-To: <20190518140759.14500-1-admin@in-ici.net>

```
Hi Adam

On 18/05/2019 15:07, Dr. Adam Nielsen wrote:
> + - If the pattern contains no slash or only a trailing slash,
> +   the pattern is matched against all files and folders (recursively)
> +   from the location of the `.gitignore` file.
> +   For example, `frotz/` matches `frotz` and `a/frotz` that
> +   is a directory (relative from the `.gitignore` file).
This "Otherwise" below could be the complement to the initial "If", or 
could be part of a "matches" pair of example sentences. At least on my 
initial reading I paired it via the 'matches'.

A blank line separator make make it more obvious.  Alternatively, make 
the "For example" parts flow as part of their previous lines.
If you go for an additional blank line then the next next para needs to 
clarify it's 'above' as their will be two paras, not one.
> +   Otherwise the pattern is matched relative to the
> +   location of the `.gitignore` file.
> +   For example, `doc/frotz/` matches `doc/frotz` directory, but not
> +   `a/doc/frotz` (relative from the `.gitignore` file).

 > + - The above pargraph also includes the case of a leading slash.

s/pargraph/paragraph/
--
Philip

```

## Dr. Adam Nielsen, 2019-05-19 15:33

Subject: Re: [PATCH] make slash-rules more readable
Message-ID: <1730c168-c4fb-0e04-dd20-c267ce510fd1@in-ici.net>
URL: https://gitlist.dev/e/1730c168-c4fb-0e04-dd20-c267ce510fd1%40in-ici.net
In-Reply-To: <7b062fd1-c793-b8b9-c997-90f53f958e2c@iee.org>

```
On 18.05.19 21:34, Philip Oakley wrote:
> Hi Adam
> 

Hi Philip

> On 18/05/2019 15:07, Dr. Adam Nielsen wrote:
> This "Otherwise" below could be the complement to the initial "If", or 
> could be part of a "matches" pair of example sentences. At least on my 
> initial reading I paired it via the 'matches'.

Now that you said it, I can see the ambiguity. Maybe its better to 
create a blank line separator, the mentioned paragraph is already very 
big. Perhaps like this:

     If the pattern contains no slash or only a trailing slash, [..].
     For example, `frotz/` matches `frotz` and `a/frotz` that
     is a directory (relative from the `.gitignore` file).

     Otherwise, if the pattern contains a non-trailing slash,
     the pattern is matched relative to the location
     of the `.gitignore` file.


On 19.05.19 03:59, Junio C Hamano wrote:
 >> Make all paragraphs valid, even if they are not read
 >> in strict order.
 >
 > I think you are giving up on this, and I do not think that is
 > particularly a bad thing ;-)

You are right. The paragraph below

 >> + - The above pargraph also includes the case of a leading slash.

can of course not be read in any order. Maybe its more precise to say:

     Remove meta-rules in a paragraph that effect the way one
     has to read upcoming paragraphs.

 > Now you (not you the author of the document, but figuratively "any
 > reader of this document") must have read all the four before this
 > point ;-)

This paragraph references to the immediate forerunner. Why do you think 
it references to all four paragraphs?

 > To put it differently, your reading of the above four
 > bullets are incomplete unless you read this too.

I would say the paragraph

 >> + - The above pargraph also includes the case of a leading slash. [...]

is redundant. Its purpose is to point out that the previous paragraph 
also included the rule about the leading slash.
So the above four paragraphs are valid in my opinion without this paragraph.

 >
 > Typofix: "pargraph" -> "paragraph".
 >
 > In any case, I cannot guess what 'also include the case of a leaning
 > slash' wants to say.

Maybe this is better understandable(?):

     Note that any pattern that starts with a leading slash contains
     a non-trailing slash and is therefore effected by the
     previous paragraph.

This might be even better after creating a new paragraph for the 
"Otherwise.." part as suggested by Philip.

 >        Note that the above rule means you cannot easily say "a file
 >        whose name contains 'hello' and in this directory only, not in
 >        its subdirectories." because a pattern 'hello.*' does not have
 >        any slash. To work around this limitation, you can prepend
 >        your pattern with a slash, i.e. '/hello.*'; the pattern now
 >        matches 'hello.txt', 'hello.c' but not 'a/hello.java'.

I think examples that are as descriptive as this should rather belong to 
the "Example" section. For the rules section I would like to keep the 
examples as short and clean as possible (I think Johannes agrees with me 
here?).

If understand you correctly, then you find my example too abstract? 
Maybe this is better(?):

     For example, the pattern `/bar` only matches the file or
     folder `bar` but not `a/bar`, whereas the pattern `bar` would
     match both (relative to the `.gitignore` file).


On 19.05.19 08:59, Johannes Sixt wrote:
 > All those examples unterrupt the flow of thought in a way that makes it
 > diffcult to follow the reasoning.

I agree with you that complex examples make it harder to read. However, 
I find that if a complex rule is accompanied by a simple example, it 
improves readability a lot. I find that for example the four paragraphs 
about the `**` have a perfect balance between rules and examples.

 >May I suggest a different approach to
 > upate this text? Provide two patches:
 >
 > - Patch 1/2 updates the Examples section such that it contains all
 >    examples that you provide in the text above, with explanation.
 >    Perhaps refer to the Examples section early above the rules.
 >
 > - Patch 2/2 updates the rules section without giving examples.

Maybe its best if discuss this for each changed/new paragraph if the 
example should be moved into the example section.

1.

 >> + - If the pattern contains no slash or only a trailing slash,
 >> +   the pattern is matched against all files and folders (recursively)
 >> +   from the location of the `.gitignore` file.
 >> +   For example, `frotz/` matches `frotz` and `a/frotz` that
 >> +   is a directory (relative from the `.gitignore` file).

I think the example very short and important, and it should stay.

2.
   - Otherwise, if the pattern contains a non-trailing slash,
     the pattern is matched relative to the
     location of the `.gitignore` file.
     For example, `doc/frotz/` matches `doc/frotz` directory, but not
     `a/doc/frotz` (relative from the `.gitignore` file).

Same here. Its a short and important. I would like to keep it there.


3.

     Note that any pattern that starts with a leading slash contains
     a non-trailing slash and is therefore effected by the
     previous paragraph.
     For example, the pattern `/bar` only matches the file or
     folder `bar` but not `a/bar`, whereas the pattern `bar` would
     match both (relative to the `.gitignore` file).

I would agree to put this entire paragraph in the example section.


4.

 >> + - An asterisk "`*`" matches anything except a slash.
 >> +   A pattern "foo/*", for example, matches "foo/test.json"
 >> +   (a regular file), "foo/bar" (a diretory), but it does not match
 >> +   "foo/bar/hello.c" (a regular file), as the asterisk in the
 >> +   patter does not match "bar/hello.c" which has a slash in it.

I would also agree to put the 4-line example into the example section.

We could also put this in the example section:

     Note that the pattern `doc/frotz` and `/doc/frotz` have the
     same effect in any `.gitignore` file, while `/bar` and `bar`
     have not the same effect (`/bar` will not match `foo/bar`).


If we do all this, I could imagine the following procedure:

  - Patch 1/2 updates all the changes but do not include
    the examples from 3. and 4.

  - Patch 2/2 improving the example section and including the
    examples from 3. and 4.

I have actually some ideas for the example section that you may see in 
my blog post in the section examples: 
https://dr-nielsen.com/git/gitignore-pattern-explained

I would like to put all of those in the example section of the docs. But 
this is clearly out of scope of patch 1/2.

 > The examples in the Examples section are overly technical by saying
 >
 >     $ cat .gitignore
 >     vmlinux*
 >     $ ls arch/foo/kernel/vm*
 >     arch/foo/kernel/vmlinux.lds.S
 >     $ echo '!/vmlinux*' >arch/foo/kernel/.gitignore
 >
 > I think that this could be made more pleasent to read if one would not
 > have to use a mental shell interpreter. ;)

I agree, I would also vote to remove this one.


All the best,
Adam



```

## Dr. Adam Nielsen, 2019-05-29 08:28

Subject: Re: [PATCH] make slash-rules more readable
Message-ID: <4a939040-b0d2-5914-f800-26903e4ec829@in-ici.net>
URL: https://gitlist.dev/e/4a939040-b0d2-5914-f800-26903e4ec829%40in-ici.net
In-Reply-To: <0c2894ce-7eab-8207-9af8-7ce5e779d4ec@iee.org>

```
On 19.05.19 19:42, Philip Oakley wrote:
> Hi Adam,
> 

Hi Philip

> a) keep going. the documentation does need improving!

Thank you for the encouragement!

> b) also have a look at the `git help glossary` for 'glob' pattern 
> descriptions for other ideas.

The glob entry looks very familiar to some entries from the gitignore 
docs. But thanks for the reference.

> c) maybe swap the order for considering the slashes (first slash vs last 
> slash). It appears as if the 'trailing slash rule' == 'always a 
> directory' could be said first, or is that last? dunno..

The first paragraph about slashes is already that a "trailing slash" == 
"always a directory".

However I was also thinking of swapping the order of

     If the pattern contains no slash or only a trailing slash,
     the pattern is matched against all files and folders (recursively)
     from the location of the `.gitignore` file.
     For example, `frotz/` matches `frotz` and `a/frotz` that
     is a directory (relative from the `.gitignore` file).

and

     Otherwise, if the pattern contains a non-trailing slash,
     the pattern is matched relative to the location
     of the `.gitignore` file.
     For example, `doc/frotz/` matches `doc/frotz` directory, but not
    `a/doc/frotz` (relative from the `.gitignore` file).

I am wondering if it would be an improvement to state it like this:

     The pattern is matched relative to the location of
     the `.gitignore` file. Except if the pattern contains
     no slash (or no slash but a trailing slash), then the pattern is
     matched against all files and folders (recursively)
     from the location of the `.gitignore` file.
     For example, `doc/frotz/` matches `doc/frotz` directory, but not
    `a/doc/frotz`; however `frotz/` matches `frotz` and `a/frotz` that
     is a directory (all paths are relative from the `.gitignore` file).


> d) It looks like its the counting of slashes that gets everyone!
> 
Yes the trailing slash is the reason we can't say, if there is any slash 
[...]. If there is no slash [...]. So counting is not enough, one also 
needs to consider the type of the slash.


> Philip
> 


All the best,
Adam

> On 19/05/2019 16:33, Dr. Adam Nielsen wrote:
>> On 18.05.19 21:34, Philip Oakley wrote:
>>> Hi Adam
>>>
>>
>> Hi Philip
>>
>>> On 18/05/2019 15:07, Dr. Adam Nielsen wrote:
>>> This "Otherwise" below could be the complement to the initial "If", 
>>> or could be part of a "matches" pair of example sentences. At least 
>>> on my initial reading I paired it via the 'matches'.
>>
>> Now that you said it, I can see the ambiguity. Maybe its better to 
>> create a blank line separator, the mentioned paragraph is already very 
>> big. Perhaps like this:
>>
>>     If the pattern contains no slash or only a trailing slash, [..].
>>     For example, `frotz/` matches `frotz` and `a/frotz` that
>>     is a directory (relative from the `.gitignore` file).
>>
>>     Otherwise, if the pattern contains a non-trailing slash,
>>     the pattern is matched relative to the location
>>     of the `.gitignore` file.
>>
>>
>> On 19.05.19 03:59, Junio C Hamano wrote:
>> >> Make all paragraphs valid, even if they are not read
>> >> in strict order.
>> >
>> > I think you are giving up on this, and I do not think that is
>> > particularly a bad thing ;-)
>>
>> You are right. The paragraph below
>>
>> >> + - The above pargraph also includes the case of a leading slash.
>>
>> can of course not be read in any order. Maybe its more precise to say:
>>
>>     Remove meta-rules in a paragraph that effect the way one
>>     has to read upcoming paragraphs.
>>
>> > Now you (not you the author of the document, but figuratively "any
>> > reader of this document") must have read all the four before this
>> > point ;-)
>>
>> This paragraph references to the immediate forerunner. Why do you 
>> think it references to all four paragraphs?
>>
>> > To put it differently, your reading of the above four
>> > bullets are incomplete unless you read this too.
>>
>> I would say the paragraph
>>
>> >> + - The above pargraph also includes the case of a leading slash. 
>> [...]
>>
>> is redundant. Its purpose is to point out that the previous paragraph 
>> also included the rule about the leading slash.
>> So the above four paragraphs are valid in my opinion without this 
>> paragraph.
>>
>> >
>> > Typofix: "pargraph" -> "paragraph".
>> >
>> > In any case, I cannot guess what 'also include the case of a leaning
>> > slash' wants to say.
>>
>> Maybe this is better understandable(?):
>>
>>     Note that any pattern that starts with a leading slash contains
>>     a non-trailing slash and is therefore effected by the
>>     previous paragraph.
>>
>> This might be even better after creating a new paragraph for the 
>> "Otherwise.." part as suggested by Philip.
>>
>> >        Note that the above rule means you cannot easily say "a file
>> >        whose name contains 'hello' and in this directory only, not in
>> >        its subdirectories." because a pattern 'hello.*' does not have
>> >        any slash. To work around this limitation, you can prepend
>> >        your pattern with a slash, i.e. '/hello.*'; the pattern now
>> >        matches 'hello.txt', 'hello.c' but not 'a/hello.java'.
>>
>> I think examples that are as descriptive as this should rather belong 
>> to the "Example" section. For the rules section I would like to keep 
>> the examples as short and clean as possible (I think Johannes agrees 
>> with me here?).
>>
>> If understand you correctly, then you find my example too abstract? 
>> Maybe this is better(?):
>>
>>     For example, the pattern `/bar` only matches the file or
>>     folder `bar` but not `a/bar`, whereas the pattern `bar` would
>>     match both (relative to the `.gitignore` file).
>>
>>
>> On 19.05.19 08:59, Johannes Sixt wrote:
>> > All those examples unterrupt the flow of thought in a way that makes it
>> > diffcult to follow the reasoning.
>>
>> I agree with you that complex examples make it harder to read. 
>> However, I find that if a complex rule is accompanied by a simple 
>> example, it improves readability a lot. I find that for example the 
>> four paragraphs about the `**` have a perfect balance between rules 
>> and examples.
>>
>> >May I suggest a different approach to
>> > upate this text? Provide two patches:
>> >
>> > - Patch 1/2 updates the Examples section such that it contains all
>> >    examples that you provide in the text above, with explanation.
>> >    Perhaps refer to the Examples section early above the rules.
>> >
>> > - Patch 2/2 updates the rules section without giving examples.
>>
>> Maybe its best if discuss this for each changed/new paragraph if the 
>> example should be moved into the example section.
>>
>> 1.
>>
>> >> + - If the pattern contains no slash or only a trailing slash,
>> >> +   the pattern is matched against all files and folders (recursively)
>> >> +   from the location of the `.gitignore` file.
>> >> +   For example, `frotz/` matches `frotz` and `a/frotz` that
>> >> +   is a directory (relative from the `.gitignore` file).
>>
>> I think the example very short and important, and it should stay.
>>
>> 2.
>>   - Otherwise, if the pattern contains a non-trailing slash,
>>     the pattern is matched relative to the
>>     location of the `.gitignore` file.
>>     For example, `doc/frotz/` matches `doc/frotz` directory, but not
>>     `a/doc/frotz` (relative from the `.gitignore` file).
>>
>> Same here. Its a short and important. I would like to keep it there.
>>
>>
>> 3.
>>
>>     Note that any pattern that starts with a leading slash contains
>>     a non-trailing slash and is therefore effected by the
>>     previous paragraph.
>>     For example, the pattern `/bar` only matches the file or
>>     folder `bar` but not `a/bar`, whereas the pattern `bar` would
>>     match both (relative to the `.gitignore` file).
>>
>> I would agree to put this entire paragraph in the example section.
>>
>>
>> 4.
>>
>> >> + - An asterisk "`*`" matches anything except a slash.
>> >> +   A pattern "foo/*", for example, matches "foo/test.json"
>> >> +   (a regular file), "foo/bar" (a diretory), but it does not match
>> >> +   "foo/bar/hello.c" (a regular file), as the asterisk in the
>> >> +   patter does not match "bar/hello.c" which has a slash in it.
>>
>> I would also agree to put the 4-line example into the example section.
>>
>> We could also put this in the example section:
>>
>>     Note that the pattern `doc/frotz` and `/doc/frotz` have the
>>     same effect in any `.gitignore` file, while `/bar` and `bar`
>>     have not the same effect (`/bar` will not match `foo/bar`).
>>
>>
>> If we do all this, I could imagine the following procedure:
>>
>>  - Patch 1/2 updates all the changes but do not include
>>    the examples from 3. and 4.
>>
>>  - Patch 2/2 improving the example section and including the
>>    examples from 3. and 4.
>>
>> I have actually some ideas for the example section that you may see in 
>> my blog post in the section examples: 
>> https://dr-nielsen.com/git/gitignore-pattern-explained
>>
>> I would like to put all of those in the example section of the docs. 
>> But this is clearly out of scope of patch 1/2.
>>
>> > The examples in the Examples section are overly technical by saying
>> >
>> >     $ cat .gitignore
>> >     vmlinux*
>> >     $ ls arch/foo/kernel/vm*
>> >     arch/foo/kernel/vmlinux.lds.S
>> >     $ echo '!/vmlinux*' >arch/foo/kernel/.gitignore
>> >
>> > I think that this could be made more pleasent to read if one would not
>> > have to use a mental shell interpreter. ;)
>>
>> I agree, I would also vote to remove this one.
>>
>>
>> All the best,
>> Adam
>>
>>
> 
> 


```
