la he liado parda con el git: como borrar cosas que ya he comiteado

¿ Quien no ha hecho un commit de una cosa que no quería ? seguramente todos hemos comiteado algo que luego nos hemos dado cuenta que no tenía que ir y no lo hemos metido en .gitignore. A veces da un poco igual, depende de lo estrictos que seamos en nuestro equipo o nosotros mismos o bien por que estemos publicando el repositorio de forma pública. Con eliminar el fichero, volver a comitear y pushear… aquí no ha pasado nada :D… pero y si quiero borrar algo que no quiero… ¿ qué hago ?

En mi caso he metido un directorio con una compilacion de node via nodeenv[1] que son unos 200MB que no pintan nada en el repo y que además pesa, el objetivo es eliminar ese contenido de una forma limpia. Para ilustrarlo y que no se me olvide voy a documentar un ejemplo ilustrativo 😉

 

# creamos un repositorio nuevo de git llamado foo
git init project
cd project

# primer commit
echo "Hola mundo" > readme.txt
git add .
git commit -m"add readme file"

# segundo commit, aquí es donde nos colamos metiendo contenido
mkdir pictures
echo "vacaciones" > pictures/readme.txt
git add .
git commit -m"add new feature"

# hacemos como que no nos hemos dado cuenta y seguimos comiteando
echo "Nuevas caracteristicas" > CHANGES
git add . 
git commit -m"add changefile"

En este punto la hemos liado por que se nos ha colado el directorio de vacaciones en el proyecto y hacemos un facepalm, por que hemos metido la carpeta de pictures con cosas de las vacaciones en el proyecto y eso no lo queremos 😀

¿Ahora como solucionamos esta situación?

Lo que necesitamos es conservar el último cambio pero eliminar el directorio pictures del proyecto de forma que no quede almacenado en git. Para ello y siguiendo la documentación de git checkout[2] vamos a hacer lo siguiente:

  • volver al paso 2 dejando los cambios de 3 en el stage area
  • Crear una rama con los cambios de stage
  • mover el head del master al paso 1
  • mergear el master con la nueva rama

Explicamos los pasos:

Necesitamos trabajar con los ficheros de forma que no modifiquemos la rama master y nos creamos una rama para reparar que se llamará ‘fix-mess-up’ y la dejamos en el punto anterior a cuando la hemos liado, es decir hace dos commits.

# creamos una rama en la que trabajar la reparacion
git checkout -b fix-mess-up
# volvemos dos commits atrás y dejamos los cambios en el stage, de forma que podemos manejarlos, quitar, añadir, etc...
git reset --soft HEAD~2
# vemos lo que hay en el stash, pendiente de comitear
git status
# quitamos del stash la carpeta de pictures
git reset HEAD pictures/
# ahora tenemos el directorio pictures que tenemos que eliminarlo o meterlo en .gitignore
rm -fr pictures
# aplicamos los cambios en nuestra rama, esto debería ser el contenido correcto
git commit -m"fixed mess up"

Ahora que ya tenemos una rama buena, vamos a eliminar el contenido no deseado de master y echunfarle nuestra rama con la reparación.

# cambiamos a la rama master
git checkout master
# volvemos dos commits atrás y nos cargamos lo que haya con el hard!
git reset --hard HEAD~2
# mezclamos lo que tenemos en la rama fix-mess-up en el master
git merge fix-mess-up

Y en este momento ya lo tenemos reparado, solo falta borrar la rama de fix-mess-up que ya no la necesitamos.

#borrar la rama de la reparación que ya no es necesaria
git branch -d fix-mess-up

 

Nota:

Para que no se me olvide, en el momento en que se hacen checkouts o resets, se entra en modo deatached, con lo que el puntero de HEAD no está en el último commit y cada modificación que se haga a partir de ahí se mete en un branch virtual. Para no perder estos cambios hay que hacer o bien un branch o un tag tal y como se indica en la documentación de git checkout[2]

It is important to realize that at this point nothing refers to commit f. Eventually commit f (and by extension commit e) will be deleted by the routine Git garbage collection process, unless we create a reference before that happens. If we have not yet moved away from commit f, any of these will create a reference to it:

$ git checkout -b foo   (1)
$ git branch foo        (2)
$ git tag foo           (3)

 

[1] http://ekalinin.github.io/nodeenv/

[2] https://git-scm.com/docs/git-checkout#_detached_head

Deja un comentario

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

 

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.