As you work on your projects, not every file belongs in your version control history. Build artifacts, log files, temporary editor files, operating system specific files (like .DS_Store
on macOS or Thumbs.db
on Windows), and directories containing downloaded dependencies (like node_modules
in JavaScript projects) are typically generated during development or specific to a user's environment. Tracking these files can clutter your repository, make merges more difficult, and unnecessarily increase the repository size.
Git provides a straightforward way to specify intentionally untracked files that Git should ignore. This is done using a special file named .gitignore
.
You create a file named exactly .gitignore
(note the leading dot) in the root directory of your Git repository. Inside this file, you list patterns for filenames or directory names that Git should ignore. Each line in the .gitignore
file specifies a pattern.
When deciding whether to ignore a path, Git normally checks .gitignore
patterns from multiple sources, with higher precedence patterns overriding lower precedence ones:
.gitignore
file in the same directory as the path, or in any parent directory, with patterns in closer directories taking precedence.$GIT_DIR/info/exclude
.core.excludesFile
(which defaults to ~/.config/git/ignore
or ~/.gitignore
).A file matching a pattern in .gitignore
will typically not be listed as "Untracked files" by git status
, and Git will prevent you from accidentally adding it with commands like git add .
.
The rules for the patterns are simple yet flexible:
#
are ignored. This allows for comments and spacing for readability.*
) matches zero or more characters (e.g., *.log
matches any file ending with .log
).?
) matches exactly one character.[]
) match one character from a specified range or set (e.g., [abc]
matches a
, b
, or c
)./
) specify directories. For example, build/
ignores the directory named build
and everything inside it./
) anchor the pattern to the repository root. For example, /TODO
matches only the TODO
file in the root directory, not src/TODO
. If there's no leading slash, the pattern matches any file or directory with that name anywhere in the repository.!
which negates the pattern; any matching file excluded by a previous pattern will become included again. If a file matches both a regular pattern and a negated pattern, the negated pattern (!
) wins if it appears later in the file. It's not possible to re-include a file if a parent directory of that file is excluded.Here's an example .gitignore
file illustrating common patterns:
# Ignore OS-generated files
.DS_Store
Thumbs.db
# Ignore log files
*.log
npm-debug.log*
# Ignore build output directories
/build/
/dist/
# Ignore dependency directories
/node_modules/
/vendor/
# Ignore editor/IDE specific files
.vscode/
.idea/
*.swp
# Ignore sensitive configuration (better stored elsewhere)
config.local
# Example of negating: ignore all .txt except important.txt
*.txt
!important.txt
.gitignore
.Important: The .gitignore
file itself should be added and committed to your repository. This ensures that the ignore rules are shared with anyone else who clones the repository, leading to consistent behavior for all collaborators.
# Check status, .gitignore might show as untracked
git status
# Stage the .gitignore file
git add .gitignore
# Commit the .gitignore file
git commit -m "Add .gitignore file"
# Check status again, ignored files should no longer appear as untracked
git status
Once .gitignore
is in place and committed, files matching its patterns will generally be invisible to Git's tracking mechanisms, helping you keep your repository focused on the essential source code and configuration. If you need to track a file that was previously ignored (perhaps you added a pattern too broadly), you can remove or modify the pattern in .gitignore
and then use git add -f <filename>
to force-add it. However, typically, files listed in .gitignore
are meant to stay untracked.
© 2025 ApX Machine Learning