Come funzionano effettivamente le regole di esclusione di gitignore?

Sto cercando di risolvere un problema di gitignore su una struttura di directory di grandi dimensioni, ma per semplificare la mia domanda l’ho ridotto a quanto segue.

Ho la seguente struttura di directory di due file (foo, bar) in un nuovo repository git (nessun commit fino ad ora):

a/b/c/foo a/b/c/bar 

Ovviamente, uno ‘git status -u’ mostra:

 # Untracked files: ... # a/b/c/bar # a/b/c/foo 

Quello che voglio fare è creare un file .gitignore che ignori tutto dentro a / b / c ma non ignori il file ‘pippo’.

Se creo un .gitignore in questo modo:

 c/ 

Quindi uno ‘git status -u’ mostra sia foo che bar come ignorati:

 # Untracked files: ... # .gitignore 

Quale è come mi aspetto.

Ora se aggiungo una regola di esclusione per foo, quindi:

 c/ !foo 

Secondo la manpage di gitignore, mi aspetto che funzioni. Ma non lo fa – ignora ancora il foo:

 # Untracked files: ... # .gitignore 

Questo non funziona neanche:

 c/ !a/b/c/foo 

Neanche questo:

 c/* !foo 

dà:

 # Untracked files: ... # .gitignore # a/b/c/bar # a/b/c/foo 

In tal caso, sebbene foo non sia più ignorato, anche la barra non viene ignorata.

Anche l’ordine delle regole in .gitignore non sembra avere importanza.

Anche questo non fa quello che mi aspetterei:

 a/b/c/ !a/b/c/foo 

Quello ignora sia il foo che il bar.

Una situazione che funziona è se creo il file a / b / c / .gitignore e inserisco lì:

 * !foo 

Ma il problema con questo è che alla fine ci saranno altre sottodirectory sotto a / b / c e non voglio dover mettere un separato .gitignore in ogni singolo – speravo di creare “progetto-based” .gitignore file che possono essere posizionati nella directory principale di ciascun progetto e coprire tutta la struttura della sottodirectory “standard”.

Anche questo sembra essere equivalente:

 a/b/c/* !a/b/c/foo 

Questa potrebbe essere la cosa più vicina a “lavorare” che posso ottenere, ma i percorsi relativi completi e le eccezioni esplicite devono essere dichiarati, il che sarà un problema se avrò molti file di nome “foo” in diversi livelli dell’albero della sottodirectory.

Comunque, o non capisco come funzionano le regole di esclusione, o non funzionano affatto quando le directory (piuttosto che i caratteri jolly) vengono ignorate – da una regola che termina con /

Qualcuno può per favore far luce su questo?

C’è un modo per far sì che gitignore usi qualcosa di sensato come le espressioni regolari invece di questa goffa syntax basata sulla shell?

Sto usando e osservo questo con git-1.6.6.1 su Cygwin / bash3 e git-1.7.1 su Ubuntu / bash3.

  / A / b / c / *
 ! foo 

Sembra funzionare per me (git 1.7.0.4 su Linux). Il * è importante in quanto altrimenti si sta ignorando la directory stessa (quindi git non guarderà dentro) invece dei file all’interno della directory (che consente l’esclusione).

Pensa alle esclusioni dicendo “ma non questo” piuttosto che “ma includi questo” – “ignora questa directory ( /a/b/c/ ) ma non questo ( foo )” non ha molto senso; “Ignora tutti i file in questa directory ( /a/b/c/* ) ma non questo ( foo )” fa. Per citare la pagina man:

Un prefisso opzionale! che nega il modello; qualsiasi file di corrispondenza escluso da un modello precedente verrà nuovamente incluso.

cioè, il file deve essere stato escluso già per essere incluso di nuovo. Spero che getti un po ‘di luce.

Ho una situazione simile, la mia soluzione era quella di utilizzare:

 /a/**/* !/a/**/foo 

Questo dovrebbe funzionare per un numero arbitrario di directory intermedie se leggo ** correttamente.

Ecco un’altra opzione:

 * !/a* !/a/* !/a/*/* !/a/*/*/* 

Quello ignorerebbe ogni file e directory, eccetto file / directory tre livelli in profondità all’interno di a.

questo non è assolutamente chiaro dalla pagina man di .gitignore. Questo funziona:

 * !/a !/a/b !/a/b/c !/a/b/c/foo # don't forget this one !.gitignore 

Come menzionato da Chris, una directory non viene nemmeno aperta se è esclusa. Quindi se vuoi essere in grado di ignorare * ma alcuni file, devi build il percorso per quei file come sopra. Per me questo è conveniente, perché voglio fare una revisione del codice su 1 file di una libreria e se voglio fare un altro dopo lo aggiungo e tutto il resto viene ignorato.

In una nota più generale, git1.8.2 includerà la patch (anche nella sua v4 , suggerita da alcune domande di Stack Overflow ) da Adam Spires per determinare quale regola gitignore ignora effettivamente il tuo file.

Vedi le note di rilascio di git1.8.2 e la domanda SO ” quale regola gitignore sta ignorando il mio file “:
quello sarà il comando git check-ignore .