0

Using git version 2.34.0.windows.1

I have a /.gitignore file at the root of my repository with the usual suspects of extension ignores in it (it's not really relevant here).

Halfway up the tree (/a/b/c/.gitignore), I have another file, where I wanted to say "recursively below this directory, ignore any directory called devl, except for one particular file extension directly inside". So I put the following rules:

devl/**
!devl/*.dat

Unfortunately, it appears this does not work -- git still reports the file /a/b/c/d/devl/test/foo.bar as untracked, not ignored. (It does not ignore anything at all in the devl directory tree.)

I was able to work around this by using the following rules instead, but as far as I can tell from the documentation, the above should have been legal and working as well:

/**/devl/**
!/**/devl/*.dat

Why is this? Is it a bug or a misunderstanding?

Miral
  • 12,637
  • 4
  • 53
  • 93
  • There's a bug in Git 2.34 `.gitignore` matching. It is fixed in Git 2.35.0. – torek Dec 14 '21 at 06:06
  • @torek Please repost that as an answer, if true; it's much more plausible than the other existing "answers". But also please cite your sources -- as far as I can see the latest available Git version is 2.34.1... – Miral Dec 14 '21 at 06:25
  • FWIW, despite there being a comment about fixing gitignores in the revision notes for 2.34.1, I have confirmed that this version still has the same problem as above. – Miral Dec 14 '21 at 06:32
  • You have 2.34.0.1, not 2.34.1. I don't have 2.34.1 or 2.35 myself to test at the moment, though. I'm going by the release notes. – torek Dec 14 '21 at 06:43
  • My last comment was after updating to `2.34.1.windows.1` which is the absolute latest at time of writing as far as I can see. – Miral Dec 14 '21 at 06:50
  • Ah, OK. Perhaps there are multiple bugs. The fix for 2.34.1 and 2.35 was to revert one offending commit, with a plan to revisit the idea again later: the code that broke things was trying to improve nonlinear (either n^2 or 2^n exponential behavior) for certain cases. The Git mailing list folks could use some sample `.gitignore` files as torture tests to make sure that the bug is really fixed and stays fixed, so if you can condense your case down to a simple version, and send it in, that would be good. – torek Dec 14 '21 at 07:03
  • @torek [There is no bug](https://git-scm.com/docs/gitignore#_pattern_format). Instead, we have all been led on a wild goose chase, and gaslit into believing we didn't know what we were talking about, didn't read carefully, making "wild guesses" and writing "non-answers". In the end these descriptions applied to the OP. – Inigo Dec 14 '21 at 17:15
  • @Inigo: well, yes and no: `devl/**` means "don't bother reading subdirectories of `devl`" while `!devl/*.dat`means "do include files that are in `devl` and are named `*.dat`. But apparently Git reads `devl/test/` here. I'm not convinced the descriptions of `**` in the documentation are correct, myself (or perhaps the descriptions are the desired behavior and the actual behavior differs). I generally try to avoid `**` in gitignore patterns. – torek Dec 14 '21 at 18:33
  • @torek, the issue isn't with `**`, it's with whether `devl/**` only applies at the level of its `.gitignore` -- i.e. `/a/b/c/devl/**` but not `/a/b/c/d/devl`. According to the rules that's how it works. See the link at [my comment here](https://stackoverflow.com/questions/70343709/gitignore-double-star-not-working-recursively-from-intermediate-directories?noredirect=1#comment124359529_70345124). – Inigo Dec 14 '21 at 19:21
  • @Inigo: interesting: the reproducer in the github issue puts the `.gitignore` in `a/b`, but the question above puts it in `a/b/c`. That suggests that the reproducer in the github issue is not the intended one. A good reproducer is always important. :-) But yes, the question above has an `a/b/c/d/devl` so the `.gitignore` would need to be in `a/b/c/d` at this point. – torek Dec 14 '21 at 19:26
  • If by "the reproducer" you mean the reporter, it is none other than @Miral. – Inigo Dec 14 '21 at 19:36
  • The number of leading directories is irrelevant, so it doesn't matter whether the prefix is `/a/b/c` or `/a/b/c/d`, the important factor is the relative relationship between the gitignore file and the `devl` directory, which in both are always one directory apart, not the same dir. So the two examples were consistent in that regard. – Miral Dec 15 '21 at 00:32

6 Answers6

4

Unfortunately, you didn't read the documentation carefully enough...

If there is a separator at the beginning or middle (or both) of the pattern, then the pattern is relative to the directory level of the particular .gitignore file itself. Otherwise the pattern may also match at any level below the .gitignore level.

Your first pattern devl/** has a / at the middle, so it's relative to the directory /a/b/c/.

Therefore, /a/b/c/devl/test/foo.bar should be excluded, while /a/b/c/d/devl/test/foo.bar should not.

lzhh
  • 852
  • 7
  • 16
  • nice catch. I actually knew this too, hence my answer which worked... but got pissed on by @Miral because: (1) i didn't have time at the moment to analyze it, I actually have a life and kids to spend time with and (2) if I had time I'd have noticed looked right past his error (which is why I wrote "But I still haven't figured out why **/dev1/** doesn't." My eyes assumed he got that basic thing right). He pissed on another, "but you clearly do not actually understand the question; please do not just make guesses", even though he clearly did not understand the .gitignore rules. smh – Inigo Dec 14 '21 at 19:37
  • btw, the second part of your answer is correct but doesn't apply to this case as dev1 is not excluded and that was never part of the complaint. – Inigo Dec 14 '21 at 19:37
  • You are correct that I overlooked that having a `/` in the middle of the pattern also excludes recursive matching (although that seems nonsensical to me, but it is what it is). So this is indeed operating as intended, even if it's a silly design. As Inigo noted the second part is not applicable as `devl` itself is never excluded. – Miral Dec 15 '21 at 00:27
  • You two are right about the second part. `devl` itself is not excluded. I misunderstood on this. – lzhh Dec 15 '21 at 00:43
1

This works:

**/dev1/**
!**/dev1/*.dat

The reason this works and OP's doesn't is because of the .gitignore rules, as @lxvs correctly identifies.

Inigo
  • 12,186
  • 5
  • 41
  • 70
1

Maybe these two things could help: Cache and Order.

Remove the cache of all or of specific file(s).

git rm -r --cached .
git rm -r --cached <your_file_name.ext>

Change order

Each line in a gitignore file specifies a pattern. When deciding whether to ignore a path, Git normally checks gitignore patterns from multiple sources, with the following order of precedence, from highest to lowest (within one level of precedence, the last matching pattern decides the outcome):

This line is important: the last matching pattern decides the outcome

Maik Lowrey
  • 15,957
  • 6
  • 40
  • 79
  • 2
    Possibly useful advice in general, but this is not the problem here. No files had yet been added -- as already noted in the question, the files that should have been reported as ignored were reported as untracked, not added or committed. – Miral Dec 14 '21 at 05:11
  • @Miral merci for response. Have you tried this? `git update-index --assume-unchanged ` Article to this command: https://web.archive.org/web/20090926065622/http://www.pagebakers.nl/2009/01/29/git-ignoring-changes-in-tracked-files/ – Maik Lowrey Dec 14 '21 at 05:25
0

Try the following:

**/devl/*
!**/devl/*.dat

It worked for me and found the answer from exclamation mark in .gitignore doesn't work. The first line ignores everything inside devl and in the second line it is excluding .dat files.

T.H.Naseri
  • 57
  • 11
  • 2
    This is not an answer; I already posted the equivalent to this in my question, – Miral Dec 14 '21 at 04:55
  • @Miral you are welcome, actually this time I tried it practically and mine worked with the following: `**/devl/*` `!**/devl/*.dat` – T.H.Naseri Dec 14 '21 at 06:17
  • please try the above or refer [this question](https://stackoverflow.com/questions/65776556/exclamation-mark-in-gitignore-doesnt-work) it can surely help you. – T.H.Naseri Dec 14 '21 at 06:19
  • @Inigo you are right, actually after Miral said that my answer was just a wild guess, I started searching and testing for answers practically by creating a git repository. When I found the answer from the link in my answer, I edited my answer but after editing I noticed that you have already got the answer. It seems that I didn't refresh the page before editing to see your updated answer. I am really sorry for that. – T.H.Naseri Dec 14 '21 at 16:12
  • @Inigo you are right about `**` , too. Thanks a lot for the point. – T.H.Naseri Dec 14 '21 at 16:18
  • @T.H.Naseri no big deal. We all came up with the right answer independently because we read the `.gitignore` spec. But we also were belittled by the OP while we were earnestly trying to help, and we all got confused as a result. – Inigo Dec 14 '21 at 16:47
0

I would make sure to not ignore folders, before not ignoring a file.

If a folder is ignored, no amount of !myFile inside that folder would work.

So for your second nested .gitignore, try:

**/devl/
!**/devl/**/         <=== Important
!**/devl/*.dat

That being said, this should be tried with Git for Windows 2.34.1 (Nov. 2021), which includes a regression fix for 2.34.0

See commit 33c5d6c (19 Nov 2021) by Derrick Stolee (derrickstolee).
(Merged by Junio C Hamano -- gitster -- in commit 1bf2673, 22 Nov 2021)

dir: revert "dir: select directories correctly"

Reported-by: Danial Alihosseini
Signed-off-by: Derrick Stolee

This reverts commit f6526728f950cacfd5b5e42bcc65f2c47f3da654.

The change in f652672 ("dir: select directories correctly", 2021-09-24, Git v2.34.0-rc0 -- merge listed in batch #13) caused a regression in directory-based matches with non-cone-mode patterns, especially for .gitignore patterns. A test is included to prevent this regression in the future.

The commit ed495847 ("dir: fix pattern matching on dirs", 2021-09-24, Git v2.34.0-rc0 -- merge listed in batch #13) was reverted in 5ceb663 ("dir: fix directory-matching bug", 2021-11-02, Git v2.34.0-rc1 -- merge) for similar reasons. Neither commit changed tests, and tests added later in the series continue to pass when these commits are reverted.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • That is different from what I want, and is not the problem. But good try. – Miral Dec 14 '21 at 07:32
  • @Miral As far as I know, that does *exactly* " ignore any directory called `devl`, except for one particular file extension directly inside". Did you test it? – VonC Dec 14 '21 at 07:33
  • Your answer would also not ignore `*.dat` files in subdirectories, but I do still want to ignore those. ("**Directly**" was not a mistake.) If you remove that part, then it is identical to what I already posted at the end of my own question (and several previous answers from people who did not read that). – Miral Dec 14 '21 at 07:36
  • @Miral What you have posted does not whitelist folders. That is the all point behind my answer, and what is missed by others. You need to explicitly whetelist folders. I have fixed the "direct" part. Again. Did you test it? – VonC Dec 14 '21 at 07:41
  • What I posted **deliberately** does not whiltelist folders, because they should not be whitelisted. It also does not blacklist the `devl` folder, so that the `*.dat` re-inclusion still works. Did **you** test it? – Miral Dec 14 '21 at 07:43
  • @Miral But, my all point of my all point is, again, whitelisting a file won't work if any of its parent folder is itself ignored. That is how Git `.gitignore` always worked. And yes, I [tested it before](https://stackoverflow.com/a/69970899/6309). – VonC Dec 14 '21 at 07:44
  • To put this another way: if what you think is the problem were actually the problem, then I would be asking why my `.dat` file was being ignored. That is **not** the question. I am asking why **nothing** in the `devl` folder and subfolders is being ignored. – Miral Dec 14 '21 at 07:45
  • @Miral Got it. I have edited the answer to include the regression fix from 2.34.1. – VonC Dec 14 '21 at 07:56
-1

This appears to be a bug in git; I have posted a report to their issue tracker.

Miral
  • 12,637
  • 4
  • 53
  • 93
  • 2
    Apparently [not](https://github.com/git-for-windows/git/issues/3587#issuecomment-993629010). – Inigo Dec 14 '21 at 15:10