El objetivo principal de trabajar con un sistema de control de código fuente como Git es, por supuesto, mantener un histórico fiel e inalterado de todas las etapas por las que ha ido pasando el código fuente de un proyecto. A medida que vamos modificando el código y haciendo commits, su historia se va ampliando. En cualquier momento podemos ver el estado exacto que tenía un archivo en cualquier momento del pasado, e incluso ver quién ha hecho un cambio concreto, lo cual es de gran utilidad. Sin embargo, a veces, podemos añadir algo a esta historia que no pretendíamos añadir. Por ejemplo, hacemos un commit sin querer, metemos archivos de más o de menos, o va con un bug vergonzoso que no queremos que nadie vea y que se nos ha colado...
Por regla general no deberíamos modificar la historia salvo que sea estrictamente necesario, pero ¡hey!, estas cosas pasan, así que deberíamos poder arreglarlo.
Git es fácil de usar en el día a día, pero cuando aparece algún problema entran siempre en juego muchas variables y puede complicarse la cosa. ¿Cómo arreglamos esto?
Vamos a ver varios casos que se refieren exclusivamente a cuando se trata del último commit realizado. Si es un commit anterior dependiendo de lo que necesitemos habría que hacer otras cosas, pero este es el caso más habitual, así que es el que vamos a ver por brevedad.
En Git existen muchas maneras de hacer las cosas. Estas que cuento a continuación no tienen por qué ser las únicas, pero son las que a mí me parecen más directas y sencillas.
El commit NO está en Github todavía
Bueno, este es el caso fácil. Si hemos hecho el commit y todavía no se ha enviado al repositorio de origen (en Github, GitLab, Bitbucket o donde sea), podemos solucionarlo de varias maneras.
Volver al último commit empezando de cero
Si lo único que necesitas es eliminar este último commit y empezar de nuevo solo tienes que abrir una línea de comandos en la carpeta del repositorio y escribir:
git reset HEAD^ --hard
Lo que hace esto es eliminar el último commit de la historia, dejando la carpeta en el punto anterior en el que estaba antes de hacer los cambios correspondientes a dicho commit.
El ^
del final de la cabecera le indica a Git que el punto de la historia en donde deseas dejarla (resetearla), es el padre del último commit en la rama actual (que se llama siempre HEAD
). Es importante indicarlo.
Ahora bien, esto hará que pierdas todos los cambios que había en éste.
Volver al último commit pero no perder los cambios actuales
Lo anterior será lo que desees hacer en muchos casos, pero en muchos otros no. A lo mejor lo que necesitas corregir está en un solo archivo y los cambios de los demás te parecen bien. En estos casos está bien eliminar el commit pero al mismo tiempo evitar perder los cambios. Conseguirlo es casi idéntico a lo anterior, y solo debes escribir:
git reset HEAD^ --soft
De este modo deja todo tal cual está.
Me he olvidado de uno o varios archivos
Si no te hace falta algo tan radical y simplemente te has olvidado de añadir algún archivo al último commit, no hace falta que deshagas todo como acabamos de ver.
Puedes escribir tan solo este comando para añadir los que te falten:
git add archivo1.ext archivo2.ext ...
Ten en cuenta que puedes usar patrones para añadir varios archivos con un nombre similar de golpe, o simplemente hacer una lista como se ve en lo anterior.
Cuando hayas añadido los archivos que te faltasen, indicas que quieres modificar el commit anterior en base a esto, escribiendo:
git commit --amend
lo cual añadirá el o los archivos al último commit que todavía está en tu equipo.
Nota: si haces esto así, desde línea de comandos, la opción --amend
te abre un editor vi por si quieres modificar el mensaje también. Para salir y terminar con la operación debes pulsar ESC
y a continuación :x
o :q
para que salga y grabe los cambios.
El commit ya se ha enviado al servidor remoto (Github, Gitlab, Bitbucket...)
Esta es una pregunta muy frecuente de la que hay muchas versiones diferentes online para su respuesta, muchas de ellas incorrectas. Se trata de hacer lo mismo que acabamos de ver, pero esta vez teniendo en cuenta que no solo está en nuestro equipo local, sino que dicho commit también se ha enviado al servidor de origen, sea éste Github, Bitbucket, Gitlab o similar.
En este caso en realidad es bastante sencillo de hacer también.
El repo local y el remoto están sincronizados
Este es el caso más habitual. Es decir, estamos trabajando en un repositorio, hacemos cambios, realizamos un commit para guardarlos en la historia y lo enviamos al remoto usando push
. Acto seguido nos damos cuenta de que va con un error muy gordo y queremos echarnos para atrás. ¿Cómo lo hacemos?
Pues en primer lugar destruyendo el commit localmente como hemos visto en el apartado anterior, con:
git reset HEAD^ --hard
y a continuación forzando los cambios al repositorio remoto de origen con:
git push origin -f
En condiciones normales un push al origen falla si el commit que está "arriba" no es un ancestro del commit que se está intentado hacer. Es decir, si el repo remoto va por delante del repo local. Con el parámetro -f
(o --force
que es lo mismo) forzamos a que esta comprobación no se haga. Esto puede tener efectos destructivos y que se pierdan los commits que van por delante de nosotros, cosa que es justo lo que queremos en este caso: con la instrucción reset
estamos situados en un commit inmediatamente anterior al último y con el push
forzado estamos haciendo que éste desaparezca.
¡Espero que te resulte útil!