Mi guía esencial de GIT – Segunda parte


githubTal como decía en la primera parte de esta guía esencial GIT, lo que pretendo es crear mi propia guía de GIT para poder consultar y tener en un punto todos los comando necesarios que voy utilizando en mi día a día, en esta segunda parte son comando algo más avanzados por así decirlo, si te es útil también, pues genial.

Como vimos el flujo de trabajo básico en GIT es que primero modificas una serie de ficheros en el directorio de trabajo, después preparas dichos ficheros  añadiendo como una instantánea (SnapShot) en un área de preparación y por último confirmas los cambios dentro del área de preparación y almacena los ficheros de forma permanente en GIT. Si una versión de un fichero está en el directorio GIT, se considera confirmada (committed), si ha sufrido cambios desde el inicio, pero ha sido añadida al área de preparación, está preparada (staged) y finalmente ha habido cambios y no se ha preparado, está modificada (modified). Ahora pasamos a hablar de ramificaciones que estoy seguro en algún momento si trabajas en equipo vas a necesitar entender para no ocasiones sensaciones amargas y frustraciones innecesarias, así que voy a explicar desde mi propia experiencia de uso de las ramificaciones, locales y remotas y comandos necesarios para moverse entre ramificaciones.

Arrancamos, veamos que son las ramificaciones y en qué nos pueden ayudar

Es necesario entender cómo GIT gestiona las ramificaciones. GIT almacena los datos como una especie de copias en un momento determinado de los archivos completos. En cada commit que hagamos, Git almacena un punto de control que será una estructura tree con los punteros a cada unos de los ficheros confirmados y los blobs con los datos de cada fichero, que almacena una copia de cada uno en el repositorio, es como tener uns estructura de commit, otra estructura de tree que almacena los punteros a los blobs con la información de cada uno de los fciheros.

Por tanto una rama GIT  es simplemente un puntero que va moviéndose por cada una de las confirmaciones que vamos realizando. La rama por defecto de GIT sin haber creado nosotros mismos ninguna, es la rama ‘master‘ y la rama ‘master’ apuntará al último commit hecho. Pues entonces cuando creamos nosotros una nueva rama, GIT crea un nuevo puntero para que lo puedas gestionar y el comando de creación de una rama es:

# git branch admin

Pero hay un detalle importante que hay que saber, aunque parezca obvio y es que mediante un apuntador especial denominado HEAD que es simplemente el puntero a la rama local en la que tú estés en ese mismo instante. En nuestro caso al ejecutar el comando anterior lo que hemos hecho es simplemente crear la rama pero seguimos estando en ‘master’. Para movernos entre ramas, disponemos del comando:

# git checkout admin (el nombre de la rama a movernos)

El ejecutar este comando, HEAD cambia de posición, si antes lo teníamos apuntando a ‘master’, ahora estará apuntando a la nueva rama en la que nos hemos movido. Para ahorrarnos algunos comandos podemos crear y cambiarnos en el mismo comando a la rama recien creada;

# git checkout  -b admin (el nombre de la rama a crear)

Siguiendo con HEAD podríamos estar interesados en el siguiente caso, hemos hecho un commit de nuestros trabajos pero resulta que nos damos cuanta que necesitamos hacer algunas cosas más que se nos han quedado en el tintero. Pera ello necesitamos relaizar las siguientes operaciones:

# git commit -a -m “Modify readme” nuestro último commit y nos damos cuenta que nos faltan cosas por añadir.

# git reset –soft HEAD^ esta operación nos referencia al último commit antes de haber hecho nuestro commit actual, por tanto volvemos a nuestra posición anterior.

Modificamos nuestros ficheros y ejecutamos:

# git add todo.txt o lo que necesitemos hacer con add ficheros que se nos han olvidado o modificaciones nuevas…..

Con la opción amend le decimos a GIT, espera que se me olvido estas cosas y ahora si es la buena:

# git commit –amend -m “Change app controller & add index.html.”

Algunos comando que podemos necesitar:

git reset –soft HEAD^ deshacer el último commit y los llevamos a staging
# git commit –amend -m “New Message” cambiamos el último commit

Estos comandos son algo más radicales de deshacer cambios y bajar los punteros de commit:

git reset –hard HEAD^ Deshacer el último commit y los cambios hechos
# git reset –hard HEAD^^ Deshacer los 2 últimos commit y los cambios hechos

Vamos a trabajar sobre nuestra rama admin y a resolver los nuevos retos que nos han propuesto:

Para crear nuestra rama ‘admin’ y posicionarnos directamente sobre ella, utilizamos el comando ‘git checkout’ con la opción ‘-b’ que ya comentamos anteriormente:

# git checkout -b admin

Trabajamos en los cambio que nos han pedido y hacemos nuestras confirmaciones confirmaciones de cambios (commits) y va avanzando nuestro puntero en la rama ‘admin’ y  HEAD. Ahora necesitamos crear nuevos cambio pero en el frontend y para ello creamos una nueva rama, esto nos permite trabajar en dos casos diferentes y que no deben estar mezclados ya que podrían estar en prioridades distintas.

# git checkout -b frontend

trabajamos sobre las modificaciones que nos han solicitado y hacemos nuestras confirmaciones

$ git commit -a -m ‘frontend new options’

Una vez que estamos seguros de que los cambios son correctos, los podemos incorporar a la rama ‘master’ para ponerlos en producción. Para hacer esto, tenemos el comando ‘git merge’:

# git checkout master desde la rama frontend nos vamos a master y desde master fusionamos
# git merge frontend

Llegado a este punto me gustaría destacar la frase de “Fast forward” que estoy seguro que la vas a oír mucho y como resumen te diría que GIT simplifica las cosas avanzando el puntero, ya que no hay ninguna otra rama de trabajo divergente a fusionar, es decir, que lo que hemos hecho es, que de master hemos creado una rama de trabajo, hemos trabajado, hemos confirmado y hemos hecho finalmente un merge. Ahora, los cambios realizados están en la snapshot de la confirmación  dentro de la rama ‘master’. Llegado a este punto recomendar que si ya hemos terminado los trabajos de nuestra rama frontend es eliminarla para no tener impurezas y marcar una pauta de trabajo. Para eliminar nuestra rama frontend que no nos es útil lo hacemos con el comando:

# git branch -d frontend

# git checkout admin 

trabajamos sobre los cambios que nos han solicitado y confirmamos

# git commit -a -m ‘finished the new panel admin’

Como ya está terminado y listo para ser fusionarlo con merge en la rama ‘master’, llevamos a cabo los siguientes pasos:

# git checkout master
# git merge admin

La fusión de esta rama con ‘master’ difiere un poco de la anterior hecha de ‘frontend’, ya que la confirmación en la rama actual ‘admin’ no es ancestro directo de la rama a fusionar, por lo que en este caso GIT tiene cierto trabajo extra que hacer, es decir, no es un “Fast forward”. Después tendremos que eliminar por el mismo concepto que antes hemos comentado, la rama que ya hemos terminado de fusionar ‘admin’:

# git branch -d admin

Pero no siempre nos encontraremos con el resultado de “sin problemas”, puede darse el caso que tengamos problemas de fusiones y tengamos conflictos con ficheros que tengamos que resolver. Para ello obtenemos resultados como:

# git merge admin

Auto-merging index.html

CONFLICT (content): Merge conflict in index.html

Automatic merge failed; fix conflicts and then commit the result.

Para la resoluciones de conflictos dependerá de lo que uses, por ejemplo puedes usar con git mergetool meld o bien puedes usar la propia que Rubymine te proporciona, que es la que he terminado por usar por claridad, pero si no tienes Rubymine, Meld está muy bien. Veamos algunos comandos de gestión de ramificaciones útiles:

# git branch

admin

* master

frontend

El * que nos proporciona git branch nos aporta información sobre la rama activa en la que nos encontramos y además todas las conformaciones que se hagan, el puntero avanzará con ella. Para ver la última confirmación de cambios en cada rama, puedes usar el comando ‘git branch -v‘, para ver las ramas que han sido fusionadas en la rama activa,  ‘git branch –merged, o para ver los trabajos sin fusionar aún, ‘git branch –no-merged‘. En el caso de intentar eliminar una rama que no ha sido fucionada nos da un error de aviso pero la vamos a poder eliminar a nuestro criterio propio, es decir:

# git branch -d testing si no está fusionada nos da un aviso que no puede ser eliminado ya que no ha sido aún fusionada, pero si aún así queremos realizar la operación debemos ejecutar lo siguiente:

# git branch -D testing con esta opción -D estamos diciendo que a pesar de todo haga el borrado.

Para las ramas remotas, las  referencias suelen ser como ‘(remoto)/(rama)’, es decir, si tenemos una rama local master y otra admin, las ramas remotas serán origin/master y origin/admin. Aquí vuelven a parecer los apuntadores para las remotas, si trabajamos sobre master, el puntero local de master avanza mientras el puntero origin master permanece quieto hasta que no hagamos actualizaciones sobre ella. Para sincronizarnos tenemos un comando, ‘git fetch origin, que localiza nuestro repositorio “https://github.com/carlossanchezp/socialbuy.git”, lo que no tengamos lo localiza, lo actualiza y después el puntero se mueve la rama ‘origin/master’.

Si tenemos una rama local llamada ‘admin’ y queremos publicarla en remoto para compartir los trabajos, necesitamos ejecutar el comando ‘git push (remoto) (rama):

# git push origin admin

o prodriamos hacer también

# git push origin admin:adimin

o en el caso de querer cambiar el nombre de la rama local admin en remoto y que se renombre por awesomeadmin

# git push origin admin:awesomeadmin

Cuando recupere otra persona desde el servidor la rama ‘admin’ con fetch, lo que obtiene es una referencia, con lo que significa que no es una copia para trabajar, lo que te proporciona es un puntero a ‘origin/admin’:

# git fetch origin

Para integrar necesitamos hacer un ‘git merge origin/admin’. Por otro lado podemos crear nuestra propia rama local desde la remota:

# git checkout -b admin origin/admin

Para cambiar el nombre de una rama local con un nombre distinto a la que tenemos en remoto, debemos ejecutar:

# git checkout -b adm origin/admin

Cuando ya hemos terminado y se ha hecho ‘merge’ a ‘master’ en el remoto, ya estamos dispuestos a eliminar la rama remota que no necesitamos con el comando: ‘git push [nombreremoto] :[rama]’. Por ejemplo,  borrar  ‘admin’ del servidor:

# git push origin :admin

Ahora pasemos a hablar de las formas de integrar cambios de una rama en otra que son temas muy comunes y que seguro necesitarás: la fusión con merge y la reorganización con rebase. Comenzamos el comando ‘git merge’, que lo que nos va hacer es es una fusión a tres partes entre las dos últimas instantáneas de cada rama y su ancestro común, esto entonces nos crea una nueva instantánea (snapshot) y claro finalmente la correspondiente confirmación (commit), pero con el comando ‘git rebase’, lo que hace es coger todos los cambios confirmados en una rama y nos lo replica sobre el destino. Por ejemplo:

# git checkout admin
# git rebase master

Con esto GIT hace que  vaya al ancestro común entre ambas ramas, es decir, en la rama donde te encuentras actualmente ‘admin’ y en la rama de donde quieres reorganizar ‘master’, saca las diferencias en la rama donde te encuentras y guarda esas diferencias en archivos temporales, hace una especie de reset de la rama actual hasta llevarla a la misma confirmación en la rama de donde quieres reorganizar y finalmente, vuelve a aplicar ordenadamente los cambios. En este momento, puedes ir a ‘master’ y hacer fast-forward, es decir un merge. Con estas operaciones quedaría todo al mismo nivel si lo ves de una forma gráfica.

# git checkout master
# git merge admin

Hagamos un ejercicio, supongamos que vamos trabajando en pequeñas operaciones y sobre estas vamos realizando commits y finalmente decidimos re-unificarlos en un único commit, para lo que haríamos:

creamos un fichero y añadimos nuestr trabajo: rebase.txt

hacemos el primer commit git add . && git commit -m “rebase.txt added to index”
añadimos más contenido al fichero rebase.txt

hacemos el segundo commit git add . && git commit -m “added content”

añadimos más contenido al fichero rebase.txt
hacemos el tercer commit git add . && git commit -m “added more content”

# git log y vemos el registro de commits

Ahora combinamos todos los commit en un solo con
# git rebase -i HEAD~3

Alguna configuración útil si no dispones de herramientas visuales de gitg por ejemplo:

# git log –oneline –abbrev-commit
# git log –graph –pretty –oneline –abbrev-commit

Para hacer identificaciones por colores en operaciones de git status y git branch

# git config –global color.status auto
#git config –global color.branch auto

Para eliminar los últimos cambios:

# git reset –hard

Un comando útil en los casos en los que tengamos que cubrir una necesidad urgente y no podemos hacer aún commit es el comando git stash, cuidado si lo dejamos en el olvido y queremos recuperarlo, si hay confictos nos lo dice:
# git stash save nameofstash

#git stash list vemos todos los stash que hemos creado

stash@{0}: WIP on master: 273e4a0 Resize issue in Dialog
stash@{1}: WIP on master: 273e4a0 Silly typo in Classname

# git stash apply stash@{0}

# git stash drop stash@{0} elimina un stash que le digamos mediante su identificador

# git stash clear elimina todos los stash

# git stash pop añade lo almacenado en el stash

Para los comandos de subida y bajada de datos, git push y git pull podríamos necesitar:

#git pull descarga todo

# git push origin admin únicamente nos sube admin o la rama que le indiquemos y no está creada la crea

#git push que nos sube todas las ramas

Pongamos por último un ejemplo de trabajo:

  1. nos vamos al directorio de trabajo y cambiamos a nuestra rama de trabajo admin, asegura que estas dentro del directorio con # git status
  2. modificamos nuestros ficheros dentro de nuestra rama de trabajo admin
  3. añadimos nuestros cambios # git add .
  4. hacemos nuestra confirmación de dichos cambios con # git commit -m “commit message”
  5. cambiamos de rama y nos vamos a master # git checkout master
  6. si hay cambio en el server los descargamos con #git pull origin master
  7. añadimos los cambios #git rebase master admin
  8. volvemos a cambiamos de rama y nos vamos a master # git checkout master
  9. después hacemos desde master # git merge admin
  10. y finalmente subimos # git push llegado a este punto si dispones de más ramas y únicamente debes poner origin master, origin admin….la rama que quieras subir

Los pasos 6, 7 y 8 si ya estamos actualizados no serían necesarios, nos llevamos a master los cambios de admin paso 9.

El siguiente caso es muy sencillo:

  1. nos vamos al directorio de trabajo y cambiamos a nuestra rama de trabajo admin, asegura que estas dentro del directorio con # git status
  2. modificamos nuestros ficheros dentro de nuestra rama de trabajo admin
  3. añadimos nuestros cambios # git add .
  4. hacemos nuestra confirmación de dichos cambios con # git commit -m “commit message”
  5. volvemos a cambiamos de rama y nos vamos a master # git checkout master
  6. después hacemos desde master # git rebase admin
  7. y finalmente subimos # git push llegado a este punto si dispones de más ramas y únicamente debes poner origin master, origin admin….la rama que quieras subir

Ahora si únicamente necesitamos mantener la rama admin sin mezclar master:

  • comenzamos y nos vamos al directorio de trabajo, cambiamos a nuestra rama de trabajo admin, asegura que estas dentro del directorio con # git status
  • modificamos nuestros ficheros dentro de nuestra rama de trabajo admin
  • añadimos nuestros cambios # git add .
  • hacemos nuestra confirmación de dichos cambios con # git commit -m “commit message”
  • finalmente subimos los cambio en la rama admin con #git push origin admin

Cuando hablemos de “rebase” lo que estamos haciendo es llevarnos los cambios confirmados de una rama a otra, es decir, que si otros programadores han hecho cambios y nos descargamos, deberíamos replicarlos en las ramas de trabajo ya creadas, en las nuevas no sería necesario. Pero una vez que ya hemos trabajado en nuestra rama y lo que queremos es aplicar los cambios debería hacerlo con “merge”. Pero recomiendo el uso de gitg en cada comando que ejecutemos y la configuración de los colores en modo comando de consola, así como fijarnos siempre en los mensajes de resultado de GIT en cada paso.

Con esta serie de comandos podrás defenderte en GIT, básico y algo avanzado. Iré actualizando con más comandos según me encuentre con ellos. Recuerda que dispones del libro de GIT y siempre puedes preguntar o hacer tus propias pruebas para ver cómo funciona realmente.

2 comentarios en “Mi guía esencial de GIT – Segunda parte

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s