{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Dónde vive un archivo antes de quedar guardado\n",
    "\n",
    "La carpeta, la foto y la historia, que son tres sitios distintos\n",
    "\n",
    "Cuaderno de soluciones del capítulo 4 de **Git desde cero**, de Miss Yera.\n",
    "\n",
    "Corre de arriba abajo. Si lo abres en Google Colab no necesitas instalar nada.\n",
    "\n",
    "Capítulo completo: https://missyera.com/guias/git-desde-cero/los-tres-estados/\n",
    "\n",
    "Este es el cuaderno de **soluciones**. Trae el código de cada ejercicio, la\n",
    "explicación de la trampa y la respuesta del quiz. Si vienes del cuaderno de\n",
    "práctica sin haberlo intentado, vuelve 🙂"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Antes de empezar\n",
    "\n",
    "Este capítulo son comandos de terminal, no Python. La celda de abajo baja el\n",
    "ayudante que los ejecuta y que **recuerda en qué carpeta quedaste**, que es lo\n",
    "que hace falta para que un `cd` de una celda siga valiendo en la siguiente.\n",
    "\n",
    "A partir de ahí, cada celda de comandos empieza por `%%consola`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import urllib.request\n",
    "\n",
    "# El ayudante de los cuadernos. Trae la corrección de los ejercicios y, en los\n",
    "# capítulos de consola, la celda mágica que ejecuta los comandos. Se baja en\n",
    "# vez de venir pegado aquí para que siempre sea el último.\n",
    "urllib.request.urlretrieve(\n",
    "    \"https://missyera.com/static/cuadernos/revisa.py\", \"revisa.py\")\n",
    "import revisa\n",
    "revisa.carga({}, lenguaje=\"bash\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tres sitios, no uno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "En el capítulo 3 dije que señalar y guardar eran\n",
    "dos pasos. Ahora te cuento por qué, porque de aquí salen casi todos los enredos\n",
    "del principio.\n",
    "\n",
    "Un archivo tuyo puede estar en tres sitios a la vez, y con distinto\n",
    "contenido en cada uno:\n",
    "\n",
    "- **La carpeta.** Lo que ves cuando abres el archivo. Aquí\n",
    "editas.\n",
    "\n",
    "- **La foto.** Lo que se guardará en el próximo commit. Aquí\n",
    "entra con `git add`.\n",
    "\n",
    "- **La historia.** Lo que ya quedó guardado. Aquí entra con\n",
    "`git commit`.\n",
    "\n",
    "Se ve clarísimo haciéndolo. Armo el repositorio de ventas:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "mkdir tienda\n",
    "cd tienda\n",
    "git init -q\n",
    "printf 'ciudad,monto\\nLima,1200\\n' > ventas.csv\n",
    "git add ventas.csv\n",
    "git commit -q -m \"Ventas de Lima\"\n",
    "git status --short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Sin salida, porque los tres sitios dicen lo mismo. Ahora los separo a\n",
    "propósito: edito el archivo y saco la foto, y después vuelvo a editarlo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "printf 'Arequipa,890\\n' >> ventas.csv\n",
    "git add ventas.csv\n",
    "printf 'Trujillo,1450\\n' >> ventas.csv\n",
    "git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahí está lo importante: **el mismo archivo aparece dos veces**.\n",
    "Una en *Changes to be committed*, que es la foto con Arequipa, y otra en\n",
    "*Changes not staged*, que es lo de Trujillo esperando en la carpeta."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preguntar qué hay en cada sitio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`git diff` a secas compara la carpeta contra la foto. O sea, te\n",
    "dice qué te falta agregar:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git diff"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y con `--staged` compara la foto contra la historia. Te dice qué\n",
    "entraría si hicieras commit ahora mismo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git diff --staged"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dos comandos casi iguales que contestan preguntas distintas. Yo los uso así:\n",
    "el primero antes del `add`, el segundo antes del commit 🔍"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Sacar algo de la foto"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Agregaste un archivo que no querías. Se quita de la foto sin perder nada de\n",
    "lo que escribiste:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git restore --staged ventas.csv\n",
    "git status --short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La `M` pasó de la primera columna a la segunda. La primera columna\n",
    "es la foto, la segunda es la carpeta. Con eso lees el estado corto de un\n",
    "vistazo y ya no vuelves a mirar el largo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El error de restaurar lo que no existe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Esto revienta a propósito**, y de eso va. La celda te muestra la queja igual que te la mostraría tu terminal."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git restore --staged clientes.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y la queja que tiene que salir es esta:\n",
    "\n",
    "```\n",
    "error: pathspec 'clientes.csv' did not match any file(s) known to git\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ese *known to git* es la clave: no es que el archivo no exista, es que\n",
    "Git no lo conoce. Un archivo que nunca entró a un commit ni a una foto es\n",
    "invisible para casi todos los comandos."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### La trampa\n",
    "\n",
    "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.\n",
    "\n",
    "```\n",
    "$ git add ventas.csv      # aquí el archivo tenía UN arreglo\n",
    "$ nano ventas.csv         # y aquí le hiciste el segundo\n",
    "$ git commit -m \"Se corrigen los precios de Lima\"\n",
    "\n",
    "[main 3c1f80a] Se corrigen los precios de Lima\n",
    " 1 file changed, 1 insertion(+), 1 deletion(-)\n",
    "```\n",
    "\n",
    "**Qué está mal**\n",
    "\n",
    "El segundo arreglo no entró 😬\n",
    "\n",
    "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.\n",
    "\n",
    "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.\n",
    "\n",
    "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."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comprueba que se entendió"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "Haces `git add ventas.csv`, después editas el archivo otra vez y haces commit. ¿Qué se guardó?\n",
    "\n",
    "a) Todo lo que hay en el archivo ahora mismo\n",
    "\n",
    "b) Solo lo que había cuando hiciste el `add`\n",
    "\n",
    "c) Nada, porque el archivo cambió después\n",
    "\n",
    "d) Git avisa y no deja hacer el commit\n",
    "\n",
    "---\n",
    "\n",
    "**La correcta es la b.**\n",
    "\n",
    "*a)* No. El commit guarda la foto, y la foto se sacó antes de tu última edición. Vuelve a la sección de los tres sitios.\n",
    "\n",
    "*c)* El commit sí se hace. Lo que pasa es que guarda una versión más vieja de la que tienes delante, y eso es peor que no guardar nada.\n",
    "\n",
    "*d)* Ojalá. Git no avisa: hace el commit y te deja creyendo que entró todo. Por eso el capítulo insiste en mirar el estado antes.\n",
    "\n",
    "El commit guarda la foto, no la carpeta 📷"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Deja el archivo en los dos sitios a la vez\n",
    "\n",
    "Agrega el canal bodega a una ciudad, saca la foto, y\n",
    "después agrega otra ciudad sin sacar foto. Mira el estado corto."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "printf 'Cusco,760\\n' >> ventas.csv\n",
    "git add ventas.csv\n",
    "printf 'Piura,540\\n' >> ventas.csv\n",
    "git status --short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "MM ventas.csv\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dos letras `M` en la misma línea: la primera es la foto, la\n",
    "segunda la carpeta. El archivo está en los dos sitios con contenido distinto."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Pregunta qué falta por agregar\n",
    "\n",
    "Muestra solo lo que está en la carpeta y todavía no en la\n",
    "foto."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git diff --stat"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    " ventas.csv | 1 +\n",
    " 1 file changed, 1 insertion(+)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El `--stat` resume en vez de mostrar línea por línea. Cuando el\n",
    "cambio es grande es lo primero que quieres ver."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Y qué entraría si guardaras ahora\n",
    "\n",
    "Lo mismo pero comparando la foto contra la historia."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git diff --staged --stat"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    " ventas.csv | 3 +++\n",
    " 1 file changed, 3 insertions(+)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Este es el que yo miro siempre antes de un commit. Si el número de líneas no\n",
    "es el que esperabas, algo se coló."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Guarda solo lo que está en la foto\n",
    "\n",
    "Haz el commit y comprueba que Piura se quedó fuera."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git commit -q -m \"Entra Cusco en las ventas\"\n",
    "git status --short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    " M ventas.csv\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Piura sigue ahí esperando, con su `M` en la segunda columna. No se\n",
    "perdió, simplemente no era parte de esa foto 🙂"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. Mira qué versión quedó guardada\n",
    "\n",
    "Pide el archivo tal como está en el último commit y\n",
    "compáralo con el de tu carpeta."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git show HEAD:ventas.csv\n",
    "echo \"--- y en la carpeta ---\"\n",
    "cat ventas.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "ciudad,monto\n",
    "Lima,1200\n",
    "Arequipa,890\n",
    "Trujillo,1450\n",
    "Cusco,760\n",
    "--- y en la carpeta ---\n",
    "ciudad,monto\n",
    "Lima,1200\n",
    "Arequipa,890\n",
    "Trujillo,1450\n",
    "Cusco,760\n",
    "Piura,540\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cinco líneas en la historia y seis en la carpeta. Los dos sitios son\n",
    "distintos y los dos son correctos."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. Tira lo que hay en la carpeta y no está guardado\n",
    "\n",
    "Descarta el cambio de Piura, que no llegó a ningún commit.\n",
    "Ojo: esto sí borra."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git restore ventas.csv\n",
    "cat ventas.csv\n",
    "git status --short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "ciudad,monto\n",
    "Lima,1200\n",
    "Arequipa,890\n",
    "Trujillo,1450\n",
    "Cusco,760\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Piura desapareció y el estado quedó limpio. `restore` sin\n",
    "`--staged` pisa la carpeta con lo que hay en la historia, y lo que\n",
    "no estaba guardado **no se recupera** 🗑️"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. Un archivo que Git no conoce\n",
    "\n",
    "Crea un CSV de clientes y trata de restaurarlo sin haberlo\n",
    "agregado nunca. Tiene que fallar."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "printf 'bodega,ciudad\\nBodega Sol,Lima\\n' > clientes.csv\n",
    "git restore clientes.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "error: pathspec 'clientes.csv' did not match any file(s) known to git\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Restaurar significa traer de vuelta algo guardado, y de este archivo no hay\n",
    "nada guardado. Para Git todavía no existe 👻"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**El commit guarda la foto que sacaste, no el archivo que tienes\n",
    "delante.**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 4 de **Git desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/git-desde-cero/los-tres-estados/\n",
    "\n",
    "Que tengas lindo día! 🌸"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
