Herramientas de Git
Reiniciar DesmitificadoUna manera facil de entender reset y checkout es pensar en Git como un administrador de contenido de tres arboles diferentes.
Por “arbol” nos referimos a “coleccion de archivos”, no necesariamente a la estructura de datos.
| Arbol | Rol |
|---|---|
| HEAD | Ultima instantanea del commit, proximo padre |
| Indice | Siguiente instantanea del commit propuesta |
| Directorio de Trabajo | Caja de arena |
HEAD es el puntero a la referencia de la rama actual, que a su vez apunta al ultimo commit realizado en esa rama. HEAD sera el padre del proximo commit que se cree. En general, es mas simple pensarlo como la instantanea de tu ultimo commit.
git cat-file -p HEAD
git ls-tree -r HEAD
El indice es tu siguiente commit propuesto, tambien conocido como el “Area de Preparacion”. Git lo rellena con una lista de todos los contenidos del archivo revisados por ultima vez en tu directorio de trabajo.
git ls-files -s
Los otros dos arboles almacenan su contenido de manera eficiente pero inconveniente dentro de la carpeta .git. El directorio de trabajo los descomprime en archivos reales, haciendo mucho mas facil editarlos. Piensalo como una caja de arena donde puedes probar cambios antes de enviarlos al indice y luego al historial.
El objetivo principal de Git es registrar instantaneas de tu proyecto en estados sucesivamente mejores, mediante la manipulacion de estos tres arboles.
Visualicemos el proceso con un ejemplo. Supongamos que entras a un directorio nuevo con un solo archivo (v1). Ejecutas git init, lo que crea un repositorio con HEAD apuntando a una rama aun no nacida.
Ejecutas git add para copiar el archivo al indice:
Luego git commit, que guarda el indice como una instantanea permanente y actualiza HEAD:
Ahora modificas el archivo (v2) y repites el proceso:
Supongamos que confirmamos el archivo por tercera vez (v3). Nuestro historial luce asi:
reset manipula los tres arboles de forma simple y predecible, realizando hasta tres operaciones en orden.
--soft)Lo primero que hace reset es mover la rama a la que apunta HEAD. Si HEAD esta en master, ejecutar git reset HEAD~ hara que master apunte al commit anterior.
Con --soft, el comando se detiene aqui. Esto deshace el ultimo git commit sin tocar el indice ni el directorio de trabajo. Es equivalente a deshacer el commit y dejar todo preparado para volver a confirmar.
--mixed)El siguiente paso es actualizar el indice con el contenido de la instantanea a la que ahora apunta HEAD.
Con --mixed (que es el comportamiento por defecto), el comando se detiene aqui. Esto deshace el ultimo commit y hace unstage de todo — retrocede a antes de ejecutar git add y git commit.
--hard)El tercer paso hace que el directorio de trabajo se parezca al indice.
Con --hard, el comando completa las tres operaciones. Deshace el ultimo commit, el git add, y todo el trabajo en el directorio de trabajo.
--hardes la unica forma de hacer queresetsea peligroso. Git destruira los datos del directorio de trabajo sin posibilidad facil de recuperacion. Usalo con cuidado.
reset sobrescribe los tres arboles en orden especifico, deteniendose cuando se le indica:
--soft)--mixed o sin opcion)--hard)Entrar al kahoot y esperar el codigo de la sala, o presionar la opcion “Aprende” para responder de forma individual.
Si especificas una ruta de archivo, reset omite el paso 1 (no puede mover HEAD a solo parte de un commit) y limita su accion a ese archivo especifico.
Por ejemplo, git restore --staged file.txt es equivalente a git reset HEAD file.txt, que copia file.txt de HEAD al indice, haciendo unstage del archivo:
Tambien puedes especificar un commit concreto para extraer una version anterior de un archivo directamente al indice:
git reset eb43bf file.txt
Una tecnica util con reset --soft es aplastar (squash) varios commits en uno. Si tienes commits intermedios de trabajo en progreso:
Puedes ejecutar git reset --soft HEAD~2 para mover HEAD dos commits atras, dejando el indice intacto:
Y luego hacer un nuevo git commit que los agrupa a todos en uno:
checkout tambien manipula los tres arboles, pero con diferencias importantes respecto a reset:
Sin rutas: git checkout <rama> es similar a git reset --hard <rama>, pero con dos diferencias clave:
checkout es seguro para el directorio de trabajo: intenta una fusion trivial antes de sobrescribir, no destruye cambios sin avisar.checkout mueve HEAD a otra rama; reset mueve la rama a la que HEAD apunta.
Con rutas: git checkout <commit> <archivo> actualiza el indice y el directorio de trabajo con esa version del archivo. No mueve HEAD, pero no es seguro para el directorio de trabajo porque sobrescribe el archivo sin avisar.
| Comando | HEAD | Indice | Dir. Trabajo | Seguro? |
|---|---|---|---|---|
reset --soft [commit] | REF | NO | NO | SI |
reset [commit] | REF | SI | NO | SI |
reset --hard [commit] | REF | SI | SI | NO |
checkout [commit] | HEAD | SI | SI | SI |
reset (commit) [file] | NO | SI | NO | SI |
checkout (commit) [file] | NO | SI | SI | NO |
La columna HEAD dice “REF” si el comando mueve la rama a la que HEAD apunta, y “HEAD” si mueve el propio HEAD. Presta atencion especial a la columna “Seguro”: si dice NO, piensalo bien antes de ejecutar.
tar -xzf 16-reset-desmitificado.tar.gzcd 16-reset-desmitificado/code .) y lee el README.md7.7 — los tres arboles, reset y checkout.