8

I find /* and * has different means when I compare with the setting:

*

!/init.el
!/README.md
!.gitignore
!/lib/

VS

/*

!/init.el
!/README.md
!.gitignore
!/lib/

The former not track /lib/ but the latter track it.

How to undertand * and /*?

UPDATE
I think this question is not exactly same as another one. Because he is focus on dir/** and dir/* but this one is focus on /* and *.

LoranceChen
  • 2,453
  • 2
  • 22
  • 48
  • 1
    Check [this](https://stackoverflow.com/questions/8783093/gitignore-syntax-bin-vs-bin-vs-bin-vs-bin) out. – nyvokub Mar 14 '18 at 14:44
  • It is a globbing pattern. See [glob(7)](http://man7.org/linux/man-pages/man7/glob.7.html) – Basile Starynkevitch Mar 14 '18 at 14:45
  • 1
    Possible duplicate of [.gitignore Syntax: bin vs bin/ vs. bin/\* vs. bin/\*\*](https://stackoverflow.com/questions/8783093/gitignore-syntax-bin-vs-bin-vs-bin-vs-bin) – Basile Starynkevitch Mar 14 '18 at 14:46
  • @BasileStarynkevitch. That doesn't actually explain anything. – Mad Physicist Mar 14 '18 at 14:46
  • Does anyone reads the [documentation of `.gitignore`](https://git-scm.com/docs/gitignore#_pattern_format)? – axiac Mar 14 '18 at 15:52
  • @axiac How often do you see people read docs? Especially among those who ask questions at SO without any research. – phd Mar 14 '18 at 16:48
  • 1
    hi @phd, document just give a global view of it's usage, for specify problem, I think learning from experienced people is the best way. – LoranceChen Mar 15 '18 at 00:52
  • @LoranceChen What about taking into account that we're all volunteers here and work for free? Shouldn't questioners help us a bit and do some research before asking the same question for 1000th time? – phd Mar 15 '18 at 00:55
  • @phd, sorry for that. I have research the qustion but I doesn't undertand good enough. I will give any test for suggestions if someone have some advice could solve problems. What I want to say is document can't explain every situation or I'm not clever enough to undertand. Maybe we tolk different point. – LoranceChen Mar 15 '18 at 01:48

2 Answers2

4

The first version ignores all files except those listed explicitly. lib is ignored because it contains no trackable files. Git does not track folders, so directories that appear empty seem to get ignored.

The second version ignores all root level files and directories except those listed explicitly. It does not ignore anything that is trackable and not in the root directory. lib is listed explicitly, so it is not ignored. Any files it contains are not at the root level, so they aren't ignored either.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • besides, `lib` is not empty.....it has a file named `/lib/custom-file.el`. – LoranceChen Mar 14 '18 at 14:50
  • @LoranceChen. That file gets ignored by `*` but not by `/*`. Git doesn't track directories. – Mad Physicist Mar 14 '18 at 14:52
  • hi, `custom-file.el` is a file which is not a directory. Why it will be ignored even though I defined `!/lib/`? Is't `!/lib/` means do not ignore `/lib/` directory and any files under it? – LoranceChen Mar 14 '18 at 15:06
  • @LoranceChen. That is correct. Also, keep in mind that `/*` means "only ignore the items in the root folder". That means not ignoring anything else. `!/lib` covers `lib` itself. Anything under `lib` is **not** covered by `/*`. That is the key here. – Mad Physicist Mar 14 '18 at 22:24
  • I'm get the means of "ignores all root level files and directories except those listed explicitly". Git is really a world. – LoranceChen Mar 15 '18 at 00:34
4

The answer is a little complicated because Git's scanning algorithm is tricky, but it boils down to the fact that * matches lib/custom-file.el but /* does not.

As a general rule, in glob patterns, * does not "cross" path name separator /-es. Hence A*B matches ANameThatEndsInB but not ADirectory/WithAFileB.

Putting a / in a glob pattern requires that the thing before the / name a directory and the thing after the / occur within the directory: A*/*B does match ADirectory/WithAFileB. The name components, ADirectory and WithAFileB, are matched individually against the glob components, A* and *B.

A glob pattern ending in /, as in */, matches only directories. One starting with / has another special meaning in Git (but note that, e.g., the .gitignore entry /foo/bar/ consists of two components: /foo/ and then bar/; the bar/ part does not start with a slash). In particular, if the pattern starts with /, it applies only to files in the top level of that Git directory. If that's the top level .gitignore then this means the root of the work-tree itself.

Now, as in Mad Physicist's answer, it's true that if Git has no existing tracked files within a directory, Git does not have to read that directory sometimes. An ignore pattern that matches a directory name will make Git skip the scanning of the directory, if Git does not already have to scan that directory for some other reason. So in general, if you have a .gitignore that has * in it anywhere, any directory tends to get skipped entirely—well, as long as Git doesn't already have to look inside it for some other reason. So * in a .gitignore tends to ignore all directories. However, Git's ignore rules say that whenever Git has hold of a file or directory name and is checking .gitignore files, it should read through the entire file and find all matches, including the ones with ! in front of them. This means that, for instance:

*
!*/

will tell Git to ignore everything (including directories), but override that by saying don't ignore the */ directories. But the * will continue to ignore all files.

If you make it read:

/*
!/*/

you'll ignore all files in this directory (the one containing the .gitignore) but have Git scan all its subdirectories. Everything within any sub-directory such as foo/name will fail to match either of these glob patterns, since the foo/name part has a slash and the * cannot cross it.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Great! If I'm use `*`, I need add `/lib/` and `/lib/*` to track `/lib/custom-file.el` – LoranceChen Mar 15 '18 at 00:38
  • If you have said *ignore `*`*, you will need a later `!/lib` or `!/lib/` (either will work) to say *but do **not** ignore /lib* (which is a directory so both `lib/` and `lib` match, and is in this level, so `/lib` and `/lib/` match *only* that name and not sub-names). Then, if you've ignored `*`, you will need `!custom-file.el` to un-ignore every file with that name, or `!/lib/custom-file.el` to un-ignore that one specific path, for instance. If you're already skipping `*` (except for `lib/custom-file.el`) you won't encounter any *other* `custom-file.el` names anywhere—at least [continued] – torek Mar 15 '18 at 02:41
  • ... at least, not unless you have un-ignored some other directory that contains a file named `custom-file.el`. – torek Mar 15 '18 at 02:41
  • Thanks again. I finally choice `/*` which is the latter one. In most situation, I think using `/*` is more general and understandable then `*` in term of affect to later configuration in `.gitignore`. – LoranceChen Mar 15 '18 at 02:58