Herramientas: Mercurial

Hola a todos:

Como algunos de vosotros ya sabréis, Media Net ha decidido plantar una pica en Flandes (más bien dos) y enviarnos a Ángel Rey y a mí al Devoxx (anteriormente llamado Javapolis). Después de dos conferencias matutinas aprovecho un receso para comenzar a escribir este artículo.

Este no trata sobre nada del Devoxx: para esto ya habrá otros artículos. Este artículo trata sobre Mercurial: una herramienta de control de versiones. Esta herramienta la estamos implantando ahora mismo en el proyecto que estoy trabajando (desarrollo de calculadoras de productos financieros en tiempo real). En este artículo os describo el escenario que nos ha llevado a utilizarlo, y cuáles son nuestras impresiones después de probarlo. La explicación la realizo en modo FAQ.

¿Que es Mercurial?

Mercurial es un sistema de control de versiones que cuenta con las siguientes características:

  • Es transaccional: Cada cambio sobre el repositorio se ejecuta atómicamente para todos los elementos implicados en el mismo; sean archivos, directorios y/o metadatos.
  • Es un sistema distribuido: El histórico de los archivos gestionados no se encuentra en un único servidor centralizado al que los desarrolladores suben sus cambios. Cuando un desarrollador descarga los archivos de un proyecto de Mercurial, éste descarga además una copia completa del histórico de cambios. De esta manera el desarrollador es capaz de reproducir el estado de la aplicación en cualquier momento de su historia sin necesidad de conectarse a un repositorio centralizado.
  • Desarrollado en python y algo de C.
  • Funciona tanto en modo Push como en modo Pull; dando flexibilidad a las políticas de versionado a aplicar.

¿Por qué nos hemos decidido a utilizarlo?

Los motivos son los siguientes:

  • El modelo de versionamiento de CVS no nos convencía. Hemos tenido bastantes problemas de inconsistencia cuando hemos querido descargar versiones anteriores de nuestro software desde el repositorio de CVS. Por otro lado, los desarrolladores de mi equipo se liaban mucho cuando bajaban una versión antigua de un archivo debido a que si posteriormente hacían un commit sobre una de las carpetas que contenía estos archivos, CVS creaba una nueva rama para estos de manera no transparente. En muchas ocasiones nos vimos en la necesidad de corregir estos problemas. En Mercurial la creación de una nueva rama (branch) forma parte del día a día. Toda descarga de fuentes es en realidad una nueva rama. Esto ha obligado a los desarrolladores de Mercurial a que la gestión de ramas sea muy eficiente.
  • Los problemas que hemos tenido con CVS al resolver colisiones. En ocasiones han desaparecido cambios muy costosos de recuperar. De su desaparición nos enteramos solo después de ver que nuestras pruebas unitarias fallaban de manera estrepitosa durante la integración. Mercurial es muy conservador para esto: no se mete a resolver colisiones de manera automática, sino que deja esta responsabilidad siempre en manos del desarrollador.
  • La posibilidad de clonar directorios de manera tan sencilla nos facilita realizar copias de seguridad con más frecuencia. Sacar una copia de seguridad del CVS era un suplicio; sobre todo teniendo en cuenta que la copia se realizaba para todos los proyectos del repositorio incluidos los de los proyectos con los cuales compartíamos el repositorio. En Mercurial clonar un repositorio es tan fácil como copiar archivos, y además toda clonación lleva asociado su histórico de cambios.
  • CVS no es transaccional. Dado que la máquina en la que está ubicado tiene problemas de estabilidad nos ha ocurrido varias veces que una subida de cambios se ha aceptado solo parcialmente. Mercurial es completamente transaccional.
  • Necesitábamos una herramienta cuyos requisitos de instalación a nivel de permisos de administración fueran los mínimos posibles. En nuestro proyecto actual el entorno de desarrollo que nos ha facilitado el cliente no es tal entorno “de desarrollo”, ya que ni lo controlamos nosotros, ni es un entorno aislado (hay como 30 aplicaciones haciendo pruebas sobre la misma máquina).
  • No tenemos posibilidad de realizar pruebas de usuario en nuestros entornos de trabajo antes de subir los cambios a un repositorio porque nuestra aplicación se conecta con sistemas externos a través de APIs que solo están instaladas en el entorno de integración. Además algunas de las librerías utilizadas solo funcionan sobre Unix, mientras que nuestros entornos de trabajo son Windows.
  • Los mercados de tiempo real tienen unas condiciones de trabajo que son continuamente monitorizadas por los operadores de los mismos. Una incidencia puede dar lugar a multas millonarias. Es fundamental que podamos reproducir cualquier versión de manera rápida para corregir cualquier error. Por otro lado necesitamos la facilidad de poder agregar o quitar funcionalidad hasta pocos días antes de publicar una versión. Mercurial permite reproducir cualquier versión del histórico a partir de cualquier clon de cualquier rama de cualquier entorno, incluido el de los desarrolladores, con lo cual es muy fácil reproducir incidencias de manera rápida. También permite agregar cambios de distintas ramas de desarrollo de manera sencilla e individual.
  • La aplicación es altamente concurrente, paralela, multi-hilo, y calcula productos financieros en base a modelos complejos. Es ventajosa la capacidad que da Mercurial al responsable de una rama estable. No son los desarrolladores quienes suben los cambios a la rama estable (modelo push), sino que es el responsable de esta rama quien va demandando los cambios a las ramas de los desarrolladores (modelo pull). Esto permite probar las aplicaciones en ramas de prueba, y posteriormente integrar los cambios individuales solo cuando ya han sido probados y revisados.
  • Uno de los problemas que veíamos al uso de Mercurial era la integración con eclipse. Clonar repositorios nos obliga a clonar los proyectos y el workspace de eclipse para poder trabajar. Por suerte existe un plugin (Merclipse) que realiza esta tarea.

¿Cómo funciona el control de versiones?

Cuando un desarrollador descarga un proyecto del control de versiones, en realidad lo que está haciendo es clonar el repositorio de origen. No existen diferencias entre ambos repositorios después de la operación. Haciendo un símil con subversión, es como si cada desarrollador tuviera un servidor de subversión instalado en su equipo. Este “servidor” contiene toda la información histórica del proyecto.

Al clonar el repositorio se crean dos espacios:

  • Repositorio público: Contiene el histórico de cambios. Es visible desde otros repositorios.
  • Espacio de trabajo: Se genera a partir del histórico. El desarrollador solicita un “update” de una versión determinada, y Mercurial actualiza el espacio de trabajo para que contenga los fuentes de dicha versión.

A la hora de trabajar, un desarrollador realiza los cambios sobre su espacio de trabajo. Cuando quiere poner los cambios a disposición de los demás, este los sube al repositorio público mediante el comando “commit”. Desde este momento los cambios están visibles desde otros repositorios. Hasta aquí el modelo de trabajo es similar al de un control de versiones centralizado con la diferencia de que el servidor es propio de cada rama.

Cuando llega el momento de sincronizar dos repositorios distintos Mercurial ofrece dos comandos: “push” y “pull”. Push se emplea cuando se desea transferir cambios desde un repositorio a otro, y Pull se emplea cuando se desea tomar desde un repositorio los cambios de otro repositorio. Este segundo modelo es más seguro porque permite que un responsable determine qué es lo que le interesa que su rama contenga.

Con estas herramientas un desarrollador tiene capacidad de clonar un repositorio estable, y a su vez clonar esta rama de nuevo para implementar cada nueva funcionalidad por separado. De este modo pueden probarse e integrarse las funcionalidades de modo independiente.

En el caso de nuestro proyecto actual las ramas existentes son las siguientes:

  • Rama estable: Es la rama desde la que se generan las versiones publicables. Ubicada en la máquina de integración. Está bajo control del responsable de proyecto y solo toma cambios desde las ramas de desarrollo.
  • Ramas de desarrollo: Cada desarrollador tiene una rama en la máquina de integración para subir y probar sus cambios. Esta rama se clona desde la rama estable al comienzo de cada iteración. Una vez probados, estos cambios se revisan para asegurar que se están cumpliendo las especificaciones de desarrollo y las buenas prácticas establecidas. Hecho esto el responsable de proyecto realiza un pull e importa los cambios sobre la rama estable.
  • Ramas locales: Cada desarrollador tiene una rama local principal que se clona a partir de su rama de desarrollo al comienzo de cada iteración. El desarrollador puede clonar tantas ramas a partir de esta como estime oportuno. Idealmente una por funcionalidad.

¿En que se diferencia de subversion?

Subversion es un sistema que nos gusta, pero no respondía a nuestras necesidades porque:

  • Únicamente se puede tener un repositorio central. No nos resuelve la papeleta de tener varias ramas en el entorno de desarrollo.
  • El esquema de versionamiento y el sistema de ramificación es mucho menos flexible. Nos permite realizar menos adaptaciones. Con Mercurial las políticas de ramificación, mezclado y subida de cambios son un mero evento social.
  • No es capaz de funcionar en modo pull. Solo admite modo push, y nos ha gustado mucho el control sobre los cambios que nos da este esquema de funcionamiento.

Está muy chulo todo esto, ¿pero donde está la pega?

Las pegas que yo veo son las siguientes:

  • Requiere por parte de los desarrolladores un cambio de mentalidad a la hora de trabajar con el control de versiones.
  • Al ser muy flexible permite hacer muchas cosas bien, pero también muchas cosas mal. Obliga a ser muy disciplinado. Un símil a lo que pasa con C++ y JAVA.
  • Las herramientas de usuario aún no están tan maduras como pueden estar las de subversión, CVS, u otros controles más populares. Sin embargo la línea de comando se la han currado mucho y es muy sencilla, muy coherente, y muy intuitiva.

¿De dónde puedo descargarlo?

Podéis descargarlo desde http://www.selenic.com/mercurial/wiki/. En este sitio Web hay manuales (muy buenos), ejecutables, código fuente y guías de ayuda rápida.
El plugin de Merclipse lo podéis descargar de http://www.goldenhammers.com/merclipse/.
¿Tengo que hacer algo en especial para instalarlo?
Nada. Se instala mediante un instalador. Instalar y ejecutar.

Leave a Reply