Dejar de ignorar subdirectorios de directorios ignorados en Git

99

Digamos que he ignorado un directorio, pero quiero dejar de ignorar subdirectorios específicos en él. Entonces tengo la configuración:

/uploads/
/uploads/rubbish/
/uploads/rubbish/stuff/KEEP_ME/
/uploads/foo/
/uploads/foo/bar/lose/

Y quiero ignorar todo menos el KEEP_MEdirectorio. Espero que el ignorado se vea así:

/uploads/*
!/uploads/rubbish/stuff/KEEP_ME/

Pero eso no funciona, y tampoco lo son varias permutaciones sobre el mismo tema.

Uno que funciona es

/uploads/**/**/**/
!/uploads/rubbish/stuff/KEEP_ME/

¿Pero eso se siente un poco restrictivo y detallado?

Wil
fuente
1
El código que proporcionaste no funcionó para mí (usando git versión 1.9.1). Uno que funcionó es / uploads / *! / Uploads / rubbish / / uploads / rubbish / *! / Uploads / rubbish / stuff / uploads / rubbish / stuff / *! / Uploads / rubbish / stuff / keep (que es similar al ejemplo en git-scm.com/docs/gitignore ). Mi estructura de carpeta; └ README.md └ uploads / foo / bar / lose / lose.txt └ uploads / rubbish / stuff / keep / keep.txt
gihanchanuka

Respuestas:

119

De acuerdo con la sección de formato de patrón de la documentación de gitignore :

Un prefijo opcional "!" que niega el patrón; cualquier archivo coincidente excluido por un patrón anterior se incluirá nuevamente. No es posible volver a incluir un archivo si se excluye un directorio principal de ese archivo. Git no enumera los directorios excluidos por razones de rendimiento, por lo que los patrones en los archivos contenidos no tienen ningún efecto, sin importar dónde estén definidos. Coloque una barra invertida ("\") delante del primer "!" para patrones que comienzan con un "!" literal, por ejemplo, "! important! .txt".

Por lo tanto, el /uploads/rubbish/stuff/keep/patrón de directorio padre previamente excluido debe negarse exclusivamente antes de negar su contenido:

#ignore everything within /uploads/ 
/uploads/*

#include everything within /uploads/rubbish/stuff/keep
!/uploads/rubbish/stuff/keep/  
!/uploads/rubbish/stuff/keep/*

Para incluir subdirectorios dentro, /uploads/rubbish/stuff/keep/agregue la tercera línea:

!/uploads/rubbish/stuff/keep/**/*
Art Shayderov
fuente
1
¿Qué versión de git estabas usando? Quizás sea algo que solo esté disponible en ciertas versiones.
Desconcertado. Olvidé que publiqué este comentario. Aunque lo hice funcionar. FWIW, no uso las barras inclinadas. No recuerdo si ese fue el problema. Estoy usando 1.7.2.5.
Tengo un archivo gitignore global donde ignoré todos los archivos * .zip. Sin embargo, para un proyecto en particular, quiero incluir archivos zip. .gitignore¡ !*.zip
Agregué
Encontré que era necesario especificar explícitamente directorios arbitrarios antes y después de la carpeta dada, tanto al excluir la carpeta como al incluir la subcarpeta . ( Respuesta completa ).
Josiah Yoder
Este método no funciona (a partir de git 2.25, tal vez algo en git cambió). He publicado stackoverflow.com/a/60288435/295691 a continuación como una corrección.
user295691
34

Incluso si agrega algo .gitignore, puede forzar a git a agregarlo al índice

git add --force uploads/rubbish/stuff/KEEP_ME/

Sin embargo, "KEEP_ME" parece ser un directorio y a git generalmente no le gusta la carpeta vacía, por lo que debería agregar un archivo de marcador de posición en su lugar, si la carpeta está vacía

git add --force uploads/rubbish/stuff/KEEP_ME/.keep_me
KingCrunch
fuente
El único problema con eso es que este ejemplo específico se refiere a un gitignore global que debería haber mencionado. Sé que puedo forzar la adición de elementos, pero tendré que hacerlo si se agregan nuevos elementos, así como inicialmente para cada nuevo repositorio. ¿El .keep garantiza que no se ignoren los contenidos?
Wil
1
Hice una pequeña prueba. Sí, debe usar git add --forcepara cada nuevo elemento o carpeta en KEEP_ME. pero después de eso, las actualizaciones simplemente se agregan (cuando se hace, git add -upor ejemplo) como si los archivos no fueran ignorados. No .keep_mehace nada, es solo un archivo para que git opere en la carpeta.
commonpike
1
git add --forcees la solución incorrecta para esto. Si mueve un directorio o mueve el archivo a otro directorio, el seguimiento de git eliminará el archivo pero no lo agregará a la nueva ubicación y tendrá que hacerlo git add --forcenuevamente. al anular la ignorancia de un patrón genérico, git rastreará el movimiento de un archivo dentro del repositorio.
Merlín
Esta es la única solución que funcionó para mí. Mi carpeta NO fue ignorada, pero no pude agregarla de ninguna manera. De esta manera me lo resolvió.
Akito
6

Estaba tratando de averiguar cómo incluir una carpeta específica al excluir todas las carpetas con la exclusión genérica

**/build

si agrega el /*al final de su exclusión genérica, continúa excluyendo todos los archivos de compilación**/build/*

Luego agrega otra línea para corregir la ruta que desea que se incluya para que se vea como

!**/folder/build/* 

dejándonos un gitignore que lee

**/build/* 
!**/folder/build/* 
Juan
fuente
2

Las respuestas de Buo-Ren Lin y John son bastante útiles, pero necesitaba combinar ambas.

Cuando quería excluir otras subcarpetas, así como archivos dentro de las cargas, encontré necesario especificar explícitamente directorios arbitrarios antes de la carpeta dada, tanto al excluir la carpeta como al incluir la subcarpeta

**/uploads/*
!**/uploads/rubbish/
!**/uploads/rubbish/*

También me pareció necesario volver a incluir explícitamente tanto la subcarpeta como su contenido para mostrar tanto los elementos dentro de la carpeta como las subcarpetas.

Josiah Yoder
fuente
Suspiro. Cero suerte aquí. En esto desde hace horas. Git 2.20.1
RichieHH
@ HörmannHH Lamento oír eso. ¿Quizás es hora de hacer una nueva pregunta?
Josiah Yoder
2

La solución presentada como la respuesta más votada a favor es incorrecta y fácilmente demostrable como tal.

Comience ignorando todo en las cargas / *:

mkdir -p uploads/rubbish/stuff/KEEP_ME
touch uploads/a uploads/rubbish/a uploads/rubbish/stuff/a uploads/rubbish/stuff/KEEP_ME/a
echo '/uploads/*' >> .gitignore
git init
git add .
git commit -m "Initial commit"

Ahora deje de ignorar el directorio principal de las cosas ignoradas como arriba:

echo 'uploads/rubbish/stuff/KEEP_ME/' >> .gitignore
echo 'uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

No muestra archivos sin seguimiento.

Para que funcione, debe ignorar todos los archivos debajo del uploads/árbol ( uploads/**/*no solo el nivel superior uploads/*) y luego agregar todos los directorios principales del árbol que desea conservar

echo '/uploads/**/*' > .gitignore
echo '!/uploads/rubbish/' >> .gitignore
echo '!/uploads/rubbish/stuff' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

Lo que da:

On branch master
...
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        uploads/rubbish/stuff/KEEP_ME/a

Si hubiéramos utilizado uploads/*lo .gitignoreanterior, entonces todos los archivos intermedios también se habrían incluido, por lo que, por ejemplo uploads/rubbish/a, aparecerían en el comando de estado anterior.

usuario295691
fuente