{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Git es el cinturón de seguridad cuando trabajas con IA\n",
    "\n",
    "Por qué esto importa más ahora que hace cinco años\n",
    "\n",
    "Cuaderno de práctica del capítulo 30 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/git-con-ia/\n",
    "\n",
    "Los ejercicios están al final y traen una celda vacía debajo de cada uno. Las\n",
    "respuestas viven en el cuaderno de soluciones, y merece la pena pelearse un\n",
    "rato antes de abrirlo 💛"
   ]
  },
  {
   "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({\n",
    "    1: \"cHVudG8gZGUgcmV0b3JubyBsaXN0bw==\",\n",
    "    2: \"IE0gYm9kZWdhcy5jc3YKIE0gcmVwb3J0ZS5weQo/PyBjYW5hbGVzLmNzdg==\",\n",
    "    3: \"IGJvZGVnYXMuY3N2IHwgMSArCiByZXBvcnRlLnB5ICB8IDMgKysrCiAyIGZpbGVzIGNoYW5nZWQsIDQgaW5zZXJ0aW9ucygrKQpkaWZmIC0tZ2l0IGEvYm9kZWdhcy5jc3YgYi9ib2RlZ2FzLmNzdgppbmRleCA5ZmU5NjA1Li5kMzAyN2QyIDEwMDY0NAotLS0gYS9ib2RlZ2FzLmNzdgorKysgYi9ib2RlZ2FzLmNzdgpAQCAtMSwyICsxLDMgQEAKIGJvZGVnYSxjaXVkYWQKIEJvZGVnYSBJbnRpLEN1c2NvCitNaW5pbWFya2V0IFNvbCxUcnVqaWxsbw==\",\n",
    "    4: \"QSAgY2FuYWxlcy5jc3YKTSAgcmVwb3J0ZS5weQpib2RlZ2EsY2l1ZGFkCkJvZGVnYSBJbnRpLEN1c2Nv\",\n",
    "    5: \"RWwgcmVwb3J0ZSBhZ3J1cGEgbGFzIGJvZGVnYXMgcG9yIGNpdWRhZAoKRXNjcml0byBjb24gYXl1ZGEgZGUgdW5hIGhlcnJhbWllbnRhIGRlIElBIHkgcmV2aXNhZG8gYW50ZXMgZGUgZW50cmFyLg==\",\n",
    "    6: \"IE0gcmVwb3J0ZS5weQo/PyBib3JyYW1lLnR4dAppbXBvcnQgY3N2CgpkZWYgYm9kZWdhc19wb3JfY2l1ZGFkKHJ1dGEpOgogICAgcGFzcw==\",\n",
    "    7: \"ZmF0YWw6IGFtYmlndW91cyBhcmd1bWVudCAnYm9kZWdhcy0yMDE5LmNzdic6IHVua25vd24gcmV2aXNpb24gb3IgcGF0aCBub3QgaW4gdGhlIHdvcmtpbmcgdHJlZS4KVXNlICctLScgdG8gc2VwYXJhdGUgcGF0aHMgZnJvbSByZXZpc2lvbnMsIGxpa2UgdGhpczoKJ2dpdCA8Y29tbWFuZD4gWzxyZXZpc2lvbj4uLi5dIC0tIFs8ZmlsZT4uLi5dJw==\",\n",
    "}, lenguaje=\"bash\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Este libro existe por una razón muy concreta, y es de 2026: hay muchísima\n",
    "gente que llegó a GitHub sin haber programado nunca, empujada por la IA. Buscan\n",
    "Claude Code, buscan skills, buscan proyectos, y todo eso vive en repositorios 🤖\n",
    "\n",
    "Y resulta que Git, que era una herramienta de programadores, se volvió lo\n",
    "que más falta hace cuando trabajas con IA. Por una razón simple: los cambios ya\n",
    "no los escribes tú de a uno, llegan de golpe."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El problema nuevo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cuando escribes tú, vas viendo. Cuando le pides a una IA que reorganice el\n",
    "proyecto, en un minuto hay seis archivos cambiados, uno borrado y una carpeta\n",
    "nueva. Si eso no funciona, ¿qué parte falló? 🤔\n",
    "\n",
    "Git contesta esa pregunta, pero solo si hiciste una cosa antes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## La costumbre que lo cambia todo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "mkdir analisis-ventas\n",
    "cd analisis-ventas\n",
    "git init -q\n",
    "printf 'ciudad,monto\\nLima,1200\\nArequipa,890\\n' > ventas.csv\n",
    "printf 'import csv\\n\\ntotal = 0\\n' > reporte.py\n",
    "git add .\n",
    "git commit -q -m \"Primera version del reporte de ventas\"\n",
    "git status --short\n",
    "echo \"todo guardado, ahora si puedo pedir cambios\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Diez segundos. Y con eso ya tienes un punto de retorno 🧷"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ahora llega el cambio grande"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Simulamos lo que haría una herramienta de IA: reescribe el script, agrega un\n",
    "archivo y toca los datos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "printf 'import csv\\n\\ndef total_por_ciudad(ruta):\\n    with open(ruta) as f:\\n        filas = list(csv.DictReader(f))\\n    return {f[\"ciudad\"]: int(f[\"monto\"]) for f in filas}\\n' > reporte.py\n",
    "printf 'canal,monto\\nBodegas,4200\\n' > canales.csv\n",
    "printf 'Cusco,760\\n' >> ventas.csv\n",
    "git status --short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tres archivos tocados. Sin el commit de antes, esto sería un montón; con\n",
    "él, es una lista de cosas que puedes revisar una por una 📋"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Mirar exactamente qué hizo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git diff --stat\n",
    "git diff ventas.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ese `diff` es la herramienta más importante de todo el capítulo.\n",
    "No estás confiando ni desconfiando: estás **mirando** 👀"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Aceptar una parte y rechazar otra"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Aquí es donde se paga el capítulo 4. No hace falta\n",
    "aceptar todo o nada:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git add reporte.py canales.csv\n",
    "git status --short\n",
    "git restore ventas.csv\n",
    "git status --short\n",
    "cat ventas.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El código nuevo se queda, el cambio en los datos se fue. Cusco desapareció y\n",
    "el resto sigue 🎯"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git commit -q -m \"El reporte calcula el total por ciudad\n",
    "\n",
    "Escrito con ayuda de una herramienta de IA y revisado antes de entrar.\"\n",
    "git log --oneline\n",
    "git status --short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Deshacerlo entero"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y si el cambio no sirve, vuelves al punto de antes sin pensar:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "printf 'algo que la IA propuso y no sirve\\n' > reporte.py\n",
    "printf 'basura.txt\\n' > basura.txt\n",
    "git status --short\n",
    "git restore .\n",
    "git clean -qfd\n",
    "git status --short\n",
    "head -3 reporte.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`restore .` devuelve lo que Git conocía y `clean -fd`\n",
    "se lleva lo que no conocía. Los dos juntos son \"vuelve a como estaba\" 🔙"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tres reglas que uso"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **Commit antes de pedir.** Siempre, aunque el mensaje diga\n",
    "\"antes de tocar nada\".\n",
    "\n",
    "- **Revisar el diff antes de aceptar.** Quien firma el commit\n",
    "eres tú, y en una revisión de equipo vas a tener que explicarlo.\n",
    "\n",
    "- **Ramas para lo experimental.** Si vas a probar algo grande,\n",
    "una rama de 10 y tu `main` se queda intacta."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Y una cosa sobre qué le das"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Las herramientas de IA leen tu carpeta. Si ahí dentro hay un\n",
    "`.env` con claves o un CSV con datos de clientes, eso puede terminar\n",
    "saliendo de tu máquina 🔐\n",
    "\n",
    "El `.gitignore` del capítulo 9 no basta\n",
    "aquí, porque muchas herramientas leen archivos ignorados igual. Lo que sirve es\n",
    "no tener secretos sueltos en la carpeta del proyecto, y trabajar con datos de\n",
    "ejemplo cuando los de verdad son de un cliente."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### La trampa\n",
    "\n",
    "Le pides a una herramienta de IA que reorganice el proyecto entero. Acepta todos los cambios de una y prueba.\n",
    "\n",
    "```\n",
    "$ git status --short\n",
    " M reporte.py\n",
    " M ventas.csv\n",
    " M canales.csv\n",
    " D total.py\n",
    " M README.md\n",
    "?? utils/\n",
    "\n",
    "# y ahora nada funciona. que cambio exactamente?\n",
    "```\n",
    "\n",
    "**¿Qué está mal?** La respuesta está en el cuaderno de soluciones. Míralo tú primero."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comprueba que se entendió"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "Vas a pedirle a una IA que reorganice tu proyecto. ¿Qué haces antes?\n",
    "\n",
    "a) Un commit, aunque sea con mensaje de \"antes de tocar\"\n",
    "\n",
    "b) Una copia de la carpeta en el escritorio\n",
    "\n",
    "c) Nada, si sale mal deshago con el editor\n",
    "\n",
    "d) Subo el proyecto a GitHub"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Deja el punto de retorno\n",
    "\n",
    "Crea el proyecto del catálogo y guárdalo antes de pedir\n",
    "nada."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 1\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Simula el cambio grande\n",
    "\n",
    "Tres archivos tocados de golpe."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 2\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Mira qué cambió de verdad\n",
    "\n",
    "El resumen y después el detalle de los datos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 3\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Acepta una parte\n",
    "\n",
    "Quédate con el código y descarta el cambio en los datos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 4\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. Guárdalo diciendo cómo se hizo\n",
    "\n",
    "El cuerpo del commit es buen sitio para dejarlo dicho."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 5\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. Deshaz un cambio entero\n",
    "\n",
    "Vuelve al punto anterior, incluidos los archivos que no\n",
    "conocía."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 6\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. Pide el diff de un archivo que no existe\n",
    "\n",
    "Comprueba qué pasa cuando el nombre está mal escrito."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 7\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Commit antes de pedir, diff antes de aceptar. Quien firma el commit\n",
    "eres tú.**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 30 de **Git desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/git-desde-cero/git-con-ia/\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
}
