Git básico II: el ciclo de cambios
Segunda entrega de la serie Git básico. Si te perdiste la primera, empieza por crear y clonar repositorios. Tiempo de lectura estimado: 5 minutos.
En el post anterior de la serie vimos cómo crear o clonar un repositorio y consultar su estado. Hoy toca lo que vas a hacer cientos de veces al día: preparar un conjunto de cambios, guardarlos como un commit y revisar qué has modificado antes de hacerlo. Tres comandos: git add, git commit y git diff.
El modelo de tres zonas
Antes de los comandos, una imagen mental. Git tiene tres "zonas" donde viven tus cambios:
- Working tree: los ficheros tal cual los ves y editas.
- Staging area (o index): una zona intermedia donde preparas lo que va a ir en el próximo commit.
- Repositorio: el histórico, los commits ya guardados.
El flujo es: editas en el working tree, promueves cambios al staging area con git add, y los congelas como commit en el repo con git commit. El staging area es lo que distingue a git de sistemas más simples: te permite hacer commits quirúrgicos, solo de una parte de lo que has tocado.
git add: preparar cambios para el commit
git add pasa cambios del working tree al staging area. No guarda nada en el histórico todavía; solo dice "esto es lo que quiero que entre en el próximo commit".
git add README.md # añade un fichero concreto
git add src/ # añade todo lo modificado en una carpeta
git add . # añade todo lo cambiado en el directorio actual
git add -A # añade todos los cambios del repo entero
La diferencia entre . y -A es sutil pero importante: . solo afecta al directorio actual y subcarpetas; -A considera todo el repo aunque estés metido en una subcarpeta. En la práctica, si estás en la raíz del repo dan casi lo mismo.
La opción que de verdad merece la pena aprender es -p:
git add -p
-p es interactivo: git te muestra los cambios por "hunks" (bloques) y te pregunta uno a uno si quieres añadirlos. Escribes y (sí), n (no), s (partir el hunk en dos) o e (editar manualmente). Esto te permite hacer commits separados de cambios que están mezclados en el mismo fichero. Lo uso constantemente cuando llevo un rato programando y veo que he tocado dos cosas distintas que deberían ser dos commits.
Un error típico: usar git add . sin mirar qué estás añadiendo. Un día incluyes sin querer un fichero con credenciales, un binario enorme o notas personales. La solución es el par git status seguido de git add de ficheros concretos, no el git add . a ciegas.
Para "despreparar" algo que añadiste por error:
git restore --staged README.md
Git mismo te sugiere este comando en el output de git status cuando tienes cosas en staging. No hace falta memorizarlo.
git commit: guardar los cambios preparados
git commit toma lo que hay en el staging area y crea un commit: un snapshot con un mensaje, un autor y una fecha. Una vez hecho, ese commit queda en el histórico del repo local. No en el remoto: para eso hace falta hacer push, que veremos en el siguiente post.
git commit # abre el editor para el mensaje
git commit -m "Añadir README inicial" # mensaje en una línea
git commit -am "Fix typo" # add automático + commit
El -a mete en staging todos los ficheros ya trackeados que hayan cambiado, y luego hace commit. Pero ojo: no añade ficheros nuevos (untracked). Para esos, siempre git add explícito.
Sobre el mensaje: gastar treinta segundos en un buen mensaje ahorra horas en el futuro. Convención razonable: primera línea corta (50 caracteres máximo) en imperativo ("Arreglar validación de email" en vez de "Arreglé la validación"), luego una línea en blanco, luego un párrafo explicando el por qué si hace falta. No repitas en el mensaje lo que el diff ya dice; explica lo que el diff no cuenta.
Lo que no se hace:
- Commits con mensaje "wip", "cambios" o "fix" y punto. En tres meses no tendrás ni idea de qué hicieron.
- Commits gigantes que tocan cinco cosas distintas. Divide; usa
git add -p. - Amend o rebase sobre commits que ya has empujado a una rama compartida. En tu rama local haz lo que quieras; en la rama de todos, no reescribas historia ya publicada.
git diff: ver exactamente qué has cambiado
git diff te muestra las diferencias entre dos estados. Sin argumentos, compara el working tree con el staging area: o sea, lo que has tocado pero no has añadido aún.
git diff # working tree vs staging
git diff --staged # staging vs último commit
git diff HEAD # working tree vs último commit (incluye staged)
git diff main # working tree vs otra rama
git diff main..develop # diferencias entre dos ramas
El que más uso es --staged (también escrito --cached): justo antes de hacer git commit, ejecuto git diff --staged para ver exactamente lo que voy a committear. Es mi última línea de defensa contra meter código comentado, console.log sueltos o trozos de debug. Dos segundos de revisión y evitas un commit avergonzante.
Flags útiles:
git diff --stat # resumen: ficheros y líneas añadidas/quitadas
git diff --word-diff # diff por palabras, no por líneas
git diff -- ruta # limita a un fichero o carpeta
--stat es el resumen rápido: si el diff completo tiene mil líneas, --stat te da un mapa de ocho líneas con los ficheros y su tamaño de cambio. Es la versión "índice" del diff.
El ciclo en vivo
Un ejemplo de sesión realista:
git status # veo qué tengo cambiado
git diff # miro los cambios sin staged
git add src/handler.go src/utils.go # añado dos ficheros concretos
git diff --staged # reviso lo que voy a commitear
git commit -m "Validar email antes de crear usuario"
git status # confirmo que todo está limpio
Tres minutos. Cinco comandos. Esto, multiplicado por diez o veinte veces al día, es buena parte del trabajo con git.
Errores típicos de esta fase
Commitear secretos. Una vez un token está en la historia de git, quitarlo es doloroso (y si ya hiciste push, prácticamente irreversible). Usa .gitignore y revisa siempre con git diff --staged antes de commitear.
Ignorar lo que dice git status. Git te dice en texto plano qué hacer. Si te pone "use git restore", haz caso: funciona.
Hacer commits enormes "para no dejar cabos sueltos". Al revés: muchos commits pequeños son más fáciles de revisar, revertir y entender. Si estás tocando varias cosas, haz varios commits con git add -p.
Lo que viene
Con add, commit y diff ya tienes el ciclo local completo. Pero los commits locales no los ve nadie más. En la tercera entrega de la serie, la conexión con el mundo: git pull, git push y git log. Sincronizar tu trabajo con un remoto y consultar la historia de quién hizo qué.
Más adelante, cuando quieras dar el salto, están las series intermedia y avanzada.