- En Git, si no conoces el nombre de una situación de error, es difícil buscar cómo resolverla, así que este material organiza los comandos por escenarios comunes de recuperación para poder encontrarlos y usarlos de inmediato
- Si dañaste gravemente el repositorio o quieres deshacer errores de borrado o merge, puedes revisar el historial de trabajo con
git reflog y volver a un estado anterior con git reset HEAD@{index}
- Para pequeños cambios o para modificar el mensaje del último commit,
git commit --amend permite resolverlo rápido, pero no debe usarse en commits que ya fueron enviados a una rama pública/compartida
- Si hiciste commit en la rama equivocada, puedes moverlo con el flujo
reset, stash, checkout, stash pop o con cherry-pick, pero el método seguro cambia según si ya hiciste push o no
reset --hard y git clean -d --force, que fuerzan la recuperación al estado del repositorio remoto, también pueden borrar archivos no rastreados, así que hay que verificar antes de ejecutarlos
Por qué es difícil recuperarse de errores en Git
- Es fácil cometer errores en Git, y muchas veces para buscar cómo corregir un problema ya necesitas conocer el nombre del concepto involucrado
- Este material organiza situaciones problemáticas comunes en Git con inglés sencillo y ejemplos de comandos
- No es una referencia completa, y puede haber otras formas de realizar la misma tarea
Volver el repositorio a un estado anterior
- Si dañaste gravemente el repositorio o quieres recuperar algo que borraste, revisa el historial de trabajo con
git reflog
git reflog
# puedes ver una lista de operaciones de Git en todas las ramas
# cada entrada tiene un índice con la forma HEAD@{index}
git reset HEAD@{index}
reflog puede usarse en estas situaciones
- recuperar contenido borrado por accidente
- eliminar un intento que dañó el repositorio
- recuperarse después de un merge problemático
- volver a un punto donde realmente funcionaba
Cómo corregir el último commit
- Si necesitas agregar un pequeño cambio justo después del último commit, usa
git commit --amend --no-edit
# después de hacer cambios
git add . # o agregar archivos individuales
git commit --amend --no-edit
- Este comando incluye los cambios nuevos en el último commit
- También podrías crear un nuevo commit y luego combinarlo con
rebase -i, pero amend es mucho más rápido
- No debes usar
amend en commits que ya fueron enviados a una rama pública/compartida
- Si solo quieres cambiar el mensaje del último commit, usa el siguiente comando
git commit --amend
# cambia el mensaje del commit siguiendo las indicaciones
Cuando hiciste commit en la rama equivocada
- Si hiciste commit por error en
master pero debía estar en una rama nueva, crea una nueva rama desde el estado actual y elimina el último commit de master
git branch some-new-branch-name
git reset HEAD~ --hard
git checkout some-new-branch-name
- Este método no es adecuado para commits que ya fueron enviados a una rama pública/compartida
- Si antes intentaste otras cosas, puede que necesites usar
HEAD@{number-of-commits-back} en lugar de HEAD~
- Si hiciste commit en una rama completamente equivocada, puedes moverlo con el flujo
reset --soft, stash, checkout, stash pop
git reset HEAD~ --soft
git stash
git checkout name-of-the-correct-branch
git stash pop
git add . # o agregar archivos individuales
git commit -m "your message here"
- También existe la opción de usar
cherry-pick en la misma situación
git checkout name-of-the-correct-branch
git cherry-pick master
git checkout master
git reset HEAD~ --hard
Revertir cambios y commits anteriores
- Si modificaste archivos pero
git diff aparece vacío, puede que ya los hayas puesto en staging, así que necesitas la bandera --staged
git diff --staged
- Para revertir cambios de hace varios commits, busca el hash con
git log y ejecuta git revert
git log
git revert [saved hash]
git revert crea un nuevo commit que deshace ese commit
- Si no quieres revertir un commit completo sino solo un archivo específico, usa el flujo de llevar a índice la versión anterior del archivo y luego hacer commit
git log
git checkout [saved hash] -- path/to/file
git commit -m "Wow, you don't have to copy-paste to undo"
Forzar la recuperación al estado del repositorio remoto
- En lugar de borrar el repositorio y clonarlo de nuevo, puedes usar comandos de Git para alinearlo con el estado del repositorio remoto
git fetch origin
git checkout master
git reset --hard origin/master
git clean -d --force
git reset --hard origin/master ajusta la rama al estado de master en el remoto
git clean -d --force elimina archivos y directorios no rastreados
- Debes repetir
checkout, reset y clean en cada rama dañada
- Estas operaciones son destructivas e irreversibles, así que debes tener cuidado antes de ejecutarlas
Alcance y contribuciones
- Este material no es una referencia completa de Git, sino una colección de procedimientos prácticos de recuperación encontrados mediante prueba y error
- Si quieres ayudar agregando traducciones, puedes enviar un PR en GitHub
1 comentarios
Opiniones de Hacker News
Hay algunas cosas que cambiaría: siempre usaría
git switchen lugar degit checkout, y evitaríareset --hardtanto como sea posible.Por ejemplo, si “por error hiciste en master un commit que debería estar en una rama nueva”, se puede resolver con
git branch some-new-branch-name,git switch -d HEAD~,git switch -C master,git switch some-new-branch-name, en ese orden.Si “hiciste commit en la rama equivocada”, también lo resolvería haciendo
git switcha la rama correcta y luegogit cherry-pick master,git switch -d master~,git switch -C master.Para “tirar todo y volver al estado remoto”, lo armaría como
git fetch origin,git restore -WS .,git clean -d --force,git switch -d origin/master,git switch -C master.Aunque entiendas bien el modelo de Git, estas recetas no son intuitivas y además hay que conocer los comportamientos peculiares de cada comando.
Por ejemplo,
git switch -c some-new-branch-nameya existe, pero creo que sería más intuitivo un comando comogit move-branch master HEAD~, que solo mueva una rama a otro commit.git switchygit restoreen lugar degit checkout, pero estos comandos se introdujeron en Git v2.23, y esa versión salió hace unos 5 años.La página de ayuda todavía incluye la advertencia
THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.Claro, esa advertencia estuvo ahí prácticamente desde que aparecieron los comandos, y después de 5 años parece que ya sería momento de dejar de llamarlos experimentales.
Aun así,
git checkouttiene mayor compatibilidad hacia atrás, y puede verse como reflejo del uso de Git de la época en que se creó originalmente este sitio web.https://github.com/git/git/blob/757161efcca150a9a96b312d9e78...
https://github.com/git/git/releases/tag/v2.23.0
https://github.com/git/git/commit/4e43b7ff1ea4b6f16b93a432b6...
git add .como opción por defecto para subir cambios al área de staging.Agregar archivos específicos de forma explícita deja menos margen para decir después “ay, la regué”.
Quisiera saber por qué
switches mejor quecheckouty por qué no debería usarsereset --hard.reset --hard”.Me da curiosidad por qué en la práctica no sería suficiente, y lo uso bastante seguido junto con
alias git-restore-file='git restore --source=HEAD --'; parece funcionar bien.Al aprender Git, deberíamos empezar a recomendar clientes GUI como ruta predeterminada.
Con eso se resolvería un tercio de estos problemas, y otro tercio ni siquiera aparecería.
Si más adelante uno decide que la línea de comandos es más rápida, que la use entonces; primero la gente necesita ver visualmente cómo interactúa con los árboles.
En lo personal me gusta fork.dev, pero hoy en día los clientes son bastante parecidos en general.
Con Magit, acciones como “abortar cherry-pick” se pueden descubrir dentro de la interfaz y usan el mismo atajo que otras operaciones de “abortar X”.
Si hubiera tenido que usar solo la línea de comandos de Git, no habría tenido idea de por dónde empezar.
También me pasó que borré un commit que no debía borrar durante un rebase interactivo, pero en cada punto de inicio del rebase se crea una instantánea accesible desde el reflog, así que es seguro deshacer un rebase incorrecto.
La UI de reflog de Magit es igual que la UI de log, así que no me perdí al verla por primera vez; con la CLI de Git probablemente no habría entendido qué estaba pasando.
Me gusta que, al ejecutar
jjsin argumentos, muestra la parte relevante del árbol de commits y la ubicación actual.De un vistazo puedes ver el commit en el que estás trabajando, las ramas conectadas y el historial, otras ramas activas dentro del repositorio, el mensaje de cada commit y si tiene cambios; es excelente para reorientarse.
Pero casi nadie hace caso, y terminan sufriendo con la CLI, rompiendo ramas, quedándose atrás de main y teniéndole miedo a rebase.
Muchas cosas que en una UI se resolverían arrastrando y soltando, o de una forma parecida, parecen una especie de autoflagelación.
Aunque la interfaz fuera horrible, era más fácil comunicarse usando la misma interfaz que el resto del equipo, y los recursos en línea para resolver problemas también suelen asumir la “forma normal”, así que resultaban más útiles.
Que en abril de 2025 Git cumpla 20 años se siente bastante raro
Estuve ahí en ese momento, y recuerdo haber dudado sobre qué aprender entre git, darcs y bazaar para reemplazar SVN o CVS
No sé si también probé Mercurial
Me pregunto si el “efecto GitHub” prácticamente mató la necesidad de nuevos entrantes en el campo de los sistemas de control de versiones
Tal vez en algún momento ya se había terminado de afeitar bastante al yak
Me pasé por completo a jj, y como tiene compatibilidad con Git, no hace falta esperar a que otros también cambien
Cada vez me frustran más varios aspectos de GitHub, así que espero que algún día todos también lo superen, pero en ese frente el camino hacia adelante no parece tan simple
SVN es intuitivo y funciona lo suficientemente bien en el 99% de los casos, así que no hace falta “enseñárselo” a la gente por separado
Ojalá todos dejáramos de fingir ser hackers 1337 y admitiéramos que Git es una herramienta excesiva para la mayoría
Creo que tengo un modelo mental bastante bueno de lo que hace Git, pero en cuanto un comando se vuelve apenas un poco complejo, no recuerdo los argumentos
Los comandos no son fáciles de descubrir ni de memorizar
No sé si el problema es que la UI de texto es mala, o si describir en texto la manipulación de árboles ya es difícil de por sí
Manipular árboles complejos con texto no es fácil, y la UI de texto es objetivamente mala: https://stevelosh.com/blog/2013/04/git-koans/
Me alegra ver resultados de búsqueda para hg y Mercurial en este hilo
Todavía no puedo creer que Mercurial haya perdido la guerra de los sistemas de control de versiones distribuidos; me parece una herramienta mejor
Es usable, estable, probada en producción y cuenta con soporte activo
Se acerca a eso de “sé el cambio que quieres ver”, así que simplemente úsalo
Decir que perdió es muy contraproducente, y la inhibición implícita que genera ese tipo de frase mantiene baja la adopción de Mercurial
Se puede alojar al menos en Sourcehut y heptapod.host
También opero una instancia privada de Heptapod, que es un fork de Gitlab con soporte directo para Mercurial, y simplemente funciona bien
Git fue una de esas tecnologías que nunca terminé de meterme en la cabeza porque en muchos aspectos no sigue la intuición
Si no llevas mucho tiempo usándolo, es muy probable que tengas que buscar en Google o mirar la página man para casi cualquier operación
Sobre todo después de vivir el terror de intentar manejar una base de código grande en SVN con muchas ramas y luego fusionarlas de vuelta, se ve que Git es absurdamente mucho mejor en esa parte
Para alguien que entra directamente con Git, la curva de aprendizaje puede ser mucho mayor, pero todavía a veces me cuesta entender dónde se traba la gente
Si usas la forma integrada,
filter-branch, aparece una advertencia, tras una larga demora, de que presiones Control+C y descargues un script de Python de terceros llamadofilter-repoNo es algo de lo que esté orgulloso, pero mi operación de Git de “la cagué” más frecuente es borrar el repositorio local, clonarlo de nuevo y volver a aplicar los cambios
Funciona muy bien el 95% de las veces; para el resto le pido ayuda a la persona de DevOps
cp -R .git ../git-backupantes de hacer algo medio riesgoso en GitPorque si lo rompo demasiado, puedo reemplazar todo el directorio
.gitpor la copia anteriorEs mucho más rápido que encontrar la forma correcta de revertir una operación específica o un conjunto de operaciones
Lo que me gustaría que la gente realmente interiorizara sobre Git es que Git es un almacén de datos solo de anexado
Si quieres meter tu trabajo en el repositorio, haz commit; y una vez que el trabajo entra, no se puede eliminar con comandos de Git
El reflog también funciona con este principio
Hagas lo que hagas, puedes volver al estado anterior de la rama y restaurar el trabajo desde el almacén de datos
Pero si no haces commit, Git no puede ayudarte, así que simplemente tienes que hacer commit
Haz commit siempre, y si eso se siente demasiado pesado o se te olvida seguido, hay que arreglar la herramienta
Si escribes código todo el día, en general deberías hacer commit al menos una vez por hora
Es una tontería, pero cada vez que veo
git reflog, lo leo como re-flogTal vez por eso me cuesta memorizar este comando, y parece que inconscientemente no lo pienso como “reference log”
En cambio, se siente como si le estuviera pidiendo a Git que vuelva a vender algo barato
No soy usuario de Git, pero al ver cosas así se me refuerza la idea de que
git commiten sí no tiene sentido, y que lo importante es solo el momento en que el commit se hace push o se mergeaEs parecido a guardar un archivo de texto
Como no escribes un mensaje corto cada vez que guardas un archivo, simplemente puedes dejarlo pasar
No necesariamente corto; cuanto más pequeño es el cambio, a veces más larga es la explicación
Alguna vez escribí 2 o 3 párrafos para un cambio de 2 o 3 líneas con mucho impacto
Un commit local es una forma de crear un punto de control en un momento en que todo compila y funciona
Así puedes hacer stash de los cambios o volver a un estado que funcionaba si arruinas algo
Antes de hacer push, puedes hacer reset y dividirlo en commits adecuados, manteniendo limpio el historial remoto y evitando que se vuelva un montón de
wipO también puedes hacer squash merge del PR y obtener lo mejor de ambos mundos
Pero no hace falta ingresar mensajes sin sentido como
more fixesNormalmente creo un commit inicial como
(WIP) nombre de la funcionalidad, repito commits con amend hasta quedar satisfecho y al final quito(WIP)del mensajeVeo el registro de revisiones de Git como algo parecido a ese diario
Está más ordenado que un documento TODO separado y te incentiva a explicar de forma legible lo que ya hiciste
Cuando decides hasta dónde revertir, puede ser útil saber qué estabas pensando en aquel commit, y si el enfoque estaba equivocado, también ayuda para el análisis posterior
Si el trabajo que no se ha mergeado ni pusheado está organizado como cambios separados con un objetivo, cuando algunas partes son buenas y otras malas es mucho más fácil conservar solo las partes buenas
Aun así, técnicamente los commits no carecen de sentido
Si no hay commits, tampoco hay nada a lo que hacer push o mergear
Incluso en un sentido no técnico, registrar en texto plano por qué se cambia algo es muy útil
Si terminas escribiendo ese tipo de explicación con demasiada frecuencia, deberías acotar más la unidad de “cambio” o seleccionar mejor qué cosas tocas al mismo tiempo
Si no usas Git, me da curiosidad saber con qué haces control de versiones y gestión de cambios