.gitignore excluye carpeta pero incluye subcarpeta específica
965
Tengo la carpeta application/que agrego a .gitignore. Dentro de la application/carpeta está la carpeta application/language/gr. ¿Cómo puedo incluir esta carpeta?
Si excluye application/, todo lo que se encuentre debajo de él siempre se excluirá (incluso si algún patrón de exclusión negativa posterior ("ignorar") puede coincidir con algo debajo application/).
Para hacer lo que quiere, debe "ignorar" cada directorio padre de todo lo que desea "ignorar". Por lo general, terminas escribiendo reglas para esta situación en pares: ignora todo en un directorio, pero no cierto subdirectorio.
# you can skip this first one if it is not already excluded by prior patterns
!application/
application/*
!application/language/
application/language/*
!application/language/gr/
Nota
El seguimiento /*es significativo:
El patrón dir/excluye un directorio llamado diry (implícitamente) todo debajo de él.
Con dir/, Git nunca mirará nada debajo diry, por lo tanto, nunca aplicará ninguno de los patrones de "no excluir" a nada debajo dir.
El patrón dir/*no dice nada sobre dirsí mismo; simplemente excluye todo debajo dir. Con dir/*, Git procesará el contenido directo de dir, dando a otros patrones la oportunidad de "excluir" un poco del contenido ( !dir/sub/).
¿Son significativos los asteriscos finales? Si es así, ¿cuál es la diferencia de significado? Según el algoritmo descrito en la documentación de gitignore , terminar con una barra inclinada final coincide con un directorio y rutas debajo de ese directorio. Terminar con un asterisco se convertiría en un tratamiento global. La experimentación muestra que la variante de asterisco funciona, pero no la que termina en una barra inclinada final. Me gustaría entender por qué es así.
seh
123
@seh: Sí, el seguimiento /*es significativo. Si se excluye un directorio, Git nunca mirará el contenido de ese directorio. El patrón dir/excluye un directorio llamado diry (implícitamente) todo debajo de él. El patrón dir/*no dice nada sobre dirsí mismo; simplemente excluye todo debajo dir. Con dir/, Git nunca mirará nada debajo diry, por lo tanto, nunca aplicará ninguno de los patrones de "no excluir" a nada debajo dir. Con dir/*, Git procesará el contenido directo de dir, dando a otros patrones la oportunidad de "excluir" un poco del contenido ( !dir/sub/).
Chris Johnsen
77
Ah, eso lo explica. No importa cuántas veces haya leído la documentación de gitignore , nunca entendí cuándo los patrones revertidos no funcionan. Con su explicación, ahora está claro. La documentación de gitignore necesita una sección de "receta" para explicar cómo hacer esto.
seh
8
No pude conseguir que esto funcionara (¡archivo .gitignore loco!), Así que en lugar de eso simplemente agregué los archivos después de cd'ing al directorio que quería. git add -f .
K0D4
2
Tenga en cuenta que no puede confiar en la salida de git status, que solo le indicará que se agregará el directorio de nivel superior. En su lugar, haga uno git adddel directorio de nivel superior y luego git status(con suerte) enumerará el subconjunto de archivos que ha coincidido con el patrón.
gitignore.txt: aclarar la naturaleza recursiva de los directorios excluidos
Un prefijo opcional " !" que niega el patrón; cualquier archivo coincidente excluido por un patrón anterior se volverá a incluir.
No es posible volver a incluir un archivo si se excluye un directorio principal de ese archivo. ( *)
( *: a menos que se cumplan ciertas condiciones en git 2.8+, ver más abajo)
Git no enumera los directorios excluidos por razones de rendimiento, por lo que cualquier patrón en los archivos contenidos no tiene ningún efecto, sin importar dónde estén definidos.
Coloque una barra diagonal inversa (" \") delante de la primera " !" para los patrones que comienzan con un literal " !", por ejemplo, " \!important!.txt".
Ejemplo para excluir todo excepto un directorio específico foo/bar(tenga en cuenta que /*, sin la barra inclinada, el comodín también excluiría todo lo que contenga foo/bar):
Traté de usar la sintaxis de reincorporación actualizada publicada al final de su respuesta en git para windows v2.8.1.windows.1pero no parece funcionar :(
David Hancock
1
@DavidHancock Lo siento, he editado la respuesta: esto aún no está disponible.
VonC
1
@DavidHancock yo también: eso es más de 13 respuestas de desbordamiento de pila que tuve que editar varias veces.
VonC
55
Git 2.9 fue lanzado ayer. Confirmar que el patrón application/+ !application/language/gr/mencionado en la respuesta funciona como se esperaba.
Ray Shan
1
@RayShan Strange: He visto la confirmación de cancelación cancelando esa función, pero no la he visto (y la nota de lanzamiento github.com/git/git/blob/master/Documentation/RelNotes/2.9.0.txt no menciona) cualquier commit que mejore las reglas de .gitignore.
VonC
52
La respuesta de @Chris Johnsen es excelente, pero con una versión más reciente de Git (1.8.2 o posterior), hay un patrón de doble asterisco que puede aprovechar para una solución un poco más abreviada:
# assuming the root folder you want to ignore is 'application'
application/**/*
# the subfolder(s) you want to track:
!application/language/gr/
De esta manera, no tiene que "ignorar" el directorio principal de la subcarpeta que desea rastrear.
Con Git 2.17.0 (No estoy seguro de qué tan temprano antes de esta versión. Posiblemente vuelva a 1.8.2), usando el **patrón combinado con exclusiones para cada subdirectorio que conduce a su (s) archivo (s). Por ejemplo:
# assuming the root folder you want to ignore is 'application'
application/**
# Explicitly track certain content nested in the 'application' folder:
!application/language/
!application/language/gr/
!application/language/gr/** # Example adding all files & folder in the 'gr' folder
!application/language/gr/SomeFile.txt # Example adding specific file in the 'gr' folder
Por desgracia, esto falla (Git 1.8.4.msysgit.0) porque el patrón **puede coincidir con cero subcarpetas, y *lo coincidirá languagey excluirá, evitando la inclusión de gr. La cadena completa de padres que @Chris Johnson recomienda parece necesaria todavía.
Sean Gugler
3
Suena perfecto pero no funciona para mí en git 2.3.7 ... /www/**/* !/www/config.xml !/www/resconfig.xml y el directorio res todavía se ignora.
Rob
@Rob también necesita agregar !/www/res/. Puede usar el folder/**/*patrón, pero aún necesita agregar exclusiones para cada subdirectorio que desea agregar. Todavía es más corto y más legible que el combo ignorar / excluir.
Ben Kane
Sé que es un comentario antiguo, pero en caso de que tenga curiosidad. He agregado una edición a la respuesta que documenta este enfoque.
Ben Kane
21
Hay un montón de preguntas similares sobre esto, así que publicaré lo que escribí antes:
La única forma en que conseguí que esto funcionara en mi máquina fue hacerlo de esta manera:
# Ignore all directories, and all sub-directories, and it's contents:
*/*
#Now ignore all files in the current directory
#(This fails to ignore files without a ".", for example
#'file.txt' works, but
#'file' doesn't):
*.*
#Only Include these specific directories and subdirectories:
!wordpress/
!wordpress/*/
!wordpress/*/wp-content/
!wordpress/*/wp-content/themes/
!wordpress/*/wp-content/themes/*
!wordpress/*/wp-content/themes/*/*
!wordpress/*/wp-content/themes/*/*/*
!wordpress/*/wp-content/themes/*/*/*/*
!wordpress/*/wp-content/themes/*/*/*/*/*
Observe cómo debe permitir explícitamente el contenido para cada nivel que desee incluir. Entonces, si tengo subdirectorios 5 profundos debajo de los temas, todavía necesito explicarlo.
La forma más simple y probablemente la mejor es intentar agregar los archivos manualmente (generalmente esto tiene prioridad sobre .gitignorelas reglas de estilo):
git add /path/to/module
Incluso puede que desee la -Nintención de añadir la bandera, para sugerir que se añada ellos, pero no inmediatamente. A menudo hago esto para archivos nuevos que aún no estoy listo para presentar.
Esta es una copia de una respuesta publicada en lo que fácilmente podría ser un control de calidad duplicado. Lo vuelvo a publicar aquí para aumentar la visibilidad. Me resulta más fácil no tener un lío de reglas de gitignore.
Gracias por esta respuesta Tuve que agregar -f ya que está en mi .gitignore así: git add -f ruta / a / archivo
jasonflaherty
6
Entonces, dado que muchos programadores usan el nodo. el caso de uso que cumple con esta pregunta es excluir node_modulesexcepto un módulo, module-apor ejemplo:
!/.vs/ <== include this folder to source control, folder only, nothing else
/.vs/* <== but ignore all files and sub-folder inside this folder
!/.vs/ProjectSettings.json <== but include this file to source control
!/.vs/config/ <== then include this folder to source control, folder only, nothing else
!/.vs/config/* <== then include all files inside the folder
Esta fue la respuesta más útil para mí ya que las imágenes ayudaron. ¡Gracias!
Joel Murphy
4
Especialmente para las versiones anteriores de Git, la mayoría de las sugerencias no funcionarán tan bien. Si ese es el caso, pondría un .gitignore por separado en el directorio donde quiero que se incluya el contenido independientemente de otras configuraciones y permitiría allí lo que se necesita.
Por ejemplo: /.gitignore
# ignore all .dll files
*.dll
/dependency_files/.gitignore
# include everything
!*
Por lo tanto, todo en / dependency_files (incluso archivos .dll) se incluye muy bien.
He encontrado un caso similar aquí, donde en laravel por defecto, .gitignoreignora todos los que usan asterix, luego anula el directorio público.
*
!public
!.gitignore
Esto no es suficiente si se encuentra con el escenario OP.
Si quieres cometer un subcarpetas específicas de public, digamos por ejemplo, en el public/productsdirectorio que desea incluir archivos que son una subcarpeta profunda por ejemplo para incluir public/products/a/b.jpgque no será detectado correctamente, incluso si se agregan específicamente como éste !/public/products, !public/products/*etc ..
La solución es asegurarse de agregar una entrada para cada nivel de ruta como este para anularlos a todos.
Solo otro ejemplo de caminar por la estructura del directorio para obtener exactamente lo que desea. Nota: no excluí Library/peroLibrary/**/*
# .gitignore file
Library/**/*
!Library/Application Support/
!Library/Application Support/Sublime Text 3/
!Library/Application Support/Sublime Text 3/Packages/
!Library/Application Support/Sublime Text 3/Packages/User/
!Library/Application Support/Sublime Text 3/Packages/User/*macro
!Library/Application Support/Sublime Text 3/Packages/User/*snippet
!Library/Application Support/Sublime Text 3/Packages/User/*settings
!Library/Application Support/Sublime Text 3/Packages/User/*keymap
!Library/Application Support/Sublime Text 3/Packages/User/*theme
!Library/Application Support/Sublime Text 3/Packages/User/**/
!Library/Application Support/Sublime Text 3/Packages/User/**/*macro
!Library/Application Support/Sublime Text 3/Packages/User/**/*snippet
!Library/Application Support/Sublime Text 3/Packages/User/**/*settings
!Library/Application Support/Sublime Text 3/Packages/User/**/*keymap
!Library/Application Support/Sublime Text 3/Packages/User/**/*theme
> git add Library
> git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: Library/Application Support/Sublime Text 3/Packages/User/Default (OSX).sublime-keymap
new file: Library/Application Support/Sublime Text 3/Packages/User/ElixirSublime.sublime-settings
new file: Library/Application Support/Sublime Text 3/Packages/User/Package Control.sublime-settings
new file: Library/Application Support/Sublime Text 3/Packages/User/Preferences.sublime-settings
new file: Library/Application Support/Sublime Text 3/Packages/User/RESTer.sublime-settings
new file: Library/Application Support/Sublime Text 3/Packages/User/SublimeLinter/Monokai (SL).tmTheme
new file: Library/Application Support/Sublime Text 3/Packages/User/TextPastryHistory.sublime-settings
new file: Library/Application Support/Sublime Text 3/Packages/User/ZenTabs.sublime-settings
new file: Library/Application Support/Sublime Text 3/Packages/User/adrian-comment.sublime-macro
new file: Library/Application Support/Sublime Text 3/Packages/User/json-pretty-generate.sublime-snippet
new file: Library/Application Support/Sublime Text 3/Packages/User/raise-exception.sublime-snippet
new file: Library/Application Support/Sublime Text 3/Packages/User/trailing_spaces.sublime-settings
gitignore: especifica los archivos intencionalmente no rastreados para ignorar.
Ejemplo para excluir todo excepto un directorio específico foo / bar (tenga en cuenta el / * - sin la barra inclinada, el comodín también excluiría todo dentro de foo / bar ):
A menudo utilizo esta solución alternativa en la CLI donde, en lugar de configurar mi .gitignore, creo un .includearchivo separado donde defino los (sub) directorios que quiero incluir a pesar de los directorios que se ignoran directamente o recursivamente .gitignore.
Por lo tanto, también uso
git add `cat .include`
durante la puesta en escena, antes de comprometerse.
Para el OP, sugiero usar un .includeque tenga estas líneas:
<parent_folder_path>/application/language/gr/*
NOTA: El uso catno permite el uso de alias (dentro .include) para especificar $ HOME (o cualquier otro directorio específico). Esto se debe a que la línea homedir/app1/*
cuando se pasa al git adduso del comando anterior aparece como git add 'homedir/app1/*', y al encerrar los caracteres entre comillas simples ('') conserva el valor literal de cada carácter dentro de las comillas, evitando así que funcionen los alias (como homedir ) (vea Bash Single Cotizaciones )
Aquí hay un ejemplo de un .includearchivo que uso en mi repositorio aquí .
.gitignore
documentación del "formato de patrón" se volvió más clara (diciembre de 2013). Vea mi respuesta a continuaciónRespuestas:
Si excluye
application/
, todo lo que se encuentre debajo de él siempre se excluirá (incluso si algún patrón de exclusión negativa posterior ("ignorar") puede coincidir con algo debajoapplication/
).Para hacer lo que quiere, debe "ignorar" cada directorio padre de todo lo que desea "ignorar". Por lo general, terminas escribiendo reglas para esta situación en pares: ignora todo en un directorio, pero no cierto subdirectorio.
Nota
El seguimiento
/*
es significativo:dir/
excluye un directorio llamadodir
y (implícitamente) todo debajo de él.Con
dir/
, Git nunca mirará nada debajodir
y, por lo tanto, nunca aplicará ninguno de los patrones de "no excluir" a nada debajodir
.dir/*
no dice nada sobredir
sí mismo; simplemente excluye todo debajodir
. Condir/*
, Git procesará el contenido directo dedir
, dando a otros patrones la oportunidad de "excluir" un poco del contenido (!dir/sub/
).fuente
/*
es significativo. Si se excluye un directorio, Git nunca mirará el contenido de ese directorio. El patróndir/
excluye un directorio llamadodir
y (implícitamente) todo debajo de él. El patróndir/*
no dice nada sobredir
sí mismo; simplemente excluye todo debajodir
. Condir/
, Git nunca mirará nada debajodir
y, por lo tanto, nunca aplicará ninguno de los patrones de "no excluir" a nada debajodir
. Condir/*
, Git procesará el contenido directo dedir
, dando a otros patrones la oportunidad de "excluir" un poco del contenido (!dir/sub/
).git add -f .
git status
, que solo le indicará que se agregará el directorio de nivel superior. En su lugar, haga unogit add
del directorio de nivel superior y luegogit status
(con suerte) enumerará el subconjunto de archivos que ha coincidido con el patrón.Commit 59856de de Karsten Blees (kblees) para Git 1.9 / 2.0 (Q1 2014) aclara ese caso:
gitignore.txt
: aclarar la naturaleza recursiva de los directorios excluidosEn tu caso:
Primero debe hacer una lista blanca de las carpetas , antes de poder hacer una lista blanca de los archivos dentro de una carpeta determinada.
Actualización febrero / marzo 2016:
Tenga en cuenta que con git 2.9.x / 2.10 (¿mediados de 2016?), Es posible volver a incluir un archivo si se excluye un directorio principal de ese archivo si no hay un comodín en la ruta que se vuelve a incluir .
Nguyễn Thái Ngọc Duy (
pclouds
) está intentando agregar esta característica:Entonces, con git 2.9+, esto podría haber funcionado, pero finalmente se revirtió:
fuente
v2.8.1.windows.1
pero no parece funcionar :(application/
+!application/language/gr/
mencionado en la respuesta funciona como se esperaba.La respuesta de @Chris Johnsen es excelente, pero con una versión más reciente de Git (1.8.2 o posterior), hay un patrón de doble asterisco que puede aprovechar para una solución un poco más abreviada:
De esta manera, no tiene que "ignorar" el directorio principal de la subcarpeta que desea rastrear.
Con Git 2.17.0 (No estoy seguro de qué tan temprano antes de esta versión. Posiblemente vuelva a 1.8.2), usando el
**
patrón combinado con exclusiones para cada subdirectorio que conduce a su (s) archivo (s). Por ejemplo:fuente
**
puede coincidir con cero subcarpetas, y*
lo coincidirálanguage
y excluirá, evitando la inclusión degr
. La cadena completa de padres que @Chris Johnson recomienda parece necesaria todavía./www/**/* !/www/config.xml !/www/res
config.xml y el directorio res todavía se ignora.!/www/res/
. Puede usar elfolder/**/*
patrón, pero aún necesita agregar exclusiones para cada subdirectorio que desea agregar. Todavía es más corto y más legible que el combo ignorar / excluir.Hay un montón de preguntas similares sobre esto, así que publicaré lo que escribí antes:
La única forma en que conseguí que esto funcionara en mi máquina fue hacerlo de esta manera:
Observe cómo debe permitir explícitamente el contenido para cada nivel que desee incluir. Entonces, si tengo subdirectorios 5 profundos debajo de los temas, todavía necesito explicarlo.
Esto es del comentario de @ Yarin aquí: https://stackoverflow.com/a/5250314/1696153
Estos fueron temas útiles:
También intenté
y
**/wp-content/themes/**
o
/wp-content/themes/**/*
Nada de eso funcionó para mí tampoco. ¡Muchas pruebas y errores!
fuente
!
reglas en la parte inferior.He encontrado que esto realmente funciona.
fuente
La forma más simple y probablemente la mejor es intentar agregar los archivos manualmente (generalmente esto tiene prioridad sobre
.gitignore
las reglas de estilo):Incluso puede que desee la
-N
intención de añadir la bandera, para sugerir que se añada ellos, pero no inmediatamente. A menudo hago esto para archivos nuevos que aún no estoy listo para presentar.Esta es una copia de una respuesta publicada en lo que fácilmente podría ser un control de calidad duplicado. Lo vuelvo a publicar aquí para aumentar la visibilidad. Me resulta más fácil no tener un lío de reglas de gitignore.
fuente
Entonces, dado que muchos programadores usan el nodo. el caso de uso que cumple con esta pregunta es excluir
node_modules
excepto un módulo,module-a
por ejemplo:fuente
2.10.2.windows.1
.Agregue una respuesta adicional:
Aquí está el resultado:
fuente
Especialmente para las versiones anteriores de Git, la mayoría de las sugerencias no funcionarán tan bien. Si ese es el caso, pondría un .gitignore por separado en el directorio donde quiero que se incluya el contenido independientemente de otras configuraciones y permitiría allí lo que se necesita.
Por ejemplo: /.gitignore
/dependency_files/.gitignore
Por lo tanto, todo en / dependency_files (incluso archivos .dll) se incluye muy bien.
fuente
He encontrado un caso similar aquí, donde en laravel por defecto,
.gitignore
ignora todos los que usan asterix, luego anula el directorio público.Esto no es suficiente si se encuentra con el escenario OP.
Si quieres cometer un subcarpetas específicas de
public
, digamos por ejemplo, en elpublic/products
directorio que desea incluir archivos que son una subcarpeta profunda por ejemplo para incluirpublic/products/a/b.jpg
que no será detectado correctamente, incluso si se agregan específicamente como éste!/public/products
,!public/products/*
etc ..La solución es asegurarse de agregar una entrada para cada nivel de ruta como este para anularlos a todos.
fuente
Solo otro ejemplo de caminar por la estructura del directorio para obtener exactamente lo que desea. Nota: no excluí
Library/
peroLibrary/**/*
> git add Library
> git status
fuente
En WordPress, esto me ayudó:
fuente
gitignore: especifica los archivos intencionalmente no rastreados para ignorar.
Ejemplo para excluir todo excepto un directorio específico foo / bar (tenga en cuenta el / * - sin la barra inclinada, el comodín también excluiría todo dentro de foo / bar ):
Otro ejemplo para WordPress :
Más información aquí: https://git-scm.com/docs/gitignore
fuente
A menudo utilizo esta solución alternativa en la CLI donde, en lugar de configurar mi
.gitignore
, creo un.include
archivo separado donde defino los (sub) directorios que quiero incluir a pesar de los directorios que se ignoran directamente o recursivamente.gitignore
.Por lo tanto, también uso
durante la puesta en escena, antes de comprometerse.
Para el OP, sugiero usar un
.include
que tenga estas líneas:NOTA: El uso
cat
no permite el uso de alias (dentro.include
) para especificar $ HOME (o cualquier otro directorio específico). Esto se debe a que la líneahomedir/app1/*
cuando se pasa algit add
uso del comando anterior aparece comogit add 'homedir/app1/*'
, y al encerrar los caracteres entre comillas simples ('') conserva el valor literal de cada carácter dentro de las comillas, evitando así que funcionen los alias (como homedir ) (vea Bash Single Cotizaciones )Aquí hay un ejemplo de un
.include
archivo que uso en mi repositorio aquí .fuente
Quería rastrear archivos js de producción js y esto funcionó:
fuente
mi configuración de JetBrains IntelliJ IDEA .gitignore, donde necesito excluir la
.idea
carpeta wholde excepto.idea/runConfigurations
:ver: https://github.com/daggerok/gitignore-idea-runConfigurations
fuente