The .gitignore File
Not every file in your project belongs in version control. Things like passwords, compiled programs, and downloaded libraries should stay on your machine and never be uploaded to a shared repository (a central copy of your code that your whole team can access). The .gitignore file is a plain text file that tells Git (the version control tool that tracks changes to your code) exactly which files and folders to ignore. Getting this right is one of the most important habits in DevOps, because a single committed secret can compromise your entire infrastructure.
What is .gitignore and why it matters
A .gitignore file lives in your project and contains a list of patterns (rules that match file and folder names). Any file that matches a pattern is invisible to Git: it will not be tracked, staged, or committed. This keeps your repository clean and, more importantly, safe.
There are three big reasons to use it:
- Secrets — files holding passwords, API keys (secret tokens that let your app talk to other services), and certificates must never leave your machine.
- Build artifacts — files your tools generate automatically, like compiled binaries or a
dist/folder. They can always be rebuilt, so storing them just bloats the repo. - Junk — editor settings, operating system files like
.DS_Store, and log files that nobody else needs.
When to use this: Create a
.gitignorefile the moment you start a new project, before your first commit. It is far easier to ignore a file from the start than to remove it after it has been committed.
Creating your first .gitignore
The file simply needs to be named .gitignore and placed in the root of your repository (the top folder). On Ubuntu you can create it from the terminal:
cd ~/my-project
nano .gitignore
Type your patterns, one per line, then save with Ctrl+O and exit with Ctrl+X. You can also create a quick starter file like this:
printf "node_modules/\n.env\ndist/\n*.log\n" > .gitignore
git add .gitignore
git commit -m "Add gitignore"
Output:
[main 4f1a9c2] Add gitignore
1 file changed, 4 insertions(+)
create mode 100644 .gitignore
Pattern syntax
The rules are short but powerful. Here is what each kind of pattern means.
| Pattern | Matches | Example |
|---|---|---|
name | A file or folder named name, anywhere | secret.txt |
name/ | Only folders named name | node_modules/ |
*.ext | Any file ending in .ext | *.log |
/name | Only name in the repo root, not subfolders | /build |
dir/*.ext | Files with that extension inside dir | logs/*.log |
**/name | name at any depth | **/.cache |
!name | A negation — do NOT ignore name even if a broader rule matched it | !important.log |
Lines starting with # are comments. Blank lines are ignored, so you can use them to group rules.
# Dependencies
node_modules/
# Environment files (secrets!)
.env
.env.local
# Build output
dist/
build/
*.o
# Logs
*.log
# But keep the example env
!.env.example
Common entries by stack
Different languages produce different junk. These are the entries you will reach for most often.
| Stack | Typical ignores |
|---|---|
| Node.js / JavaScript | node_modules/, dist/, .env, npm-debug.log |
| Python | __pycache__/, *.pyc, .venv/, .env |
| Java | target/, *.class, *.jar |
| Terraform (infrastructure code) | .terraform/, *.tfstate, *.tfvars |
| All projects | .DS_Store, *.log, .idea/, .vscode/ |
You do not have to memorize these. The site gitignore.io generates a complete file for your chosen tools.
A global .gitignore for your machine
Some files are junk on your computer specifically — for example your editor’s config or macOS’s .DS_Store. It is rude to push those rules into every project’s .gitignore, because your teammates may use different tools. Instead, set up a global gitignore that applies to every repository on your machine.
nano ~/.gitignore_global
Add your personal junk:
.DS_Store
.idea/
*.swp
.vscode/
Then tell Git to use it:
git config --global core.excludesFile ~/.gitignore_global
Output:
(no output — the command succeeds silently)
Now those files are ignored everywhere, and your project .gitignore can stay focused on project-specific rules.
When NOT to use a global ignore: Never put project-relevant rules (like
node_modules/) in the global file. New teammates cloning the repo would not have your global config, and they would accidentally commit those files.
Never commit secrets
This is the single most important rule in this entire guide. Never commit passwords, API keys, private keys, or .env files. Public and even private repositories get leaked, copied, and scanned by bots constantly. A secret pushed to GitHub can be found and abused within minutes.
Always add this before your first commit:
.env
.env.*
*.pem
*.key
credentials.json
secrets.yaml
Critical:
.gitignoreonly stops Git from tracking files that are not yet tracked. If a file is already committed, adding it to.gitignoredoes nothing — Git keeps tracking it. You must remove it from tracking explicitly.
What to do if you already committed a secret
If a secret made it into a commit, follow these steps. Do not panic, but act fast.
Step 1 — Rotate the secret immediately. This is the most important step. Assume the secret is now public forever. Log into the service (AWS, your database, your API provider) and generate a new key, then delete the old one. Cleaning Git history does NOT undo the exposure — only rotation does.
Step 2 — Stop tracking the file so it does not get committed again:
git rm --cached .env
echo ".env" >> .gitignore
git commit -m "Remove .env from tracking"
The --cached flag removes the file from Git but keeps it safely on your disk.
Step 3 — Scrub it from history (optional but recommended). The secret still exists in old commits. Use git filter-repo (the modern, supported tool) to erase it:
sudo apt update
sudo apt install git-filter-repo
git filter-repo --path .env --invert-paths
Output:
Parsed 47 commits
New history written in 0.21 seconds; now repacking/cleaning...
Completely finished after 0.83 seconds.
Then force-push the rewritten history (warn your team first, as this changes shared history):
git push origin --force --all
Best Practices
- Create
.gitignorebefore your first commit, never after. - Always ignore
.envand any file containing credentials — treat secrets as radioactive. - Commit a
.env.example(with fake values) so teammates know which variables to set. - Use a global gitignore for personal editor and OS junk, not the project file.
- If a secret leaks, rotate it first and clean history second — rotation is what actually protects you.
- Generate stack-specific files with gitignore.io instead of guessing.
- Review
git statusbefore every commit to catch files you did not mean to add.