Skip to content

Excluir ficheros del proyecto

Juan Antonio Tubio edited this page Apr 27, 2015 · 1 revision

##Excluir ficheros del repositorio.

Según el tipo de proyecto que estemos desarrollando, habrá ficheros que no queramos que se incluyan en el repositorio. O bien por tamaño, o bien porque contienen información privada o particular del entorno de trabajo, etc.. Un ejemplo pueden ser ficheros de log, de la cache, temporales, con las contraseñas de las bases de datos, ficheros binarios del resultado de las compilaciones, de backups, etc..

Para excluir ficheros de un repositorio, lo configuramos mediante unas reglas o patrones. Git usa un fichero de texto plano en el que cada línea es un patrón de exclusión. Pueden usarse comodines y algunos tipos de patrones especiales que nos permitirán posibilidades casi ilimitadas.

Puedes usar '#' al principio de una línea para escribir comentarios en el fichero.

En internet tienes una estupenda herramienta online que te ayudará a generar tus ficheros .gitignore: https://www.gitignore.io/

###Fichero .gitignore

El método más habitual y sencillo es utilizar el fichero .gitignore.

Este es un fichero que se crea en la raíz del proyecto. Y como hemos dicho anteriormente, contiene una línea por cada patrón que queramos excluir. La reglas que escribamos en este fichero se aplican a todos los directorios del repositorio a no ser que alguno de ellos tenga a su vez su propio fichero .gitignore.

Los ficheros .gitignore se incluyen en el repositorio, es decir, se versionan. Por tanto, estos ficheros se utilizan para aquellos patrones de exclusión que queremos distribuir junto con el proyecto y que todos los programadores van a utilizar.

Por ejemplo, los puedes utilizar para excluir ficheros temporales que se generen durante la ejecución o compilación de la aplicación, como los ficheros .log, .tmp, .bak, etc.., o por el editor o IDE que estés utilizando si lo usan la mayotía de los desarrolladores del proyecto.

Además del fichero de la raíz del proyecto, podemos crear tantos ficheros como queramos en otros directorios. De ese modo podemos tener patrones sólo para algunos directorios. Los patrones de los directorios 'hijos' sobrescriben siempre a los patrones de sus directorios 'padre'. Excepto si el directorio ha sido explícitamente excluído en una regla anterior.

Para indicar un patrón a excluir, puedes usar el nombre de un fichero, por ejemplo: composer.lock, el nombre de un directorio, por ejemplo: vendor, comodines del sistema operativo (*,?), por ejemplo: *.log o cualquier combinación de esos patrones como por ejemplo: app/cache/*.tmp.

Puedes usar también el patrón de corchetes [] para indicar un carácter de los introducidos entre los corchetes.

Algunos ejemplos de patrones:

# Excluye todos los ficheros con extensión .log
*.log

# Excluye los ficheros cuya extensión empiece por b y tengan a continuación 2 letras.
# Excluye prueba.bak y test.bat pero no temp.backup o test.b
*.b??

# Excluye los ficheros cuyo nombre sea `test`, `tust`  o `tast`. Pero no `teest`.
t[eua]st*

Cada línea tiene preferencia sobre las líneas precedentes, es decir, tienen mayor preferencia las líneas al final del fichero.

Para indicar una 'excepción' o un patrón de 'inclusión', puedes usar una exclamación ! al comienzo de la línea. Te permitirá añadir una excepción a un patrón anterior Excepto para patrones en los que excluimos un directorio usando su nombre completo. En ese caso, cualquier regla que sea una excepción a ese directorio, no se aplica.

Para especificar un patrón únicamente para carpetas y no para ficheros, usa una barra / al final. Por ejemplo, vendor excluirá todos los ficheros y carpetas que se llamen vendor y vendor/ excluirá las carpetas pero no un fichero que se llame vendor.

Dos asteriscos seguidos tienen un significado especial:

  • ** al comienzo seguidos por una barra / significa buscar en todos los directorios por debajo del raíz. Por ejemplo, **/test es equivalente a test excluye todos los directorios o ficheros con nombre test del repositorio.

  • ** al comienzo seguidos por una barra / y una ruta significa buscar en todos los directorios por debajo de esa ruta. La última parte es el patrón a buscar. Por ejemplo, **/cache/test excluye todos los directorios o ficheros con nombre test por debajo del directorio cache.

  • /** al final significa buscar en todos los directorios y ficheros por debajo de la ruta. Por ejemplo, cache/** excluye todos los ficheros y directorio por debajo de la carpeta cache relativa al fichero .gitignore.

  • /**/ entre medias de dos patrones, quiere decir 'cero o más directorios'. Por ejemplo, vendor/**/cache excluye vendor/cache, vendor/laravel/cache, vendor/superadmin/login/test/cache, etc...

Un fichero de ejemplo podría ser:

#Test files
phpunit.xml

#Composer files
composer.lock
composer.phar

#Others
build
vendor
coverage.clover

/cache/*
temp/*.tmp

#Mac files
.DS_Store

Ejemplos de patrones:

Hemos representado el sistema de archivos de un proyecto de ejemplo y hemos marcado con un + los ficheros incluidos y con un - los excluidos del repositorio y a continuación la regla que ha determinado su estado. Suponiendo que el fichero .gitignore esté en el directorio raíz:


# Excluye todos los archivos o directorios que empiecen por 'composer'
# 
composer*

# Pero incluye el fichero composer.lock de la ráiz
!/composer.lock

# Pero incluye todos los archivos o directorios dentro de la carpeta app/composer relativa al fichero `.gitignore` recursivamente.
!app/composer

Este sería el resultado:

composer.lock (+) .... !/composer.lock
composer.xml (-) ..... composer*
composer/last.txt (-) ..... composer*

app/composer/cache/app_composer_cache.xxx (+) .... La regla composer* no lo excluye
app/composer/composer.lock (+) .... !app/composer
app/composer/migration.php (+) .... !app/composer
app/composer/files.txt (+) .... !app/composer
app/composer/migration.php (+) .... !app/composer

vendor/composer/cache/app_composer_cache.xxx (-) ..... composer*
vendor/composer/composer.lock (-) ..... composer*
vendor/composer/files.txt (-) ..... composer*
vendor/composer/migration.php (-) ..... composer*

vendor/app/composer/cache/app_composer_cache.xxx (-) ..... composer*
vendor/app/composer/composer.lock (-) ..... composer*
vendor/app/composer/files.txt (-) ..... composer*
vendor/app/composer/migration.php (-) ..... composer*

``` --- # Incluye todos los ficheros cache.properties # Esta línea no tendrá resultado porque hay una exclusión que incluye este patrón en una línea posterior !cache.properties

Excluye todos los archivos cuya extensión empiece por xml

.xml

Pero incluye el fichero phpunit.xml de la carpeta /pruebas

!/pruebas/phpunit.xml

Pero incluye los ficheros *.xml que estén dentro de la carpeta pruebas relativa a este directorio

!pruebas/*.xml

Pero incluye los ficheros *.xml que cuya segunda letra sea una 'r' o por 'a'

!?[ra]*.xml

Pero incluye los ficheros phpunit.xml que estén dentro de cualquier directorio llamado app recursivamente

!app/**/phpunit.xml

Excluye todos los ficheros con extensión .properties

*.properties


	Este sería el resultado:

	```
	phpunit.xml (-) .... *.xml*
	composer.xml (-) .... *.xml*
	app/composer/cache/phpunit.xml (+) .... !app/**/phpunit.xml
	app/composer/cache/test.xml (-) .... *.xml*
	app/pruebas/phpunit.xml (+) .... !app/**/phpunit.xml
	app/pruebas/travis.xml (+) .... !?[ra]*.xml
	app/pruebas/users.xml.tmp (-) .... *.xml*
	app/travis.xml (+) .... !?[ra]*.xml
	app/users.xml (-) .... *.xml*
	pruebas/phpunit.xml (+) .... !pruebas/*.xml
	pruebas/travis.xml (+) .... !pruebas/*.xml
	test/phpunit.xml (-) .... *.xml*
	test/travis.xml (+) .... !?[ra]*.xml
	test/users.xml (-) .... *.xml*
	vendor/pruebas/phpunit.xml (-) .... *.xml*
	vendor/pruebas/test.xmls (-) .... *.xml*
	vendor/pruebas/test.xmlt (-) .... *.xml*
	vendor/pruebas/travis.xml (+) .... !?[ra]*.xml	
	
	/cache.properties.tmp (+) .... La regla *.properties no lo excluye
	/app/cache.properties (-) .... *.properties
	/cache.properties (-) .... *.properties
	/build/project.properties (-) .... *.properties
	```
--- 
<br>
**Importante:**

- En Windows tienes que usar las barras al estilo Unix `/`.

- Si quieres excluir un fichero que ya está siendo versionado por Git, además de incluirlo en el fichero `.gitignore`, tienes que borrarlo del repositorio con el comando `git rm --cached <fichero>` para que deje de ser versionado pero se mantenga el fichero físico en el directorio.

> Usa `git rm --cached -r <fichero>` para que dejen de ser versionados todos los ficheros de los directorios que cumplan con el patrón. Por ejemplo: `git rm --cached -r *.log`para excluir todos los ficheros `*.log` del proyecto.

- Git sólo versiona ficheros y no directorios. Por lo tanto, no versionará los directorios vacíos. Si quieres versionarlos, un truco es incluir en el directorio un fichero `.gitignore` vacío. Puedes hacerlo desde la línea de comandos con `touch .gitignore`.

 En algunos entornos hay una convención para usar un fichero llamado `.gitkeep` para este tipo de directorios. Por ejemplo Ruby on Rails suele utilizarlos para los directorios de la cache y de los logs.
 
- Ten en cuenta que los patrones en estos ficheros son siempre **relativos**. Utiliza una barra `/` al principio de un patrón que quieras que se aplique sólo al directorio en el que se encuentra el fichero `.gitignore` y no a todos los subdirectorios. Por ejemplo, si en el fichero `.gitignore` del directorio raíz del repositorio añadimos la línea: `*.txt`, Git ignorará todos los ficheros de texto del repositorio. Si únicamente queremos ignorar los de la carpeta raíz, tendremos que usar: `/*.txt`.

- Recuerda que `*` es igual a ninguno o varios caracteres, mientras `?` hace referencia a un carácter. Y que `**` tiene un significado especial.

- Si usas `/*/` el asterisco representa únicamente a un directorio y no a varios. Por ejemplo, `/vendor/*/*/cache/` excluye la carpetas `vendor/flysystem/composer/cache` y `vendor/illuminate/db/cache' pero no `vendor/flysystem/cache' ni `vendor/flysystem/composer/test/cache'.

- Para utilizar caracteres especiales (`*?[]#`) en un patrón, tienes que `escaparlos` con una barra invertida `\`. Si el primer carácter del patron es una exclamación, también tienes que escaparlo. Por ejemplo: `\!importante!.txt` 

- Los directorios con un patrón explícito son excluidos SIEMPRE en su totalidad. Es decir, cuando excluimos un subdirectorio, no se procesa y por tanto, aunque contenga ficheros `.gitignore` con excepciones, no se tendrán en cuenta. Por tanto, para excluir (o incluir) únicamente algunos ficheros de un subdirectorio, hay que hacerlo en un fichero `.gitignore` en ese subdirectorio.

###Más información.
[GitIgnore.Io - Para generar ficheros .gitignore](https://www.gitignore.io/)  
[gitignore en la documentación de git (En inglés)](http://git-scm.com/docs/gitignore)