{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tu primer repositorio\n",
    "\n",
    "Cuatro comandos, y qué hace cada uno de verdad\n",
    "\n",
    "Cuaderno de soluciones del capítulo 3 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/tu-primer-repositorio/\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": [
    "## Los cuatro comandos"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Este es el capítulo más corto del libro y el que más vas a repetir. Cuatro\n",
    "comandos, en este orden, y ya tienes un repositorio funcionando.\n",
    "\n",
    "Primero la carpeta, y entrar en ella. Es en serio lo de entrar: si te saltas\n",
    "el `cd`, Git convierte en repositorio la carpeta donde estés\n",
    "parada, y ahí empiezan los problemas de la trampa del capítulo\n",
    "1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "mkdir ventas-miss-yera\n",
    "cd ventas-miss-yera\n",
    "git init"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mira dónde dice que lo creó: dentro de la carpeta, en un sitio llamado\n",
    "`.git`. Ese punto delante significa oculto, y por eso no lo ves en el\n",
    "explorador de archivos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "ls -a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esa carpeta `.git` **es** el repositorio. Toda la\n",
    "historia vive ahí dentro. Si la borras, la carpeta vuelve a ser una carpeta\n",
    "normal y pierdes la memoria pero no los archivos."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El error de empezar al revés"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Antes de crear nada, intento señalar un archivo que todavía no existe. Este\n",
    "error lo vas a ver mucho al principio:"
   ]
  },
  {
   "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 add ventas.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y la queja que tiene que salir es esta:\n",
    "\n",
    "```\n",
    "fatal: pathspec 'ventas.csv' did not match any files\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Did not match any files*: no encontró ningún archivo con ese nombre.\n",
    "Casi siempre es un nombre mal escrito o que estás en otra carpeta. Se resuelve\n",
    "con un `ls`, mirando qué hay de verdad ahí dentro."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El estado, que es tu tablero"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Creo el archivo de ventas y pregunto cómo está la cosa:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "printf 'ciudad,monto,canal\\nLima,1200,bodega\\n' > ventas.csv\n",
    "git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Léelo despacio porque este mensaje te va a acompañar toda la vida:\n",
    "\n",
    "*On branch main*, estás en la rama principal. *No commits yet*,\n",
    "todavía no has guardado ningún momento. *Untracked files*, hay archivos\n",
    "que Git ve pero no está siguiendo.\n",
    "\n",
    "Y de yapa te dice qué hacer: *use git add*. Git es de los pocos\n",
    "programas que te propone el siguiente comando en el propio mensaje. Léelos, no\n",
    "los saltes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Señalar y guardar, que son dos cosas"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git add ventas.csv\n",
    "git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cambió una palabra y cambió todo. Ahora dice *Changes to be committed*,\n",
    "cambios listos para guardarse, y el archivo aparece como *new file*.\n",
    "\n",
    "Ese sitio intermedio donde está ahora el archivo se llama\n",
    "**el área de preparación**, y es lo que hace distinto a Git. En\n",
    "otros sistemas guardas todo lo que cambió, sí o sí. Aquí eliges: tocaste ocho\n",
    "archivos en la mañana pero solo tres son de la misma tarea, señalas esos tres y\n",
    "haces un commit limpio.\n",
    "\n",
    "Ahora sí, guardo el momento:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git commit -m \"Primeras ventas de Lima por bodega\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y el estado vuelve a estar tranquilo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Nothing to commit, working tree clean*. Todo lo que hay en la carpeta\n",
    "está guardado en la historia. Cuando algo te asuste, este es el mensaje que\n",
    "quieres ver 🧘"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tu hash no va a ser el mío"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mira el commit completo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git log"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esos cuarenta caracteres son el nombre del momento. Salen de mezclar lo que\n",
    "guardaste, quién lo firmó y a qué hora, así que **si tú haces los mismos\n",
    "pasos te va a salir otro número**, porque tu nombre y tu reloj son\n",
    "otros.\n",
    "\n",
    "Lo digo temprano porque es la duda que más veo: \"me salió distinto al del\n",
    "libro, ¿hice algo mal?\". No. Lo que tiene que coincidir es la forma, no el\n",
    "número.\n",
    "\n",
    "Y como cuarenta caracteres no se leen, casi siempre vas a usar la versión\n",
    "corta, que toma los siete primeros:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git log --oneline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Con siete basta para que no haya dos iguales en un proyecto normal, y ese es\n",
    "el que copias cuando alguien te pregunta en qué commit está algo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### La trampa\n",
    "\n",
    "Terminas de configurar la conexión a la base de datos de la tienda, guardas las claves en un archivo `.env` al lado de tu código y haces tu primer commit del día como siempre.\n",
    "\n",
    "```\n",
    "$ git add .\n",
    "$ git commit -m \"Conexion a la base de ventas\"\n",
    "$ git push\n",
    "\n",
    "[main 8f2a91c] Conexion a la base de ventas\n",
    " 4 files changed, 62 insertions(+)\n",
    "```\n",
    "\n",
    "**Qué está mal**\n",
    "\n",
    "Ese punto se llevó el `.env` con tus claves 🔑 y ahora están en internet.\n",
    "\n",
    "`git add .` significa \"agrega todo lo que haya cambiado\", y todo incluye lo que no querías. El commit no avisa: dice cuatro archivos y tú creías que eran tres.\n",
    "\n",
    "Lo peor no es eso. Lo peor es que **borrar el commit no arregla nada**: la clave ya se publicó, ya la copiaron los robots que rastrean GitHub buscando exactamente esto, y lo único que sirve es entrar al proveedor y rotarla. El archivo se quita después, con calma.\n",
    "\n",
    "La costumbre que evita esto es mirar antes de guardar: `git status` primero, y nombrar los archivos uno por uno en el `git add`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comprueba que se entendió"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "Cambiaste cinco archivos pero solo tres son de la misma tarea. ¿Qué haces?\n",
    "\n",
    "a) `git add .` y un commit con todo\n",
    "\n",
    "b) `git add` con los tres archivos y un commit, y después los otros dos aparte\n",
    "\n",
    "c) Guardar los cinco y arreglarlo después\n",
    "\n",
    "d) Borrar los dos que no van y volver a escribirlos luego\n",
    "\n",
    "---\n",
    "\n",
    "**La correcta es la b.**\n",
    "\n",
    "*a)* Eso guarda los cinco en el mismo momento, y el día que quieras deshacer una de las dos tareas te llevas la otra por delante. Además es la trampa de este capítulo.\n",
    "\n",
    "*c)* Se puede, pero reescribir la historia es de los capítulos difíciles. Es mucho más barato elegir bien al momento de guardar.\n",
    "\n",
    "*d)* Nunca borres trabajo para ordenar la historia. Para eso existe justamente el área de preparación.\n",
    "\n",
    "El área de preparación existe para que tus commits cuenten una cosa cada uno 🎯"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Un segundo archivo, con los clientes\n",
    "\n",
    "Crea un CSV con dos bodegas y míralo en el estado, sin\n",
    "guardarlo todavía."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "printf 'bodega,ciudad\\nMinimarket Sol,Lima\\nBodega Rosita,Arequipa\\n' > clientes.csv\n",
    "git status --short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "?? clientes.csv\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El `--short` es la versión resumida del estado. Las dos\n",
    "interrogaciones significan que Git no conoce ese archivo todavía."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Señálalo y mira cómo cambia la marca\n",
    "\n",
    "Haz el `add` y vuelve a pedir el estado corto."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git add clientes.csv\n",
    "git status --short"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "A  clientes.csv\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La `A` es de *added*. Con la versión corta lees el estado de\n",
    "un vistazo, y cuando tengas veinte archivos lo vas a agradecer."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Guárdalo con un mensaje que se entienda\n",
    "\n",
    "Haz el commit. Regla del libro: el mensaje dice qué pasó,\n",
    "nunca dice \"cambios\" ni \"update\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git commit -m \"Se agregan las bodegas de Lima y Arequipa\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "[main cad0faa] Se agregan las bodegas de Lima y Arequipa\n",
    " 1 file changed, 3 insertions(+)\n",
    " create mode 100644 clientes.csv\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Un buen mensaje se lee como el titular de una noticia: qué pasó, en presente,\n",
    "sin adornos."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Dos archivos, un solo commit, a propósito\n",
    "\n",
    "Toca los dos archivos y guárdalos juntos, porque esta vez sí\n",
    "son la misma tarea: agregar Cusco como ciudad nueva."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "printf 'Cusco,760,minimarket\\n' >> ventas.csv\n",
    "printf 'Bodega Inti,Cusco\\n' >> clientes.csv\n",
    "git add ventas.csv clientes.csv\n",
    "git commit -m \"Entra Cusco en ventas y en clientes\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "[main 54d6b5d] Entra Cusco en ventas y en clientes\n",
    " 2 files changed, 2 insertions(+)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dos archivos cambiados en el mismo momento porque cuentan la misma historia.\n",
    "Ese es el criterio: **un commit, una idea** 💡"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. Lee la historia en dos formatos\n",
    "\n",
    "Pide el log corto y cuenta cuántos commits llevas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git log --oneline\n",
    "git log --oneline | wc -l"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "54d6b5d Entra Cusco en ventas y en clientes\n",
    "cad0faa Se agregan las bodegas de Lima y Arequipa\n",
    "2e3153e Primeras ventas de Lima por bodega\n",
    "3\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tres momentos, cada uno con su frase. Y el `wc -l` cuenta las\n",
    "líneas, que es un truco de terminal que sirve para todo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. Qué entró en el último commit\n",
    "\n",
    "Pide el detalle del último momento, solo los nombres de los\n",
    "archivos que tocó."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git show --stat --oneline HEAD"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "54d6b5d Entra Cusco en ventas y en clientes\n",
    " clientes.csv | 1 +\n",
    " ventas.csv   | 1 +\n",
    " 2 files changed, 2 insertions(+)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los dos archivos que guardaste juntos, y cuántas líneas entraron en cada uno.\n",
    "Esto es lo primero que mira alguien que revisa tu trabajo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. El commit vacío\n",
    "\n",
    "Intenta guardar un momento cuando no hay nada que guardar.\n",
    "Tiene que fallar, y el mensaje te va a resultar familiar."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git commit -m \"Otro commit\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "On branch main\n",
    "nothing to commit, working tree clean\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Git no crea momentos vacíos. Si te sale esto y tú sí cambiaste algo, casi\n",
    "siempre es que se te olvidó el `git add` 🔁"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Señalar y guardar son dos pasos porque tú decides qué historia\n",
    "cuenta cada commit.**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 3 de **Git desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/git-desde-cero/tu-primer-repositorio/\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
}
