gitignore todos los files en carpetas pero mantenga la estructura de la carpeta

Tengo la siguiente estructura de carpetas:

/foo/ /foo/test.txt /foo/.gitkeep /foo/bar/test.txt /foo/bar/.gitkeep /foo/bar/baz/test.txt /foo/bar/baz/.gitkeep 

Ahora quiero excluir todos los files en la carpeta "foo" y todos los files en sus subcarpetas (y subcarpetas), excepto todos los .gitkeeps (para que la estructura de la carpeta se mantenga). Esto también debería funcionar para más de 3 niveles de subcarpetas.

Las siguientes reglas de gitignore funcionan:

 /foo/** !/foo/**/ !/foo/**/.gitkeep 

¿Alguien puede explicar por qué esto funciona? ¿Hay una forma más limpia de hacer esto?

La regla es simple:

No es posible volver a include un file si se excluye un directory principal de ese file.

Es por eso que necesitas

  • ignorar files y carpetas recursivamente:

     /foo/** 

(Si solo ignoras /foo/ , esa es la carpeta, entonces no funcionará ninguna cantidad de la regla de exclusión ' ! ', ya que se ignora la carpeta foo/ : Git se detendrá allí)

  • A continuación, excluya las carpetas de las reglas de ignorar:

     !/foo/**/ 
  • Antes de .gitkeep la list blanca files como .gitkeep

     !/foo/**/.gitkeep 

Eso funciona porque las carpetas .gitkeep parent están excluidas de las reglas de ignorar.

A diferencia de la propuesta original de Bernardo ( antes de su edición ):

 /foo/** !**/.gitkeep 

Si no excluye las carpetas de la regla /** ignore, entonces la regla de exclusión para los files no está operativa.

Puedes verificar eso con:

 git check-ignore -v -- /path/to/.gitkeep 

Como se menciona en scm .gitignore :

  • usar ' * ' es lo mismo que ' ** '
  • el uso de !.gitkeep (sin any / anchor) excluiría ese file recursivamente.

En ambos casos, ' recursively ' es el término key que explica por qué pueden aplicarse las reglas de exclusión: si ignora una carpeta (como . O /foo/ ), no podrá excluir nada dentro de esa carpeta.
Pero si ignora los elementos (files y carpetas) recursivamente ( * o ** ) y excluye las carpetas de las reglas de gitignore (¡nuevamente a través de la regla recursiva !* ), Entonces puede excluir (list blanca) los files.

Lo he hecho. Parece que lo que se necesita es un file .gitignore dentro de la carpeta deseada.

Mira este repository , que hace exactamente lo que quieres.

Intenté agregar cualquier nombre de file dentro de foo/ , foo/bar/ y foo/bar/baz/ pero solo acepta .gitkeep.

El truco es crear un .gitignore con este contenido, dentro de la carpeta :

 * !*/ !.gitignore !.gitkeep 

[Editar: añadido en base a los comentarios]

Y deberías poder acortar esto a:

 * !*/ !.git* 

Aunque puede ser less claro en el futuro lo que se pretendía.

Si bien esta solución no acorta el número de líneas requeridas desde su .gitignore original, esto tiene otras ventajas, la principal es que será un file .gitignore dentro de la carpeta , lo que significa que puede ser un file limpio que tiene solo estas líneas, y es específico solo para esta carpeta.

Eso significa que este file .gitignore se puede mover fácilmente a cualquier carpeta específica que requiera este filter. Además, toda la carpeta se puede mover fácilmente dentro del repository, o incluso se puede mover a un repository diferente, sin necesidad de modificar el .gitignore . Es mucho más limpio y más .gitignore mantener, y no está enterrado en el file .gitignore típicamente grande en la carpeta raíz del repository.