Here is my file folder.
- a
- b
- b1.txt
- b2.txt
- a1.txt
- a2.txt
- b
- .gitignore
Firstly:
I found if I wanna ignore the folder a, a/
and a/*
and a/**
all can complete.
Secondly:
I wanna ignore all the things in folder a except the folder b, the only way to do this is :
a/*
!a/b/
I don't know why a/**
can't do this?
# this way can't except folder b
a/**
!a/b/
Or you can tell me how can I use a/**
?
To a first approximation, Git doesn't "do" directories ("folders") at all.
Gitignore files are an exception to this rule, but in a tricky way.
First, Git is mainly about files. Files are either tracked or untracked. A file is untracked if and only if it is not currently in the index. Note that Git can read its own index very quickly, usually much faster than the underlying operating system can read through directory trees ("folders and subfolders").
Next,
gitignore
rules are mainly about files, since only files can be untracked or become tracked. Whengit status
says that some directory ("folder") is untracked, what it means is that there are one or more untracked files contained within that directory. (Usinggit add
works similarly, except that instead of "complain about", the action to be taken is "copy into index".)In order to find untracked files, Git would have to open and read every directory (or "folder") in your work-tree. To make Git perform faster, however, Git uses this trick:
a
ora/b
) names a directory, anda/b/b1.txt
and noa/a2.txt
in the index, for instance), andGit skips reading the directory P entirely. It never looks to see if there are any untracked files within it. It does this because reading directories in Linux (and other OSes) is relatively slow.
So now we come to a pattern like
a/*
ora/**
, where eithera
is currently not ignored, or there are files in the index whose paths start witha/
. In order to decide whether there are files ina
that are untracked and should be complained-about (if not ignored) or not-complained-about (if ignored), Git must read directorya
.Having read directory
a
, Git finds that there are two filesa1.txt
anda2.txt
and a directoryb
. Assuminga1.txt
anda2.txt
are currently untracked, it scans all.gitignore
patterns to see if those match the two files. If not, Git complains about them (or adds them to the index). Butb
is a directory, so the optimization kicks in:b/
paths in the index, andb
matches thea/*
ora/**
ruleAs long as there is no
!a/b
or!a/b/
rule, Git will ignore directorya/b
at this point and never look inside it. It does not matter whether you use*
or**
.Should there be at least one tracked file in the index whose name starts with
a/b/
, however, the optimization fails. Or, if you override the ignore with!a/b
or!a/b/
, the directory itself is not ignored. In either of these cases, Git reads directorya/b/
. Having read the directory, Git will find filesa/b/b1.txt
anda/b/b2.txt
. It then checks whether these match a.gitignore
rule.As Vampire noted,
**
matches zero or more directories. (If the pattern ends with**
it also matches all files in those zero-or-more directories.) To make this have some action that differs froma/*
, so that we could see a difference, we would need additional levels of sub-directories (which we would need to force Git to read, either by explicitly un-ignoring at least one such asa/b/
with!
rules, or by having tracked files within them).(In experiments I ran a while ago, I found cases where
**
matches one or more directories in Git, instead of zero or more. I think this occurs in pathname expansion, e.g., if you usegit log -- 'a/**/file.txt'
for instance. So watch out: the ignore rules for**
matching may differ from other rules.)**
matches any amount of directories,*
only one.So if you e. g. ignore
/a/**/d/
, then/a/b/d/
and/a/b/c/d/
both are ignored.If you e. g. ignore
/a/*/d/
, then/a/b/d/
is ignored while/a/b/c/d/
is not ignored.If a folder is ignored, then Git does not even look at its contents to check for inclusions. That is why you cannot ignore
/a/
and then include/a/b/
, as Git does not even look into/a/
. Because of this you must instead ignore all contents in/a/
with/a/*
and then include/a/b/
to ignore everything in/a/
, except all contents of/a/b/
.try (without
/
):**
is used in ignoring "in any subdirectory", for example, you haveyou can ignore all
b1.txt
files in any subdirectories witha/**/b1.txt