5 comandos de Git más allá de commit y push
Cinco comandos de Git más allá de commit y push: stash, reflog, cherry-pick, rebase -i y bisect para recuperar, limpiar y hallar bugs.
La mayoría de los desarrolladores viven en add, commit, push y pull, pero el verdadero poder de Git está en los comandos de recuperación, edición de historial y depuración que el ciclo diario nunca toca.
Uno suele conocer el resto por las malas. Un reset --hard se traga una tarde entera de trabajo, o aparece un bug en algún punto de 200 commits y nadie sabe decir cuál lo rompió. Los cinco que siguen resuelven problemas que lo básico no puede: guardar temporalmente trabajo a medias, recuperar commits que dabas por perdidos, mover una única corrección entre ramas, limpiar un historial desordenado antes de un PR y localizar con precisión el commit que introdujo un bug. Cada uno viene con un disparador mental, la sintaxis exacta y el detalle que suele hacer tropezar a la gente.
Puntos clave
git stashguarda temporalmente tu trabajo a medias y te devuelve un árbol de trabajo limpio, lo que te permite cambiar de contexto sin hacer un commit desechable.git reflogregistra cada posición a la que ha apuntado HEAD, así que tras un reset o un rebase desafortunado puedes encontrar el hash del commit perdido y restaurarlo congit reset --hard <ref>.git cherry-pick <hash>copia un único commit sobre tu rama actual, lo cual es ideal para llevar un hotfix a una rama de release sin fusionar todo lo demás.- Los comandos que reescriben el historial, como
git rebase -iygit reset --hard, son seguros en trabajo local sin publicar y peligrosos en ramas compartidas;git refloges tu vía de recuperación cuando algo sale mal. git bisectrealiza una búsqueda binaria en tu historial para encontrar el commit exacto que introdujo un bug en log₂(n) pasos.
Discover how at OpenReplay.com.
git stash: guarda el trabajo para cambiar de contexto rápido
Úsalo cuando llega un reporte de bug mientras tu árbol de trabajo es un desastre a medio terminar y necesitas cambiar de rama ya mismo. git stash aparca tus cambios sin confirmar en un lugar seguro y te devuelve el árbol de trabajo limpio, igual que en tu último commit. Sin necesidad de un commit “WIP” desechable.
git stash # shelve tracked changes, clean the tree
git stash --include-untracked # also shelve new, untracked files
git stash list # see all stashes: stash@{0}, stash@{1}, ...
git stash pop # reapply the latest stash and delete it
git stash apply stash@{1} # reapply a specific stash, keep it in the list
El detalle: pop y apply no son intercambiables. git stash pop aplica los cambios guardados y elimina el stash; git stash apply los aplica pero conserva el stash, lo cual es más seguro si la reaplicación puede provocar conflictos. Si un pop produce un conflicto de merge, el stash no se descarta. Resuelve primero el conflicto y luego comprueba antes de dar por hecho que ya no está.
git reflog: recupera trabajo que creías perdido
Úsalo cuando un reset --hard desafortunado, un rebase mal hecho o una rama eliminada hacen desaparecer commits y cunde el pánico. git reflog registra cada posición que ha ocupado HEAD en tu repositorio local, así que el commit “perdido” casi siempre sigue existiendo. Solo necesitas su hash.
git reflog
# ab12cd3 HEAD@{0}: reset: moving to HEAD~1
# ef45gh6 HEAD@{1}: commit: the work you thought vanished
git reset --hard ef45gh6 # restore HEAD to that commit
# or, to inspect it on a new branch first:
git switch -c recovery ef45gh6
Encuentra la referencia del estado que quieres y luego usa git reset --hard <ref> para volver a él, o revísalo en una rama nueva para inspeccionarlo con seguridad antes. Este es el héroe del “oh no, perdí mi trabajo” dentro del conjunto de herramientas.
El detalle: el reflog es estrictamente local y propio de cada clon. No viaja al remoto ni existe en un clon nuevo, así que volver a clonar para “recuperar tu trabajo” no servirá de nada. Además, las entradas se van eliminando con el tiempo mediante el recolector de basura, así que recupera cuanto antes.
git cherry-pick: mueve un solo commit entre ramas
Úsalo cuando un único commit de hotfix debe llegar a una rama de release, pero no quieres fusionar toda la rama de feature de la que proviene. git cherry-pick <hash> copia un commit específico sobre tu rama actual y deja todo lo demás atrás.
git switch release-2.4
git cherry-pick 9f3c1a7 # apply one commit here
git cherry-pick 9f3c1a7 3b8e2d0 # apply several, in order
El detalle: cherry-pick crea un commit nuevo con un hash nuevo. El original no se conserva ni se mueve. Si más adelante ese mismo commit llega a esta rama a través de un merge normal, puedes acabar con cambios duplicados en el historial. Úsalo de forma deliberada, no como sustituto rutinario del merge.
git rebase -i: limpia el historial antes de un PR
Úsalo cuando tu rama de feature tiene cinco commits del tipo “fix typo” y “wip” y quieres un historial ordenado y revisable antes de abrir un pull request. git rebase -i <base-branch> abre un editor donde puedes reordenar, combinar (squash), editar o descartar commits.
git rebase -i main
# pick a1b2c3d Add feature scaffold
# squash e4f5g6h fix typo
# reword h7i8j9k Wire up handler
# drop k0l1m2n debug logging
Marcar un commit como squash lo fusiona con el que está encima, reword cambia únicamente su mensaje y drop lo excluye por completo del resultado. Si solo necesitas colapsar una rama entera en un único conjunto de cambios preparados, git merge --squash <branch> es la herramienta hermana. Deja los cambios combinados en el área de staging sin crear un commit, así que aún tienes que ejecutar git commit tú mismo.
El detalle, y la regla de oro: reescribe el historial con total libertad mientras siga siendo local, pero nunca hagas rebase de commits que ya has publicado en una rama compartida. Reescribir el historial compartido obliga a todos los demás a una reconciliación dolorosa, un riesgo que Pro Git denomina “Los peligros del rebase”.
git bisect: encuentra el commit que introdujo un bug
Úsalo cuando algo funcionaba la semana pasada y ahora está roto, y no tienes ni idea de cuál de los 200 commits fue el culpable. git bisect realiza una búsqueda binaria en el historial: marcas un commit malo y uno bueno, pruebas los puntos intermedios que Git va extrayendo, y localiza el primer commit defectuoso en log₂(n) pasos.
git bisect start
git bisect bad # current commit is broken
git bisect good v2.3.0 # this older tag worked
# Git checks out a midpoint — test it, then tell Git:
git bisect good # this one is fine
git bisect bad # this one is broken
# ...repeat until Git reports "<hash> is the first bad commit"
git bisect reset # return HEAD to where you started
Puedes automatizar toda la búsqueda: git bisect run <script> usa el código de salida de un script para marcar cada commit como bueno o malo sin intervención manual. Termina cada sesión con git bisect reset para devolver HEAD al punto donde estabas antes de la búsqueda.
El detalle: bisect asume que cada commit extraído compila y ejecuta tus pruebas sin problemas. Un commit que no compila por un motivo ajeno distorsiona el resultado. Marca esos casos con git bisect skip en lugar de adivinar si son buenos o malos.
Una red de seguridad para los destructivos
Dos de estos comandos reescriben el historial, y la regla para ambos es la misma: git rebase -i y git reset --hard son seguros en trabajo local sin publicar y peligrosos en ramas compartidas. Cuando necesites deshacer algo de forma segura en una rama de la que otros ya han hecho pull, opta por git revert, que registra un nuevo commit que revierte el cambio sin alterar el historial existente. Y cuando una reescritura local sale mal, git reflog es la vía de escape que te devuelve tus commits.
Estos cinco se ganan su lugar porque cada uno responde una pregunta que commit y push no pueden: guarda esto, recupera aquello, mueve uno, ordena, caza el bug. Asocia cada uno con su disparador y échale mano en cuanto se presente la situación.
Preguntas frecuentes
¿Cuál es la diferencia entre git reset --hard y git revert?
git reset --hard retrocede HEAD y descarta commits, reescribiendo el historial, lo que lo hace peligroso en cualquier rama de la que otros hayan hecho pull. git revert, en cambio, registra un nuevo commit que revierte el cambio objetivo dejando intacto el historial existente. Usa reset --hard solo en trabajo local sin publicar; usa revert como la forma segura de deshacer en ramas compartidas. Si un reset sale mal, git reflog puede recuperar los commits descartados a partir de su hash.
¿Cómo recupero un commit después de que git reset --hard lo haya eliminado?
Ejecuta git reflog, que registra cada posición que ha ocupado HEAD en tu repositorio local. Busca la entrada del estado que quieres, anota su hash y luego ejecuta git reset --hard <hash> para restaurarlo, o git switch -c recovery <hash> para inspeccionarlo primero en una rama nueva. El reflog es local y propio de cada clon, así que volver a clonar no recuperará el trabajo, y las entradas se van eliminando con el tiempo mediante el recolector de basura, así que recupera cuanto antes.
¿Reemplaza git switch a git checkout para cambiar de rama?
git switch y git restore se introdujeron en Git 2.23 (agosto de 2019) para dividir los roles sobrecargados de git checkout: switch se encarga de moverse entre ramas y restore de restaurar archivos. Ambas páginas del manual incluyeron una advertencia de carácter experimental durante años, pero esa advertencia se eliminó a partir de Git 2.55.0, por lo que ahora son simplemente los comandos recomendados para esas operaciones. git checkout sigue funcionando y no está obsoleto, así que los flujos de trabajo existentes siguen siendo válidos.
¿Cuándo debería usar git cherry-pick en lugar de un merge?
Usa git cherry-pick cuando necesites exactamente un commit en otra rama (por ejemplo, llevar un único hotfix a una rama de release) sin arrastrar el resto del historial de la rama de origen. Un merge trae los cambios de la rama completa, lo que resulta la herramienta equivocada para aislar una sola corrección. Ten en cuenta que cherry-pick crea un commit nuevo con un hash nuevo, así que si el mismo cambio llega más adelante mediante un merge normal puedes acabar con cambios duplicados en el historial.