Subversion multiusuario

Por Rafaël Garcia-Suarez (http://rgarciasuarez.free.fr), 19 de diciembre de 2002
Publicado en The O'Reilly Network (http://www.onlamp.com/pub/a/apache/2002/12/19/svn2.html)

Traducción: Enrique Matías Sánchez (Quique) (http://cronopios.net/), abril de 2003.

Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.
Se permite la distribución y copia literal de este artículo en su totalidad por cualquier medio, siempre que se conserve esta nota.

Instalación de un servidor Subversion

En un artículo anterior vimos como instalar y usar Subversion, en el contexto de un único usuario, y usarlo en un único sistema. Este artículo le llevará un paso más allá y le mostrará como instalar un servidor Subversion, accesible a través de la red y a un grupo de usuarios. Veremos también como Subversion puede ayudar a gestionar un proyecto al que contribuyen varios desarrolladores.

Subversion usa Apache como su capa de transporte HTTP. El cliente en línea de órdenes se comunica con los servidores remotos con un protocolo basado en las extensiones a HTTP 1.1 WebDAV/DeltaV. Esto significa que un servidor Subversion, aunque no implementa WebDAV totalmente, puede responder a los clientes HTTP y WebDAV (sólo lectura) normales, tales como navegadores web y gestores de ficheros.

Montaje de un servidor Apache con Subversion

Para montar un servidor Subversion necesitará una versión reciente de Apache 2. Obviamente el proceso de preparación es un poco más complejo que para un cliente independiente, pues deberá preparar un Apache con el módulo específico mod_dav_svn. Por esta razón vamos a detallar los pasos necesarios.

En nuestro anterior artículo, asumimos que estaba compilando a partir de una instantánea del código fuente en una plataforma Unix y que lo instalaba todo bajo /usr/local/subversion-rXXXX (donde XXXX es el número de revisión de la instantánea que estaba usando, y este directorio estaba enlazado desde /usr/local/subversion). Esta disposición de los directorios hace que sea más fácil actualizar Subversion, un punto importante cuando se usa software que todavía no ha alcanzado una versión estable. En este caso, asegúrese de que su sistema pueda encontrar bibliotecas compartidas en /usr/local/subversion/lib. (Para compilar Subversion a partir de las últimas fuentes, lea el fichero INSTALL, que explica como obtener y compilar desde el servidor de desarrollo). En el momento de escribir este artículo, la versión estable es la 0.16, revisión número 3987.

El primer paso es preparar el directorio de subversion y construir la base de datos. Para subversion 0.15, necesitará Berkeley DB, versión 4.0.14. Si no está instalada en su sistema, instálela en el mismo directorio que Subversion.

# mkdir /usr/local/subversion-rXXXX
# ln -s /usr/local/subversion-rXXXX /usr/local/subversion

$ gunzip -c db-4.0.14.tar.gz | tar xf -
$ cd db-4.0.14/build_unix
$ ../dist/configure --prefix=/usr/local/subversion-rXXXX
$ make

# make install

Después, instale Apache. Debería usar como mínimo la versión 2.0.42. La opción --enable-dav compilará e incluirá mod_dav y --enable-so habilitará soporte para DSO (Dynamic Shared Object). Las otras opciones especifican que Apache será instalado con Subversion y que usará la Berkeley DB que acaba de instalar, un punto importante.

$ gunzip -c httpd-2.0.43.tar.gz | tar xf -
$ cd httpd-2.0.43
$ ./configure --prefix=/usr/local/subversion-rXXXX \
        --enable-dav --enable-so \
        --with-dbm=db4 --with-berkeley-db=/usr/local/subversion-rXXXX
$ make

# make install

Por último, compile e instale Subversion. Aquí la opción importante es --with-apxs, que proporciona la ruta a la herramienta apxs(8), usada para compilar e instalar los módulos de extensión de Apache. En este caso, el proceso de instalación debería instalar mod_dav_svn, el módulo de Apache que gestiona las peticiones de los clientes Subversion.

$ cd ..
$ gunzip -c subversion-rXXXX.tar.gz | tar xf -
$ cd subversion-rXXXX
$ ./configure --prefix=/usr/local/subversion-rXXXX \
        --with-berkeley-db=/usr/local/subversion-rXXXX \
        --with-apxs=/usr/local/subversion-rXXXX/bin/apxs
$ make
$ make check         # opcional: ejecuta las comprobaciones

# make install

Eso es todo.

Configuración del servidor

Como Apache proporciona la capa de red, el servidor Subversion disfruta sin más de todas las características de Apache: robustez, autenticación HTTP, compresión de datos vía mod_deflate, cifrado vía mod_ssl, etc.

Para habilitar que algunos URL sean manejados por mod_dav_svn, sólo tiene que añadir en el fichero httpd.conf:

<Location /svn>
        DAV svn
        SVNPath /home/rafael/svn
</Location>

Este bloque le dice a Apache que sirva las rutas que empiecen con /svn a través de mod_dav_svn, y que éstas apuntan al repositorio de Subversion almacenado físicamente en /home/rafael/svn. Para obtener una copia de trabajo del tronco del proyecto frobnizer de este repositorio, la orden adecuada será:

$ svn checkout http://mi.maquina/svn/frobnizer/trunk directorio_de_trabajo

Por omisión, Apache escucha en el puerto 80, lo que significa que debe ser iniciado por el usuario root. Puede cambiar esto si lo desea. Observe, sin embargo, que los procesos de Apache deben ser capaces de escribir en el repositorio de Subversion. Una de las maneras limpias de hacer esto es crear una cuenta svn en su sistema, que sea la propietaria del repositorio Subversion. Configure Apache para que se ejecute con este usuario a través de la directiva de configuración User. Una vez haya hecho esto, estará preparado para iniciar el servidor:

$ /usr/local/subversion/bin/apachectl start

Para restringir el acceso de lectura o escritura a su repositorio, puede usar las capacidades de control de acceso de Apache. Puede limitar las máquinas que tienen permitido el acceso al repositorio y requerir un nombre de usuario y una contraseña para algunas operaciones (vía autenticación HTTP). Por ejemplo, las siguientes líneas, insertadas en el bloque <Location>, limitan el acceso de escritura a un grupo de usuarios específico:

<LimitExcept GET PROPFIND OPTIONS REPORT>
        Require group commiters
</LimitExcept>

Esto indica que todas las peticiones salvo las que usen los métodos HTTP listados deben ser enviadas por un usuario autenticado, un miembro del grupo commiters (enviadores). (Visite http://httpd.apache.org/docs-2.0/mod/core.html para encontrar una descripción detallada del control de accesos y de las directivas de configuración relacionadas). Cuando el envío se haga vía HTTP, los registros de cambios generados por Subversion recogerán el nombre de usuario HTTP.

Observe que el cliente Subversion deposita su nombre de usuario y contraseña en su copia de trabajo por defecto, de modo que no tenga que introducirlos cada vez que acceda al repositorio. Si le preocupa la seguridad, puede desactivar este comportamiento a través del fichero de configuración de usuario $HOME/.subversion/config o en el fichero de configuración global /etc/subversion/config en la máquina cliente.

Si desea implantar Subversion en su organización, puede encontrar más fácil compilar un cliente svn enlazado estáticamente. De esta manera, sólo tendrá que copiar este fichero binario a las máquinas de los usuarios, sin tener que instalar las bibliotecas necesarias. (Necesitará, sin embargo, compilar este cliente por separado usando la opción de configuración --enable-all-static. No es posible compilar un svn enlazado estáticamente y mod_dav_svn al mismo tiempo. El módulo de Apache necesita ser compilado como una biblioteca compartida).

Uso colaborativo de Subversion

Cuando varios usuarios tienen permisos de envío al repositorio Subversion, necesitan, en algún momento, integrar en sus copias de trabajo las modificaciones enviadas por los otros. La orden svn update realiza esta tarea, actualizando sus objetivos (por defecto, el directorio actual y su contenido, recursivamente) a la última revisión.

¿Qué sucede cuando usted actualiza un fichero que ha editado localmente, pero al que otro usuario ha enviado sus propias modificaciones? Si ha leído el primer artículo, ya sabe que Subversion no exige que bloquee un fichero cuando desee modificarlo. Este comportamiento es diferente del de otro software de control de código fuente que le impide editar un fichero que haya sido reservado por otro usuario. Subversion intenta fundir los cambios que ha hecho usted con los realizados por otros.

Mientras se realiza una actualización, svn mostrará una lista de ficheros actualizados, marcando cada línea con una letra para indicar la acción tomada sobre el fichero correspondiente. Éste puede ser añadido (A), borrado (D), actualizado (U), y, cuando su copia local tenga modificaciones, serán fundidos (G) o el fichero quedará en un estado de conflicto (C). Por ejemplo, la siguiente salida:

U foo.c
G bar.c
C hot.c

indica que foo.c ha sido actualizado, y que no tenía ninguna modificación local. Sus modificaciones locales a bar.c han sido fundidas con éxito. Subversion no ha sabido como fundir hot.c, porque los cambios en el servidor se superponían con los suyos.

En este último caso, Subversion creará tres ficheros temporales que contendrán su versión local, la versión del repositorio que usted había usado como base para sus modificaciones, y la última versión obtenida del repositorio. Su fichero original será también modificado: las modificaciones combinables serán combinadas, y las otras serán señaladas con marcas de conflicto similares a las que inserta la orden diff3(1) (específicamente, diff3 -E).

Entonces tendrá que resolver esos conflictos manualmente y borrar los ficheros temporales. (Para protegerse contra envíos no deseados, Subversion no le dejará enviar un fichero si detecta por ahí estos ficheros temporales). Para su comodidad, la orden svn resolve borra todos esos ficheros temporales por usted.

Observe también que Subversion no le permitirá enviar ficheros para los que exista una versión más reciente. Necesitará actualizarlos previamente.

Metadatos

Una interesante funcionalidad de Subversion es que permite que se añada una cantidad arbitraria de metadatos a cualquier recurso versioneado (ficheros y directorios). Los metadatos, como los ficheros, también están versioneados. Estos metadatos son un conjunto de parejas clave/valor, conocidas como propiedades.

Usted puede usar las propiedades para anotar ficheros (digamos, review-status a este fichero está siendo revisado por Joe), o directorios. Por ejemplo, en un directorio etiqueta frobnizer-1.09b, puede añadir una nota versión beta, sólo para uso interno.

Las propiedades cuyos nombres comienzan con svn: están reservadas para Subversion. Algunas de ellas son reconocidas y gestionadas específicamente. Por ejemplo, svn:executable marca un fichero para que sea obtenido con el indicador de ejecución activado en los sistemas de ficheros que lo soporten. Otras propiedades interesantes son:

Ramas, conmutación y fundido

En el primer artículo se ofreció una visión general de las etiquetas y ramas. Las ramas demuestran ser útiles principalmente en proyectos multiusuario. Con las ramas, un desarrollador o equipo de desarrolladores puede trabajar en una funcionalidad experimental sin interferir con el desarrollo principal. Las ramas también pueden usarse para llevar el control de las modificaciones en una versión de mantenimiento de un producto. Pueden usarse para manejar versiones beta y las respuestas de los beta-testers. Subversion hace que crear ramas sea fácil y barato, así que ¿por qué no usarlas?

Normalmente las ramas se crean fuera de la copia de trabajo para ahorrar espacio en disco con la forma de la orden copy que opera directamente sobre los URL. La siguiente orden crea una rama de mantenimiento a partir del tronco del proyecto actual (por convención, el directorio raíz de sus ficheros del proyecto):

$ svn copy http://mi.maquina/svn/frobnizer/trunk \
        http://mi.maquina/svn/frobnizer/maint-1.0

Para empezar a trabajar en una rama, puede por supuesto obtener una nueva copia de trabajo completa que le corresponda, pero es más fácil conmutar su copia de trabajo (o partes de ella) a la rama. Suponiendo que su copia de trabajo ya contiene el tronco, puede hacerla apuntar a la rama maint-1.0 con la siguiente orden, ejecutada en la raíz de su copia de trabajo:

$ svn switch http://mi.maquina/svn/frobnizer/maint-1.0 .

svn switch funciona un poco como update, salvo que no mueve conceptualmente su copia de trabajo a lo largo del tiempo (revisiones), sino a lo largo del espacio (ramas). Consecuentemente, la salida de switch es similar a la de update.

Finalmente, para integrar las modificaciones de otra rama en su copia de trabajo, puede usar la poderosa orden svn merge. merge puede compararse a diff, pero en vez de mostrar las modificaciones como un diff unificado por la salida estándar, las aplica a su copia de trabajo (como si aplicara un parche).

Por ejemplo, las siguientes órdenes integran una serie de modificaciones del tronco en su copia de trabajo de mantenimiento:

$ svn merge -r149:155 http://mi.maquina/svn/frobnizer/trunk
U foo.c
U foo.h
A bar.c

$ svn status
M      foo.c
M      foo.h
A  +   bar.c

$ svn commit -m 'Integrar revisiones 150 a 155 del tronco'

La salida de svn merge indica qué ficheros han sido afectados por las modificaciones, exactamente como svn update. La orden svn status informa del estado de los ficheros en su copia de trabajo. En este ejemplo, foo.c y foo.h tienen modificaciones locales, y bar.c está programado para ser añadido en el siguiente envío. El signo + en la línea de estado indica que Subversion sabe que este fichero ha sido ramificado desde otra parte, y conservará esta información cuando se envíe.

Observe que puede que tenga que solucionar manualmente posibles conflictos entre el fundido y el envío.

Un uso interesante de merge es obtener las modificaciones de la rama actual. De esta manera puede volverse atrás una modificación. La siguiente orden aplica los cambios de la revisión 200 a su copia de trabajo, en sentido contrario:

$ svn merge -r200:199 .

Mientras tanto, en el Mundo Real

Una vez se vaya acostumbrando a Subversion, se dará cuenta de que le puede ayudar de maneras que no esperaba.

Un primer ejemplo sería tratar con los ficheros de configuración en tiempo de ejecución durante actualizaciones. Cuando estoy trabajando en un proyecto de software en el que algunas variables de configuración global (direcciones IP, variables de entorno o niveles de traza) son leídas de un fichero, tengo que modificar este fichero casi cada vez que se instala la aplicación en otra máquina. Con las fuentes se proporciona un fichero de configuración por defecto, y se guarda bajo control de versiones porque el conjunto de variables de configuración cambia en las diferentes versiones. ¿Qué puedo hacer cuando quiero actualizar una instantánea instalada en una máquina de pruebas, pero sin perder los cambios locales realizados al fichero de configuración?

La solución es sencilla. En vez de instalar la aplicación en la máquina de pruebas a partir de un tarball del código fuente, copié mi cliente svn enlazado estáticamente allí y realicé una obtención (check-out). Entonces, ajusté los ficheros de configuración a mis necesidades, sin enviar los cambios. Actualizar el software a otra instantánea de desarrollo es tan fácil como un svn update seguido por un make all. El proceso de actualización integra las modificaciones comunes al fichero de configuración (vg, nuevas variables) con las modificaciones locales (vg, usuario/contraseña para acceder a una base de datos local). Esto puede aplicarse a cualquier fichero de configuración en evolución que necesite implantar: un /etc/profile, un .vimrc o un httpd.conf.

Las ramas también pueden usarse de maneras creativas. Trabajo en una aplicación de intranet que se entrega con varios conjuntos de hojas de estilo. Por ejemplo, algunas están diseñadas para pantallas con baja resolución y proporcionan diferentes tamaños de letra e imágenes de fondo.

Establezco dos directorios, /html/css/800 y /html/css/1024 para guardar estas CSS. El directorio 1024, para hojas de estilo adaptadas a resoluciones de pantalla más altas, es una rama del otro. Cuando se aumenta o modifica una CSS, es fácil incorporar sus modificaciones en la otra rama al tiempo que se conservan inalteradas las preferencias específicas de letras o imágenes.

Estoy seguro de que Subversion será usado en maneras que sus diseñadores no imaginaron. Esto es lo que provoca el éxito de una herramienta.

Consejos y enlaces


Gracias a Karl Fogel por haber tenido la amabilidad de revisar este artículo.


Rafaël Garcia-Suarez es un ingeniero de software y administrador de sistemas Unix francés.