Aviso de cookies

Estoy de acuerdo Este sitio web guarda pequeños fragmentos de información (cookies) en su dispositivo con la finalidad de ofrecer un mejor contenido y para finalidades estadísticas. Usted puede desactivar el uso de cookies modificando la configuración de su navegador. Navegar por nuestro sitio web sin cambiar la configuración del navegador hace que usted nos esté autorizando a guardar esta información en su dispositivo.

Ramas y Fusiones en Git

16 de Octubre de 2013 a las 22:00| git

Una de las ventajas de Git  es el trabajo con ramas, se pueden crear ramas de forma muy fácil y es cómodo trabajar con ellas. Es muy importante tener muy claro que es una rama, para que sirve y los diferentes tipos ramas que existen(ramas locales o remotas), teniendo esto claro se podrá utilizar todo el potencial que proporcionan las ramas.

Otro concepto relacionado con las ramas son las fusiones, que nos permite unir el trabajo desarrollado en diferentes ramas. Se puede fusionar el trabajo de varias formas( merge o rebase) y dependiendo del escenario de trabajo se deberá escoger el tipo de fusión mas conveniente.

También se explicaran otros comandos que podemos utilizar cuando trabajamos con ramas, como  cherry pick .

 

RAMAS LOCALES Y REMOTAS

Una rama en Git es un apuntador  a un commit y todos sus ancestros,que  va moviendose conforme vamos añadiendo commit a esa rama.

En un repositorio hay varios apuntadores, tenemos el apuntador HEAD  y el apuntador que tiene cada rama. De esta forma, Git sabe en que commit estamos en cada contexto.

En una rama el programador  podrá  ver la evolución del código examinando sus commit, y  en caso necesario se podrá  volver a un estado anterior. Podemos considerar a una rama como una "linea de tiempo de commit".

Cuando creamos un repositorio en Git  crea  una rama principal que se denomina master y a partir de esta, podemos crear todas las ramas que necesitemos. Todas las ramas tienen un punto inicial común pero desde ese momento cada rama tiene su propia evolución.

Las ramas son muy útiles para trabajar de forma simultanea en el desarrollo de  código, podemos tener varias ramas, y en  cada una podemos desarrollar una funcionalidad diferente, para después fusionar el código de cada rama y obtener la aplicación en su totalidad. También las ramas nos facilita la tarea para trabajar con varios desarrolladores en el mismo repositorio.

Ramas locales

Este tipo de ramas son con las que trabajamos en nuestro repositorio, donde realizamos nuestros commits. Para crear una nueva rama se utiliza el comando.

git branch desarrollo

Creamos una rama denominada desarrollo, para trabajar en ella debemos  "movernos" a esa rama.

git checkout desarrollo

Para realizar los dos pasos en uno.

git checkout -b desarrollo

Crea la rama y  cambias a esa rama.

Para borrar una rama.

git branch -d desarrollo

Si queremos ver un listados ramas del repositorio.

git branch

En este listado solo aparecen las ramas locales, para el  listado incluyendo las ramas remotas.

git branch -a

Hay diferentes estrategias de ramas para un repositorio, las mas conocida es utilizar la rama master para  código estable y una rama desarrollo donde para el desarrollo, cuando el código sea estable se fusiona con la rama master. Dentro de la rama desarrollo se pueden crear otras ramas para trabajar en otros aspectos del código, como arreglar errores o nuevas funcionalidades, estas ramas son de corta de duración y cuando se finaliza el trabajo en ella se fusiona con la rama desarrollo y se borra la rama.

Ramas remotas

Este tipo de  rama son ramas locales que hacen referencia a una rama que se encuentra  en un repositorio remoto,son ramas  no editables, no se puede realizar commit, por lo que  deben fusionarse con una rama local para poder trabajar. Con las ramas remotas podemos saber el estado en que se encuentra una rama del repositorio remoto.

Para añadir una rama remota a nuestro repositorio, necesitamos la URL donde se encuentra el repositorio remoto.

git remote add dev ssh://pepe@1example.com:repos/hotel

Crea una rama local  denominada desarrollo que hace referencia al repositorio especificado. Esta rama no esta actualizada, para actualizar el contenido.

git fetch dev

En la rama remota actualizara con el contenido del repositorio remoto que hace referencia(dev), creando tantas ramas remotas como ramas tenga el repositorio remoto.

Pero el contenido de las ramas remotas no es editable, se debe crear una rama local .El repositorio remoto tiene dos ramas ;master y desarrollo, nosotros solo nos interesa la rama desarrollo, para poder utilizarla.

git checkout --track dev/desarrollo

Esto creara una rama local denominada desarrollo basada en la rama desarrollo del repositorio dev.

Si queremos que nuestra rama local tenga un nombre diferente al de la rama remota.

git checkout -b local dev/desarrollo

Ahora que tenemos una rama local donde se descargara el contenido de repositorio remoto.

 

RECUPERACION INFORMACIÓN

Si en el repositorio remoto se han introducidos nuevos commit, tenemos que descargar el contenido nuevo a nuestro repositorio. Aquí hay dos formas de realizarlo.

1) Nos situamos en la rama local desarrollo,descargamos el contenido a la rama remota desarrollo.

git fetch

Nota:Si ha  utilizado la opción track para crear la rama local, no debemos especificar el nombre del repositorio remoto (dev). En caso contrario habrá que especificar el nombre en el comando fetch.

Y fusionar el contenido a nuestra rama local desarrollo.

git merge dev/desarrollo

Fusionara el contenido del rama remota dev,con la rama local desarrollo.

2) La otra opción, unir los dos pasos anteriores en solo uno.

git pull

Descarga el contenido del repositorio remoto y lo fusiona a la rama desarrollo de nuestro repositorio.

Con la primera opción podemos inspeccionar los cambios antes de fusionarlos a nuestra rama y ver si puede provocar algún conflicto,  utilizar esta opción suele mas recomendable. Si sabemos perfectamente que el contenido del repositorio remoto no va a provocar ningún conflicto, utilizar la segunda opción.

 

VER HISTORIAL

Como se ha comentado anteriormente, es útil examinar los cambios introducidos en la rama remota antes de fusionarlos. Git almacena en un historial todos los commit, conocer algunos comandos que nos mostrara la información que almacena el historial será de bastante utilidad.

Para ver el historial.

git log

Nos muestra el historial de la rama donde estamos.

Para ver el historial de una rama remota.

git log dev/desarrollo

Nos muestra el historial de la rama desarrollo del remoto dev.

Este comando muestra información del commit: mensaje,autor,fecha y el hash, pero no muestra información de los cambios que se ha producido en ese commit. Para eso tenemos una serie de opción para el comando log.

git log --name-status dev/desarrollo

Este comando muestra mas información, como los ficheros donde se han producido los cambios y a cada fichero se le añade una etiqueta que indica que tipo de cambio se ha producido, como M(modificado) o A(añadido).

Si queremos mas información, tenemos.

git log --stat dev/desarrollo

Que muestra de forma mas detallada los cambios producido en los ficheros.

Con estos comandos, podemos examinar los cambios introducidos antes de realizar una fusión.

 

FUSIONES

Cuando se trabaja con ramas en Git , en algún momento el trabajo realizado en una rama sera fusionado con otra rama. Hay dos formas de fusionar, utilizando el comando merge o el comando rebase, el resultado es el mismo,fusionar el trabajo de dos ramas ,la diferencia es como  realiza la fusión.

Merge

Anteriormente en este articulo se ha visto un ejemplo donde se ha utilizado este comando. Si tenemos dos ramas ;master y desarrollo,  cuando el código de la rama desarrollo  es estable y lo fusionamos con la rama master.

En la rama master el commit mas reciente es C4 y en la rama desarrollo es C5. Para fusionar la rama desarrollo con la rama master.

git checkout master
git merge desarrollo

Primero nos situamos en la rama hacia donde se va realizar la fusión, en este caso la rama desarrollo se va a fusionar con la rama master, y realizamos la fusión especificando la otra rama.

El proceso de la fusión con merge, se creara un nuevo commit C6 donde se realizara la fusión y el apuntador master se moverá a ese nuevo commit.

Otro  escenario para merge seria lo que se denomina fast-forward. En este caso, no se crearía un nuevo commit con la fusión, simplemente se adelantaría la posición del apuntador master al commit mas reciente. Dependiendo del escenario el merge se ejecutara de una forma u otra.

Rebase

La alternativa a merge es el comando rebase,este comando nos deja un historial mas "limpio" reorganizando los commits para tener un "historial lineal".

Tenemos dos ramas; desarrollo y master, vamos a utilizar rebase para fusionar la rama desarrollo con master.

Se va a fusionar la rama desarrollo en la rama master, nos situamos en la rama master y ejecutamos.

git checkout desarrollo
git rebase master

Este comando rebase mueve todos los commit de la rama desarrollo a continuación del  último commit de la rama master. A continuación actualizamos el apuntador master .

git checkout master
git merge desarrollo

Realiza un fast-forward y el apuntador master se sitúa en el último commit, ahora tenemos un historial lineal.

Como se puede ver los commits de la rama desarrollo se han movido a continuación de los commits de la rama master.. En el proceso de mover los commits pierden su hash y se le asigna uno nuevo, el contenido no cambia. Esto es muy importante porque en algunas situaciones  no es recomendable utilizar rebase, no se debe utilizar este comando  en commits que vayas a compartir en un repositorio público.

Cuando varios programadores utilizan un repositorio remoto, los cambios de cada uno de ellos se comparten con los demás. De esta forma, todos los programadores cuando se sincronizan con el repositorio remoto  obtienen el historial de los cambios de  los demás. Si un programador hace un rebase, se modifica los hash de algunos commits, reescribe el historial, y lo sube al repositorio remoto. Cuando el resto de los programadores se descarguen los nuevos cambios y los integren en su repositorio local para trabajar, verán que algunos commits que ellos tienen en su repositorio local tienen diferente hash en el repositorio remoto, con lo que se producirá un conflicto que tendrán que resolver.

Si se hubiera producido algún conflicto al realizar rebase o algún otro error, siempre podemos cancelar la reorganización.

git rebase --abort

Las ramas se quedaran en el estado inicial, antes del rebase.

Si el conflicto que se ha producido se ha solucionado, debemos indicar que continué la reorganización.

git rebase --continue

Reorganización interactiva

El comando rebase tiene una opción "interactiva" que nos permite de forma manual reorganizar un conjunto de commit .

git rebase -i desarrollo

Abrirá el editor que tenga Git en su configuración, por defecto creo que es vim, nos mostrara todos los commit de la rama desarrollo.

Podemos editar los commit, en la parte superior se muestran los commit que podemos editar con su id y el mensaje del commit.

Todos los commit mostrados, aparecen con comando pick, que indica que usamos ese commit sin modificación. Podemos utilizar diversos comandos.

Unir commits: Debemos sustituir el comando pick por squash en los commit que queremos unir, después deberemos escoger el mensaje del nuevo commit resultante de la unión.

Unir commit manteniendo un mensaje: Utilizamos el comando fixup, este comando unirá los commits marcados manteniendo el mensaje del primer commit.

Borrar commit: Simplemente borrar la línea del commit en el editor.

Mover commit: Podemos mover la línea del commit en el editor, la posición  se modificara en el historial.

Editar el mensajeUtilizando el comando reword, indicamos el commit que desea editar el mensaje y después se nos mostrara el mensaje de ese commit para modificarlo.

Podemos reorganizar una conjunto de commit de una rama, deberemos especificar el rango de commit que queremos reorganizar.

git rebase -i master~3

Realiza un "rebase interactivo" de los tres últimos de la rama master.

Reorganizando ramas

El comando rebase nos permite reorganizar ramas . Por ejemplo, utilizando la estructura de rama  utilizada anteriormente (master y desarrollo), nos situamos en la rama desarrollo y  creamos una rama bd  para trabajar en una funcionalidad.

git checkout -b bd

Ahora tenemos una rama bd  que se basa en la rama desarrollo, podemos trabajar en la rama nueva creando varios commits.

Si queremos fusionar la rama desarrollo en la rama master, se ha explicado anteriormente las diferentes formas de fusionar esas ramas. Pero si deseamos fusionar la bd con la rama master, la rama bd no se origina de la rama master , no serviría lo que se ha explicado anteriormente. Pero podemos reorganizar las ramas con rebase.

 Cuando deseamos fusionar una rama sobre otra, podemos utilizar el comando rebase con la opción --onto.

git rebase --onto master desarrollo bd

 Haciendo un fast-forward a master, tendríamos.

El comando anterior realiza lo siguiente, selecciona un rango de commit , en el ejemplo los commit de bd(1234,a221,b333) y los mueve a continuación de los commit de la rama master, recordar que rebase cambia el hash de los commit.

De forma generica la opcion --onto consta de tres argumento.

git rebase --onto arg1 arg2 arg3

arg1: identifica la rama donde se va realizar la reorganización, rama master.

arg2 : el principio del rango de commit que se va a seleccionar (este commit no se incluye en rango, en el ejemplo la rama desarrollo.

arg3: final del rango de commit, rama bd.

Dicho de otra forma, "haz un rebase en la rama master de los commit que empiecen en la rama desarrollo y acaben en la rama bd", esta selección de commit solo incluyen de la rama bd.

Otro escenario que podemos encontrarnos Podemos realizar otro tipo de reorganizaciones en las ramas que no impliquen una fusión.Por ejemplo, tenemos una rama master,desarrollo y bd.

reabaseonto

Como se ve en la imagen, la rama bd se crea a partir de la rama desarrollo, ahora necesitamos que la rama bd  de la rama master. Utilizando git rebase, escribimos:

git rebase --onto master desarrollo bd

Ahora la rama bd esta se genera a partir de la rama master,igual que la rama desarrollo.

REORGANIZANDO COMMIT

En algunas ocasiones nos interesa mover un commit,o rango, de una rama a otra, para realizar esta tarea tenemos el comando cherry-pick

Con este comando especificamos un conjunto de commit que serán movidos a la rama que indiquemos.Por ejemplo, queremos mover un commit de la rama desarrollo a master, primero nos situamos en la rama donde queremos mover los commits(master) y escoger el commit mediante su id.

git cherry-pick 54b47f

Aplica ese commit a la rama master.

Si queremos un conjunto de commit.

git cherry-pick desarrollo~3..desarrollo~1

 

Generar PDF de Ramas y Fusiones en Git