Cómo deshacer el último commit en git

Aquí os dejo una manera sencilla de dar marcha atrás si habéis hecho un commit y os habéis arrepentido de hacerlo. El motivo por el que queréis “borrarlo” puede ser múltiple: porque el trabajo no está terminado y queréis continuar trabajando, habéis introducido un bug sin daos cuenta o sencillamente os habéis equivocado y lo habéis hecho antes de tiempo.

Existen dos maneras de borrar ese commit:

  • Eliminando junto al commit las modificaciones que este contiene
  • Recuperándolas en el área de trabajo para seguir trabajando en ellas

En ambos casos, el comando que utilizaremos será “git reset”.

Deshacer el commit perdiendo las modificaciones

Supongamos que tenemos nuestro repositorio en el siguiente estado:

Voila_Capture283y queremos deshacer el último commit. En este primer caso, queremos desechar los cambios introducidos en ese commit que contiene una serie de tests funcionales.

Para ello, ejecutamos el comando:

git reset --hard HEAD~1

Tras ejecutar el comando, el estado del repositorio es el siguiente:

Repositorio tras borrar el commit

Como podéis ver, el commit 600cc08 ha desaparecido que era lo que queríamos. Además, la rama activa se ha desplazado un commit hacia abajo y nuestro área de trabajo ha quedado en el estado del commit 6eb9f2d. Los tests funcionales que estaban en el commit se han perdido y tendríamos que recurrir al reflog para recuperarlos.

La sintaxis HEAD~1 del comando anterior la podríamos traducir como “El commit al que está apuntando la rama activa menos uno”. Si hubiésemos ejecutado el comando:

git reset --hard HEAD~3

en lugar de acabar en el commit 6eb9f2d (uno por detrás) habríamos acabado en 63db9fa (tres por detrás).

Deshacer el commit manteniendo las modificaciones

Existe la posibilidad de eliminar el commit pero manteniendo las modificaciones que contiene ese commit en el área de trabajo. ¿Y por qué querríamos hacer esto? Por varios motivos, por ejemplo por que los tests funcionales del commit 600cc08 están incompletos, son incorrectos o he introducido algún bug en él.

Partiendo de nuevo del mismos estado inicial de antes:

Estado inicial del repositorio.ejecutaríamos el siguiente comando:

git reset HEAD~1

Tras lo cual, el estado del repositorio sería:

Voila_Capture285Si miráis el estado veréis los siguiente:

  • Al igual que en el caso anterior, el commit 600cc08 ha desaparecido
  • La rama activa (rest) ha pasado al apuntar al commit 6eb9f2d
  • A diferencia del  caso anterior, el área de trabajo contiene las modificaciones que estaban en el commit que acabamos de borrar.

Así que podemos seguir trabajando, corregir el bug o completar los tests que habíamos dejado incompletos y hacer un nuevo commit con los cambios completos. ¡Así de fácil!

Muy útil pero…

Muy importante tener en cuenta que estas dos operaciones sobreescriben la historia del repositorio ¡estamos borrando un commit!. Si estamos trabajando en local y no hemos hecho push a nuestro remoto no hay ningún problema. Si ha habéis hecho push de este commit tened en cuenta que vuestros compañeros lo seguirán viendo si alguna de sus ramas lo referencia.

Espero que os haya resultado útil.

 

 

12 pensamientos en “Cómo deshacer el último commit en git

    1. alfonso Autor

      Hola Rafa:

      Efectivamente, como bien pones en tu post está la opción git reset –soft HEAD~1. La opción por defecto es –mixed. La diferencia entre las dos:

      –mixed: mantiene los ficheros pero no los marca como para hacer commit
      –soft: mantiene los ficheros y los marca para hacer commit. Si ejecutas un git status, te aparecerán en la sección “Changes to be commited”

      ¡Gracias por la aclaración!

      P.D. En la página de manual están las tres opciones: –hard –soft –mixed (https://www.kernel.org/pub/software/scm/git/docs/git-reset.html)

      Responder
  1. Mario

    Hola!

    Vengo de Subversion y se me esta haciendo muy complicado comprender git. Esta explicación me lo ha dejado claro. Gracias!

    Un saludo!:)

    Responder
  2. hector

    Hola cuando realizo un git rebase -i HEAD~2 y utlilizo el edit en el ultimo commit
    y me di cuenta que quiero eliminar el ultimo commit realizo git reset HEAD^
    apreto enter y me sale por consola ¿Más? por lo que no se que estoy haciendo mal.
    Si me pueden orientar se los agradeceria.
    Saludos

    Responder
    1. admin

      Hola Hector:

      cuando has ejecutado el comando git reset ¿la consola sólo te ha mostrado el mensaje “¿Más?” ? No recuerdo haber visto ese mensaje.

      En cualquier caso, si has ejecutado “git reset HEAD^” estás utilizando la opción –mixed del comando reset de manera implícita y esto hace que tras ejecutar el comando que has puesto, el último commit se “elimine” y que las modificaciones del mismo permanecen en tu área de trabajo. De esta manera, aunque el commit lo dejes de ver, el código fuente sigue disponible en tu área de trabajo. Al ejecutar este comando de git, no te sale ningún mensaje por consola, git lo ejecuta y ya está.

      Si quieres “eliminar” completamente ese commit y que el código fuente que se ha modificado vuelva estar como estaba antes de hacerlo, tendrías que ejecutar el comando “git reset –hard HEAD^”. Pero ten mucho cuidado porque la opción –hard del comando reset borra cualquier cambio que tengas en tu área de trabajo. Antes de hacerlo asegurate de que tu área de trabajo está limpia y si no lo está usa el comando git stash para guardarla. Los comandos serían:

      • git stash
      • git reset –hard HEAD^
      • git stash pop

      ¿Te he aclarado un poco lo que me estabas preguntando?

      Responder
  3. Pingback: Mis Comandos Gits – Pedro Caicedo

  4. JAvi

    Buenos días,
    en mi caso no es que me interese borrar un commit tal cual, sino que tengo la problemática de que necesito borrar ciertos ficheros que he subido en un commit.

    Son ficheros que nunca mas voy a utilizar, ni siquiera para hacer un rollback ¿Como podría hacer ese borrado?

    un saludo
    Javi

    Responder
    1. admin

      Hola Javi:

      Si lo que quieres es borrar ciertos ficheros debes usar el comando “git rm”. Por ejemplo:


      #git rm fichero1.txt app/fichero2.txt
      #git commit -m'Borrando ficheros!!'

      A partir de este commit, los ficheros ya no estarán. Ten en cuenta, es sí, que si haces checkout de un commit anterior los ficheros volverán a aparecer en tu área de trabajo.

      Responder
      1. JAvi

        Muy buenas,
        no es que quiera borrar un fichero.

        Pongamos siguiente ejemplo de ficheros que subo por commit:

        Commit 1 –> fichero a modificado
        Commit 2 –> fichero a modificado
        Commit 3 –> fichero a modificado
        Commit 4 –> fichero a modificado

        De alguna manera sé, que el fichero “a” del commit 1 ya no lo voy a necesitar nunca mas.
        La pregunta viene en como podría borrar ese fichero.

        Responder
        1. admin

          Creo que ahora entiendo mejor la pregunta. Según me indicas, imagina tienes un fichero “index.html” que modificas en 3 commits consecutivos (según el ejemplo que me has puesto).

          Supongamos que este es el contenido del fichero index.html en cada commit según me has indicado en el comentario anterior (en cada commit que haces modificas el fichero)


          # index.html Commit1
          <a href="pagina1.html" rel="nofollow">Página 1</a>


          # index.html Commit2
          <a href="pagina1.html" rel="nofollow">Página 1</a>
          <a href="pagina2.html" rel="nofollow">Página 2</a>


          # index.html Commit3
          <a href="pagina1.html" rel="nofollow">Página 1</a>
          <a href="pagina2.html" rel="nofollow">Página 2</a>
          <a href="pagina3.html" rel="nofollow">Página 3</a>

          Si quieres borrar el fichero “index.html” del primer commit, podrías hacerlo con un rebase interactivo en el que seleccionas la opción “edit” del primer commit para borrarlo. Eso sí, cuando regenere el segundo commit durante el rebase te va a dar conflictos ya que estarás modificando un fichero que en el paso anterior del rebase has borrado. Te pongo un ejemplo como hacerlo con un repo con commits reales:

          Imagina que este es tu repositorio:

          * d36db1d (master) Commit 3
          * d7c982c Commit 2
          * ac1a1c8 Commit 1
          * 49bbab1 Commit inicial

          Quieres borrar el fichero index del Commit 1 (ac1a1c8). El comando sería


          #git rebase -i 49bbab1

          Y en la interfaz que te sale para seleccionar las acciones del rebase interactivo estas quedarían:

          edit ac1a1c8 Commit 1
          pick d7c982c Commit 2
          pick d36db1d Commit 3

          Como te he comentado antes, en el primer paso del rebase al poner edit git te permite editar el commit en lugar de hacerlo automáticamente y ahí podrías borrar el fichero index.html. También podrías usar la opción “exec” del rebase interactivo y borrar el fichero ejecutando un comando rm.

          Cuando termines el primer paso del rebase interactivo y git genere el siguiente commit, te dará un conflicto ya que estarías intentando modificar el fichero index.html que acabas de borrar. Lo resuelves y continúas el rebase hasta que aplique todos los commits.

          ¿Te he respondido a la pregunta?

          Responder

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *