Gitignore Explained: What is Gitignore and How to Add it to Your Repo
If you‘ve spent any time working with Git repositories, you‘ve likely encountered a file named .gitignore
. This unassuming file plays a crucial role in keeping your repositories clean, focused, and secure. In this comprehensive guide, we‘ll dive deep into everything you need to know about .gitignore
files and how to use them effectively in your projects.
What is .gitignore?
At its core, .gitignore
is a simple text file that tells Git which files and directories to ignore when committing changes to your repository. Each line in the file specifies a file, folder, or pattern that Git should disregard. When you commit changes, Git automatically ignores any files or directories that match the patterns defined in your .gitignore
file.
So why is this useful? Not every file in your project needs to be tracked by Git. In fact, tracking certain types of files can cause problems. Here are a few common examples of files you‘ll often want to exclude:
- Compiled source code (e.g.,
.class
files for Java,.pyc
files for Python) - Packages and compressed files (e.g.,
.jar
,.zip
,tar.gz
) - Log files and databases
- Files generated by your operating system (e.g.,
.DS_Store
on macOS,Thumbs.db
on Windows) - User-uploaded assets like images, PDFs, and videos
- Files containing sensitive information such as API keys, credentials, and secrets
By ignoring these types of files, you can keep your repository focused on the essential source code and assets that matter. This not only helps keep your repository more manageable but also prevents accidentally exposing sensitive data.
According to a study by the University of Waterloo, nearly 100,000 GitHub repositories have potentially leaked API or cryptographic keys (Meli, M., McNiece, M. R., & Reaves, B., 2019). By properly utilizing .gitignore
, you can help mitigate this risk in your own projects.
Creating a .gitignore File
To create a .gitignore
file, simply create a new text file in your repository‘s root directory and name it .gitignore
(note the leading dot).
Each line in this file specifies a file, folder, or pattern for Git to ignore. Here‘s an example of what a .gitignore
file might look like:
# Ignore compiled Python files
*.pyc
# Ignore log files
*.log
# Ignore the build directory
/build
# Ignore node dependency directories
node_modules/
# Ignore API keys file
api_keys.js
Let‘s break this down:
- Lines starting with
#
are comments and are ignored by Git *.pyc
tells Git to ignore any files ending with.pyc
*.log
ignores all files with the.log
extension/build
ignores thebuild
directory in the repository rootnode_modules/
ignores any directory namednode_modules
api_keys.js
ignores a specific file namedapi_keys.js
Glob Patterns
.gitignore files use glob patterns, not regular expressions, to match against file names. Glob patterns are a simplified way to specify sets of filenames with wildcard characters. Here are some common patterns:
*
matches any number of characters, except /?
matches any single character[abc]
matches any character inside the brackets (in this case a, b, or c)[0-9]
matches any single digit from 0 to 9**
matches nested directories (e.g.,a/**/b
matchesa/b
,a/c/b
,a/c/d/b
, and so on)/
at the end of a pattern matches directories only!
at the start of a pattern negates it (forces Git to not ignore these files)
Here‘s a more complex .gitignore
example demonstrating some of these patterns:
# Ignore all .a files
*.a
# But do track lib.a, even though you‘re ignoring .a files above
!lib.a
# Only ignore the TODO file in the current directory, not subdir/TODO
/TODO
# Ignore all files in any directory named build
build/
# Ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt
# Ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf
It‘s important to remember that .gitignore
uses glob patterns, not regular expressions, to match against file names.
Creating a Global .gitignore
In addition to project-specific .gitignore
files, you can also create a global .gitignore
file that applies to all of your Git repositories. This is useful for ignoring files that you never want to commit, regardless of which repository you‘re working in.
To create a global .gitignore
file, run the following command in your terminal:
git config --global core.excludesfile ~/.gitignore_global
This will create a new file called .gitignore_global
in your user‘s home directory. You can then edit this file and add any files or patterns you want to be globally ignored.
Some common entries in a global .gitignore
might include:
- Operating system files (
.DS_Store
,Thumbs.db
) - Editor backup files (
*~
,.swp
) - Personal IDE config directories (
.idea/
,.vscode/
)
Using a global .gitignore
can help keep your project-specific .gitignore
files more concise and focused on ignores unique to that project.
Untracking Previously Committed Files
If you‘ve previously committed a file that you now want Git to ignore, simply adding it to your .gitignore
isn‘t enough. Git will continue tracking any files that are already being tracked, even if they match a pattern in .gitignore
.
To untrack a single file that you‘ve previously committed, you can use the following command:
git rm --cached filename
This removes the file from Git‘s index (staging area) without deleting it from your working directory.
If you want to untrack all files listed in your .gitignore
, you can use this process:
- Commit any outstanding code changes
- Run
git rm -r --cached .
to recursively remove all files from the index - Run
git add .
to re-add all files, respecting the rules in.gitignore
- Commit the changes with
git commit -m "Untrack files in .gitignore"
If you accidentally run git rm --cached
on a file and want to undo it, you can use git add filename
to start tracking the file again.
Debugging .gitignore Files
If Git is still tracking files that you expect to be ignored based on your .gitignore
, you can use the git check-ignore
command to diagnose the issue:
git check-ignore -v path/to/file
This will show the specific pattern in .gitignore
that‘s causing the file to be ignored (or not ignored).
Precedence Rules
When you have multiple .gitignore
files in your repository (e.g., in subdirectories), how does Git handle conflicting patterns? Here are the precedence rules:
- Patterns in the deepest
.gitignore
file in a directory tree take precedence over higher-level ones. - Within a single
.gitignore
file, later patterns override earlier ones.
For example, consider this repository structure:
/
.gitignore
foo/
.gitignore
bar.txt
If /.gitignore
contains foo/
, and /foo/.gitignore
contains !bar.txt
, then bar.txt
will not be ignored, because the deeper /foo/.gitignore
takes precedence.
Ignoring Files Without .gitignore
Sometimes, you may want to ignore certain files in your local repository without committing those ignore rules to .gitignore
(which would affect all other users of the repository).
To do this, you can create a file named .git/info/exclude
in your repository. This file follows the same pattern format as .gitignore
, but is not committed with your repository, so it only applies to your local copy.
The Risks of Over-Ignoring
While .gitignore
is a powerful tool for keeping unwanted files out of your repository, it‘s possible to take it too far. If you ignore too much, you can end up with a repository that:
- Is harder for other developers to use, because they can‘t reproduce your full working environment from the repository alone.
- Hides bugs that only occur when certain ignored files are present.
- Breaks the "single source of truth" principle by requiring extra setup outside of what‘s committed to the repository.
As a general rule, you should only ignore generated files that can be recreated from the committed source. For example, it‘s usually fine to ignore compiled binaries (which can be rebuilt from source), but not fine to ignore all configuration files (which may be needed to run the compiled binary).
When to Force-Add Ignored Files
In some situations, you may actually want to force-add a file to your repository even though it matches an ignore pattern. Some common examples:
- Committing a specific configuration file that‘s needed to build or run the project, even though you normally ignore all
.config
files. - Generating code coverage reports, which often go into directories that are usually ignored.
- Committing lock files (
Gemfile.lock
,yarn.lock
, etc.) in some languages to ensure all developers use the same dependencies, even though you normally ignore installed dependencies.
To force-add an ignored file, use:
git add -f filename
Use this sparingly, and always double-check that you‘re not accidentally committing sensitive data!
Language-Specific .gitignore Templates
While you can craft your .gitignore
files from scratch, you don‘t always have to. For many popular languages and frameworks, the community has settled on a standard set of ignore patterns that are widely used.
Here are some examples:
Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# Virtual environments
venv/
.venv/
# Unit test / coverage reports
htmlcov/
.coverage
.coverage.*
# Sphinx documentation
docs/_build/
JavaScript
# npm
node_modules/
npm-debug.log*
# yarn
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
# Coverage directory used by tools like istanbul
coverage/
Java
# Compiled class file
*.class
# Package Files
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# build output directory
target/
You can find a extensive collection of .gitignore
templates for various languages and frameworks in GitHub‘s official gitignore repository.
Automatically Generating .gitignore Files
In addition to using templates, there are tools that can automatically generate .gitignore
files for you based on your project‘s language and dependencies.
Many IDEs, including IntelliJ IDEA, PyCharm, and NetBeans, can automatically create .gitignore
files when you create a new project. These generated files include common ignore patterns for the language and framework you‘re using.
There are also web-based tools, like gitignore.io, that can generate .gitignore
files based on a list of languages, IDEs, and operating systems you provide.
Writing Maintainable .gitignore Files
As your project grows, so too can your .gitignore
file. To keep it maintainable over time, consider adopting these practices:
- Use comments to explain why a pattern is being ignored. This can help future maintainers understand the rationale behind the ignores.
- Group related ignores together under comments that describe the group. This makes the file easier to scan and understand.
- Adopt widely used ignore patterns for your language and framework. This makes your
.gitignore
more familiar to other developers. - Avoid ignoring files that are essential to building or running the project. If a file is truly needed, it‘s better to commit it than to force all developers to recreate it.
Here‘s an example of a well-structured and commented .gitignore
file:
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it‘s better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
By taking the time to organize and document your .gitignore
, you can make it a valuable part of your project‘s documentation, rather than just a dumping ground for unwanted files.
Key Takeaways
.gitignore
is a file that specifies intentionally untracked files that Git should ignore- Each line in
.gitignore
file specifies a pattern for files/directories to ignore - Ignored files are usually build artifacts, machine generated files, or sensitive information
- You can create a global
.gitignore
for patterns you want ignored across all repositories - To untrack a file committed before adding it to
.gitignore
, usegit rm --cached
- Be careful not to over-ignore files, as it can make your project harder to use and hide bugs
- Organize and document your
.gitignore
file to keep it maintainable over time - Use language-specific templates and generation tools to create effective
.gitignore
files
Properly utilizing .gitignore
is an essential skill for any developer working with Git. By understanding how to write and maintain effective .gitignore
files, you can keep your repositories clean, focused, and secure. Armed with the knowledge from this guide, you‘re well-equipped to manage unwanted files in your Git projects with confidence!
References
- Meli, M., McNiece, M. R., & Reaves, B. (2019). How Bad Can It Git? Characterizing Secret Leakage in Public GitHub Repositories. In NDSS.
- Git documentation: gitignore
- GitHub: Ignoring Files
- GitHub: Collection of gitignore templates
- gitignore.io: Create Useful .gitignore Files For Your Project