{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Proponer un cambio en el proyecto de otra persona\n",
    "\n",
    "Qué es un fork, qué es un pull request y por qué no da miedo\n",
    "\n",
    "Cuaderno de práctica del capítulo 20 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/pull-request/\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: \"b3JpZ2luCS9ob21lL21pc3MteWVyYS9mb3JrLWJvZGVnYXMuZ2l0IChmZXRjaCkKb3JpZ2luCS9ob21lL21pc3MteWVyYS9mb3JrLWJvZGVnYXMuZ2l0IChwdXNoKQp1cHN0cmVhbQkuLi9jYXRhbG9nby1zZXJ2aWRvci5naXQgKGZldGNoKQp1cHN0cmVhbQkuLi9jYXRhbG9nby1zZXJ2aWRvci5naXQgKHB1c2gp\",\n",
    "    2: \"KiBhZ3JlZ2EtbWluaW1hcmtldHMKICBtYWlu\",\n",
    "    3: \"ZGlmZiAtLWdpdCBhL2JvZGVnYXMuY3N2IGIvYm9kZWdhcy5jc3YKaW5kZXggOWZlOTYwNS4uZDMwMjdkMiAxMDA2NDQKLS0tIGEvYm9kZWdhcy5jc3YKKysrIGIvYm9kZWdhcy5jc3YKQEAgLTEsMiArMSwzIEBACiBib2RlZ2EsY2l1ZGFkCiBCb2RlZ2EgSW50aSxDdXNjbworTWluaW1hcmtldCBTb2wsVHJ1amlsbG8=\",\n",
    "    4: \"YTlhMDQ5MWM0ZGU0YzM2YzdiN2NjOGFkZWEzMzg1ODMyZjk2Yjg1MAlyZWZzL2hlYWRzL2FncmVnYS1taW5pbWFya2V0cwphOTg3NGFlNWFkZTllYmZmNDgwZWM5ZjI5NjI5YjFiNjUxNTczODQ5CXJlZnMvaGVhZHMvbWFpbg==\",\n",
    "    5: \"Ym9kZWdhcy5jc3YKY2l1ZGFkZXMuY3N2\",\n",
    "    6: \"Ym9kZWdhcy5jc3YKY2l1ZGFkZXMuY3N2CmJvZGVnYSxjaXVkYWQKQm9kZWdhIEludGksQ3VzY28KTWluaW1hcmtldCBTb2wsVHJ1amlsbG8KYmMzMzMxNiBNZXJnZSBicmFuY2ggJ21haW4nIGludG8gYWdyZWdhLW1pbmltYXJrZXRzCmI2NDhjODcgRW50cmEgZWwgY29ydGUgcG9yIGNpdWRhZAphOWEwNDkxIFNlIGFncmVnYSBlbCBtaW5pbWFya2V0IGRlIFRydWppbGxv\",\n",
    "    7: \"ZmF0YWw6ICdvdHJvLXJlbW90bycgZG9lcyBub3QgYXBwZWFyIHRvIGJlIGEgZ2l0IHJlcG9zaXRvcnkKZmF0YWw6IENvdWxkIG5vdCByZWFkIGZyb20gcmVtb3RlIHJlcG9zaXRvcnkuCgpQbGVhc2UgbWFrZSBzdXJlIHlvdSBoYXZlIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMKYW5kIHRoZSByZXBvc2l0b3J5IGV4aXN0cy4=\",\n",
    "}, lenguaje=\"bash\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Aquí es donde Git deja de ser una herramienta personal. Un pull request es\n",
    "la forma en que millones de personas mejoran proyectos que no son suyos, y\n",
    "también es la forma en que trabaja cualquier equipo por dentro 🤝\n",
    "\n",
    "Y la palabra asusta más que la cosa. Traducida es: *\"te dejé unos\n",
    "cambios listos, ¿te los llevas?\"*."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fork y clone no son lo mismo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "|  | Fork | Clone |\n",
    "|---|---|---|\n",
    "| Dónde queda la copia | En tu cuenta de GitHub | En tu computadora |\n",
    "| Es de | GitHub, no de Git | Git |\n",
    "| Puedes subir cambios | Sí, es tuya | Solo si tienes permiso en el original |\n",
    "| Para qué | Proponer cambios en algo ajeno | Trabajar en tu máquina |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El orden real es: **fork primero, clone después**. Clonas tu\n",
    "copia, no la original 🍴"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Los cuatro pasos, con la parte de Git ejecutada"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El fork es un botón en GitHub. Todo lo demás es esto, y lo vamos a hacer con\n",
    "el servidor de práctica del capítulo 12: uno hace de\n",
    "proyecto original y otro de tu bifurcación."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "mkdir original\n",
    "cd original\n",
    "git init -q\n",
    "printf 'ciudad,monto\\nLima,1200\\nArequipa,890\\n' > ventas.csv\n",
    "printf '# Ventas por ciudad\\n' > README.md\n",
    "git add .\n",
    "git commit -q -m \"Primera version del reporte de ventas\"\n",
    "cd ..\n",
    "git clone -q --bare original original-servidor.git\n",
    "git clone -q --bare original mi-fork.git\n",
    "git clone -q mi-fork.git mi-copia\n",
    "cd mi-copia\n",
    "git remote add upstream ../original-servidor.git\n",
    "git remote -v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dos remotos y esto es la costumbre del mundo entero: `origin` es\n",
    "tu bifurcación, donde sí puedes subir, y `upstream` es el proyecto\n",
    "original, de donde traes las novedades 🔀"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Una rama por propuesta"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Este es el paso que la gente se salta y el que más problemas causa después:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git switch -q -c agrega-cusco\n",
    "printf 'Cusco,760\\n' >> ventas.csv\n",
    "git add ventas.csv\n",
    "git commit -q -m \"Se agregan las ventas de Cusco\"\n",
    "git branch\n",
    "git log --oneline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El nombre de la rama importa porque va a ser el título por defecto de tu\n",
    "propuesta. `agrega-cusco` se entiende; `cambios` o\n",
    "`arreglo2` no 🏷️"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Subirla a tu bifurcación"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git push -q -u origin agrega-cusco\n",
    "git ls-remote --heads origin"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahí está tu rama en tu copia de GitHub. Al entrar a la web te va a salir\n",
    "sola una barra amarilla que dice *\"Compare & pull request\"*. Ese es\n",
    "el único clic obligatorio del capítulo 🖱️"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Qué escribir en la propuesta"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tres cosas, cortas:\n",
    "\n",
    "- **Qué cambia**, en una frase.\n",
    "\n",
    "- **Por qué**, sobre todo si no es obvio.\n",
    "\n",
    "- **Cómo comprobarlo**, si hace falta ejecutar algo.\n",
    "\n",
    "Y si el proyecto tiene un archivo `CONTRIBUTING.md`, léelo antes.\n",
    "Ahí está lo que quien mantiene el proyecto ya se cansó de repetir."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ver exactamente lo que estás proponiendo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Antes de abrir el pull request conviene mirar tu propio cambio con los ojos\n",
    "de quien lo va a revisar:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "git diff main..agrega-cusco\n",
    "git log --oneline main..agrega-cusco"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Eso, exactamente eso, es lo que va a ver la otra persona. Si ahí aparece algo\n",
    "que no querías mandar, ahora es el momento 👀"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Cuando el original avanza mientras esperas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los pull requests tardan. Mientras tanto el proyecto sigue, y hay que traer\n",
    "lo nuevo para que tu propuesta no envejezca:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%consola\n",
    "cd ../original\n",
    "printf 'Trujillo,1450\\n' >> ventas.csv\n",
    "git add ventas.csv\n",
    "git commit -q -m \"Entran las ventas de Trujillo\"\n",
    "git push -q ../original-servidor.git main\n",
    "cd ../mi-copia\n",
    "git fetch -q upstream\n",
    "git switch -q main\n",
    "git merge -q upstream/main\n",
    "cat ventas.csv\n",
    "git log --oneline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`fetch` trae sin mezclar, `merge` mezcla. Tu\n",
    "`main` vuelve a estar al día con el original 🔄"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### La trampa\n",
    "\n",
    "Quieres proponer un arreglo en un proyecto ajeno. Lo bifurcas, clonas, arreglas el CSV de ventas ahí mismo y abres el pull request.\n",
    "\n",
    "```\n",
    "$ git branch\n",
    "* main\n",
    "\n",
    "$ git commit -am \"Se corrige el monto de Lima\"\n",
    "$ git push origin main\n",
    "\n",
    "# y al dia siguiente, otro arreglo distinto...\n",
    "$ git commit -am \"Se agrega Chiclayo\"\n",
    "$ git push origin main\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 proponer un arreglo en un proyecto que no es tuyo. ¿Dónde haces el commit?\n",
    "\n",
    "a) En `main` de mi bifurcación\n",
    "\n",
    "b) En una rama nueva de mi bifurcación\n",
    "\n",
    "c) En `main` del proyecto original\n",
    "\n",
    "d) Da igual, el pull request los separa"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Monta el original y tu bifurcación\n",
    "\n",
    "Crea el proyecto del catálogo de bodegas, publícalo y haz\n",
    "tu copia."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 1\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Crea la rama de tu propuesta\n",
    "\n",
    "Una rama con nombre de lo que hace."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 2\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Mira lo que vas a proponer\n",
    "\n",
    "El diff contra `main` es exactamente lo que\n",
    "verá quien revise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 3\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Súbela a tu bifurcación\n",
    "\n",
    "Manda la rama a `origin`, que es tu copia."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 4\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. Trae lo nuevo del original\n",
    "\n",
    "El proyecto avanzó mientras esperabas. Ponte al día."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 5\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. Actualiza tu propuesta\n",
    "\n",
    "Lleva lo nuevo a tu rama para que la propuesta no envejezca."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 6\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. Intenta subir al proyecto original\n",
    "\n",
    "Prueba a mandar tu rama a una dirección que no existe,\n",
    "que es lo que pasa cuando escribes mal el remoto."
   ]
  },
  {
   "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": [
    "**Fork, clone, rama, push y un clic. Y una rama por propuesta,\n",
    "siempre.**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 20 de **Git desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/git-desde-cero/pull-request/\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
}
