2010-06-08 11 views
123

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.Come funzionano effettivamente le regole di esclusione di gitignore?

Ho la seguente struttura di directory dei due file (foo, bar) in un nuovo repository git (non impegna finora):

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

Ovviamente, un 'git stato -u' spettacoli:

# 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 così:

c/ 

Poi un 'git stato -u' mostra sia foo e bar come ignorato:

# Untracked files: 
... 
#  .gitignore 

Che è come mi aspetto.

Ora, se posso aggiungere una regola di esclusione per foo, in tal modo:

c/ 
!foo 

Secondo la pagina di manuale gitignore, mi aspetto questo per funzionare. Ma non lo fa - ignora ancora foo:

# Untracked files: 
... 
#  .gitignore 

Questo non funziona neanche:

c/ 
!a/b/c/foo 

Né fa questo:

c/* 
!foo 

Dà:

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

In tal caso, anche se foo non è più ignorante ed, la barra non viene ignorata.

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

Anche questo non fa quello che ci si aspetta:

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

che si ignora sia foo e bar.

Una situazione che funziona è che se creo il file a/b/c/.gitignore e mettere in là:

* 
!foo 

Ma il problema è che alla fine ci saranno altri sottodirectory sotto un/b/c e non voglio dover mettere un .gitignore separato in ognuno di essi - speravo di creare file ".gitignore" basati su progetto che si possono trovare nella directory principale di ogni progetto e coprire tutti la struttura della sottodirectory "standard".

Questo sembra anche essere equivalente:

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

Questa potrebbe essere la cosa più vicina a "lavoro" che posso raggiungere, ma i percorsi relativi pieni e le eccezioni esplicite devono essere indicati, che sta per essere un dolore se ho un sacco di file di nome 'pippo' in diversi livelli dell'albero della sottodirectory.

In ogni caso, o io non capisco come funzionano le regole di esclusione, o non funzionano affatto quando le directory (piuttosto che i caratteri jolly) vengono ignorati - da una regola che termina in un/

Qualcuno può far luce su questo?

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

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

+0

domanda correlata: http://stackoverflow.com/questions/2820255/how-do-negated-patterns-work-in-gitignore/2820310#2820310 – Cascabel

risposta

121
/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).

Pensate alle esclusioni dicendo "ma non questo" piuttosto che "ma includi questo" - "ignora questa directory (/a/b/c/) ma non questa (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.

vale a dire, il file di deve essere stato escluso già da inserire di nuovo. Spero che getti un po 'di luce.

+0

Sì, l'esempio che date funziona anche per me. Il problema è che/a/b/* non funziona se foo è in c, il che significa che se ho più file foo in varie sottodirectory in c (es. D /, e /, f/g/h /, i/j /, ecc.) quindi la regola di negazione "! pippo" non li catturerà. – meowsqueak

+0

@meowsqueak Effettivamente non lo farà. Se ignori/a/b/*, non c'è una directory in cui si possa trovare foo! Se stai cercando di ignorare l'intero albero delle directory sotto/a/b ma includi qualsiasi file chiamato "foo" che può essere ovunque nell'albero, non penso che sia fattibile con i modelli .gitignore: \ – Chris

+0

In realtà ciò potrebbe spiegare perché questo non funziona per me - le seguenti regole non funzionano: "/ a/b/*", "! c/foo". Se ciò ha funzionato, potrebbe non esserci un problema. – meowsqueak

4

questo non è sicuramente 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 aperta nemmeno se è esclusa. Quindi se vuoi essere in grado di ignorare * ma alcuni file, devi costruire 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.

6

Ecco un'altra opzione:

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

che ignorerebbe ogni file e directory, ad eccezione di file/directory tre livelli di profondità all'interno di una.

19

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.

+0

Genio! grazie, questo mi ha aiutato a risolvere il problema per cui ho battuto la testa per l'ultima ora. – Baggers

+0

Perfetto, funziona come un fascino! – hungdoan

+0

Bello, questo è stato per me! –

4

Su una nota più generale, git1.8.2 includerà il patch (anche in its v4, prompted by some Stack Overflow question) da Adam Spiers su come determinare quale gitignore regola in realtà ignora il file.

Vedi git1.8.2 release notes e la questione SO "which gitignore rule is ignoring my file":
che sarà il comando git check-ignore.

+0

Grazie per aver trasmesso questa informazione. 'check-ignore' ti dirà anche quale regola * impedisce * al tuo file di essere ignorato, se questo è il caso. –

+0

@AdamSpiers suona alla grande. Dovrò sicuramente giocarci. – VonC

Problemi correlati