100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Bash

.gitignore and Clean Repositories

Learn how .gitignore patterns keep build artifacts, secrets, and local config out of version control, and how to handle already-tracked files that should be ignored.

Advanced GitBeginner7 min readJul 9, 2026
Analogies

.gitignore and Clean Repositories

Not everything in a project directory belongs in version control. Compiled binaries, dependency folders like node_modules, IDE configuration, log files, and environment files containing secrets are all things you generally want present on disk but absent from your commit history. The .gitignore file tells Git which untracked files and directories to exclude from git status, git add ., and similar commands, keeping the repository focused on source code and intentional configuration. A clean, well-maintained .gitignore reduces noisy diffs, prevents accidental leaks of credentials, and keeps clone sizes manageable by excluding regenerable build output.

🏏

Cricket analogy: A team doesn't publish the practice-net footage or a bowler's private fitness diary alongside the official match highlights reel; .gitignore is like the production team's exclusion list keeping raw, sensitive, or bulky material out of the public broadcast package.

Pattern syntax

.gitignore uses a simple but expressive glob-based pattern language. A bare name like *.log matches that pattern anywhere in the tree; a pattern starting with / (e.g. /dist) is anchored to the repository root; a trailing / (e.g. build/) matches only directories; ** matches across directory boundaries (e.g. **/node_modules matches node_modules at any depth); and a leading ! negates a pattern, re-including something that would otherwise be excluded by an earlier rule — useful for carving out an exception like keeping one specific file inside an otherwise-ignored folder. Patterns are evaluated in order, and later, more specific rules can override earlier, broader ones, though a negation cannot un-ignore a file inside a directory that was itself ignored wholesale.

🏏

Cricket analogy: A ground's 'no cameras beyond this point' sign anchored only at the main gate (like /dist anchored to the root) differs from a blanket 'no filming' rule that applies at every entrance across the stadium (like **/node_modules matching at any depth), and a special 'except press box' exception (like ! negation) re-admits one specific spot.

bash
# Example .gitignore for a typical Node + Python full-stack project
node_modules/
dist/
build/
*.log
.env
.env.local
__pycache__/
*.pyc
.DS_Store
.vscode/
!.vscode/extensions.json

# Check which rule (and which .gitignore line) is causing a file to be ignored
$ git check-ignore -v config/.env
.gitignore:5:.env	config/.env

# See untracked files Git would ignore vs track
$ git status --ignored

# A .gitignore only affects UNTRACKED files — it has no effect on files
# already committed. To stop tracking a file while keeping it on disk:
$ git rm --cached secrets/local-config.json
$ echo "secrets/local-config.json" >> .gitignore
$ git commit -m "Stop tracking local-config.json; add to .gitignore"

Global and per-directory ignores

Beyond a project-level .gitignore committed to the repo, Git supports a global ignore file (configured via git config --global core.excludesfile ~/.gitignore_global) for personal, machine-specific patterns you don't want to impose on every collaborator — for example, your particular editor's swap files. Git also honors nested .gitignore files inside subdirectories, which apply only to that subtree and are useful for module-specific exclusions in a monorepo. Additionally, .git/info/exclude provides a local-only ignore mechanism that isn't committed or shared at all, handy for personal scratch files.

🏏

Cricket analogy: Beyond the team's official kit list, a player keeps a personal 'always pack my lucky wristband' checklist for themselves alone, the way a global .gitignore holds personal patterns; some grounds also post a local-only 'no photos in the changing room' notice, like .git/info/exclude, that never leaves that venue.

GitHub maintains a well-curated collection of starter .gitignore templates per language and framework (github.com/github/gitignore) — starting from one of these instead of writing from scratch avoids missing common, easy-to-forget patterns like OS-specific junk files or IDE folders.

Adding a pattern to .gitignore does NOT remove or untrack a file that's already committed — it only prevents new, untracked instances of matching files from being added going forward. If a secret like a .env file was already committed, ignoring it afterward leaves the secret sitting in history forever unless you actively rewrite history (e.g. with git filter-repo) and rotate the leaked credential.

  • .gitignore excludes untracked files from git status and git add, keeping build artifacts and secrets out of commits.
  • Patterns support globs, directory anchoring with /, recursive ** matching, and negation with !.
  • git check-ignore -v shows exactly which rule and file caused something to be ignored.
  • Ignoring a file that is already tracked has no effect until you explicitly git rm --cached it.
  • Global (core.excludesfile) and local-only (.git/info/exclude) ignores exist alongside the shared, committed .gitignore.
  • A leaked secret already committed must be removed via history rewrite and rotated, not just added to .gitignore.

Practice what you learned

Was this page helpful?

Topics covered

#Bash#GitVersionControlStudyNotes#SoftwareEngineering#GitignoreAndCleanRepositories#Gitignore#Clean#Repositories#Pattern#StudyNotes#SkillVeris