2010-06-08 6 views
123

Estoy tratando de resolver un problema de gitignore en una gran estructura de directorios, pero para simplificar mi pregunta, la he reducido a lo siguiente.¿Cómo funcionan las reglas de exclusión de gitignore?

que tienen la siguiente estructura de directorios de los dos archivos (foo, bar) en un nuevo repositorio git (no compromete hasta ahora):

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

Obviamente, un 'git status -u' shows:

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

Lo que quiero hacer es crear un archivo .gitignore que ignore todo dentro de a/b/c pero no ignore el archivo 'foo'.

Si creo un .gitignore así:

c/ 

A continuación, un 'git status -u' muestra tanto foo y bar, ignorado:

# Untracked files: 
... 
#  .gitignore 

Cuál es como espero.

Ahora bien, si puedo añadir una regla de exclusión de foo, por lo tanto:

c/ 
!foo 

De acuerdo con la página de manual gitignore, yo esperaría que esto funcione. Pero no es así - que todavía ignora foo:

# Untracked files: 
... 
#  .gitignore 

Esto no funciona bien:

c/ 
!a/b/c/foo 

Tampoco esto:

c/* 
!foo 

Da:

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

En ese caso, aunque foo ya no es ignor ed, la barra tampoco se ignora.

El orden de las reglas en .gitignore tampoco parece importar.

Esto también no hace lo que cabe esperar:

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

que uno ignora tanto foo y bar.

Una situación que hace el trabajo es si creo el archivo a/b/c/.gitignore y poner ahí:

* 
!foo 

Pero el problema con esto es que con el tiempo habrá otros subdirectorios bajo una/b/c y no quiero tener que poner un .gitignore por separado en cada uno de ellos - Tenía la esperanza de crear archivos .gitignore 'basados ​​en proyectos' que puedan ubicarse en el directorio superior de cada proyecto y cubrir todos la estructura del subdirectorio "estándar".

Esto también parece ser equivalente:

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

Esto podría ser lo más parecido a "trabajo" que puedo lograr, pero las rutas relativas completos y excepciones explícitas necesita ser dicho, que se va a Sería un dolor si tengo muchos archivos con el nombre 'foo' en diferentes niveles del árbol de subdirectorios.

De todas formas, ya sea que no acabo de entender cómo funcionan las reglas de exclusión, o que no funcionan en absoluto cuando se ignoran los directorios (en lugar de comodines) - por una regla que termina en un/

Puede alguien por favor arrojar algo de luz sobre esto?

¿Hay alguna manera de hacer que gitignore use algo sensato como expresiones regulares en lugar de esta torpe sintaxis basada en shell?

Estoy usando y observo esto con git-1.6.6.1 en Cygwin/bash3 y git-1.7.1 en Ubuntu/bash3.

+0

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

Respuesta

121
/a/b/c/* 
!foo

Parece que funciona para mí (git 1.7.0.4 en Linux). El * es importante ya que de lo contrario está ignorando el directorio en sí (para que git no mire adentro) en lugar de los archivos dentro del directorio (lo que permite la exclusión).

Piense en las exclusiones como diciendo "pero no esta" en lugar de "pero incluya esto" - "ignore este directorio (/a/b/c/) pero no este (foo)" no tiene mucho sentido; "ignore todos los archivos en este directorio (/a/b/c/*) pero no este (foo)". Para citar la página man:

¡Un prefijo opcional! que niega el patrón; cualquier archivo coincidente excluido por un patrón anterior se incluirá nuevamente.

es decir, el archivotiene que haber sido excluidos ya ser incluido de nuevo. Espero que arroje algo de luz.

+0

Sí, el ejemplo que das también funciona bien para mí. El problema es que/a/b/* no funciona si foo está en c, lo que significa que si tengo varios archivos foo en varios subdirectorios en c (por ejemplo, d /, e /, f/g/h /, i/j /, etc.) entonces la regla de negación '! foo' no los detectará. – meowsqueak

+0

@meowsqueak De hecho no lo hará. ¡Si ignoras/a/b/* entonces no hay un directorio para que foo esté! Si intenta ignorar todo el árbol de directorios bajo/a/b pero incluye cualquier archivo llamado "foo" que pueda estar en cualquier parte del árbol, no creo que sea factible con los patrones .gitignore: \ – Chris

+0

En realidad, esto podría explicar ¿Por qué esto no funciona para mí? Las siguientes reglas no funcionan: "/ a/b/*", "! c/foo". Si eso funcionó, puede que no haya un problema. – meowsqueak

4

esto definitivamente no está claro en la página de manual de .gitignore. Esto funciona:

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

# don't forget this one 
!.gitignore 

Como lo menciona Chris un directorio ni siquiera se abre si se excluye. Entonces, si desea poder ignorar * pero algunos archivos, debe compilar la ruta a esos archivos como se indicó anteriormente. Para mí, esto es conveniente, porque quiero hacer una revisión de código en 1 archivo de una biblioteca y si quiero hacer otra más adelante, simplemente lo agrego, y todo lo demás se ignora.

6

Aquí hay otra opción:

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

Eso sería ignorar todos los archivos y directorios, excepto los archivos/directorios tres niveles de profundidad dentro de una.

19

Tengo una situación similar, mi solución fue usar:

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

que debería funcionar para un número arbitrario de directorios intermedios si leo ** correctamente.

+0

¡Genio! gracias, esto me ayudó a resolver el problema que me he estado golpeando en la cabeza durante la última hora. – Baggers

+0

¡Perfecto, trabaja como un encanto! – hungdoan

+0

¡Bien, esto lo hizo por mí! –

4

En una nota más general, git1.8.2 incluirá la patch (también in its v4, prompted by some Stack Overflow question) de Adam Spiers sobre la determinación de regla que gitignore hecho, desconoce su archivo.

Ver git1.8.2 release notes y la cuestión SO "which gitignore rule is ignoring my file":
que será el comando git check-ignore.

+0

Gracias por transmitir esta información. 'check-ignore' también le dirá qué regla * impide * que su archivo sea ignorado, si ese es el caso. –

+0

@ AdamSpiers suena genial. De seguro tendré que jugar con eso. – VonC

Cuestiones relacionadas