Git Reset y Reflog

GitBeginner
Practicar Ahora

Introducción

¡Bienvenido, viajero del tiempo de Git! Hoy vamos a explorar dos funciones potentes de Git que te otorgarán un control sin precedentes sobre el historial de tu repositorio: git reset y git reflog. Estas herramientas son como los controles avanzados de tu máquina del tiempo de Git, permitiéndote moverte entre diferentes estados de tu proyecto e incluso recuperar trabajo que creías "perdido".

El comando git reset es una herramienta versátil que puede ayudarte a deshacer cambios, sacar archivos del área de preparación (unstage) e incluso reescribir tu historial de commits. Sin embargo, un gran poder conlleva una gran responsabilidad, y git reset puede resultar un poco intimidante para los principiantes. Ahí es donde entra git reflog: es como una red de seguridad que registra todos los cambios realizados en las referencias de tu repositorio (como las puntas de las ramas), permitiéndote recuperarte incluso de los resets más drásticos.

En este laboratorio, cubriremos:

  1. Soft Reset: Mover el HEAD sin alterar el directorio de trabajo ni el área de preparación.
  2. Mixed Reset: Sacar cambios del área de preparación manteniendo las modificaciones en el directorio de trabajo.
  3. Hard Reset: Descartar los cambios por completo.
  4. Uso de Reflog para recuperarse de operaciones "destructivas".
  5. Resets basados en tiempo: Mover tu repositorio al estado en que se encontraba en un momento específico.

Al finalizar este laboratorio, tendrás una comprensión sólida de cómo utilizar estas potentes funciones de Git de manera segura y efectiva. Podrás manipular el historial de tu repositorio con confianza, sabiendo que siempre puedes encontrar el camino de regreso si es necesario.

¡Sumerjámonos y comencemos a dominar git reset y reflog!

Configuración de tu Espacio de Trabajo

Antes de empezar a resetear y consultar el reflog, configuremos un espacio de trabajo con algunos commits para experimentar. Crearemos un nuevo directorio, inicializaremos un repositorio Git y añadiremos algunos archivos con múltiples commits.

Abre tu terminal y escribe estos comandos:

cd ~/project
mkdir git-reset-lab
cd git-reset-lab
git init

Ahora, vamos a crear algunos archivos y realizar una serie de commits, copiando y pegando los siguientes comandos en tu terminal:

echo "## Git Reset and Reflog Lab" > README.md
git add README.md
git commit -m "Initial commit"

echo "function add(a, b) { return a + b; }" > math.js
git add math.js
git commit -m "Add addition function"

echo "function subtract(a, b) { return a - b; }" >> math.js
git add math.js
git commit -m "Add subtraction function"

echo "function multiply(a, b) { return a * b; }" >> math.js
git add math.js
git commit -m "Add multiplication function"

Analicemos lo que acabamos de hacer:

  1. Creamos un archivo README y realizamos nuestro commit inicial.
  2. Creamos un archivo JavaScript con una función de suma y lo confirmamos.
  3. Añadimos una función de resta al mismo archivo y realizamos el commit.
  4. Finalmente, añadimos una función de multiplicación y la confirmamos.

¡Ahora tenemos un repositorio con historial para experimentar!

Soft Reset: Moviendo el HEAD

El primer tipo de reset que exploraremos es el reset "soft" (suave). Un soft reset mueve el HEAD (y la rama actual) a un commit diferente, pero no cambia el área de preparación (staging area) ni el directorio de trabajo. Esto es útil cuando quieres "deshacer" algunos commits pero mantener todos los cambios listos para un nuevo commit.

Probemos un soft reset:

git reset --soft HEAD~2

Este comando mueve el HEAD dos commits atrás (al commit anterior a "Add subtraction function"). El símbolo ~2 significa "dos commits antes del HEAD actual". Puedes usar ~N para retroceder N commits.

Ahora, si ejecutas git status, verás que los cambios de los commits "Add subtraction function" y "Add multiplication function" están preparados juntos en el área de staging. Los archivos en tu directorio de trabajo no han cambiado. Todo el trabajo de esos dos commits está ahora listo para ser confirmado como un único y nuevo commit.

Esto es muy útil en escenarios donde quieres combinar (hacer "squash") tus últimos commits en uno solo. Puedes hacer un soft reset hacia atrás unos cuantos commits y luego realizar un nuevo commit con todos esos cambios unificados.

Vamos a confirmar estos cambios de nuevo con un nuevo mensaje:

git commit -m "Add subtraction and multiplication functions"

Recuerda que, aunque el soft reset es generalmente seguro (ya que no descarta ningún cambio), reescribe el historial. Si ya has subido (push) los commits originales, necesitarás hacer un force push para actualizar la rama remota, lo cual puede causar problemas a tus colaboradores. ¡Comunícate siempre con tu equipo antes de reescribir el historial compartido!

Mixed Reset: Deshaciendo el Preparado de Cambios

El siguiente tipo de reset que veremos es el reset "mixed" (mixto). Este es, de hecho, el modo por defecto de git reset si no especificas ninguna bandera. Un mixed reset mueve el HEAD y actualiza el área de preparación para que coincida, pero no toca el directorio de trabajo.

Vamos a realizar algunos cambios y prepararlos:

echo "function divide(a, b) { return a / b; }" >> math.js
git add math.js

Ahora, supongamos que hemos cambiado de opinión y no queremos preparar este cambio todavía. Podemos usar un mixed reset:

git reset HEAD

Esto saca nuestros cambios del área de preparación (unstage) pero los mantiene en el directorio de trabajo. Si ejecutas git status ahora, verás que math.js está modificado pero no preparado para commit.

El mixed reset es útil cuando has preparado algunos cambios pero luego decides que aún no estás listo para confirmarlos. Quizás quieras revisar los cambios de nuevo o hacer más modificaciones antes de prepararlos.

Recuerda que, a diferencia del soft reset, el mixed reset sí modifica el área de preparación. Sin embargo, sigue siendo seguro en el sentido de que no descarta nada de tu trabajo: todo permanece intacto en tu directorio de trabajo.

Hard Reset: Descartando Cambios

El tercer tipo de reset, y el más drástico, es el reset "hard" (duro). Un hard reset mueve el HEAD, actualiza el área de preparación Y actualiza el directorio de trabajo para que coincidan. Esto significa que descarta todos los cambios realizados desde el commit al que estás reseteando.

Probemos un hard reset:

git add math.js
git commit -m "Add division function"
git status
git reset --hard HEAD~1

Esto prepara y confirma nuestra función de división, y luego realiza un hard reset al commit anterior, "deshaciendo" efectivamente nuestro último commit y descartando los cambios.

Si miras math.js ahora, verás que la función de división ha desaparecido. Es como si nunca la hubiéramos escrito.

El hard reset es potente pero peligroso. Es útil cuando quieres descartar completamente un trabajo y empezar de nuevo desde un commit anterior. Sin embargo, ten mucho cuidado con él, ya que puede eliminar cambios de forma permanente.

Comprueba siempre dos veces que estás reseteando al commit correcto antes de hacer un hard reset. Si no estás seguro, es más seguro usar un soft o mixed reset, o crear una nueva rama antes de experimentar.

Uso de Reflog para Recuperar Commits Perdidos

Ahora bien, ¿qué pasa si te das cuenta de que no querías descartar esa función de división? Aquí es donde git reflog acude al rescate. El reflog es un registro de todos los lugares donde ha estado el HEAD en tu repositorio local. Es como un súper-historial que incluso registra comandos que reescriben el historial, como el reset.

Echemos un vistazo al reflog:

git reflog

Deberías ver una lista de todas las acciones recientes que has realizado, incluyendo tus resets. Cada entrada tiene un identificador del tipo HEAD@{n}.

Para recuperar tu commit perdido, puedes resetear al estado anterior a tu hard reset:

git reset --hard HEAD@{1}

Esto resetea al estado en que estaba el HEAD justo antes de tu última acción (que fue el hard reset).

Revisa math.js ahora, ¡y verás que tu función de división ha vuelto!

cat math.js
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
function multiply(a, b) { return a * b; }
function divide(a, b) { return a / b; }

El reflog es una red de seguridad muy potente que te permite recuperarte de casi cualquier accidente en Git. Sin embargo, recuerda que es local de tu máquina y temporal (las entradas suelen conservarse entre 30 y 90 días). No sustituye a las copias de seguridad regulares ni al hecho de subir tu trabajo a un repositorio remoto.

Resets Basados en Tiempo

Git también te permite resetear tu repositorio a su estado en un punto específico en el tiempo. Esto puede ser útil si recuerdas aproximadamente cuándo estaba el repositorio en el estado al que deseas volver.

Probemos un reset basado en tiempo:

git reset --hard master@{"1 hour ago"}

Esto resetea tu repositorio al estado en que se encontraba hace 1 hora. Puedes usar varios descriptores de tiempo como "yesterday", "2 days ago", "3 minutes ago", etc.

Ten cuidado con los resets basados en tiempo, ya que pueden ser menos precisos que resetear a un commit específico. Comprueba siempre el estado de tu repositorio después de un reset de este tipo para asegurarte de que has llegado a donde pretendías.

Recuerda que siempre puedes usar el reflog para deshacer un reset basado en tiempo si no te da el resultado esperado.

Resumen

¡Felicidades, señor del tiempo de Git! Acabas de dominar algunos de los comandos más potentes y potencialmente peligrosos de Git. Repasemos los conceptos clave que hemos cubierto:

  1. Soft Reset: Mueve el HEAD sin cambiar el área de preparación ni el directorio de trabajo. Útil para combinar commits.
  2. Mixed Reset: Mueve el HEAD y actualiza el área de preparación, pero no toca el directorio de trabajo. Ideal para sacar cambios del área de preparación.
  3. Hard Reset: Mueve el HEAD, actualiza el área de preparación y actualiza el directorio de trabajo. Potente pero potencialmente destructivo.
  4. Reflog: Una red de seguridad que registra todos los cambios en el HEAD, permitiéndote recuperarte de casi cualquier error en Git.
  5. Resets Basados en Tiempo: Te permiten resetear tu repositorio a su estado en un momento específico del pasado.

Recuerda: un gran poder conlleva una gran responsabilidad. Aunque estos comandos te dan un control increíble sobre el historial de tu repositorio, también pueden ser peligrosos si se usan sin cuidado. Verifica siempre antes de realizar un reset, especialmente un hard reset, y recuerda que el reflog es tu mejor amigo si las cosas salen mal.

A medida que continúes tu camino con Git, practica estos comandos en un entorno seguro hasta que te sientas cómodo con ellos. Son herramientas formidables que pueden mejorar enormemente tu flujo de trabajo cuando se utilizan correctamente.

¡Feliz reseteo, y que tu historial de Git sea siempre limpio y significativo!