Have you ever wondered what kind of patterns
.gitignore allows? Was it
*target*?? Read on and find out!
Everyone who uses Git sooner or later has to define a
.gitignore in a newly created project. We simply don’t want to version control everything, especially generated files like Maven’s
target or Gradle’s
build folder. So how exactly can we specify which files to exclude? Can we use Ant-style syntax like
**/*, simple Wildcards
*target or even Regex
There is only one source of truth. The official Git documentation on
If only people would read this before posting to Stackoverflow…
As it turns out Git does not use regex, nor wildcards, nor Ant-style syntax, but unix glob patterns (specifically those valid for
fnmatch(3)). Don’t worry, you don’t need to read the
fnmatch(3) documentation, simply refer to the tables in the next sections.
First things first, how can we exclude every
target folder created by Maven in every sub-module?
The answer is very easy:
This will match any directory (but not files, hence the trailing
/) in any subdirectory relative to the
.gitignore file. This means we don’t even need any
* at all.
Here is an overview of the most relevant patterns:
|.gitignore entry||Ignores every…|
|target/||…folder (due to the trailing /) recursively|
|target||…file or folder named target recursively|
|/target||…file or folder named target in the top-most directory (due to the leading /)|
|/target/||…folder named target in the top-most directory (leading and trailing /)|
|*.class||…every file or folder ending with .class recursively|
For more complicated use cases refer to the following table:
|.gitignore entry||Ignores every…|
|#comment||…nothing, this is a comment (first character is a #)|
|\#comment||…every file or folder with name #comment (\ for escaping)|
|target/logs/||…every folder named logs which is a subdirectory of a folder named target|
|target/*/logs/||…every folder named logs two levels under a folder named target (* doesn’t include /)|
|target/**/logs/||…every folder named logs somewhere under a folder named target (** includes /)|
|*.py[c]||…file or folder ending in .pyc or .pyo. However, it doesn’t match .py!|
|!README.md||Doesn’t ignore any README.md file even if it matches an exclude pattern, e.g. *.md. |
NOTE This does not work if the file is located within a ignored folder.
target/ *.class *.jar *.war *.ear *.logs *.iml .idea/ .eclipse
# ignore everything ... /* # ... but the following !/.profile !/.bash_rc !/.bash_profile !/.curlrc
There are several locations where Git looks for ignore files. Besides looking in the root folder of a Git project, Git also checks if there is a
.gitignore in every subdirectory. This way you can ignore files on a finer grained level if different folders need different rules.
Moreover, you can define repository specific rules which are not committed to the Git repository, i.e. these are specific to your local copy. These rules go into the file
.git/info/exclude which is created by default in every Git repository with no entries.
One useful file you can define yourself is a global ignore file. It doesn’t have a default location or file name. You can define it yourself with the following command:
git config --global core.excludesfile ~/.gitignore_global
Every rule which goes into this file applies to every Git repository in your user account. This is especially useful for OS-specific files like
.DS_Store on MacOS or
thumbs.db on Windows.
As we have seen it is fairly easy to ignore files and folders for the typical use cases. Even though ignore rules don’t support regex,
gitignore is highly flexible and can be adapted to more complicated project structures using unix globs and different files on different levels.
So now you know. Go ahead, rework your existing
.gitignore files and add a global ignore file to you system!
For each and every detail on
gitignore refer to these resources.