¿Cómo funcionan realmente las reglas de exclusión de gitignore?


Estoy tratando de resolver un problema de gitignore en una estructura de directorios grande, pero para simplificar mi pregunta la he reducido a lo siguiente.

Tengo la siguiente estructura de directorios de dos archivos (foo, bar) en un nuevo repositorio git (no hay confirmaciones hasta ahora):

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

Obviamente, un' git status-u ' muestra:

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

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

Si creo un .gitignore así:

c/

Entonces un 'git status-u' muestra tanto foo como bar como ignorados:

# Untracked files:
...
#       .gitignore

Que es como espero.

Ahora si agrego una regla de exclusión para foo, así:

c/
!foo

De acuerdo con la página de manual de gitignore, esperaría que esto funcionara. Pero no lo hace - todavía ignora foo:

# Untracked files:
...
#       .gitignore

Esto tampoco funciona:

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 ignorado, bar tampoco es ignorado.

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

Esto tampoco hace lo que yo esperaría: {[13]]}

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

Que uno ignora tanto foo como bar.

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

*
!foo

Pero el problema con esto es que eventualmente habrá otros subdirectorios bajo a/b/c y no quiero tener que poner un separado .gitignore en cada uno tenía la esperanza de crear "proyectos".archivos gitignore que pueden ubicarse en el directorio superior de cada proyecto, y cubrir toda la estructura de subdirectorios 'estándar'.

Esto también parece ser equivalente:

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

Esto podría ser lo más parecido a "trabajar" que pueda lograr, pero las rutas relativas completas y las excepciones explícitas deben indicarse, lo que va a ser un dolor si tengo muchos archivos de nombre ' foo ' en diferentes niveles del subdirectorio arbol.

De todos modos, o no entiendo muy bien cómo funcionan las reglas de exclusión, o no funcionan en absoluto cuando se ignoran los directorios (en lugar de los comodines), por una regla que termina en a /

¿Puede alguien por favor arrojar algo de luz sobre esto?

¿Hay alguna manera de hacer que gitignore use algo sensible 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.

 130
Author: meowsqueak, 2010-06-09

5 answers

/a/b/c/*
!foo

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

Piense en las exclusiones como diciendo "pero no este" en lugar de "pero incluya este" - "ignorar este directorio (/a/b/c/) pero no este (foo)" no tiene mucho sentido; "ignorar todos los archivos en este directorio (/a/b/c/*) pero no este (foo)" lo hace. Citar la página de manual:

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

Es decir, el archivo tiene que haber sido excluido ya para ser incluido de nuevo. Espero que eso arroje algo de luz.

 131
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-08 23:00:44

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

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

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

 22
Author: medge799,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-07 16:11:18

Aquí hay otra opción:

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

Que ignoraría todos los archivos y directorios, excepto los archivos / directorios tres niveles profundos dentro de a.

 6
Author: Peter Petrik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-06 00:18:27

Esto definitivamente no está claro de la.página man de gitignore. Esto funciona:

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

# don't forget this one
!.gitignore

Como menciona Chris, un directorio ni siquiera se abre si se excluye. Así que si desea ser capaz de ignorar * pero algunos archivos, usted tiene que construir la ruta a esos archivos como arriba. Para mí esto es conveniente, porque quiero hacer una revisión de código en 1 archivo de una biblioteca y si quiero hacer otro más tarde simplemente lo añado, y todo lo demás se ignora.

 4
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-10 00:42:39

En una nota más general, git1. 8. 2 incluirá el parche (también en su v4, solicitado por alguna pregunta de desbordamiento de pila ) de Adam Spiers sobre la determinación de qué regla gitignore ignora realmente su archivo.

Ver git1.8. 2 notas de la versión y la pregunta SO " ¿qué regla de gitignore está ignorando mi archivo":
que será el comando git check-ignore.

 4
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:30