¿ 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)
Deja una respuesta