Home > Enterprise >  Unexpected behavior with .gitignore, git-status and git-check-ignore
Unexpected behavior with .gitignore, git-status and git-check-ignore

Time:09-23

I am using Git for Windows version 2.34.1 x86. I have a folder with the following contents (all path names are relative to that folder):

.git/
.gitignore
.vs/OS1/FileContentIndex/a
.vs/OS1/v17/Browse.VC.db
.vs/OS1/v17/Solution.VC.db
.vs/OS1/v17/ipch/AutoPCH/a
econv.txt

As we can see, the folder itself is under Git control. However, none of the files or folders shown above have ever been staged or committed yet, except .gitignore, which is already tracked.

I am unable to understand the different behavior of git status vs. git check-ignore in the following two situations:

Situation 1

.gitignore has the following content:

/.vs/**/
!*/

git status outputs (shortened to the interesting part)

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .vs/OS1/FileContentIndex/
        .vs/OS1/v17/Browse.VC.db
        .vs/OS1/v17/Solution.VC.db
        .vs/OS1/v17/ipch/
        econv.txt

git check-ignore -v .vs/OS1/FileContentIndex/ outputs

.gitignore:3:!*/        .vs/OS1/FileContentIndex/

which means that .vs/OS1/FileContentIndex/ is not ignored. This is consistent with the above output of git status. So far, so good.

Situation 2

.gitignore has been changed minimally and now contains

/.vs/**
!*/

git status outputs (shortened to the interesting part)

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        econv.txt

git check-ignore -v .vs/OS1/FileContentIndex/ outputs

.gitignore:3:!*/        .vs/OS1/FileContentIndex/

The question

I understand the behavior in situation 1. git check-ignore .vs/OS1/FileContentIndex/ tells me that .vs/OS1/FileContentIndex/ is not ignored, and therefore git status puts it into the list of untracked files (it has not been added, staged or committed yet).

But I am unable to understand the behavior in situation 2. Here, git check-ignore .vs/OS1/FileContentIndex/ yields literally the same output as in situation 1, which again means that .vs/OS1/FileContentIndex/ is not ignored.

However, git status does not have it in the list of untracked files any more. This seems inconsistent to me, because it should appear in the list of untracked files if it is not ignored, shouldn't it?

Could somebody please explain what is going on there?

CodePudding user response:

Git never stores any directories (folders). But .gitignore directives can make Git not look inside folders, so things get confusing here.

This rule:

/.vs/**/

applies only to folders, and tells Git "do not look inside these folders".

This rule:

!*/

also applies only to folders, and tells Git: "do look inside every folder, every time". Since this second rule comes later, it overrides the first rule. Since the second rule completely overrides the first rule, the first rule is irrelevant and can be removed without changing any behavior.

When you change the first rule to:

/.vs/**

it now applies to both folders and files. This tells Git that for each untracked file in .vs, that file should not be added. As all folders are by definition untracked, they're also to be "ignored" (i.e., not looked-inside). However, the next (unchanged) rule overrides this status for folders, so folders are inspected, even if they are under .vs/. Once inspected, all untracked files in those folders are ignored via the first rule. So that first rule now matters!

So:

git status does not have [.vs/OS1/FileContentIndex/] in the list of untracked files any more.

The git status command reports on untracked files, not untracked folders (all folders are by definition untracked and this would therefore be noisy and useless). But git status will summarize a whole bunch of files by stripping off the file name portion and mentioning only the containing folder, unless you use one of the git status options that prevents this.

The first git status listing:

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .vs/OS1/FileContentIndex/
        .vs/OS1/v17/Browse.VC.db
        .vs/OS1/v17/Solution.VC.db
        .vs/OS1/v17/ipch/
        econv.txt

really means:

  • multiple files within .vs/OS1/FileContentIndex/, not individually listed;
  • .vs/OS1/v17/Browse.VC.db, individually listed
  • .vs/OS1/v17/Solution.VC.db, individually listed
  • multiple files within .vs/OS1/v17/ipch/, not individually listed
  • econv.txt, individually listed

To make git status list the specific files within some folder that would otherwise be grouped together like this, use -uall or the longer spelling, --untracked-files=all.

Put another way ...

To put this another way:

  • If a folder contains no files at all, it's never listed in git status output. Empty folders cannot be added. See also How do I add an empty directory to a Git repository? (there's a trick with fake or semi-fake submodules that works for this).
  • If a folder contains some files, but all of those files are both currently untracked and ignored, it's not listed in git status output either. That's the case for your second .gitignore set of rules, which carefully ignore all the files within the .vs folder even while carefully looking (recursively) all the way down into all sub-folders (wasted effort by definition).
  • If a folder contains some tracked files but they're not modified, those files aren't listed in git status output. Only if they're modified do they get listed.1

1"Modified" here includes newly-added or deleted when in the "changes staged for commit" output section. That's because this is a a git diff --name-status between the HEAD commit and the current index content. By definition, though, the "not staged for commit" section includes only deleted or modified, not new, files. That's because this second section's output is from a comparison between what's in Git's index and what's in your working tree, and if the file is not present in Git's index, it is by definition untracked, so any mention of it—if there is to be any such—belongs in the "untracked files" section.

  •  Tags:  
  • git
  • Related