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.
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.
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.
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).
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.
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:
svn:keywords controla la expansión de palabras
clave. Al igual que CVS, Subversion puede reemplazar cadenas de la
forma $Keyword$ o $Keyword:...$ embebidas
en ficheros de texto. Las palabras clave que desee reemplazar deben
listarse en el valor de la propiedad svn:keywords.
Subversion proporciona palabras clave para el último usuario
que haya modificado el fichero, el último número de
revisión que afectó al fichero, la fecha de esta
última revisión y un URL absoluto para el fichero en
el repositorio. Por ejemplo, si las cabeceras estándar de
algunos de sus ficheros contienen las palabras $Rev$ y
$Author$, puede habilitar su sustitución
automática con las siguientes órdenes:
$ svn propset svn:keywords 'Rev Author' *.c
$ svn commit -m "Habilitar palabras clave Rev y Author en los ficheros en C" *.csvn:mime-type adjunta un tipo MIME a un fichero para
usarlo cuando se entregue el fichero vía HTTP. También
se usa para determinar si el fichero debe almacenarse internamente
como texto o como binario. Si no hay tipo MIME, o si el tipo MIME
comienza con text/, indica que se trata de un fichero
de texto. Todos los demás tipos indican un fichero binario.
Observe que las órdenes svn import y svn
add intentan reconocer los ficheros binarios y etiquetarlos
como tales, con el tipo MIME por defecto application/octet-stream.
Subversion no intenta hacer diffs entre diferentes
versiones de un fichero binario.
svn:eol-style es muy útil cuando varios
desarrolladores trabajan en diferentes plataformas. Se usa para
hacer que los finales de línea sean CR, LF
o CRLF, o para obtener siempre el fichero usando los
finales de línea usados en la plataforma del desarrollador.
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 .
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.
La página de Subversion (http://subversion.tigris.org). Aquí puede conseguir la última versión del Libro de Subversion, que todavía está escribiéndose.
The Apache Software Foundation (http://www.apache.org).
Sleepycat Software (http://www.sleepycat.com), que proporciona la Berkeley DB.
El protocolo WebDAV (http://www.webdav.org). Subversion usa un subconjunto de los protocolos WebDAV y DeltaV. DeltaV es una extensión a WebDAV, que añade funcionalidades de versioneamiento.
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.