gitignore and gitattributes¶
Overview¶
Without .gitignore, engineers commit .terraform/ directories, node_modules/, and .env files containing secrets — triggering security incidents and bloated repositories. Without .gitattributes, Windows and Linux developers fight line-ending wars in YAML and shell scripts. These two files are infrastructure-as-code hygiene essentials.
This is Tutorial 12 in Module 4: Collaboration of the REBASH Academy Git series.
Prerequisites¶
Learning Objectives¶
By the end of this tutorial, you will be able to:
- Write
.gitignorepatterns for common DevOps stacks - Understand gitignore precedence and negation rules
- Remove accidentally tracked files from Git history scope
- Configure
.gitattributesfor line endings and diff behavior - Mark binary files and generated files appropriately
- Use global gitignore for personal editor files
- Apply linguist and export-ignore attributes for GitHub
Ignore Flow Diagram¶
flowchart TB
FILES[Working Directory Files]
GI[.gitignore patterns]
GA[.gitattributes rules]
STAGE["git add / staging"]
REPO[Repository]
FILES --> GI
GI -->|excluded| SKIP[Not tracked]
GI -->|allowed| STAGE
GA --> STAGE
STAGE --> REPO```
## Theory
### .gitignore Purpose
Gitignore tells Git which files to **ignore** — never stage or commit unless forced with `git add -f`.
Patterns apply to:
- Untracked files (primary use)
- Already tracked files are NOT ignored until removed from index
### Pattern Syntax
| Pattern | Matches |
|---------|---------|
| `*.log` | Any `.log` file in any directory |
| `/build/` | `build/` at repo root only |
| `**/tmp/` | `tmp/` anywhere |
| `!important.log` | Negation — do track this file |
| `config/**` | Everything under config/ |
Later rules override earlier; negation un-ignores specific paths.
### DevOps gitignore Essentials
**Terraform:**
```gitignore
.terraform/
*.tfstate
*.tfstate.*
.terraform.lock.hcl
# Note: some teams commit .terraform.lock.hcl — document policy
crash.log
override.tf
*.tfvars
!example.tfvars Python:
Kubernetes / general:
Use templates from gitignore.io or GitHub's gitignore repository.
Global gitignore¶
Personal editor files shouldn't be in project gitignore:
Removing Tracked Files That Should Be Ignored¶
git rm --cached secrets.env
git commit -m "chore: stop tracking secrets.env"
echo "secrets.env" >> .gitignore
--cached removes from index only — keeps local file.
.gitattributes Purpose¶
Controls how Git handles files:
- Line ending normalization (
text,eol=lf) - Diff driver (how diffs display)
- Merge strategy for specific files
- Linguist language detection (GitHub)
- Export-ignore for archive
Line Endings¶
* text=auto lets Git normalize line endings on checkout/commit — critical for cross-platform teams editing YAML and shell scripts.
Custom Diff Drivers¶
Requires config:
Merge Strategies for Lock Files¶
Controversial — many teams regenerate lock files post-merge instead.
export-ignore¶
Exclude CI artifacts from git archive:
Hands-on Lab¶
Step 1 – Create repo and demonstrate ignore¶
Command:
mkdir -p /tmp/gitignore-lab && cd /tmp/gitignore-lab
git init -b main
cat > .gitignore << 'EOF'
*.log
.terraform/
.env
!example.env
EOF
echo "secret=1" > .env
echo "secret=example" > example.env
echo "debug" > app.log
mkdir .terraform && echo "state" > .terraform/plugin
git status
Explanation: .env and .log ignored; example.env tracked via negation.
Step 2 – Commit allowed files¶
Command:
git add .
git status
git commit -m "chore: add gitignore and example env"
git check-ignore -v app.log .env example.env
Step 3 – Add gitattributes¶
Command:
cat > .gitattributes << 'EOF'
* text=auto eol=lf
*.sh text eol=lf
*.png binary
*.md diff=markdown
EOF
echo '#!/bin/sh' > deploy.sh
echo 'echo deploy' >> deploy.sh
git add .gitattributes deploy.sh && git commit -m "chore: add gitattributes"
Step 4 – Remove accidentally tracked file¶
Command:
echo "oops" > .env
git add -f .env && git commit -m "mistake: tracked secret"
git rm --cached .env
git commit -m "chore: untrack .env"
git status
test ! -f .env && echo "file missing" || echo ".env still on disk"
Step 5 – Verify attributes¶
Command:
Step 6 – Clean up¶
Command:
Commands & Code¶
| Command | Description | Example |
|---|---|---|
git check-ignore -v file | Why file is ignored | git check-ignore -v .env |
git rm --cached file | Untrack without deleting | git rm --cached secrets.env |
git add -f file | Force add ignored file | Rare — usually wrong |
git check-attr -a file | Show attributes | git check-attr -a deploy.sh |
git config core.excludesfile | Global ignore path | Set global gitignore |
Terraform starter .gitignore¶
# Local .terraform directories
.terraform/
# .tfstate files contain sensitive data
*.tfstate
*.tfstate.*
# Variable files with secrets
*.tfvars
*.tfvars.json
!terraform.tfvars.example
# CLI config
.terraformrc
terraform.rc
# Crash logs
crash.log
crash.*.log
Common Mistakes¶
Committing .terraform.lock.hcl without team policy
Hashicorp recommends committing lock file for provider consistency. Document whether your org commits it.
gitignore does not untrack existing files
Must git rm --cached after adding pattern for already-tracked files.
Overly broad ignore patterns
*.yaml ignoring all YAML breaks K8s manifests. Be specific.
Missing binary attribute on images
Git may corrupt binary files with line-ending conversion. Mark binary.
Best Practices¶
Commit example env files
example.env or terraform.tfvars.example with dummy values — never real secrets.
Scan repos for secrets in CI
gitignore is not foolproof. Use gitleaks or trufflehog in pipelines.
Standardize gitattributes org-wide
Platform team maintains template copied into new repos.
Review gitignore in every new repo PR
First commit should include stack-appropriate ignore rules.
Troubleshooting¶
| Issue | Cause | Solution |
|---|---|---|
| File still tracked after gitignore | Already in index | git rm --cached |
| Negation not working | Order wrong | Put ! pattern after ignore |
| CRLF in Linux CI | Missing gitattributes | Add * text=auto eol=lf |
| Huge repo size | Committed artifacts | BFG/filter-repo; fix gitignore |
| check-ignore shows nothing | File not ignored | Verify pattern syntax |
| Wrong diff for generated file | Missing -diff attribute | generated.xml -diff |
Summary¶
- .gitignore excludes files from tracking — essential for secrets, build output, and local state
- Negation patterns (
!) re-include specific files under broad rules - git rm --cached stops tracking without deleting local files
- .gitattributes controls line endings, binary handling, and diff/merge behavior
- DevOps repos need stack-specific patterns for Terraform, Python, Node, and secrets
Interview Questions¶
- What is the purpose of .gitignore?
- How do you stop tracking a file without deleting it locally?
- What does the negation pattern
!important.logdo? - Why doesn't gitignore affect already-tracked files?
- What is .gitattributes used for?
- What should a Terraform .gitignore include?
- What does
* text=auto eol=lfaccomplish? - What is a global gitignore, and when use it?
- Why mark files as
binaryin gitattributes? - How would you prevent secrets.env from ever being committed again?
Sample Answers (Questions 2 and 6)
Q2 — Untrack without delete: Run git rm --cached filename to remove from index while keeping the working tree file. Commit the change. Add filename to .gitignore so it won't be re-added. Local file remains for developer use.
Q6 — Terraform gitignore: Exclude .terraform/ provider cache, *.tfstate and backups (contain secrets), local *.tfvars with credentials, override files, crash logs. Optionally include .terraform.lock.hcl per team policy. Include !example.tfvars for documentation templates.
Related Tutorials¶
- Pull Requests and Code Review (previous)
- Undoing Changes — Reset, Revert, and Stash (next — Module 5)
- Basic Git Workflow — Add, Commit, Push
- Git Installation and Configuration
- Git – Category Overview