Introducción a git en Betabeers Badajoz

Hola de nuevo:

Coincidiendo con el curso de git que impartimos en Badajoz, dimos una presentación de 40 minutos de introducción a git. La charla fue grabada y la podéis ver en youtube.

Ese mismo día, Álvaro de la Mata compartió con todos nosotros cómo cambiaron la forma de trabajo de toda la empresa aplicando metodologías ágiles en una charla que no tiene desperdicio. Aunque no se habla de git explícitamente, git y agilismo van bastante de la mano así que aquí os dejo el enlace.

Git: la he liado parda

Aquí os dejo el vídeo de la presentación que hice ayer (24 de abril de 2013) en el grupo de desarrolladores de Symfony de Madrid.

Una presentación de una hora en la que hablamos de las herramientas que nos da git para no tener que recurrir al famoso borrar-y-volver-a-clonar-repositorio para recuperar nuestro repo cuando nos equivocamos.

Durante la presentación hacemos varias demos:

  • Cómo detener un merge que nos ha dado conflictos
  • Cómo deshacer un merge una vez finalizado
  • Cómo deshacer un rebase que hemos hecho al revés, sobreescribiendo la historia del repositorio
  • Cómo usar git-bisect para encontrar un bug
  • Cómo usar git-revert para solucionarlo

¡No está mal para una hora! Espero que os guste y os resulte útil.

Aprovechamos para recordaros que en Aprendegit estamos siempre dispuestos para dar charlas y presentaciones sobre nuestra herramienta favorita. Así que si quieres que vayamos a hablar de git a cualquier sitio, sólo tienes que proponernoslo 😉

Uso avanzado de referencias: github y pull requests

El viernes pasado (19 de abril de 2013) Jesús Espino dio una charla titulada “Git internals” en Kaleidos. Lo primero que es digno de mención es que una empresa de una “charla interna” e invite a cualquiera que quiera asistir “de fuera”. Iniciativas como esta deberían estar a la orden del día en empresas en todo nuestro país. Desde aquí animo a cualquier colega de profesión, trabaje donde trabaje (cárnicas, startups o lo que se tercie) a que comparta lo que sabe, bien sea en un blog, dando charlas en grupos locales o imitando este tipo de iniciativas aunque sea internamente dentro de su empresa. “Hay que subir el nivel” como dice Diego Freniche. Y como me gusta repetirme a mi mismo todos los días: “si quieres cambiar las cosas, empieza cambiando tú y tu entorno”.

La charla, que está escrita en TeX, podéis encontrarla en github. Independientemente de los recuerdos que me trajo ver el código fuente (la tesis la escribí en LaTeX) el contenido de la misma no tiene desperdicio. Si os interesa el tema, aunque sea árido, y queréis profundizar en él os recomiendo que leáis el capítulo 9 del libro de Scott Chacon.

Durante la charla se habló bastante de las referencias. Cuando Jesús acabó su magistral intervención, comenté un pequeño truco que aprendí en twitter para poder descargarnos a nuestra máquina los pull requests que recibimos desde github. Llevaba tiempo queriendo sacar un rato para contarlo y Jesús me dio el empujón que me faltaba.

Accediendo a los pull requests

En este artículo usaremos como base el repositorio que utilizamos para la serie de artículos sobre pull requests.

Cuando un usuario hace un pull request desde su fork al repositorio original, github crea en el repositorio orignal una referencia a los commits cuya incorporación se ha solicitado. El repositorio original, el que recibe el pull request, guarda estas referencias en refs/pull/*/head. Recordad que las referencias en git no son más que ficheros que contienen hashes a objetos de git. Estos ficheros están en los servidores de github.

Para poder acceder a esas referencias, y por lo tanto a esos commits, lo único que hay que hacer es decirle a git que se descargue los ficheros con las referencias cuando ejecutamos el comando fetch. Para ello, abrimos el fichero .git/config de nuestro repositorio y modificamos la sección correspondiente al remoto “origin”, añadiendo la línea en cursiva que os pongo a continuación:

[remote "origin"]
 url = https://github.com/aprendegit/fork
 fetch = +refs/heads/*:refs/remotes/origin/*
 fetch = +refs/pull/*/head:refs/remotes/origin/pr/*/head

Antes de ejecutar git-fetch, veamos cómo están las referencias remotas del repositorio en SourceTree:

Referencias remotas antes de importar los pull-requests

Referencias remotas antes de importar los pull-requests

Hagamos un fetch:

$ git fetch
From https://github.com/aprendegit/fork
 * [new ref]         refs/pull/1/head -> origin/pr/1/head
 * [new ref]         refs/pull/2/head -> origin/pr/2/head
 * [new ref]         refs/pull/3/head -> origin/pr/3/head

¡Ahí las tenéis! Si actualizáis la pantalla de SourceTree:

El repositorio después de hacer fetch de los pull requests

El repositorio después de hacer fetch de los pull requests

En la captura podéis ver los dos pull requests que ha recibido el proyecto y cómo ha evolucionado cada uno de ellos.

¿Y esto para qué sirve? Pues para probar el código que estáis recibiendo antes de aceptar el pull request, por ejemplo.

Para terminar, quería dar las gracias de nuevo a Jesús por su charla, a Kaleidos por la iniciativa y a Bert Belder (piscisaureus) por colgar el gist con la información que ha dado pie a este artículo.

git-flow: Resumen y conclusiones

A lo largo de las últimas semanas hemos escrito una serie de cinco artículos en los que hemos hablado sobre git-flow:

  • En la introducción, vimos por qué surge esta extensión de git, qué hace y qué tipo de flujos de trabajo nos permite implementar.
  • Después instalamos git-flow, creamos un repositorio e inicializamos la extensión en el mismo.
  • Creamos las ramas develop y master y empezamos a desarrollar las historias de usuario del sprint usando feature branches.
  • Cuando terminamos nuestro sprint, utilizamos un release branch para testar y ajustar nuestro código antes de pasarlo a producción.
  • Finalmente vimos cómo corregir bugs urgentes en producción mediante el uso de hotfix branches.

 Qué nos aporta git-flow

  • Un flujo de trabajo básico para organizar el repositorio y nuestro trabajo.
  • Un convenio de nombres para nuestras ramas que permite a todos los miembros del equipo saber qué es cada cosa.
  • Unas reglas comunes a la hora de mover la información de una rama a otra.
  • Un conjunto de comandos que nos ahorra tiempo.
  • ¡Sourcetree tiene soporte en la aplicación! Si has entendido cómo funciona, puedes investigar cómo usarlo en la interfaz gráfica. Tienes el botón en la barra de herramientas.

Botón de git-flow en sourcetree

A lo largo de la serie siempre hemos relacionado los comandos de git-flow con los comandos git que la extensión ejecuta por detrás. Aunque nos facilite el trabajo, el uso de git-flow no nos exime de entender cómo funcionan las ramas, saber utilizar merge y rebase o entender la diferencia entre un pull y un fetch. Es entendiendo estos conceptos como le sacarás rendimiento a esta y a cualquier otra extensión de git.

He utilizado este flujo de trabajo en proyectos en los que he trabajado solo y proyectos con equipos de entre 3 y 5 personas.  Mi experiencia es que esta forma de organizar el repositorio es un buen punto de partida para el desarrollo de procesos más complejos, especialmente si el equipo no tiene mucha experiencia en el uso de git.

Como dijimos en la introducción, estas no son reglas absolutas. Y aunque funcionan en un gran número de equipos, puede que en tu caso necesites adaptarlas a tu forma de trabajar. Confío en que después de haber leído los artículos de esta serie, estés en condiciones de hacerlo.

git-flow: hotfix branches

Seguimos hablando de git-flow. En la entrada anterior vimos cómo utilizar un release branch para poner a punto nuestra aplicación antes de llevarla a producción. En esta última entrega de la serie veremos cómo utilizar git-flow para gestionar la resolución de bugs urgentes y, en general, cualquier tipo de modificación que requiera un rápido despliegue en producción.

¿Qué son las hotfix branches de git-flow?

Recordemos cómo había quedado nuestro repositorio tras la puesta en producción:

  • La rama master, que actualmente contiene la versión 1.0, ya ha sido desplegada en producción
  • La rama develop, que ya incorpora todos los cambios y ajustes que hicimos durante la puesta a punto de la versión 1.0, está lista para avanzar en el desarrollo de la versión 1.1

Recordemos cómo dejamos el repositorio en la entrega anterior:

Repositorio tras cerrar release/1.0

Estamos listos para empezar un nuevo sprint. Tenemos una reunión de planificación, ponemos en el backlog las historias de usuario que vamos a desarrollar para la versión 1.1, y empezamos a trabajar.

A los pocos días, recibimos un aviso de nuestros compañeros del departamento de atención al cliente: ¡hay un bug de la aplicación en producción! Git-flow utiliza hotfix branches para implementar un flujo de trabajo que permite:

  • Interrumpir el trabajo que estamos haciendo en la rama develop para la versión 1.1
  • Resolver el bug
  • Incorporar la corrección del bug en la rama master para desplegarlo en producción lo más rápido posible
  • Incorporar la corrección del bug en la rama develop (si procede)
  • Retomar el trabajo que estábamos haciendo en la rama develop

Para los que estáis familiarizados con la administración de sistemas, a mí cada vez que me pasa esto me siento como el kernel de Linux haciendo context switching. Cada vez que tenemos que dejar cambiar de rama tenemos que cambiar de contexto. Eso implica recordar qué estábamos haciendo, qué teníamos en la nueva rama y en qué estado estábamos. Sin una herramienta como git, que permite hacer este cambio de forma rápida y viendo la historia de las dos ramas, el tiempo necesario para hacer el cambio de contexto nos hace menos productivos. Las ramas hotfix nos ayudan a hacer estos cambios de contexto de forma más eficiente y a corregir el problema con el mínimo impacto sobre el resto del trabajo que estamos haciendo.

Creando la rama hotfix/bug-14

Como hemos comentado antes, supongamos que ya llevamos unos cuantos días trabajando en el sprint. Habremos creado una (o varias) feature branches y el estado de nuestro repositorio puede ser algo parecido a esto:

Estado de la rama develop antes del aviso de bug

Estado de la rama develop antes del aviso de bug

Nos encontramos trabajando en la historia de usuario H5 cuando recibimos la llamada de nuestros compañeros avisándonos del bug.

Lo primero que haremos será almacenar el trabajo que estamos haciendo y que vamos a tener que interrumpir porque tenemos que cambiar de contexto. El objetivo es guardar este trabajo a medias y recuperarlo cuando hayamos terminado de corregir el bug. Hay varias formas de hacer esto, nosotros lo guardaremos en el stash ya que prevemos que la corrección del bug no nos llevará mucho tiempo:

$ git stash save 'Antes de empezar a corregir el bug #14'
Saved working directory and index state On feature/h5: Antes de empezar a corregir el bug #14
HEAD is now at f6609a9 Primera implementación de las páginas estáticas

Podemos ver el contenido del stash con el comando git stash list

$ git stash list
[email protected]{0}: On feature/h5: Antes de empezar a corregir el bug #14

El objetivo de esta entrada no es hablar del stash, así que entraremos en detalle en otra ocasión. Si no sabes lo que es, puedes consultar este enlace. Seguimos.

Una vez tenemos nuestro trabajo almacenado y listo para cambiar de contexto, creamos la rama hotfix/bug14:

$ git flow hotfix start bug14
Switched to a new branch 'hotfix/bug14'

Follow-up actions:
- Bump the version number now!
- Start committing your hot fixes
- When done, run:

git flow hotfix finish 'bug14'
Creando la rama hotfix/bug14

Estado del repositorio tras crear la rama hotfix/bug14

Los comandos que git-flow ha ejecutado por nosotros son en este caso bastante sencillos:

$ git checkout master
$ git checkout -b hotfix/bug14

Con la rama creada, empezamos a trabajar en la corrección del bug. Pasadas unas horas y unos cuantos commits después, tenemos el bug corregido y listo para subir a producción. Este es el estado del repositorio:

bug #14 corregido

Estado del repositorio después de haber localizado y corregido el bug.

Cerrando la rama hotfix/bug14

Nos acercamos al final. Una vez corregido el bug, procedemos a cerrar la rama hotfix:

$ git flow hotfix finish bug14

Cuando ejecutamos este comando, git-flow nos pide que introduzcamos tres mensajes:

  • El primero de ellos es el mensaje del merge commit resultado de incorporar los cambios de hotfix/bug14 en master
Introducir mensaje para el merge commit con la rama master

Se abre el editor predeterminado para introducir el mensaje del merge commit

  • El segundo es el mensaje que git-flow pondrá a la etiqueta que va a crear para identificar esta versión (vbug14)
Introducir mensaje para la etiqueta

Mensaje para la etiqueta de versión

  • El tercero y último será el mensaje que git-flow pondrá en el merge commit resultado de incorporar la rama hotfix/bug14 en develop
Introducir mensaje para el merge commit con la rama develop

Se abre el editor predeterminado para introducir el mensaje del merge commit con la rama develop

Al igual que cuando cerramos la rama release/1.0, al finalizar la ejecución del comando se muestra un resumen de todas las acciones que han tenido lugar:

Salida de git-flow al cerrar un hotfix branch

En rojo hemos indicado las acciones que git-flow ha ido ejecutando y que pueden resumirse en los siguientes comandos:

git checkout master
git merge hotfix/bug14 --no-ff
git tag vbug14
git checkout develop
git merge hotfix/bug14 --no-ff
git branch -d hotfix/bug14

El nombre que git-flow ha puesto a la etiqueta no es precisamente el más adecuado, así que borramos esa etiqueta y creamos una nueva que se llama v1.0.1. El repositorio queda de la siguiente manera:

Repositorio tras cerrar hotfix/bug14

Y ya está, casi hemos terminado… Sólo nos falta volver a cambiar de contexto y recuperar el repositorio como lo teníamos antes de empezar a corregir el bug.

Volviendo a la rama feature/h5

Este paso es el más sencillo, basta ejecutar el comando

$ git checkout feature/h5

Ahora bien: ¿cómo recuperamos ese trabajo a medias que habíamos tenido que interrumpir y que almacenamos en el stash?

$ git stash list
[email protected]{0}: On feature/h5: Antes de empezar a corregir el bug #14

$ git stash pop [email protected]{0}
Auto-merging index.html

(Nota: dado que sólo tenemos una cosa guardada en el stash, podríamos ejecutar sencillamente git stash pop).

Y con esto hemos terminado, ya tenemos todo listo para seguir trabajando en la historia de usuario H5.

Conclusión

En esta entrega hemos visto cómo git-flow nos ayuda a gestionar la corrección de bugs del sistema en producción a través de hotfix branches. Creando una rama específica para corregir el bug, conseguimos que mientras una parte del equipo está trabajando en la rama develop, otra parte pueda corregir el bug. Si es una misma persona la que tiene que hacer este trabajo, la creación de estas ramas auxiliares facilita el cambio de contexto al desarrollador.

Este tipo de ramas no tienen mucho sentido en las ramas develop ya que la detección y corrección de bugs forma parte del proceso de desarrollo de nueva funcionalidad

En la siguiente entrega haremos un pequeño resumen de lo que hemos visto en esta serie de artículos y daremos por terminada la serie.

git-flow: release branches

En la entrada anterior vimos cómo utilizamos la rama develop y las features branches para desarrollar la primera versión de la aplicación. En este entrega veremos cómo utilizar las release branches  para preparar la puesta en producción de nuestra aplicación.

¿Para qué necesitamos una release branch?

El objetivo de estas ramas es preparar nuestra aplicación para su puesta en producción. En algunos equipos, estas ramas son las que se vuelcan en los servidores de pre-producción para hacer el testing final: se corrigen bugs, se pule la interfaz, se ajusta la maquetación…se hace la puesta a punto final de la aplicación antes de liberar la versión definitiva. Vamos a crear una release branch para la versión 1.0. Utilizando la línea de comandos, ejecutamos

$ git flow release start 1.0

Switched to a new branch 'release/1.0'
Summary of actions:
- A new branch 'release/1.0' was created, based on 'develop'
- You are now on branch 'release/1.0'

Follow-up actions:

- Bump the version number now!
- Start committing last-minute fixes in preparing your release

- When done, run:

git flow release finish '1.0'

Tras ejecutar estos comandos el repositorio queda de la siguiente manera:

Creando la rama release/1.0

Una vez creada la rama, empezamos el proceso de corrección y depuración, que en el ejemplo que nos ocupa da como resultado varios commits a la rama release/1.0. Así queda el repositorio cuando hemos terminado de arreglar todos los bugs y estamos listos para que nuestro proyecto pase a producción:

Repositorio justo antes de subir a producción

Cerrando la rama release con git-flow

En este punto, nuestro código fuente está testado, todos los bugs corregidos (o eso pensamos) y todo está listo para entregar la versión 1.0. Para cerrar la rama, ejecutamos

$ git flow release finish 1.0

Cuando ejecutamos este comando git-flow nos va a pedir que introduzcamos tres mensajes:

  • El primero de ellos es el mensaje del merge commit resultado de incorporar los cambios de release/1.0 en master

Introducir mensaje para el merge commit

  • El segundo mensaje es el mensaje que git-flow pondrá a la etiqueta que va a crear para identificar esta versión

Introducir mensaje para la etiqueta

  • El tercero y último será el mensaje que git-flow pondrá en el merge commit resultado de incorporar la rama release/1.0 en develop

Introducir mensaje para el merge commit con la rama develop

Cuando el comando termina, se nos muestra un resumen de todas las acciones que han tenido lugar:

Salida de git-flow al cerrar un release branchEn rojo hemos indicado las acciones que git-flow ha ido ejecutando y que pueden resumirse en los siguientes comandos:

git checkout master
git merge release/1.0 --no-ff
git tag v1.0
git checkout develop
git merge release/1.0 --no-ff
git branch -d release/1.0

El repositorio queda de la siguiente manera:

Repositorio tras cerrar release/1.0

Despliegue en producción

Dado que en este ejemplo estamos trabajando con una web HTML, el despliegue en producción es muy sencillo:

  • Sincronizamos las rama master con git push
git checkout master
git push
  • En el servidor en producción ejecutamos
git checkout master
git pull

Variaciones de este flujo

Cuando estamos trabajando en la rama release, puede darse el caso de que algunos bugs sean más complicados de resolver de lo esperado. Si eso ocurre, siempre podemos crear una rama dentro de release para corregir ese bug y, una vez terminado, incorporar los cambios a la rama release.

Conclusión

En esta entrega hemos visto cómo git-flow nos ayuda a gestionar la liberación de nuevas versiones de nuestro código fuente. Creando una rama específica para la puesta a punto de la versión, conseguimos que mientras una parte del equipo está trabajando release/1.0, otra parte puede avanzar en nuevas funcionalidades usando feature branches en la rama develop.

Lo que se debe evitar es utilizar la rama release para desarrollar nuevas funcionalidades. Si esto ocurre quiere decir que hemos pasado el código a pre-producción demasiado pronto.

En la siguiente entrega veremos cómo prepara hotfixes para nuestro código en producción.

git-flow: la rama develop y uso de feature branches

Seguimos con la serie de artículos sobre git-flow. Después de ver cómo pueden ayudarnos estas extensiones de git e instalarlas, vamos a empezar el desarrollo de nuestro proyecto utilizando git-flow.

Trabajaremos con una sencilla página HTML como ejemplo. No queremos complicar la explicación ni distraernos con el código fuente; el objetivo es entender el flujo que vamos a implementar con git.

Git-flow y metodologías ágiles

Los próximos artículos vamos a escribirlos en el contexto de las metodologías ágiles. Hablaremos de iteraciones, reuniones de planificación, reuniones diarias del equipo… El objetivo es poner git-flow en contexto y ver cómo nos puede ayudar.

Supongamos que ya hemos pasado por la reunión de planificación y hemos acordado en el equipo qué historias de usuario vamos a implementar en la primera iteración.

Las historias de usuario del primer sprint son las siguientes:

  • H-1: La web dispondrá de una home con un menú de acceso al resto de páginas
  • H-2: La página de inicio dispondrá de un hero con un texto y un botón de enlace al último artículo

Implementaremos la primera de las historias de forma manual y la segunda con git-flow. De esta forma entenderemos bien qué es lo que estas extensiones hacen por debajo.

Antes de empezar: git-flow-init

Dado que se trata de un proyecto nuevo, lo primero que haremos antes de empezar el desarrollo es, como no, crear el repositorio y prepararlo para usar git-flow. Para ello seguimos los siguientes pasos:

$ mkdir nuestro-proyecto
$ cd nuestro-proyecto
$ git init
$ git-flow init

No branches exist yet. Base branches must be created now.
Branch name for production releases: [master]
Branch name for "next release" development: [develop]

How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? [] v

Al ejecutar el último comando, entramos en un menú interactivo que nos va preguntando las opciones que aparecen arriba:

  • Al inicializar git-flow, nos pregunta el nombre de la rama de producción y de la rama de desarrollo (master y develop respectivamente). Seleccionamos los nombres por defecto.
  • Después nos preguntará los prefijos que asignará a las ramas de tipo feature, release, hotfix y support. Volvemos a seleccionar los nombres por defecto.
  • Por último, nos pregunta el prefijo que queramos utilizar para etiquetar las versiones.

Si no os gustan los prefijos que usa git-flow por defecto, podéis utilizar otros. En un artículo posterior veremos como cambiar a posteriori estos nombres.

¿Y en qué estado queda nuestro repositorio después de hacer esto? Aquí tenéis una captura de SourceTree:

Estado del repositorio tras ejecutar git-flow

Estado del repositorio tras ejecutar git-flow

Vemos el commit inicial así como las ramas master y develop. Desde la línea de comandos, el repositorio tiene este aspecto:

$git branch -av
* develop 87ee184 Initial commit
  master  87ee184 Initial commit

Desarrollando H-1: gestionando las ramas manualmente

En el proyecto, en una de las reuniones diarias, se decide que vamos a usar bootstrap para maquetar la web, así que en la primera historia descargaremos bootstrap, lo incluiremos en la carpeta vendor y crearemos la página de inicio (nota para los usuarios más avanzados: somos conscientes de que hay mejores maneras de añadir bootstrap al proyecto como por ejemplo usar submódulos. Usamos este enfoque más simple porque no queremos distraernos con detalles ajenos al objetivo de esta serie que es entender git-flow).

Dado que se trata de un desarrollo planificado que formará parte de un futuro release (la versión 0.1) usaremos una feature branch.

Recordamos: las feature branches nacen de la rama develop y se incorporan a esa misma rama. Así que creamos una nueva rama a partir de develop que llamamos feature-H-1:

$ git checkout -b feature-H-1 develop
$ git branch -av
  develop     87ee184 Initial commit
* feature-H-1 87ee184 Initial commit
  master      87ee184 Initial commit

Una vez creada la rama feature-H-1, hacemos la siguiente serie de commits:

  • Añadimos bootstrap al proyecto
  • Creamos la página de inicio
  • Ponemos el menú

Cuando terminamos el desarrollo de la historia H-1, este es el estado de nuestro repositorio:

Terminado el desarrollo de la historia H1

Así queda el repositorio cuando terminamos de hacer el desarrollo de la historia H-1 en la rama feature-H-1

Ya hemos terminado nuestra primera historia, así que ha llegado el momento de incorporar los cambios a la rama develop (recuerda, las feature branches se incorporan a la rama develop):

$ git checkout develop
$ git merge --no-ff feature-H-1

Si no sabes qué es la opción –no-ff y porqué la usamos, lee este artículo. Al ejecutar el comando se nos pide el mensaje para el merge commit:

Merge branch 'feature-H-1' into develop

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

Cuando guardamos y cerramos, este es el estado del repositorio:

Repositorio después de incorporar la rama feature-H-1

Estado del repositorio después de incorporar la rama feature-H-1

Como la rama feature-H-1 ha quedado visibles en el repositorio con un merge commit, podemos borrarla:

$ git branch -d feature-H-1
Deleted branch feature-H-1 (was 765ce08).

Pues bien, ya hemos terminado nuestra primera historia, vamos a por la segunda.

Desarrollando H-2: gestionando las ramas con git-flow

Para hacer esta historia, necesitaremos crear una nueva feature branch que llamaremos feature-H-2. Esta vez usaremos git-flow:

$ git-flow feature start H-2
Switched to a new branch 'feature/H-2'

Summary of actions:
- A new branch 'feature/H-2' was created, based on 'develop'
- You are now on branch 'feature/H-2'

Now, start committing on your feature. When done, use:

     git flow feature finish H-2

Notar que no necesitamos poner el prefijo “feature” para crear la rama, git-flow lo hace por nosotros. El propio git-flow se encarga de activar la rama feature/H-2 y de decirnos qué tenemos que hacer cuando terminemos. El estado del repositorio después de ejecutar el comando es el siguiente:

Usando git-flow para crear feature/H-2

Estado del repositorio después de crear la rama feature/H-2 con gitflow

Con la rama creada, nos ponermos a trabajar. Implementamos el hero de la página de inicio y hacemos los commits correspondientes:

rama feature/H-2 antes de cerrarla

Estado de la rama feature/H-2 una vez terminado el desarrollo

Así vemos las ramas desde la línea de comandos:

$ git branch -av
  develop     b7bd517 Merge branch 'feature-H-1' into develop
* feature/H-2 4604003 Introduciendo el texto definitivo
  master      87ee184 Initial commit

Si en un momento dado queréis listar las ramas de tipo feature desde la línea de comandos, basta con ejecutar git flow feature:

$ git flow feature
* H-2

Esto mismo es aplicable para las ramas hotfix, release y support.

Continuamos con el desarrollo. Revisamos y testamos nuestro código y cuando vemos que hemos terminado, utilizamos git-flow para cerrar la rama:

$ git flow feature finish H-2
Switched to branch 'develop'
Merge made by the 'recursive' strategy.
 index.html | 7 +++++++
 1 file changed, 7 insertions(+)
Deleted branch feature/H-2 (was 4604003).

Summary of actions:
- The feature branch 'feature/H-2' was merged into 'develop'
- Feature branch 'feature/H-2' has been removed
- You are now on branch 'develop'

Es decir, hemos vuelto a la rama develop, se ha incorporado la rama feature/H-2 a develop y la feature branch se ha borrado. Después de ejecutar el comando, este es el resultado:

Estado del repositorio tras cerrar la feature branch

Estado del repositorio tras cerrar la feature branch

Si os fijáis, hemos hecho lo mismo ejecutando menos comandos.

En esta captura vemos cómo en este flujo de trabajo queda reflejado en la historia del repositorio de forma bastante limpia y clara, cuándo se empezó y finalizó el desarrollo de cada una de las feature branches.

Ahora toca prepararlo todo para hacer el release a producción, aunque eso lo haremos en la siguiente entrega.

Hemos subido este repositorio a nuestra cuenta de github. Podéis verlo en este enlace: https://github.com/aprendegit/articulo-sobre-gitflow

Organizando las ramas en carpetas

Si en el momento de crear una rama utilizas como nombre una ruta, como por ejemplo “mi-carpeta-de-ramas/nombre-de-rama”, verás que en la carpeta .git/refs/heads de tu repositorio se creará una subcarpeta “mi-carpeta-de-ramas”. Dentro de la misma verás el fichero “nombre-de-rama” con la referencia. Es decir, git convierte la cadena con formato de ruta que pasamos como argumento en una estructura real de carpetas.

Esta forma de crear ramas soporta subcarpetas, es decir, si creamos una rama que se llame carpeta1/carpeta2/mirama:

$ git checkout -b carpeta1/carpeta2/mirama

git creará el fichero .git/refs/heads/carpeta1/carpeta2/mirama con la referencia.

¿Y cómo muestra SourceTree las ramas creadas de esta manera?

Organizando las ramas en carpetas

Esta forma de clasificar las ramas en carpetas es especialmente útil cuando trabajamos con ramas para hacer hotfixes, corregir bugs o desarrollar funcionalidades organizadas en historias de usuario.

Desde la interfaz de línea de comandos, así es como veríamos las ramas:

$ git branch -av
   carpeta1/carpeta2/mirama 4604003 Introduciendo el texto definitivo
   develop                  b7bd517 Merge branch ‘feature-H-1’ into develop
*  feature/H-2              4604003 Introduciendo el text definitive
   master                   87ee184 Initial commit

Si quisiésemos ver sólo las ramas feature, podemos usar la opción –list:

$ git branch --list feature*
feature/H-2

Para borrar la rama, usamos el comando git-branch con la ruta completa a la rama:

$ git branch -D carpeta1/carpeta2/mirama

Un truco muy sencillo que nos ayuda a organizar las ramas un poco mejor, especialmente útil si estáis usando SourceTree.

Instalación de git-flow en linux, windows y mac

Continuamos con la serie de artículos sobre git-flow. En la entrega anterior conocimos a Vincent Driessen y su flujo de trabajo. Hoy vamos a ver cómo instalar las extensiones en nuestra máquina.

Instalación de git-flow

Mac

Si habéis instalado git a través de homebrew o macports, la instalación se muy sencilla:

$ brew install git-flow
$ port install git-flow

Si tienes problemas con XCode 4.2 y Macports 2.0.4, sigue las instrucciones que se dan en la página de git-flow. También es posible utilizar la instalación a través de wget usando el script de instalación de Rick Osborne:

wget --no-check-certificate -q -O - https://github.com/nvie/gitflow/raw/develop/contrib/gitflow-installer.sh | sudo bash

Linux

git-flow tiene paquetes para distribuciones basadas en debian y Ubuntu. Utiliza el gestor de paquetes de tu distribución, busca el paquete e instálalo. En debian/Ubuntu, el paquete se llama git-flow, en fedora gitflow y en Archlinux gitflow-git.

Si tu distribución no tiene paquete disponible en los repositorios oficiales como ocurre con centos 5, la mejor manera de instalarlo es utilizar el script de instalación:

wget --no-check-certificate -q -O - https://github.com/nvie/gitflow/raw/develop/contrib/gitflow-installer.sh | sudo bash

Windows

Las instalación es un poco más tediosa, aunque no es complicada. Seguiremos las instrucciones que se dan en la página de git-flow aunque con un poco más de detalle:

 util-linux-ng para windows

  • Descomprimimos los dos ficheros descargados: util-linux-ng-[version]-bin.zip y util-linux-ng-[version]-dep.bin
  • Dentro de la carpeta “util-linux-ng-[version]-bin”, copiamos el fichero bin/getopt.exe a la carpeta C:\Program Files\Git\bin
  • Dentro de la carpeta “util-linux-ng-[version]-dep”, copiamos  el fichero bin/libintl3.dll a la carpeta C:\Program Files\Git\bin
  • Nota: en mi caso, tuve que hacer esto desde la línea de comandos lanzando un terminal de git bash como administrador de la máquina

descomprimiendo getopt.exe y libintl2.dll

  • Una vez copiados los ficheros, se clona el repositorio git://github.com/nvie/gitflow.git. Puedes clonarlo utilizando la línea de comandos o tu cliente gráfico favorito.
  • Por último, abrimos una terminal de windows dentro del repositorio que acabamos de clonar y ejecutamos el comando contrib/msysgit-install.cmd “C:\Program Files\Git” (sustituyendo la ruta si en tu máquina la tienes en una carpeta diferente). Nota: este terminar también tuve que lanzarla como usuario administrador, mi usuario de trabajo no tiene permiso en la carpeta C:\Program Files\Git.

msysgit-install.cmd

Listo, para confirmar que lo tenemos instalado, abrimos git bash, creamos una carpeta vacía y dentro inicializamos el repositorio con el siguiente comando:

 

$ git flow init

Si todo ha ido bien, esto es lo que deberíamos observar:

Comprobando la instalación

¿Qué es git-flow?

Empezamos una serie de artículos sobre git-flow, conjunto de extensiones de git que facilitan la gestión de ramas y flujos de trabajo.

Si quieres seguir esta serie, debes disponer de una máquina con git instalado:

  • Windows: msysgit que puedes descargar de este enlace
  • Mac: a través de homebrew o macports
  • Linux: a través del gestor de paquetes de tu distribución

Flujos de trabajo

Hace unos días participé en el Open Space de Calidad del Software organizado en Madrid este mes de febrero. En la reunión se abordaron varios temas que iban desde responder a preguntas como ¿qué se calidad del software? ¿cuánto cuestan los tests funcionales? o ¿cómo hacer testing de desarrollos para dispositivos móviles? pasando por otros tan exóticos como el Pirata Roberts, llegando incluso a plantearse hasta la eliminación de los responsables de calidad de la faz de la tierra.

En casi todas las conversaciones en las que tuve la oportunidad de participar había un denominador común: las ramas. Se hablaba de ramas para hacer hot-fixes urgentes, ramas para desarrollar nuevas versiones separadas de las ramas maestras donde está la versión en producción. Ramas para probar nuevas versiones, ramas y repositorios para trabajar con proveedores externos, ramas para hacer pruebas en pre-producción, ramas para que los departamentos de calidad hagan sus pruebas antes de liberar nuevas versiones. Con git podemos crear ramas “como churros” y ese fin de semana tuve la oportunidad de compartir con varios colegas de profesión cómo utilizar las ramas para hacer el bien. Sin embargo, esta facilidad para crear ramas también se puede utilizar para hacer el mal y sembrar el terror. Más de una vez he visto ramas creadas sin ningún criterio, sin ningún flujo de información detrás que las sustente. Esta situación suele llevar al repositorio al caos más absoluto.

Para no acabar en el caos, debemos establecer unas “reglas del juego” que todo el equipo debe respetar. Aunque a grandes rasgos casi todos los proyectos pueden utilizar unas reglas de base comunes, las reglas deben ser flexibles para adaptarse a los cambios que puedan surgir en el tablero de juego; al fin y al cabo, las necesidades y particularidades de cada equipo, empresa o proyecto no son las mismas.

¿Y cuáles son estas reglas base comunes? En enero de 2010 Vincent Driessen publicó en su blog un artículo en el que compartía con la comunidad un flujo de trabajo que a él le estaba funcionando: “A successful Git branching model”. Como él mismo cuenta en el artículo (te recomiendo encarecidamente que lo leas) Vincent propone una serie de “reglas” para organizar el trabajo del equipo.

Ramas master y develop

El trabajo se organiza en dos ramas principales:

  • Rama master: cualquier commit que pongamos en esta rama debe estar preparado para subir a producción
  • Rama develop: rama en la que está el código que conformará la siguiente versión planificada del proyecto

Cada vez que se incorpora código a master, tenemos una nueva versión.

Además de estas dos ramas, Se proponen las siguientes ramas auxiliares:

  • Feature
  • Release
  • Hotfix

Cada tipo de rama, tiene sus propias reglas, que resumimos a continuación.

Feature or topic branches

feature branches

fuente: nvie http://nvie.com/posts/a-successful-git-branching-model/

  • Se originan a partir de la rama develop.
  • Se incorporan siempre a la rama develop.
  • Nombre: cualquiera que no sea master, develop, hotfix-* o release-*

Estas ramas se utilizan para desarrollar nuevas características de la aplicación que, una vez terminadas, se incorporan a la rama develop.

Release branches

  • Se originan a partir de la rama develop
  • Se incorporan a master y develop
  • Nombre: release-*

Estas ramas se utilizan para preparar el siguiente código en producción. En estas ramas se hacen los últimos ajustes y se corrigen los últimos bugs antes de pasar el código a producción incorporándolo a la rama master.

Hotfix brancheshotfix branches

  • Se origina a partir de la rama master
    fuente http://nvie.com/posts/a-successful-git-branching-model/
  • Se incorporan a la master y develop
  • Nombre: hotfix-*

Esas ramas se utilizan para corregir errores y bugs en el código en producción. Funcionan de forma parecida a las Releases Branches, siendo la principal diferencia que los hotfixes no se planifican.

¿Qué es git-flow?

Si queremos implementar este flujo de trabajo, cada vez que queramos hacer algo en el código, tendremos que crear la rama que corresponda, trabajar en el código, incorporar el código donde corresponda y cerrar la rama. A lo largo de nuestra jornada de trabajo necesitaremos ejecutar varias veces al día los comandos git, merge, push y pull así como hacer checkouts de diferentes ramas, borrarlas, etc. Git-flow son un conjunto de extensiones que nos ahorran bastante trabajo a la hora de ejecutar todos estos comandos, simplificando la gestión de las ramas de nuestro repositorio.

La flexibilidad de git…y el sentido común

Las “reglas” que Vincent plantea en su blog son un ejemplo de cómo git nos permite implementar un flujo de trabajo para nuestro equipo. Estas no son reglas absolutas, bien es cierto que pueden funcionar en un gran número de proyectos, aunque no siempre será así. Por ejemplo ¿qué pasa si tenemos que mantener dos o tres versiones diferentes de una misma aplicación? digamos que tenemos que mantener la versión 1.X, la 2.X y la 3.X. El tablero de juego es diferente así que necesitaremos ampliar y adaptar estas reglas para poder seguir jugando.

git es una herramienta que nos permite modificar estas reglas y, lo que es más importante, irlas cambiando y adaptando a medida que el proyecto avanza y el equipo madura. Una vez más, una buena dosis de sentido común será nuestra mejor aliada para responder las preguntas que nos surjan durante el camino.

Referencias: