Un recorrido del tutorial Deshacer un commit: por qué el último commit está roto y cómo git reset --soft te permite arreglarlo sin perder trabajo.
Este escenario comienza en un proyecto de portfolio donde el último commit está sutilmente roto. Vas a leer la historia, deshacer ese commit conservando tus cambios y volver a commitearlo correctamente. Esto es lo que pasa en cada paso y por qué.
La situación
El proyecto tiene dos commits. El último, "Add header section", añadió una cabecera de navegación a index.html. El CSS correspondiente para esa cabecera se escribió en style.css, pero nunca se preparó: sigue en el árbol de trabajo como cambio no commiteado.
Así que el commit está incompleto. El sitio commiteado tiene el marcado de la cabecera apuntando a estilos que no se guardaron. Quien haga checkout de ese commit verá una cabecera rota.
Empieza ejecutando git log --oneline y git status. El log muestra el commit "Add header section"; el status muestra style.css como modificado pero no preparado. Ese desajuste es todo el problema.
La solución, paso a paso
Inspeccionar lo que se commiteó
git log confirma el último commit, y git status muestra que style.css sigue modificado en el árbol de trabajo. Ya sabes que el commit capturó index.html pero no style.css.
Deshacer el commit, conservar los cambios
git reset --soft HEAD~1
Esto retrocede el puntero de la rama un commit. El cambio en index.html que estaba en el commit vuelve al área de preparación, listo para commitearse de nuevo. Nada en tus archivos se borra.
Preparar todo esta vez
git add index.html style.css
Ahora el marcado y sus estilos están preparados juntos, para que el próximo commit sea completo.
Recommitear el cambio completo
git commit -m "Add header section"
La historia vuelve a tener un único commit "Add header section", pero esta vez incluye style.css. El sitio está íntegro.
Por qué --soft es el modo correcto aquí
git reset tiene tres modos, y la diferencia solo está en dónde aterrizan tus cambios:
--soft mueve HEAD atrás y mantiene los cambios preparados. Ideal aquí, porque quieres recommitear de inmediato.
--mixed (el predeterminado) conserva los cambios pero no preparados, en el árbol de trabajo.
--hard descarta los cambios por completo.
Aquí git reset --hard HEAD~1 borraría el trabajo de la cabecera junto con el commit. Reserva --hard para cuando de verdad quieras que los cambios desaparezcan.
Si llegas a ejecutar --hard por accidente, el commit suele ser todavía recuperable con git reflog, que lista todas las posiciones por las que ha pasado HEAD. El tutorial "Recover Lost Commits" cubre ese flujo.
Un matiz: commits compartidos
Todo lo anterior reescribe la historia, lo cual es perfectamente seguro para un commit que solo existe en tu máquina. Una vez que un commit ha sido pusheado y recogido por otros, reescribirlo obliga a todos a lidiar con una rama divergida. En una rama compartida, deshaz el cambio con un nuevo commit:
git revert HEAD