Skip to content
This page has been auto-translated and may contain errors.View in English

Ignorar archivos y buenas prácticas

docs.scrimba.com

Clonas un proyecto llamado weather-app, ejecutas npm install, y verificas el estado de tu nuevo repositorio.

bash
$ git status
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	node_modules/
	dist/
	.env

Tres carpetas y archivos aparecen como sin rastrear, y ninguno de ellos pertenece a un commit. node_modules/ contiene miles de archivos que npm install regenera desde package.json en segundos. dist/ es la salida de compilación que se reconstruye desde tu fuente cada vez. Y .env contiene una clave API. Nada de eso debería llegar jamás al historial de tu proyecto, y escribir git add . sin pensar es cómo sucede de todas formas.

Indicarle a Git qué ignorar

Un archivo .gitignore lista patrones de archivos y carpetas que Git nunca debe rastrear. Lo creas una vez en la raíz de tu proyecto, en el mismo lugar donde ejecutaste git init cuando configuraste el repositorio en Tu primer repositorio, y desde entonces, git status y git add . omiten silenciosamente cualquier cosa que coincida.

bash
# .gitignore
node_modules/
dist/
.env

Cada línea es un patrón: un nombre de carpeta simple como dist/ ignora esa carpeta completa, en cualquier lugar donde aparezca en el proyecto. Haz commit del archivo .gitignore en sí. Es pequeño, es útil para todos los que clonan el proyecto, y pertenece al historial de la misma manera que tu código fuente.

bash
$ git status
On branch main
nothing to commit, working tree clean

Con los patrones en su lugar, git status se queda en silencio. Ese es exactamente el punto: las carpetas y archivos que nunca quieres hacer commit dejan de aparecer como ruido, así que las cosas que sí aparecen son las que realmente importan.

Los patrones admiten globs, así que *.log ignora cada archivo que termina en .log, sin importar su nombre. Una barra inclinada final restringe un patrón a directorios, así que dist/ coincide solo con una carpeta llamada dist y deja en paz cualquier archivo que comparta el nombre. Comienza una línea con ! para dejar de ignorar algo que un patrón más amplio capturaría de otro modo, útil cuando un archivo dentro de una carpeta ignorada necesita ser rastreado:

bash
# .gitignore
logs/
!logs/keep-this.log

Git también lee un archivo de ignore global, uno por máquina, para patrones que quieres en cada repositorio sin importar el proyecto: basura de editor como .DS_Store o *.swp. Configúralo una vez con git config --global core.excludesfile ~/.gitignore_global, y nunca tendrás que agregar esos patrones proyecto por proyecto nuevamente.

Los patrones de ignore se emparejan de la misma manera que los globs de shell: * para cualquier secuencia de caracteres, ? para uno, ** para emparejar a través de directorios. Un patrón sin barra inclinada coincide a cualquier profundidad en el proyecto, mientras que un patrón que contiene una barra inclinada está anclado a esa ruta. Emparejar esos patrones es un comportamiento puramente local: Git solo consulta .gitignore cuando decide qué git status y git add te muestran. No evita que un archivo sea rastreado una vez que Git ya lo tiene, lo cual importa en la siguiente sección.

JunoIndicarle a Git qué ignorar Un archivo .gitignore lista lo que Git nunca debe rastrear: node_modules/, dist/, y .env son los sospechosos usuales en casi cualquier proyecto. Haz commit del archivo .gitignore en sí para que todos los que clonan el proyecto obtengan el mismo estado limpio. Desperdicié toda una tarde una vez organizando miles de archivos de dependencias por accidente antes de aprender esta.
JunoIndicarle a Git qué ignorar Los patrones admiten globs como *.log, una barra inclinada final significa "solo directorio", y un ! inicial desactiva el ignore para algo dentro de un coincidencia más amplia. Un archivo de ignore global, configurado con core.excludesfile, es donde pertenece la basura de editor y del SO para que dejes de agregar .DS_Store al .gitignore de cada proyecto a mano.
JunoIndicarle a Git qué ignorar Las reglas de ignore son coincidencias de glob al estilo de shell, aplicadas del lado del cliente, y solo cambian lo que Git te muestra como sin rastrear. Ten en mente que una regla solo puede afectar un archivo que Git aún no conoce. Esa distinción es pequeña en papel y cara en la práctica.

Nunca hagas commit de secretos

Una clave API, una contraseña de base de datos, o un certificado de firma nunca debe aparecer en un commit. Eso aplica para un repositorio privado tan firmemente como para uno público, y aplica desde el primer commit en adelante. Pon los secretos en un archivo como .env, agrega ese archivo a .gitignore el primer día, y carga los valores en tu aplicación desde allí en lugar de escribirlos en tus archivos de fuente.

bash
# .env
WEATHER_API_KEY=sk_live_9f8e7d6c5b4a
bash
# .gitignore
.env

Sigue esta regla automáticamente, cada vez, sin excepciones. Una clave que está en un commit es accesible por cualquiera con acceso al repositorio, y en un repositorio público, por cualquiera en absoluto.

En un proyecto real, los secretos generalmente viven en más de un lugar: un archivo .env para tu propia máquina, y un administrador de secretos o la configuración de variables de entorno de tu host para cualquier cosa desplegada. Ambos funcionan de la misma manera en la práctica: el valor vive fuera de tus archivos de fuente y fuera de Git, y tu código lo lee desde el entorno en tiempo de ejecución. Envía un archivo .env.example en su lugar, con los nombres de variables pero sin valores reales, para que los compañeros de equipo sepan qué configurar sin ver nunca tu clave real.

Aquí está el hecho que hace que esta regla sea innegociable: un commit del cual eliminas un secreto no lo elimina del historial. Cada commit anterior que tenía la clave todavía la tiene, guardada para siempre en el historial del repositorio, y cada clon que alguien haya hecho lleva esos commits antiguos junto con él. Eliminar el archivo en un nuevo commit solo significa que la snapshot más nueva ya no lo tiene; el objeto que contiene el valor antiguo todavía está en .git, accesible por cualquiera que revise un commit anterior o hurguee en el log.

"Eliminar el archivo y hacer commit nuevamente" nunca soluciona un secreto que ya ha sido filtrado. Si un secreto real llega a un commit, rótalo o revócalo en el proveedor (emite una clave nueva, invalida la antigua) para que el valor filtrado deje de ser útil, sin importar lo que hagas con el repositorio después. Reescribir el historial para eliminar un secreto es posible, pero no deshacer ningún uso que la clave ya haya tenido mientras estaba expuesta. Trata la rotación como la solución que importa e la limpieza del historial como algo opcional adicional.

JunoNunca hagas commit de secretos Nunca pongas una clave API real, contraseña, o certificado en un commit. Mantén los secretos en un archivo como .env y agrega .env a tu .gitignore antes de ejecutar nunca git add. Esta es la única regla en este capítulo que vale la pena tratar como absoluta.
JunoNunca hagas commit de secretos Los secretos locales van en .env, los secretos desplegados van en las variables de entorno de tu host o un administrador de secretos, y ninguno se hace commit nunca. Envía un .env.example solo con los nombres de variables, para que los compañeros de equipo sepan qué configurar sin ver un valor real.
JunoNunca hagas commit de secretos Eliminar un secreto en un nuevo commit no lo elimina del historial. Cada commit anterior y cada clon existente todavía lo tiene. Rota la clave en el proveedor en el momento en que se filtra: esa rotación es la solución que realmente importa.

Agregar un archivo a .gitignore después de que está rastreado

Este es el obstáculo que atrapa a casi todos al menos una vez. Haces commit de un archivo por accidente, te das cuenta de tu error, lo agregas a .gitignore (la línea echo de abajo añade la ruta a ese archivo), y esperas que Git lo olvide. No lo hace.

bash
$ git add config/settings.json
$ git commit -m "Add app settings"

# más tarde, te das cuenta de que fue un error
$ echo "config/settings.json" >> .gitignore
$ git status
On branch main
nothing to commit, working tree clean

git status muestra un árbol limpio, pero config/settings.json todavía está rastreado y todavía aparece en cada git log futuro y en cada clon. Las reglas de ignore solo aplican a los archivos que Git aún no conoce. Una vez que un archivo ha sido agregado y hecho commit, es parte de tu historial, y .gitignore no tiene opinión sobre los archivos ya en ese historial.

Para dejar de rastrearlo realmente de ahora en adelante, dile a Git que suelte el archivo de lo que sigue mientras dejas el archivo en tu disco:

bash
$ git rm --cached config/settings.json
$ git commit -m "Stop tracking config/settings.json"

git rm --cached <file> elimina el archivo del rastreo de Git sin borrarlo de tu directorio de trabajo. Haz commit de esa eliminación, y desde ese punto en adelante tu patrón .gitignore hace el trabajo que querías que hiciera desde el principio.

La misma solución funciona en una carpeta completa con git rm -r --cached <folder>, que es el movimiento usual después de darse cuenta de que node_modules/ o dist/ fueron hechos commit al principio de la vida de un proyecto, antes de que alguien agregara un .gitignore en absoluto. Ejecútalo una vez, haz commit de la eliminación, y la carpeta desaparece de los commits futuros mientras la copia local de los archivos de cada compañero de equipo permanece intacta en el disco.

Este comportamiento se sigue directamente de lo que el área de preparación realmente es. Git rastrea archivos a través del index, el registro de exactamente lo que irá en el próximo commit. Agregar y hacer commit de un archivo escribe una entrada para él en el index y en la snapshot del commit; .gitignore solo se consulta cuando Git está decidiendo qué hacer con un archivo que no tiene entrada de index todavía.

Una vez que existe una entrada, los patrones de ignore son irrelevantes para él. git rm --cached elimina la entrada de index mientras mantiene el archivo en el disco, que es por qué es el comando que realmente soluciona esto, donde editar el patrón de ignore solo no hace nada.

JunoAgregar un archivo a .gitignore después de que está rastreado Agregar un archivo a .gitignore después de que Git ya lo rastrea no hace nada a ese archivo. Las reglas de ignore solo aplican a los archivos que Git nunca ha agregado. Para dejar de rastrear un archivo que se coló por accidente, ejecuta git rm --cached <file> y haz commit de ese cambio.
JunoAgregar un archivo a .gitignore después de que está rastreado.gitignore solo afecta los archivos sin rastrear. Para cualquier cosa ya hecha commit, suéltala con git rm --cached <file>, o git rm -r --cached <folder> para un directorio completo, luego haz commit. Los archivos locales de todos permanecen en su lugar, solo el rastreo de Git de ellos cambia.
JunoAgregar un archivo a .gitignore después de que está rastreado El index mantiene una entrada para cada archivo rastreado, y .gitignore solo se consulta cuando no hay entrada todavía. git rm --cached elimina la entrada de index sin tocar el archivo en el disco, que es la solución real aquí. Agrega el patrón de ignore por si acaso para que el archivo no pueda colarse de nuevo.

Buenas prácticas: commits pequeños y un repositorio limpio

Un .gitignore ordenado es la mitad de mantener un repositorio que vale la pena trabajar. La otra mitad es cómo das forma a tus commits. Haz que cada commit sea un cambio enfocado: una corrección de error, una pequeña característica, un solo refactoring. Si una tarde de trabajo toca varias cosas no relacionadas, divídela en varios commits en lugar de dejarla caer todo en uno al final del día.

bash
$ git add src/weather-widget.js
$ git commit -m "Fix temperature rounding in weather widget"

Los commits pequeños son más fáciles de revisar, más fáciles de revertir si algo se rompe, y más fáciles de leer seis meses después cuando estás intentando recordar por qué una línea de código existe. El bucle de commit cubre lo que hace que un mensaje de commit sea útil; este hábito se trata de mantener el cambio en sí lo suficientemente pequeño para que un mensaje bueno sea incluso posible de escribir.

Combina ese hábito con un .gitignore limpio y la recompensa se compone: un historial hecho de commits pequeños y propositivos, sin carpetas generadas o archivos de config extraños ensuciando el diff. Revisar un cambio lleno de churn de dist/ junto con las dos líneas reales que alguien editó es miserable para todos los involucrados, y es completamente evitable con un .gitignore configurado el primer día.

A escala esto paga dividendos de maneras más allá de la legibilidad. Un repositorio libre de archivos generados y carpetas de dependencias se mantiene lo suficientemente pequeño para clonar rápidamente y buscar limpiamente, y un historial de commits enfocados es lo que hace que git log --oneline y git diff entre dos puntos en el tiempo realmente sean útiles para entender qué pasó y por qué. Nada de eso funciona bien contra un historial donde la mitad de los commits son churn de node_modules/ y la otra mitad mezclan cinco cambios no relacionados juntos.

JunoBuenas prácticas: commits pequeños y un repositorio limpio Mantén cada commit a un cambio enfocado, y mantén tu .gitignore cubriendo las carpetas y secretos que nunca deben ser rastreados. Esos dos hábitos juntos son la mayoría de lo que hace que un repositorio sea agradable de trabajar. Hábitos pequeños, formados temprano, te ahorran mucha limpieza después.
JunoBuenas prácticas: commits pequeños y un repositorio limpio Commits pequeños y enfocados más un .gitignore limpio hacen que las revisiones y diffs sean realmente legibles en lugar de enterrados en ruido generado. Configura el .gitignore antes de tu primer commit. Esperar hasta que node_modules/ aparezca en un pull request por quinta vez cuesta más limpieza de la que ahorra.
JunoBuenas prácticas: commits pequeños y un repositorio limpio Un repositorio delgado y un historial de commits enfocados son lo que mantiene los clones rápidos e historial legible cuando lo buscas. Cada archivo generado o carpeta de dependencia que se cuela en el historial es un pequeño impuesto que cada clon y búsqueda futura pagan. Configura las reglas de ignore desde el principio y deja de ser un problema que vale la pena pensar de nuevo.