Torna al blog

.gitignore non funziona? Ecco il fix vero

17 settembre 2026

TL;DR: se .gitignore non funziona, il file è quasi sempre già tracciato. Git ignora i file che non ha mai visto — un file nell’indice è immune a qualunque regola tu scriva. Trova la verità con git check-ignore -v <path>: output silenzioso significa che il percorso è tracciato e nessuna regola vale. Sistemale con git rm --cached <path>, committa, e la regola di ignore comincia a valere da quel commit in poi. Ordine delle regole, trappole di negazione e falsi indizi di VS Code spiegano i casi rimanenti.

Perché .gitignore non funziona?

Un solo meccanismo copre la maggioranza dei casi: il file era stato committato prima che la regola esistesse. .gitignore non è un filtro che nasconde i file a git — è una regola su cosa git add deve raccogliere da uno stato non tracciato. Una volta che un file è nell’indice, git ne traccia le modifiche al contenuto per sempre, finché non lo sganci esplicitamente. Modificare .gitignore a posteriori non cambia nulla per i file tracciati, ed è per questo che la classica sequenza «committo .env, panico, aggiungo .env a .gitignore, ricommitto» spedisce comunque il segreto a ogni push.

Ci cascano in tanti perché git è quasi universale — lo Stack Overflow 2022 survey misura l’uso di Git oltre il 93% degli sviluppatori professionali (survey.stackoverflow.co) — e ognuno di quegli sviluppatori prima o poi scrive una regola per un file committato la settimana prima.

Il resto del post copre i casi minoritari: errori nell’ordine delle regole, trappole di negazione, casi limite delle cartelle e la questione IDE. Ma lancia prima il controllo di salute della sezione successiva — più di nove volte su dieci chiude l’indagine.

Come vedere quale regola gitignore corrisponde a un file?

git check-ignore è lo strumento diagnostico, e il suo silenzio è la diagnosi:

# Stampa la regola corrisposta + file + numero di riga quando una regola vale
git check-ignore -v debug.log
# .gitignore:3:*.log    debug.log

# NON stampa NULLA quando nessuna regola vale — il file è tracciato (o non esiste una regola)
git check-ignore -v src/.env
# (silenzio = .gitignore non sta ignorando questo percorso, qualunque cosa tu abbia scritto)

# Codici di uscita: 0 = ignorato, 1 = non ignorato — scriptabile
git check-ignore -q debug.log && echo "ignored" || echo "tracked or unruly"

Lettura dell’output di -v: la sorgente dell’ignore (.gitignore, .git/info/exclude, o il tuo file globale), poi line-number:pattern, poi il percorso. Se una regola successiva ti sorprende, ricorda la precedenza: vince l’ultima regola corrisposta, quindi !important.log dopo *.log re-include quello e solo quel file.

Perché gitignore non funziona sui file già committati?

Sgancia il file, tienilo su disco, committa la rimozione:

# Sgancia un file (la copia locale sopravvive — --cached tocca solo l'indice)
git rm --cached .env
git commit -m "stop tracking .env"

# Verifica che la regola di ignore ora valga
git check-ignore -v .env

Da questo commit in poi, .gitignore comanda sul percorso: le modifiche al file non compaiono più in git status, e git add . non lo riprende. Il file resta però nella cronologia — se era un segreto, toglierlo dall’ultimo commit non basta. Ruotare la credenziale è l’unico fix vero; riscrivere la cronologia è quello estetico (e git undo last commit: tenere le modifiche aiuta solo finché il commit cattivo è ancora la punta).

Per un repo pieno di roba committata in passato — output di build, residui dell’editor, node_modules entrati di soppiatto — lo sgancio di massa sono due righe:

git rm -r --cached .
git add .
git commit -m "apply .gitignore to tracked files"

Ricostruisce l’indice secondo le regole attuali: i percorsi ignorati cadono, tutto il resto viene riaggiunto identico. Il diff sembra drammatico (migliaia di cancellazioni) ma non cancella nulla dal disco. Se il tuo obiettivo è cancellare quei file e non solo sganciarli, è territorio git clean -fdx — vedi git remove untracked files, in sicurezza.

Git ignora i file che non ha mai visto. Un file già nell’indice è immune a .gitignore — nessuna regola lo farà dimenticare.

Perché gitignore non funziona su una cartella?

Tre trappole specifiche delle cartelle:

1. Le barre finali contano per l’intento, non per il matching. build e build/ corrispondono entrambi a una directory, ma build/ documenta che intendi solo una directory — un file di nome build le sopravvivrebbe. La simmetria però si rompe sulla re-inclusione (trappola successiva).

2. La negazione non può salvare i file dentro una directory esclusa. I documenti git sono inequivocabili: “It is not possible to re-include a file if a parent directory of that file is excluded” (git-scm.com/docs/gitignore). È una decisione di performance — git salta le directory escluse in blocco invece di percorrerle. Quindi questo non funziona:

build/
!build/keep.me        # regola morta — git non guarda mai dentro build/

Il fix è escludere il contenuto, non la directory:

build/*
!build/keep.me        # funziona — build/ in sé resta aperta all'ispezione

3. I .gitignore annidati vincono nel loro ambito. Le regole in subdir/.gitignore scavalcano il file root per i percorsi sotto subdir. Quando git check-ignore -v nomina una sorgente di ignore che non ti aspettavi, di solito è questo il motivo.

Perché gitignore non funziona in VS Code?

Quasi mai per colpa di VS Code. La vista Source Control legge lo stesso indice che legge git, quindi il sintomo è identico: il file era già committato, e nessun riavvio dell’IDE cambia l’indice. Due realtà adiacenti a VS Code vale la pena conoscere:

  • Explorer in grigio = ignorato; arancione/giallo = tracciato con modifiche. Un file che risulta modificato dopo che l’hai ignorato è la tua conferma che è tracciato — lancia il fix git rm --cached qui sopra.
  • Un .gitignore assente dalla lista changed dell’Explorer significa che la regola funziona — il file non compare mai come untracked in partenza. Spesso la gente segnala «VS Code ignora il mio gitignore» quando git status da CLI non concorda con una vista SCM stantia; ricarica la finestra (Cmd/Ctrl+Shift+P → “Reload Window”) prima di incolpare git.

.gitignore vs .git/info/exclude vs globale: quale e quando?

FileAmbitoCommittato?Per cosa
.gitignore (repo)Chiunque cloni il repoOutput di build, dipendenze, .env — regole condivise
.git/info/excludeSolo il tuo cloneNoRoba personale: .scratch/, residui dell’editor
core.excludesFile (globale)Tutti i tuoi repoNoRifiuti dell’OS: .DS_Store, Thumbs.db, *.swp
.gitignore + negazioneRepoRe-includere eccezioni a config tracciati

Il file globale è quello che la maggior parte degli sviluppatori non imposta mai e dovrebbe impostare:

git config --global core.excludesFile ~/.gitignore_global
printf '.DS_Store\nThumbs.db\n*.swp\n' >> ~/.gitignore_global

Regola di casa da copiare: se una regola giova a tutto il team, sta nel repo; se giova solo a te, sta in exclude o nel file globale. Committare regole di ignore personali è così che i .gitignore finiscono lunghi 300 righe e nessuno sa più quale metà conta ancora.

Come ignorare le modifiche a un file tracciato?

A volte vuoi un file tracciato (un template di config, un file di impostazioni dell’IDE) ma vuoi che le modifiche locali smettano di comparire in git status. Due flag su git update-index, nessuno dei quali appartiene a un workflow di team:

git update-index --skip-worktree config/local.dev   # le modifiche locali vanno in silenzio
git update-index --no-skip-worktree config/local.dev  # ...e si torna indietro

--skip-worktree è quello difendibile — dice «la mia versione locale diverge di proposito». Il cugino --assume-unchanged è una promessa di performance («questo file non cambierà»), non un meccanismo di ignore, e git può romperlo in silenzio. Entrambi i flag falliscono rumorosamente al pull quando anche upstream ha cambiato il file — le risposte durevoli sono una config solo locale via exclude fin dalla creazione, o un file template (config.example) che git traccia e tu copi.

Il controllo di salute di gitignore in 30 secondi

git check-ignore -v <path>        # quale regola? (silenzio = tracciato, nessuna regola)
git ls-files --error-unmatch <path>  # è tracciato o no?
git rm --cached <path>            # sgancia, tienilo su disco
git commit -m "stop tracking <path>"
git check-ignore -v <path>        # ora la regola appare

Diagnosi, sgancio, verifica. Il pattern dietro ogni segnalazione «gitignore not working» è lo stesso file con due cappelli — tracciato da un lato dell’indice, ignorato dall’altro — e un solo flag --cached toglie il secondo cappello.

FAQ

Perché .gitignore non funziona?

Nella maggior parte dei casi il file è già tracciato. Git ignora solo i file non tracciati; un file nell'indice è immune a .gitignore finché non lo sganci con git rm --cached e committi.

Come controllo quale regola gitignore corrisponde a un file?

Lancia git check-ignore -v <path>. Stampa la riga esatta di .gitignore e il numero di riga, oppure esce in silenzio quando il file è tracciato e nessuna regola si applica.

git rm --cached cancella il mio file locale?

No. --cached toglie il file solo dall'indice; la copia su disco resta. Committa la rimozione e il file diventa non tracciato, dopodiché .gitignore si applica.

Perché gitignore non può re-includere un file dentro una cartella ignorata?

Git salta interamente le directory escluse per motivi di performance. Come dicono i documenti git, è impossibile re-includere un file se una directory padre di quel file è esclusa.

— mrsaynothing

Get the next one by email

One email per post. No spam, no algorithms.

self-hosted · no third parties · one-click unsubscribe

what is this?

Ollama non usa la GPU? Fix su Linux, Windows e WSL

Ti piacciono gli articoli? È così che costruisco per lavoro. assumimi