Git no guarda cambios en una fila: el staging decide qué historia tendrá tu próximo commit

Artículo ID 145. Git no guarda cambios en una fila: el staging decide qué historia tendrá tu próximo commit.

Tesis y apertura

Tesis: el área de staging no es un lujo ni un detalle implementacional: es la selección explícita del próximo snapshot que quedará en tu repositorio. Esa elección es deliberada y separa dos preguntas distintas que solemos mezclar: «¿qué ha cambiado en mi árbol de trabajo?» frente a «¿qué se incluirá en el próximo commit?». git status y git diff responden a esas preguntas diferentes; entender esa distinción evita sorpresas cuando crees haber guardado algo y el commit no lo contiene.

Contexto técnico breve

Git mantiene tres espacios conceptuales relevantes aquí: HEAD (el último commit en tu rama), el índice o staging area (index) —una instantánea provisional que prepara el próximo commit— y el working tree (tu copia de trabajo con archivos modificados). Cuando haces git add actualizas la copia del archivo que hay en el índice, no el HEAD; cuando haces git commit creas un nuevo commit a partir del contenido del índice. Las fuentes oficiales explican esto de forma detallada: What is Git — Pro Git y Recording Changes — Pro Git. Para la sintaxis y la semántica de git status, consulta la documentación oficial de git-status.

Guía paso a paso — único archivo README

Vamos a trabajar únicamente con un archivo README.md para ver, con comandos reproducibles, cómo el staging decide el contenido del commit final. Supondremos un repositorio ya inicializado (git init) y que HEAD apunta a un commit inicial.

Paso 1: estado inicial

Contenido inicial de README.md (en el commit HEAD):

# Proyecto
Descripción breve.

Verifica el estado:

git status --porcelain
# nada que informar si estás en un estado limpio

Paso 2: editar README — primer cambio

Abre README.md y cambia una línea:

# Proyecto
Descripción breve. Añadí una línea nueva que quiero revisar.

Ahora ejecuta:

git status
git diff

Observa: git status te dirá que README.md está modificado en el working tree (por ejemplo, «modified: README.md»). git diff mostrará las diferencias entre tu working tree y el índice (index). En este momento, como no hiciste git add todavía, git diff mostrará el cambio que acabas de escribir.

Paso 3: stage (git add) del primer cambio

Ahora añadimos el archivo al índice:

git add README.md
git status
git diff
git diff --staged

Interpretación:

  • git status mostrará «changes to be committed» para README.md: ese es el contenido ahora en el índice, y será lo que se use para el próximo commit.
  • git diff (sin opciones) ahora compara working tree vs índice: como el índice ya contiene tu primera edición, git diff mostrará diferencias entre tu working tree actual y el índice —ahora mismo no debería mostrar nada si no has editado de nuevo.
  • git diff –staged (o –cached) compara el índice con HEAD y mostrará las diferencias que se van a grabar en el siguiente commit: en este caso, la edición que agregaste con git add.

Paso 4: editar README otra vez (segunda edición)

Sin hacer commit, edita README.md de nuevo para añadir otra frase:

# Proyecto
Descripción breve. Añadí una línea nueva que quiero revisar.
Otra línea que modifiqué después.

Ahora ejecuta:

git status
git diff
git diff --staged

Comportamiento esperado y por qué importa:

  • git status mostrará README.md en dos secciones: «changes to be committed» (la primera edición que ya está en el índice) y «changes not staged for commit» (la edición nueva en el working tree).
  • git diff mostrará la diferencia entre working tree e índice: verá la segunda edición (la que aún no pusiste en staging).
  • git diff –staged seguirá mostrando la diferencia entre índice y HEAD: esa salida no incluye la segunda edición porque no forma parte del índice.

Paso 5: decidir el snapshot — añadir selectivamente

Opciones prácticas:

  • Si quieres que sólo la primera edición vaya en el commit, no añadas la segunda edición al índice y ejecuta git commit. El commit contendrá el primer cambio y la segunda seguirá sin formar parte del historial.
  • Si quieres incluir ambas, añade de nuevo README.md (o usa git add -p para trozos específicos) y then commit.
  • Si prefieres descartar la segunda edición, puedes restaurar el working tree desde el índice con git restore –source=:/ –staged=false README.md o, en versiones antiguas, git checkout — README.md (aunque se recomienda usar restore/restore –staged en versiones modernas).
# incluir sólo la primera edición en el commit
git commit -m "Agregar primera línea de descripción"

# incluir ambas ediciones
git add README.md
git commit -m "Actualizar README con dos líneas"

# descartar la segunda edición y volver al estado staged
git restore --source=HEAD --staged=false README.md

Ejemplo técnico concreto — salidas reales y su significado

A continuación reproduzco la secuencia de salidas (resumidas) que verías tras los pasos anteriores.

$ git status
On branch main
Changes to be committed:
  (use "git restore --staged ..." to unstage)
    modified: README.md

Changes not staged for commit:
  (use "git add ..." to update what will be committed)
    modified: README.md

$ git diff
diff --git a/README.md b/README.md
index e69de29..abcd123 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
 # Proyecto
-Descripción breve. Añadí una línea nueva que quiero revisar.
+Descripción breve. Añadí una línea nueva que quiero revisar.
+Otra línea que modifiqué después.

$ git diff --staged
diff --git a/README.md b/README.md
index e69de29..1234abc 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
 # Proyecto
-Descripción breve.
+Descripción breve. Añadí una línea nueva que quiero revisar.

La lectura de estas salidas explica por qué el commit que hagas ahora puede contener sólo la primera modificación: git diff –staged muestra lo que HEAD recibirá si confirmas ahora mismo.

Preguntas contextuales incrustadas (3–5)

¿Qué hago si quiero commitear sólo parte de un archivo? Usa git add -p para trocear cambios y seleccionar hunks. ¿Cómo verifico exactamente qué irá en el commit antes de pulsar commit? Usa git diff –staged y git status; la primera te muestra el contenido preciso que el commit tomará. ¿Por qué muchas guías recomiendan commits pequeños? Porque el staging te permite agrupar cambios coherentes en snapshots significativos, facilitando revisiones y deshacer cambios.

Enlaces internos para profundizar

Si te interesa refinar cómo escribes tus mensajes de commit para que el snapshot tenga sentido histórico, consulta Buenas prácticas: mensajes de commit. Para herramientas que integran staging de forma visual en editores, mira Extensiones VSCode para principiantes. Si trabajas con utilidades complementarias y flujos de trabajo, Herramientas esenciales para programar puede ser útil. Y para quienes versionan código JavaScript, Conceptos básicos de JavaScript contiene enlaces y prácticas relacionadas con bundlers y cómo afectan al repositorio.

Por qué status y diff responden preguntas distintas (matemática mental)

Piensa en tres conjuntos: A = archivos en HEAD, B = archivos en el índice, C = archivos en working tree. Las operaciones que ejecutas comparan pares diferentes:

  • git diff (sin opciones) produce C \ B (los cambios que aún no se han llevado al índice).
  • git diff –staged (o –cached) produce B \ A (lo que el índice contiene respecto a HEAD, es decir, lo que se grabará si confirmas ahora).
  • git status informa sobre ambos conjuntos y su relación: te dice qué está en B \ A y qué está en C \ B, con sugerencias de acciones.

Esta separación de conjuntos es la razón por la que muchas «sorpresas» ocurren: confundir C \ B con B \ A cuando crees que has hecho git add para todo. Staging te obliga a ser explícito sobre la historia que construirás.

Cierre técnico (sin llamada a la acción)

En un flujo de trabajo consciente, el staging no es un paso accidental: es la herramienta que te permite construir snapshots intencionales. Dominar git status, git diff y git diff –staged te da control para responder dos preguntas distintas y complementarias: «¿qué está modificado ahora mismo en mi copia de trabajo?» y «¿qué pasará al historial si confirmo ahora?». Cuando aceptes la idea de que stage = selección explícita del próximo snapshot, dejarás de perder cambios en commits y empezarás a usar el historial como una narrativa deliberada, no como un volcado accidental del directorio.

El área de staging (índice) en Git es una zona intermedia que te permite preparar exactamente qué cambios irán en el próximo commit. Un caso típico que confunde a muchos es: modificas README, haces git add README (lo staged) y luego modificas README otra vez sin volver a añadirlo. En ese momento el archivo contiene dos estados diferentes: el contenido en el índice (lo que se añadió) y el contenido en tu directorio de trabajo (la versión más reciente).

Para ver rápidamente estos estados puedes usar git status -s (la salida corta). Ese modo muestra dos columnas de estado antes del nombre del fichero. La primera columna representa el estado de ese archivo en el índice respecto al último commit (HEAD): qué hay staged. La segunda columna representa el estado del directorio de trabajo respecto al índice: qué hay sin stage todavía. Algunos códigos habituales son M (modified), A (added), D (deleted), R (renamed), C (copied), U (unmerged). Además aparecen ? para archivos no rastreados y ! para ignorados.

Ejemplos de interpretación:

 M README.md    -> primera columna en blanco, segunda M: modificado pero no staged
M  README.md    -> primera M, segunda espacio: modificado y ya staged (listo para commit)
MM README.md    -> ambas columnas M: se modificó, se hizo stage, y luego se modificó de nuevo sin stage

En el flujo que describimos (modificas, añades, modificas de nuevo) verás precisamente algo como MM README.md. El commit siguiente incluirá la versión que está en el índice (la que añadiste), no la última modificación en tu directorio de trabajo, a menos que vuelvas a hacer git add antes de commitear.

Para inspeccionar diferencias hay dos comandos que conviene distinguir: git diff y git diff --staged (o --cached, sinónimos). git diff muestra las diferencias entre el directorio de trabajo y el índice: es lo que aún no has staged. Por eso, justo después de modificar README y antes de añadir, git diff README te mostrará esos cambios recientes. En cambio git diff --staged muestra las diferencias entre el índice y el HEAD (el último commit): es lo que se incluirá en el próximo commit. Si hiciste git add README y luego corriste git diff --staged, verás lo que añadirás al histórico.

Seleccionar partes de un cambio (por ejemplo con git add -p, git add --patch o herramientas gráficas de staging parcial) altera la historia futura porque defines precisamente qué contenido entra en cada commit. Un commit es una instantánea del árbol construida a partir del índice: si stageas solo ciertas líneas o trozos, el commit reflejará únicamente esas porciones. El resto queda para commits posteriores. Esto tiene consecuencias importantes:

  • Legibilidad y atomicidad: dividir cambios en commits pequeños y coherentes mejora la revisión y la trazabilidad. Cada commit puede representar una idea o corrección independiente.
  • Asignación de autoría y blame: la atribución de líneas a commits (y por tanto a autores) dependerá de cómo partiste las modificaciones.
  • Bisect y revert: aislar cambios facilita usar git bisect y revertir solo lo necesario. Si mezclas varias ideas en un solo commit, será más difícil localizar fallos.
  • Contexto y conflictos: al stagear fragmentos sin el contexto adecuado puedes crear commits que pasan los tests pero dejan el código menos comprensible; además, separar refactorizaciones de correcciones evita conflictos y ruido histórico.

Un flujo recomendable cuando trabajas con archivos como README es: después de editar, usar git status -s para ver si tienes cambios sin stage; usar git add -p si quieres partir los cambios; verificar con git diff (cambios sin stage) y git diff --staged (lo que irá al commit); y finalmente hacer git commit. Este control te da historia más clara y facilita la colaboración.

Para ampliar conceptos ligados al desarrollo y herramientas que complementan Git, puede ser útil revisar artículos sobre fundamentos de programación y recursos para desarrolladores, como por ejemplo una guía de conceptos básicos de JavaScript, una lista de herramientas esenciales para programar y estas buenas prácticas para mensajes de commit. Estas lecturas ayudan a entender mejor por qué mantener commits limpios y comprensibles mejora el flujo de trabajo en equipo.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio