15%

Ahorra 15%<\/span> en todos los servicios de hosting

Pon a prueba tus habilidades y obtén Descuento<\/span> en cualquier plan de hosting

Usa el código:

Skills
Comenzar
22.10.2024

Git Reset vs. Git Checkout vs. Git Revert: Una Guía Técnica Completa

Comprender la diferencia entre git reset, git checkout y git revert es esencial para cualquier desarrollador que trabaje con control de versiones. En resumen: git reset reescribe el historial moviendo el puntero HEAD; git checkout navega entre ramas, commits o archivos sin alterar el historial; y git revert deshace un commit creando un nuevo commit inverso, dejando el historial intacto. Elegir el comando incorrecto — especialmente en una rama compartida — puede corromper el historial de commits de tu equipo o causar pérdida irreversible de datos.

Esta guía va más allá de la sintaxis superficial para explicar la mecánica interna de Git, el estado exacto de tu árbol de trabajo e índice después de cada operación, y los escenarios del mundo real donde cada comando es la elección correcta (o catastróficamente incorrecta).

Cómo Git Gestiona el Estado: Los Tres Árboles

Antes de comparar comandos, necesitas un modelo mental sólido de cómo Git rastrea el estado. Git opera en tres capas distintas:

  • Directorio de trabajo — los archivos que ves y editas en disco.
  • Área de preparación (índice) — una instantánea de lo que irá en el próximo commit.
  • Historial de commits (HEAD) — la cadena de objetos commit inmutables almacenados en .git/.

Cada comando de deshacer en Git apunta a una o más de estas capas. La confusión entre reset, checkout y revert casi siempre surge de no saber qué capas toca un comando determinado.

git reset: Reescribiendo el Historial Local

git reset mueve el puntero HEAD de la rama actual a un commit especificado. Dependiendo del indicador de modo que pases, también puede actualizar el índice y el directorio de trabajo. Es una operación de reescritura de historial y debe tratarse como destructiva cuando se usa con --hard.

Modos de Reset Explicados

git reset --soft <commit>   # Move HEAD only; index and working tree unchanged
git reset --mixed <commit>  # Move HEAD + reset index; working tree unchanged (default)
git reset --hard <commit>   # Move HEAD + reset index + reset working tree
ModoHEAD Se MueveÍndice ReiniciadoÁrbol de Trabajo ReiniciadoCambios Preservados
--softNoNoPreparados y no preparados
--mixedNoSolo no preparados
--hardNinguno — perdidos permanentemente

Casos de Uso Prácticos

Combinar commits antes de un push. Si tienes tres commits de trabajo en progreso desordenados que aún no se han enviado, git reset --soft HEAD~3 los colapsa de vuelta al índice para que puedas hacer un nuevo commit como uno solo y limpio.

Deshacer la preparación de un archivo añadido accidentalmente. Ejecutar git reset HEAD <file> (o git reset sin una referencia de commit) elimina un archivo del índice sin tocar el directorio de trabajo — idéntico en efecto a git restore --staged <file> en Git 2.23+.

Recuperarse de una fusión local fallida. git reset --hard ORIG_HEAD restaura el estado que existía inmediatamente antes de una fusión, porque Git escribe el HEAD previo a la fusión en ORIG_HEAD automáticamente.

Trampa Crítica: Hacer Push Después de un Reset

Si restableces una rama que ya ha sido enviada a un remoto y luego haces un push forzado, cada colaborador cuya rama local rastrea ese remoto tendrá un historial divergente. Esta es una de las causas más comunes de commits perdidos en entornos de equipo. Nunca ejecutes git reset seguido de git push --force en una rama compartida sin coordinación explícita del equipo.

# Dangerous on shared branches — use only on private/local branches
git reset --hard HEAD~2
git push --force origin feature/my-branch

git checkout: Navegación Sin Modificación del Historial

git checkout es un comando multipropósito que cambia el árbol de trabajo para que coincida con una rama, un commit específico o un solo archivo. No modifica el historial de commits. En Git 2.23 y versiones posteriores, sus responsabilidades se dividieron en git switch (para ramas) y git restore (para archivos), pero git checkout sigue siendo completamente funcional y aún predomina en entornos de producción.

Referencia de Sintaxis

git checkout <branch_name>          # Switch to an existing branch
git checkout -b <new_branch>        # Create and switch to a new branch
git checkout <commit_hash>          # Enter detached HEAD state at a specific commit
git checkout -- <file_name>         # Discard working directory changes to a file
git checkout <commit_hash> -- <file> # Restore a single file from a specific commit

Estado de HEAD Desconectado: Lo Que Realmente Significa

Cuando ejecutas git checkout <commit_hash>, Git mueve HEAD para apuntar directamente a un objeto commit en lugar de a una referencia de rama. Esto se llama estado de HEAD desconectado. Cualquier commit que hagas en este estado no es accesible desde ninguna rama — están huérfanos y eventualmente serán eliminados por el recolector de basura de Git a menos que crees una rama para capturarlos.

git checkout 4f7a2c1          # HEAD now points directly to commit 4f7a2c1
git checkout -b hotfix/patch  # Rescue those commits by creating a branch

Un escenario común del mundo real: un desarrollador hace checkout de un commit antiguo para probar una regresión, accidentalmente hace una corrección, la confirma y luego vuelve a main — perdiendo la corrección por completo porque nunca estuvo vinculada a una rama.

Restaurar un Solo Archivo desde el Historial

Una de las formas más infrautilizadas de git checkout es la restauración de archivos específicos:

git checkout HEAD~3 -- src/config/database.php

Esto extrae database.php tal como existía hace tres commits directamente en tu índice y directorio de trabajo, sin tocar ningún otro archivo ni mover HEAD. Es el equivalente quirúrgico de un cambio completo de rama.

git revert: Deshacer de Forma Segura en el Historial Compartido

git revert crea un nuevo commit que aplica el diff inverso de un commit especificado. El commit original permanece en el historial sin cambios. Este es el único mecanismo seguro de deshacer para commits que ya han sido enviados a una rama remota compartida, porque no reescribe el historial — lo extiende.

Referencia de Sintaxis

git revert HEAD                  # Revert the most recent commit
git revert <commit_hash>         # Revert a specific commit by hash
git revert HEAD~3..HEAD          # Revert a range of commits (creates multiple revert commits)
git revert -n <commit_hash>      # Stage the revert without committing (--no-commit)

El Indicador –no-commit: Agrupando Reversiones

Al revertir múltiples commits, crear un commit de reversión por cada commit original puede contaminar el registro. El indicador -n (o --no-commit) prepara todas las reversiones sin confirmarlas, permitiéndote agruparlas en un único commit de reversión:

git revert -n HEAD~4..HEAD
git commit -m "Revert: roll back broken authentication refactor"

Las Reversiones de Commits de Fusión Requieren Cuidado Extra

Revertir un commit de fusión requiere especificar el padre principal con el indicador -m, porque Git necesita saber qué lado de la fusión tratar como el historial "correcto":

git revert -m 1 <merge_commit_hash>

Aquí, -m 1 designa al primer padre (típicamente la rama en la que se fusionó) como la línea principal. Omitir este indicador en un commit de fusión hará que Git arroje un error. Este es un obstáculo común al revertir una fusión de lanzamiento defectuosa en pipelines CI/CD.

Comparación Lado a Lado: Reset vs. Checkout vs. Revert

Criterio`git reset``git checkout``git revert`
Modifica el historial de commitsNoNo (lo extiende)
Afecta el directorio de trabajoCon --hard o --mixedSí (mediante nuevo commit)
Afecta el área de preparación (índice)Sí (excepto --soft)Solo con la forma de archivoNo
Seguro en ramas compartidas/remotasNoSí (solo lectura)
Crea un nuevo commitNoNo
ReversibleParcialmente (mediante ORIG_HEAD)
Maneja commits de fusiónNoSí (navegación)Sí (con -m)
Equivalente moderno en Git 2.23+Igualgit switch / git restoreIgual

Cuándo Usar Cada Comando: Matriz de Decisión

Usa git reset cuando:

  • Estás trabajando en una rama local no enviada y quieres limpiar, combinar o descartar commits.
  • Necesitas deshacer la preparación de archivos antes de un commit.
  • Quieres deshacer una fusión local que no ha sido compartida.
  • Eres el único desarrollador en una rama de funcionalidad y necesitas reescribir su historial antes de abrir una solicitud de extracción.

Usa git checkout cuando:

  • Necesitas cambiar entre ramas durante el desarrollo activo.
  • Quieres inspeccionar el estado del repositorio en un commit histórico sin cambiar nada.
  • Necesitas restaurar un solo archivo a su estado en un commit específico.
  • Estás creando una nueva rama desde un punto específico en el historial.

Usa git revert cuando:

  • Un commit ya ha sido enviado a una rama remota o compartida.
  • Estás trabajando en equipo y necesitas mantener un historial transparente y auditable.
  • Necesitas deshacer un commit específico que no es el más reciente (reversión no lineal).
  • Tu proyecto requiere cumplimiento normativo o registros de auditoría donde la eliminación del historial está prohibida.

Escenario Avanzado: Recuperarse de git reset –hard

Si ejecutaste accidentalmente git reset --hard y perdiste commits, no han desaparecido inmediatamente. El reflog de Git registra cada posición a la que HEAD ha apuntado, incluso después de un reset hard:

git reflog
# Output example:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~3
# 7e8f9a0 HEAD@{1}: commit: Add payment gateway integration
# ...

git reset --hard HEAD@{1}   # Restore to the commit before the accidental reset

Las entradas del reflog expiran después de 90 días por defecto (gc.reflogExpire), por lo que esta ventana de recuperación no es infinita. En un servidor de producción o un entorno de Hosting VPS que ejecuta un servicio Git autohospedado como Gitea o GitLab, debes asegurarte de que tu directorio .git esté incluido en las rutinas de copia de seguridad regulares precisamente por esta expiración.

Alojando Tu Infraestructura Git

Ejecutar un servidor Git autohospedado — ya sea GitLab CE, Gitea o Gogs — exige un almacenamiento I/O confiable y un tiempo de actividad constante. Un solo archivo pack corrupto o un push interrumpido durante un ciclo git gc puede dañar la integridad del repositorio. Para equipos que gestionan múltiples repositorios, un Servidor Dedicado proporciona recursos aislados, acceso root completo para ajustar la configuración core.packedGitWindowSize y pack.threads de Git, y el rendimiento NVMe necesario para grandes monorepos.

Para equipos más pequeños o desarrolladores individuales que necesitan un entorno Linux limpio para ejecutar hooks de Git, scripts CI y pipelines de despliegue, un VPS con cPanel ofrece un panel de control gestionado junto con acceso SSH completo — eliminando la sobrecarga de la administración manual del servidor mientras se conserva la flexibilidad para configurar hooks del lado del servidor de Git y controles de acceso.

Si tu flujo de trabajo implica despliegues automatizados activados por git push, asegurar tu servidor con un Certificado SSL válido es innegociable — tanto para cifrar las cargas útiles de los webhooks como para autenticar remotos Git basados en HTTPS sin deshabilitar la verificación de certificados.

Conclusiones Técnicas Clave

  • git reset --hard es el único comando entre los tres que puede causar pérdida de datos permanente e irrecuperable si el reflog ha expirado.
  • git revert es el único comando que es seguro usar después de un git push sin requerir un push forzado.
  • El estado de HEAD desconectado de git checkout <hash> no elimina commits — pero cualquier nuevo commit realizado en ese estado quedará huérfano a menos que ejecutes inmediatamente git checkout -b <new_branch>.
  • El indicador -n en git revert es fundamental para mantener un registro limpio al revertir múltiples commits a la vez.
  • Git 2.23+ divide git checkout en git switch y git restore para mayor claridad — comprender el comando original hace que ambas alternativas modernas sean inmediatamente intuitivas.
  • Siempre verifica tu rama actual con git status y git log --oneline -5 antes de ejecutar cualquier operación de deshacer.
  • En infraestructura compartida, aplica reglas de protección de ramas (GitHub, GitLab y Gitea todas lo admiten) para bloquear git push --force en las ramas main y release a nivel del servidor.

Preguntas Frecuentes

¿Cuál es la diferencia entre git reset --soft y git reset --mixed?

Ambos mueven HEAD al commit especificado, pero --soft deja tus cambios preparados en el índice, mientras que --mixed (el predeterminado) también limpia el índice, dejando los cambios solo en el directorio de trabajo. Ninguno toca los archivos en disco.

¿Puedo recuperar commits después de git reset --hard?

Sí, dentro de la ventana de expiración del reflog (90 días por defecto). Ejecuta git reflog para encontrar el hash del commit del estado perdido, luego ejecuta git reset --hard <hash> o git checkout -b recovery <hash> para restaurarlo.

¿Por qué git revert en un commit de fusión requiere el indicador -m?

Un commit de fusión tiene dos padres. Git no puede determinar qué diff del padre invertir sin que especifiques la línea principal. -m 1 le dice a Git que trate al primer padre como el tronco, revirtiendo los cambios introducidos por la rama fusionada.

¿Es git checkout -- <file> lo mismo que git restore <file>?

Funcionalmente sí — ambos descartan los cambios no preparados del directorio de trabajo en un archivo restaurándolo desde el índice. git restore fue introducido en Git 2.23 como un reemplazo menos ambiguo, pero git checkout -- <file> produce resultados idénticos en todas las versiones de Git.

¿Cuándo nunca debo usar git reset en una rama?

Nunca uses git reset (especialmente con --hard o --mixed) en ninguna rama que otros desarrolladores ya hayan clonado o extraído. Hacerlo diverge su historial local del remoto, requiriendo que cada colaborador realice un reset forzado o vuelva a clonar — y arriesga descartar silenciosamente commits que existen solo en sus máquinas.

15%

Ahorra 15%<\/span> en todos los servicios de hosting

Pon a prueba tus habilidades y obtén Descuento<\/span> en cualquier plan de hosting

Usa el código:

Skills
Comenzar