Capítulo 4 de 33 7 secciones 6 min

Dónde vive un archivo antes de quedar guardado

La carpeta, la foto y la historia, que son tres sitios distintos

Un archivo tuyo pasa por tres sitios: la carpeta donde lo editas, una foto intermedia que tomas con <code>git add</code>, y la historia donde entra con el commit. Lo que a mí me destrabó todo fue entender que <strong>el commit guarda la foto, no la carpeta</strong>. Si editas después de sacar la foto, eso no entra 📸

Tres sitios, no uno

En el capítulo 3 dije que señalar y guardar eran dos pasos. Ahora te cuento por qué, porque de aquí salen casi todos los enredos del principio.

Un archivo tuyo puede estar en tres sitios a la vez, y con distinto contenido en cada uno:

  • La carpeta. Lo que ves cuando abres el archivo. Aquí editas.
  • La foto. Lo que se guardará en el próximo commit. Aquí entra con git add.
  • La historia. Lo que ya quedó guardado. Aquí entra con git commit.

Se ve clarísimo haciéndolo. Armo el repositorio de ventas:

mkdir tienda
cd tienda
git init -q
printf 'ciudad,monto\nLima,1200\n' > ventas.csv
git add ventas.csv
git commit -q -m "Ventas de Lima"
git status --short


Sin salida, porque los tres sitios dicen lo mismo. Ahora los separo a propósito: edito el archivo y saco la foto, y después vuelvo a editarlo.

printf 'Arequipa,890\n' >> ventas.csv
git add ventas.csv
printf 'Trujillo,1450\n' >> ventas.csv
git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   ventas.csv

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   ventas.csv

Ahí está lo importante: el mismo archivo aparece dos veces. Una en Changes to be committed, que es la foto con Arequipa, y otra en Changes not staged, que es lo de Trujillo esperando en la carpeta.

Preguntar qué hay en cada sitio

git diff a secas compara la carpeta contra la foto. O sea, te dice qué te falta agregar:

git diff
diff --git a/ventas.csv b/ventas.csv
index 0c80877..2961128 100644
--- a/ventas.csv
+++ b/ventas.csv
@@ -1,3 +1,4 @@
 ciudad,monto
 Lima,1200
 Arequipa,890
+Trujillo,1450

Y con --staged compara la foto contra la historia. Te dice qué entraría si hicieras commit ahora mismo:

git diff --staged
diff --git a/ventas.csv b/ventas.csv
index b5256c1..0c80877 100644
--- a/ventas.csv
+++ b/ventas.csv
@@ -1,2 +1,3 @@
 ciudad,monto
 Lima,1200
+Arequipa,890

Dos comandos casi iguales que contestan preguntas distintas. Yo los uso así: el primero antes del add, el segundo antes del commit 🔍

Sacar algo de la foto

Agregaste un archivo que no querías. Se quita de la foto sin perder nada de lo que escribiste:

git restore --staged ventas.csv
git status --short
 M ventas.csv

La M pasó de la primera columna a la segunda. La primera columna es la foto, la segunda es la carpeta. Con eso lees el estado corto de un vistazo y ya no vuelves a mirar el largo.

El error de restaurar lo que no existe

git restore --staged clientes.csv
error: pathspec 'clientes.csv' did not match any file(s) known to git

Ese known to git es la clave: no es que el archivo no exista, es que Git no lo conoce. Un archivo que nunca entró a un commit ni a una foto es invisible para casi todos los comandos.

La trampa

Arreglas un precio mal puesto en el CSV de ventas, haces el add y antes de guardar te das cuenta de que había otro error y lo corriges también. Commit y a otra cosa.

$ git add ventas.csv      # aquí el archivo tenía UN arreglo
$ nano ventas.csv         # y aquí le hiciste el segundo
$ git commit -m "Se corrigen los precios de Lima"

[main 3c1f80a] Se corrigen los precios de Lima
 1 file changed, 1 insertion(+), 1 deletion(-)
Qué está mal

El segundo arreglo no entró 😬

Lo que se guarda no es el archivo que tienes delante, es la foto que sacaste con el add. Todo lo que edites después de esa foto se queda esperando en la carpeta.

Y el commit no miente ni avisa: dice una inserción y una eliminación, que es exactamente lo que había en la foto. Por eso el número de líneas del resumen es de lo más útil que imprime git, y por eso conviene mirarlo.

La costumbre que lo evita es git status antes de cada commit. Si un archivo aparece a la vez en Changes to be committed y en Changes not staged, es justo esto.

Comprueba que se entendió

Comprueba que lo tienes

Haces git add ventas.csv, después editas el archivo otra vez y haces commit. ¿Qué se guardó?

  • Todo lo que hay en el archivo ahora mismo
  • Solo lo que había cuando hiciste el add
  • Nada, porque el archivo cambió después
  • Git avisa y no deja hacer el commit

Ejercicios

1. Deja el archivo en los dos sitios a la vez

Agrega el canal bodega a una ciudad, saca la foto, y después agrega otra ciudad sin sacar foto. Mira el estado corto.

printf 'Cusco,760\n' >> ventas.csv
git add ventas.csv
printf 'Piura,540\n' >> ventas.csv
git status --short
MM ventas.csv

Dos letras M en la misma línea: la primera es la foto, la segunda la carpeta. El archivo está en los dos sitios con contenido distinto.

2. Pregunta qué falta por agregar

Muestra solo lo que está en la carpeta y todavía no en la foto.

git diff --stat
 ventas.csv | 1 +
 1 file changed, 1 insertion(+)

El --stat resume en vez de mostrar línea por línea. Cuando el cambio es grande es lo primero que quieres ver.

3. Y qué entraría si guardaras ahora

Lo mismo pero comparando la foto contra la historia.

git diff --staged --stat
 ventas.csv | 3 +++
 1 file changed, 3 insertions(+)

Este es el que yo miro siempre antes de un commit. Si el número de líneas no es el que esperabas, algo se coló.

4. Guarda solo lo que está en la foto

Haz el commit y comprueba que Piura se quedó fuera.

git commit -q -m "Entra Cusco en las ventas"
git status --short
 M ventas.csv

Piura sigue ahí esperando, con su M en la segunda columna. No se perdió, simplemente no era parte de esa foto 🙂

5. Mira qué versión quedó guardada

Pide el archivo tal como está en el último commit y compáralo con el de tu carpeta.

git show HEAD:ventas.csv
echo "--- y en la carpeta ---"
cat ventas.csv
ciudad,monto
Lima,1200
Arequipa,890
Trujillo,1450
Cusco,760
--- y en la carpeta ---
ciudad,monto
Lima,1200
Arequipa,890
Trujillo,1450
Cusco,760
Piura,540

Cinco líneas en la historia y seis en la carpeta. Los dos sitios son distintos y los dos son correctos.

6. Tira lo que hay en la carpeta y no está guardado

Descarta el cambio de Piura, que no llegó a ningún commit. Ojo: esto sí borra.

git restore ventas.csv
cat ventas.csv
git status --short
ciudad,monto
Lima,1200
Arequipa,890
Trujillo,1450
Cusco,760

Piura desapareció y el estado quedó limpio. restore sin --staged pisa la carpeta con lo que hay en la historia, y lo que no estaba guardado no se recupera 🗑️

7. Un archivo que Git no conoce

Crea un CSV de clientes y trata de restaurarlo sin haberlo agregado nunca. Tiene que fallar.

printf 'bodega,ciudad\nBodega Sol,Lima\n' > clientes.csv
git restore clientes.csv
error: pathspec 'clientes.csv' did not match any file(s) known to git

Restaurar significa traer de vuelta algo guardado, y de este archivo no hay nada guardado. Para Git todavía no existe 👻

Lo que te llevas

El commit guarda la foto que sacaste, no el archivo que tienes delante.

¿Tienes alguna duda o consulta?