En el artículo anterior prometí volver a hablar de Mercurial y heme aquí cumpliendo la promesa.
En este caso quiero hablar de uno de los cambios más importantes en la filosofía respecto a subversion: la ramificación (o branching).
Ramificando en Subversion
En svn la ramificación se realiza de un modo bastante rudimentario, aunque bonito a su manera. Ya sabéis cómo funciona, así que no me extenderé, y lo contaré todo en plan resumen.
La ramificación se hace con la orden branch. Al ejecutarla, se crea una copia de la estructura del directorio origen, al directorio destino, incluyendo toda la información de historial y revisiones.
Las convenciones nos dicen que en el directorio trunk se encuentra la rama principal (de ahí el nombre, tronco), donde está el desarrollo estable. Las ramas de desarrollo se almacenan todas dentro del directorio branches (ramas), y a veces se ramifican también las versiones estables que salieron a la luz en releases.
Pera esta estrucutura no es más que, como hemos dicho, convenciones. SVN no sabe qué directorio es una rama, o cuál es el principal. Nosotros usamos source/trunk en lugar de trunk, y podríamos usar ramas en lugar de branches como nombre de directorio para las ramas.
De hecho SVN, no sabe qué es rama y qué es tronco, y aquí es donde vienen los quebraderos de cabeza. Cuando fusionamos ramas mediante la orden merge, tenemos que especificar qué revisiones vamos a mezclar. Eso significa muchas veces bucear por los historiales de unas ramas y otras para saber cuándo se creó la rama y cuál fue el último cambio en fusionarse.
Ramificación en Mercurial
En Mercurial no existen ramas en un repositorio. Cuando quieres hacer una rama, te creas otro, clonándolo del padre (orden clone).
Esto puede embrollar un poco el desarrollo con varias ramas, sobre todo si hay distintos desarrolladores trabajando sobre distintas ramas, pero el control de las ramas y los cambios que van de una a otra puede ser más fino, menos rudimentario.
Así, resulta muy cómodo para el programador crearse las ramas de los diferentes aspectos o versiones en las que esté trabajando, y propagar los cambios de una a otra.
Yo recomiendo una estructura absolutamente jerárquica, en la que estén muy claros qué rama empuja los cambios a cuál, y no mezclarlas, ni crear flujos extraños.
Ejemplo
En la entrega anterior hablé de las ramas o repositorios que creé para las modificaciones de OpenTPV. Hoy, aparte de repetirlo, voy a poner un gráfico.
Partimos de la base de Openbravo POS, la aplicación original. Openbravo POS tiene su respositorio en Mercurial, de ahí mis inicios con este SCV. Opensistemas tiene su propio fork de Openbravo POS. Cuando se usaba SVN, mantener OpenTPV actualizado era muy laborioso, puesto que había que ir generando parches e irlos aplicando. Ahora con Mercurial, sólo tenemos que ir haciendo pull del contenido cuando haya alguna actualización.
Por tanto creé OpenTPV como un clon de Openbravo POS, sobre el que hice las modificaciones. Además, consideré oportuno crear un repositorio estable y otro de desarrollo, por lo que cloné el estable.
Ahora, ciertas modificaciones que quería nuestro cliente no las consideraba apropiadas para la versión oficial de OpenTPV, por lo que creé otro repositorio más, clon del de desarrollo. Por último, el cliente quería una versión para resoluciones pequeñas, así que creé otro clon para poder ofrecer ambas.
Una vez tenemos definidos los repositorios que vamos a tener, hay que diseñar la dirección en la que se propagarán los cambios. Si colocamos cada clon debajo de su original, podemos considerar útil propagar los cambios hacia arriba (push) o hacia abajo (pull). En la corta experiencia que tengo con Mercurial no recomiendo mezclar direcciones.
Juntando todo, la estructura más lógica es la siguiente:

Así, cada vez que tenía que añadir una funcionalidad (o corregir un bug), analizaba la parte a la que correspondía aplicar:
- Si la funcionalidad era apropiada para OpenTPV, la aplicaba a la rama OpenTPV desarrollo. Después propagaba los cambios hacia las versiones de los clientes.
- Si era una funcionalidad querida por el cliente, pero no apropiada para OpenTPV, lo aplicaba sobre la versión del cliente. Después propagaba los cambios hacia la versión de baja resolución.
- Si era un cambio de interfaz para baja resolución, lo aplicaba sobre la personalización de baja resolución exclusivamente.

