Come funzionano effettivamente le regole di esclusione .gitignore?


146

Sto cercando di risolvere un problema gitignore su una struttura di directory di grandi dimensioni, ma per semplificare la mia domanda l'ho ridotto al seguente.

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

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 all'interno di 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

È 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 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, anche se foo non viene più ignorato, anche la barra non viene ignorata.

L'ordine delle regole in .gitignore non sembra importare neanche.

Anche questo non fa quello che mi aspetto:

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

Quello ignora sia foo che bar.

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

*
!foo

Ma il problema è che alla fine ci saranno altre sottodirectory sotto a / b / c e non voglio dover inserire un .gitignore separato in ognuna - speravo di creare .gitignore "basato su progetto" file che possono trovarsi nella directory superiore di ogni progetto e che coprono 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 al "lavoro" che posso ottenere, ma devono essere dichiarati i percorsi relativi completi e le eccezioni esplicite, il che sarà un problema se avrò molti file di nome "pippo" in diversi livelli dell'albero della sottodirectory.

Ad ogni modo, o non capisco bene come funzionano le regole di esclusione, oppure non funzionano affatto quando le directory (anziché i caratteri jolly) vengono ignorate - da una regola che termina con un /

Qualcuno può far luce su questo?

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

Lo sto usando e osservo con git-1.6.6.1 su Cygwin / bash3 e git-1.7.1 su Ubuntu / bash3.



4
Domanda scritta in modo eccellente! La quantità di casi che hai provato mi ha davvero aiutato a capire cosa stavo facendo di sbagliato nel mio caso simile. Grazie a Dio, stavo cercando da molto tempo oggi.
Alex G,

Risposte:


153
/ A / b / c / *
! foo

Sembra funzionare per me (git 1.7.0.4 su Linux). Il *è importante in quanto in caso contrario si sta ignorando la directory stessa (in modo git non guardare dentro) al posto 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 questa ( foo)" non ha molto senso; msgstr "ignora tutti i file in questa directory ( /a/b/c/*) ma non questo ( foo)". Per citare la pagina man:

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

cioè, il file deve essere già stato escluso per poter essere nuovamente incluso. Spero che faccia luce.


Sì, l'esempio che fai funziona bene anche per me. Il problema è che / a / b / * non funziona se foo è in c, il che significa che 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 cattura.
davidA

1
@meowsqueak In effetti non lo farà. Se ignori / a / b / *, allora non c'è una directory in cui possa trovarsi Foo! Se stai cercando di ignorare l'intero albero di directory in / a / b ma includi qualsiasi file chiamato "pippo" che può trovarsi in qualsiasi punto dell'albero, non credo sia fattibile con schemi .gitignore: \
Chris

In realtà questo potrebbe spiegare perché questo non funziona per me - le seguenti regole non funzionano: "/ a / b / *", "! C / foo". Se funzionasse, potrebbe non esserci un problema.
davidA

5
"Non credo sia fattibile con i modelli .gitignore" - Penso che tu abbia ragione, sfortunatamente.
David,

@meowsqueak Potresti forse ignorare /a/b/ce quindi scrivere un hook a git add --forcequalsiasi file corrispondente pre-commit o qualcosa del genere
Chris

24

Ho una situazione simile, la mia soluzione era usare:

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

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


6

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 viene esclusa. Quindi, se vuoi essere in grado di ignorare * ma alcuni file, devi creare 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 ne voglio fare un altro in seguito, lo aggiungo e tutto il resto viene ignorato.


6

Ecco un'altra opzione:

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

Ciò ignorerebbe ogni file e directory, ad eccezione di file / directory a tre livelli di profondità all'interno di a.


5

Su una nota più generale, git1.8.2 includerà la patch (anche nella sua v4 , richiesta da una domanda Stack Overflow ) di Adam Spires per determinare quale gitignoreregola 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.


1
Grazie per aver trasmesso queste informazioni. check-ignoreti dirà anche quale regola impedisce che il tuo file venga ignorato, in questo caso.
Adam Spires

@AdamSpiers suona alla grande. Dovrò sicuramente giocarci.
VonC
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.