Lingua:Italiano
STRUMENTO DEV

Gitignore Debugger

Scopri esattamente perché Git non ignora il tuo file.

Incolla il percorso di un file e le tue regole .gitignore. Ti mostriamo quale regola corrisponde, e perché.

Tutto gira nel tuo browser. I tuoi file non vengono mai inviati.

Che cos'è un file .gitignore?

Un file .gitignore è un file di testo che dice a Git quali file tenere fuori dal controllo di versione. Ogni riga è un pattern — *.log, node_modules/, .env — e ogni percorso non tracciato che corrisponde a un pattern sparisce da git status, viene saltato da git add . e non finisce mai in un commit.

L'espressione non tracciato porta quasi tutto il peso di quella frase e, da sola, spiega più casi di «gitignore non funziona» di tutti gli errori nei pattern messi insieme. Git consulta il .gitignore solo per i file che non sta già tracciando. Dal momento in cui un file è stato committato, Git continua a tracciarlo per sempre, qualunque cosa tu aggiunga dopo al .gitignore.

Cosa fa il Gitignore Debugger

Incolla il percorso di un file e il contenuto del tuo .gitignore: questo debugger di .gitignore dà lo stesso verdetto di Git — ignorato o non ignorato — insieme alla regola esatta e al numero di riga responsabili. Poi elenca tutte le regole che corrispondono al percorso, nell'ordine in cui Git le valuta, e segnala quella che ha davvero deciso.

È quest'ultima parte che un semplice validatore di gitignore lascia fuori. Sapere che un file è ignorato non è quasi mai la parte difficile. Sapere quale delle tue quaranta regole l'ha fatto — e perché ha perso quella che ti aspettavi — sì. Funziona in entrambe le direzioni: perché Git ignora il file che vuoi committare, e perché non ignora quello di cui vuoi liberarti.

Il motore reimplementa le regole di corrispondenza dei pattern di Git: pattern sul nome base contro pattern ancorati, * che non attraversa mai una /, le tre forme di **, i suffissi / validi solo per le directory, le classi di caratteri, gli spazi finali con escape. Il suo comportamento è verificato contro l'output reale di git check-ignore, non dato per scontato.

Come si usa

  1. Inserisci il percorso così come appare nel tuo repository, relativo alla radice — src/config/local.json, non C:\projects\app\src\config\local.json. Usa le barre in avanti; i backslash di Windows vengono convertiti per te.
  2. Incolla tutto il tuo .gitignore. Non ridurlo alla sola regola che sospetti: di solito il vero bug è la precedenza tra le regole, e tagliare il file butta via proprio quell'informazione.
  3. Leggi il verdetto e poi la catena di regole più sotto. È lì che una regola gitignore che non funziona smette di essere un mistero.

Per provare le regole gitignore su una directory invece che su un file, termina il percorso con una barra — build/. La distinzione conta, perché una regola che finisce con / corrisponde solo a directory.

Perché a volte le regole gitignore non funzionano

I colpevoli, più o meno in ordine di frequenza:

Precedenza delle regole gitignore: vince l'ultima corrispondenza

Questa è quella che frega tutti. All'interno dello stesso .gitignore, è l'ultimo pattern che corrisponde a un percorso a decidere il suo destino, non il primo. Questi due file contengono regole identiche e danno risultati opposti per important.log:

*.log
!important.log        → important.log viene committato
!important.log
*.log                 → important.log viene ignorato

Quindi metti prima le regole ampie e poi le eccezioni. Tra file diversi, un .gitignore in una sottodirectory vince su uno più in alto per i percorsi che stanno sotto. Git legge anche .git/info/exclude, proprio del repository e mai committato, e il tuo core.excludesFile globale. Una regola che non trovi in nessun .gitignore spesso si nasconde in uno di quei due posti: git check-ignore -v mostra il file e la riga che hanno deciso.

Le regole di negazione, e perché ! fallisce così spesso

Mettere ! davanti a un pattern reinclude qualcosa che una regola precedente aveva ignorato. Ha due limiti, e il secondo spiega quasi tutti i casi di «la negazione di gitignore non funziona».

Primo: qualcosa prima deve aver ignorato quel percorso. !important.log da solo non fa niente, perché non c'è mai stato nulla da sovrascrivere.

Secondo, e assai più sorprendente: non puoi reincludere un file che sta dentro una directory ignorata. Questo non funziona, e nessun riordino lo sistema:

build/
!build/keep.txt

Quando build/ è ignorata, Git non ci entra mai. Non esamina build/keep.txt, quindi non arriva mai alla riga 2. Ignora invece il contenuto della directory, così la directory stessa resta percorribile:

build/*
!build/keep.txt

Per salvare qualcosa di più profondo, anche ogni directory intermedia deve restare accessibile — build/*, poi !build/assets/, poi !build/assets/logo.svg.

Directory superiori ignorate

La scansione delle directory di Git si ferma alla prima directory ignorata che incontra, e tutto ciò che sta sotto eredita il verdetto senza essere esaminato. È per questo che una directory superiore ignorata vince su qualsiasi regola scritta per il file stesso, quanto specifica possa sembrare.

In quel caso il debugger nomina la directory che ha bloccato la scansione invece di dire soltanto che il file è ignorato, e mostra comunque le regole di negazione che hai scritto per il file — segnate come irraggiungibili, perché Git non è mai andato abbastanza in profondità da prenderle in considerazione. Sistema prima la directory e le regole più sotto ricominciano a funzionare da sole.

Errori comuni nel .gitignore

Qualche esempio concreto

Il percorso src/logs/debug.log con queste regole non è ignorato. La negazione è l'ultima corrispondenza e nessuna directory superiore blocca la scansione, quindi viene raggiunta e vince:

*.log
!src/logs/debug.log

Il percorso build/keep.txt con queste regole è ignorato, per via di build/ alla riga 1, che corrisponde alla directory superiore. La riga 2 non scatta mai:

build/
!build/keep.txt

Il percorso docs/api/notes.md con questa regola non è ignorato, perché il pattern è ancorato dalla sua barra e * non attraverserà quella di api/notes.md. Quello che serviva era docs/**/*.md:

docs/*.md

Incolla uno qualsiasi di questi esempi nel tester gitignore qui sopra per vedere l'intera catena di regole. Tornando al terminale, git check-ignore -v path/to/file è l'equivalente integrato: nomina il file di origine, il numero di riga e il pattern che hanno deciso, e vale la pena conoscerlo.

Domande frequenti

Perché Git ignora il mio file?

Un qualche pattern gli corrisponde, e spesso non è quello che stai guardando. I soliti colpevoli sono un .gitignore in una sottodirectory, una directory superiore ignorata, o il tuo file di esclusione globale. Esegui git check-ignore -v path/to/file: stampa esattamente il file di origine, il numero di riga e il pattern che hanno deciso. Incollare percorso e regole nel debugger qui sopra mostra la stessa cosa, più le regole che corrispondevano e hanno perso.

Perché la mia regola .gitignore non funziona?

Quattro cause coprono quasi tutti i casi, più o meno in ordine di frequenza: il file è già tracciato, quindi la regola viene saltata del tutto; una regola successiva l'ha sovrascritta, perché vince l'ultima corrispondenza; una directory superiore è ignorata, quindi Git non è mai arrivato alla regola; oppure il pattern è ancorato in modo diverso da come pensavi — una barra in qualsiasi posizione diversa dalla fine ancora un pattern alla directory che contiene il .gitignore.

Perché ! non reinclude il mio file?

O prima non c'era nulla che ignorasse quel percorso, e quindi la negazione non aveva niente da sovrascrivere, oppure — molto più probabile — il file sta dentro una directory ignorata. Git non entra nelle directory ignorate, quindi non vede mai il file e non valuta mai la tua regola !.

Ignora il contenuto della directory invece della directory stessa: sostituisci build/ con build/*, tieni !build/keep.txt dopo, e la negazione viene raggiunta.

Vince l'ultima regola del .gitignore?

Sì. All'interno di un file, è l'ultimo pattern che corrisponde a un percorso a deciderne il destino: non il primo, né il più specifico. *.log seguito da !important.log conserva important.log; scambia quelle due righe e viene ignorato. Metti prima le regole ampie e poi le eccezioni.

Perché una cartella ignorata impedisce a una regola di negazione di funzionare?

Perché la scansione delle directory di Git si ferma alla prima directory ignorata. Quando build/ corrisponde, Git marca tutto il sottoalbero come ignorato senza elencare cosa c'è dentro, quindi !build/keep.txt non viene sovrascritto: semplicemente non viene mai raggiunto. Riordinare non cambia niente; l'unica cosa che cambia qualcosa è rendere di nuovo percorribile la directory, ed è quello che fa build/*.

Come faccio a testare una regola .gitignore?

Incolla il percorso del file e le tue regole nel debugger in cima a questa pagina. Ti dà il verdetto, la regola e la riga decisive, e tutte le regole che corrispondevano lungo la strada — comprese le negazioni che non avrebbero mai potuto avere effetto.

Su un repository vero, git check-ignore -v path/to/file nomina il file di origine, la riga e il pattern responsabili, e git status --ignored elenca tutto ciò che è ignorato in questo momento.

Il .gitignore vale per i file già tracciati?

No. .gitignore si applica solo ai percorsi non tracciati. Dal momento in cui un file è stato committato, Git continua a tracciarlo e la regola viene saltata: è il motivo più frequente per cui una regola perfettamente corretta sembra non fare nulla. Per smettere di tracciare un file senza cancellarlo, esegui git rm --cached path/to/file e committa quella modifica.

Un dettaglio che inganna: git check-ignore segnalerà comunque una corrispondenza per un file tracciato, perché prova i pattern senza guardare l'indice. Un «sì, ignorato» da quel comando non significa che Git abbia smesso di tracciare il file.

Le regole .gitignore possono contenere spazi?

Sì, in mezzo. my logs/ corrisponde a una directory con uno spazio nel nome, senza alcun escape. Gli spazi finali sono un'altra storia: Git li taglia, quindi *.log seguito da uno spazio si comporta esattamente come *.log. Per far corrispondere un nome di file che termina davvero con uno spazio, usa l'escape — foo\ .

Gli spazi iniziali invece contano e non vengono mai tagliati: una regola indentata per sbaglio corrisponde solo ai percorsi che iniziano con quello spazio. Se una regola sembra inerte senza motivo, controlla che non abbia indentazione di troppo.

Dove cerca Git le regole di esclusione oltre al .gitignore?

In altri tre posti, consultati in questo ordine di precedenza: i file .gitignore stessi, dove vince la directory più profonda; poi .git/info/exclude, proprio del repository e mai committato; poi ciò a cui punta core.excludesFile, il tuo elenco di esclusioni globale.

Quindi una regola che non trovi da nessuna parte nel repository di solito sta in uno di quegli ultimi due. git config --get core.excludesFile rivela il percorso globale, e git check-ignore -v nomina il file che ha davvero deciso.

Qual è la differenza tra * e **?

* corrisponde a qualsiasi sequenza di caratteri tranne /, quindi non esce mai da un singolo segmento di percorso. src/*/test.js scende esattamente di un livello.

** attraversa i separatori, ma solo nelle tre posizioni che Git riconosce: un **/ iniziale per qualsiasi profondità, un /** finale per tutto ciò che sta dentro una directory, e /**/ in mezzo per zero o più directory. Altrove, come in a**b, gli asterischi in più si comportano come un singolo *.