Introducción a Subversion

Introducción

Subversion es un sistema de control de versiones, es decir, sirve para tener un control sobre nuestro proyecto y permitirnos realizar cambios a los distintos componentes del mismo manteniendo un histórico de estos cambios y permitiéndonos en cualquier momento deshacer los cambios hechos en un momento dado, actualizar el proyecto a la última versión de los programadores, ver históricos de cambios y comentarios, y unir nuestros cambios con los que otros hayan podido hacer sobre los mismos ficheros.

De hecho uno de los motivos por los que estos sistemas se utilicen tanto en el mundo del software libre se debe a que permite, de forma cómoda, coordinar el trabajo de varios profesionales a través de Internet cómodamente.

Sin duda el sistema de control de versiones (SCV de aquí en adelante) más utilizado actualmente por los programadores de software libre es el viejo y probado CVS. Este sistema tiene ya bastantes años detrás y aunque sirve bastante bien para sus propósitos tiene una serie de limitaciones que han hecho que poco a poco otros SCV están ocupando su (todavía predominante) cuota de mercado.

Entre estos nuevos sistemas podemos destacar tres: Arch, BitKeeper y Subversion. De los tres, en mi opinión, uno de los más interesantes para los que conozcan y hayan utilizado CVS con anterioridad es Subversion porque es el que más se le parece dado que sus programadores lo que han intentado es hacer una evolución natural de CVS superando sus limitaciones y mejorándolo allá donde estaba claro que se podía mejorar. Arch sigue una filosofía bastante distinta de CVS y BitKeeper, aún siendo probablemente el más avanzado de los tres, no es libre (sí de uso gratuito si se va a utilizar en proyectos libres).

Así que en este artículo vamos a explicar como trabajar con Subversion, aunque dada la similitud con CVS lo aprendido aquí es fácilmente aplicable a ese otro SCV.

Ciclo de uso de Subversion

La mayorí a de los programadores utilizan CVS y Subversion de una forma más bien cíclica. En este apartado vamos a ver en que consiste ese ciclo y que comandos vamos a utilizar para cada paso.

1. Obteniendo una copia de trabajo

Antes de empezar a explicar comandos y operaciones conviene entender un poco como se va a trabajar normalmente con un SCV como Subversion. Supongamos que decidimos colaborar a un proyecto de software libre que utiliza Subversion como SCV y dispone de un repositorio publico del que podemos bajarnos las fuentes listas para trabajar, y que disponemos de permiso de escritura para ese repositorio. Si tenemos ya instalado Subversion, el comando habitual para descargar esas fuentes serí a algo parecido a esto (supongamos que el proyecto se llama SuperMail):

svn co http://www.supermail.org/repositorio/svn/tronco supermail

Esto nos copiaráa desde la red a un directorio ’supermail’ en nuestro sistema de archivos todo el código fuente del proyecto hospedado en el repositorio Subversion del proyecto. ‘svn’ es el comando que vamos a utilizar casi siempre mientras trabajamos con Subversion, indicándolo subcomandos que especifican la operación a realizar; ‘co’ es la abreviatura de ‘checkout’ que es la operación que creará una copia del repositorio en nuestro sistema de archivos local sobre la que podamos trabajar y a continuación vemos una URL que indica la dirección de donde obtener las fuentes (Podemos observar que la es una dirección HTTP: Subversion utiliza Apache+WebDav para los repositorios de acceso por Internet; si nuestro repositorio va a ser privado no necesitaremos Apache). Por último, la palabra ’supermail’ indica el nombre del directorio local donde se copiará el contenido del anterior repositorio (de no existir se crearía) y es necesario porque en este caso (como sucede con bastantes repositorios de Subversion) el repositorio del proyecto no se ha denominado ’supermail’ sino ‘tronco’ (o más habitualmente su equivalente en inglés ‘trunk’). Esto suele hacerse así porque en ocasiones puede convenir que en un mismo repositorio coexista más de un proyecto.

Una vez hemos ejecutado el comando vemos que empieza a aparecer una salida en la que se va enumerando cada fichero y directorio contenido en el proyecto con una letra ‘A’ antepuesta. Esta letra indica que el fichero se ha añdido nuevo, más adelante veremos que existen otras letras que indican otras operaciones sobre nuestra copia del repositorio.

2. Trabajando

Cuando los ficheros se han terminado de descargar ya podemos meternos en el directorio supermail/ y empezar a hacer los cambios que queramos (programación, documentación, etc), teniendo solamente en cuenta que cuando creemos un fichero nuevo tenemos que utilizar el comando ‘svn add fichero’ (si el fichero no existe en el directorio especificado lo creará vacío) para informar a Subversion de los ficheros nuevos que añdamos, ‘svn rm fichero’ para informarle de los ficheros que eliminemos, y ‘svn mv fichero’ y ‘svn cp fichero’ para mover y copiar, respectivamente, los ficheros. Es decir, si dividiéramos los tipos de cambios en ‘cambios a ficheros’ y ‘cambios al árbol de directorios’ los primeros no necesitarían de ningún comando especial (tan sólo necesitamos hacer los cambios como los haríamos si no estuviera Subversion, es decir, con nuestro editor favorito en el caso de ficheros de texto) mientras que los cambios al árbol de directorios del proyecto si necesitan utilizar los comandos que hemos visto para indicarle a Subversion estos cambios (svn [add|rm|cp|mv], normalmente).

3. Comprobando los cambios

Una vez hemos quedado satisfechos con los cambios realizados, es hora de comprobar el conjunto de cambios que hemos realizado sobre la copia original que descargamos al principio.

Esto se realiza mediante el comando ‘svn status’ que producirá una salida con un lista de los ficheros que han cambiado con respecto al original y una letra indicando el tipo de cambio. el significado para algunas de estas letras es:

A El fichero ha sido añdido. D El fichero ha sido eliminado. M El fichero contiene modificaciones con respecto al original _M El fichero contiene modificaciones de propiedades respecto al original (veremos más tarde que son las propiedades) ? El fichero existe en la copia local, pero no en el repositorio (quizás sea un fichero temporal creado por compilaciones, o es un fichero que hemos creado nosotros pero se nos ha olvidado hacer ‘svn add’). ! El fichero existe en el repositorio pero no es nuestra copia local (quizás se nos ha olvidado hacer ‘svn remove’). ~ Algo que está marcado como fichero es un directorio o viceversa. Como podemos ver por el significado de cada carácter, este comando es muy útil para asegurarnos de que no nos ha olvidado añdir o eliminar ficheros o de que no hemos realizado modificaciones inesperadas a ficheros que no pretendíamos modificar (en este caso podríamos deshacer las modificaciones inesperadas haciendo ‘svn revert FICHERO’).

Por defecto svn status ignora los ficheros que concuerdan terminan con .o, .lo, .la, y algunos más, pues casi siempre estos ficheros son ficheros temporales creados por la compilación de archivos. La expresión regular que contiene los ficheros a ignorar es la propiedad svn:ignore del directorio padre (veremos más sobre propiedades un poco más adelante).

También, como con casi todos los comandos de Subversion, podemos obtener información de estado sobre un sólo fichero o directorio indicando su ruta:

svn status supermail/README

Además, si ejecutamos svn status con el parámetro -v aparecerán dos nuevas columnas indicando cual fue la última revisión en la que se cambió el fichero y quien lo hizo.

4. Actualizando la copia de trabajo

El último paso antes de hacer efectivos nuestros cambios con el repositorio global es actualizar nuestra copia local para que se reflejen esos cambios, y poder resolver los conflictos que hayan podido surgir.

Para ello utilizamos ‘svn up’ (de update) que nos irá mostrando una lista de los ficheros que han cambiado con, de nuevo, una letra indicando el tipo de cambio. El significado de esta letra es el mismo que hemos explicado con ‘svn status’ pero además pueden darse:

U El fichero, que no habíamos cambiado, se ha actualizado G Un fichero que habíamos cambiado se ha actualizado, y Subversion ha unido ambos cambios sin ningún problema. C Un fichero que habíamos cambiado se ha actualizado, y el cambio ha provocado un conflicto. Si se produce un conflicto en algún fichero debemos resolverlo manualmente (Subversion aún no sabe programar) para lo cual abrimos el fichero, observamos las partes que Subversion nos ha marcado indicando los cambios locales y los del repositorio global y resolvemos el conflicto. Una vez lo hemos hecho ejecutamos tenemos que ejecutar ‘svn resolve FICHERO’ para indicar a Subversion que el conflicto está resuelto.

5. Envíando nuestros cambios

Una vez hemos comprobado (mediante svn status y svn update) que nuestros cambios son correctos y que no son conflictivos con lo que actualmente existe en el repositorio global (y si no lo fueran, lo resolvemos y ejecutamos de nuevo svn status y svn update para asegurarnos) llega el momento de enviar nuestros cambios a dicho repositorio.

Para ello se utiliza el commando ‘svn commit’ al que normalmente le vamos a pasar el parámetro -m con un mensaje de texto indicando los cambios que hemos realizado (luego la gente podrá ver ese mensaje cuando consulte los históricos). Si no le pasamos el parámetro -m utilizará la variable de entorno $EDITOR para abrir un editor de texto en el que introduzcamos un mensaje.

Por ejemplo, el comando podría quedar de la siguiente forma:

svn commit -m “He mejorado mucho la ritratransfusión de los megabixeloides”

svn commit fallará si se han realizado nuevos cambios en el repositorio global; en este caso tendremos que actualizar (svn update) y volver al punto 4.

En el caso de que no tuviéramos permiso de escritura, Subversion nos permite crear un parche, que podamos enviar por email a los autores, de forma muy sencilla; Sólo tenemos que ejecutar desde el directorio superior del proyecto:

cvs diff > parche.diff

Y ya tendríamos nuestro parche en el archivo parche.diff, que podríamos mandar al autor o autores para que lo añdieran utilizando el comando patch < parche.diff desde el mismo directorio.

Y ya está, en realidad, salvo casos muy concretos, no vamos a salirnos casi nunca de los comandos especificados en este apartado. Una vez hemos terminado de trabajar, y nos hemos asegurado de que nuestros cambios se han enviado correctamente al repositorio global podemos o bien borrar nuestro directorio de trabajo y volver a hacer el checkout la próxima vez que queramos trabajar en el, o no borrarlo y hacer el update en su lugar.

Otras operaciones con Subversion

Una vez que hemos visto el manejo fundamental de Subversion, vamos a recorrer otras operaciones habituales que podemos realizar con el mismo, y algunas ‘bases teóricas’ fundamentales.

El sistema de versiones El sistema de versiones de Subversion es distinto al de CVS. En el segundo, cada fichero tiene su propia versión, y los directorios no tienen versiones pues CVS los considera simplemente como ‘contenedores de ficheros’, lo que causa muchos dolores de cabeza a sus usuarios a la hora de reorganizar el árbol de un proyecto. En Subversion las versiones se aplican a todo el árbol de nuestro proyecto (incrementándose en uno en cada commit), y por lo tanto todos los ficheros tendrán la misma versión en una misma ‘captura’ del árbol, incluyendo los directorios.

Por ejemplo, si tuviéramos un sencillo proyecto que contuviera los siguientes ficheros:

hola/README hola/INSTALL hola/holamundo.c

En la primera versión todos los ficheros tendrían la versión ‘1’. Si después hiciéramos un cambio al fichero INSTALL y ejecutáramos el commit, las versión del árbol, y por lo tanto la de todos sus archivos, cambiaría a ‘2’.

Creando nuestro repositorio

Crear un repositorio es tan sencillo como utilizar los comandos:

mkdir /home/usuario/svn svnadmin create /home/usuario/svn

Con esto se nos crearía un repositorio básico (vacío) en el cual podríamos empezar a crear ficheros y directorios. Pero normalmente nos interesará importar algún arbol de código existente, para lo cual tendríamos que hacer a continuación:

svn import file:///home/usuario/svn /home/usuario/HolaMundo holamundo

Analicemos. El comando para importar un código existente es ‘svn import’. A continuación le hemos pasado la URL a nuestro repositorio (que como resulta que está en nuestro sistema de archivos tiene la forma file://[ruta_completa], hay que recordar que svn siempre trabaja con URLs cuando se refiere a repositorios globales, no así svnadmin), después le indicamos donde está el árbol existente que queremos importar (en este caso /home/usuario/HolaMundo) y por último el subdirectorio dentro del repositorio en el que queremos que se importe, de modo que si quisiéramos hacer un checkout para crear una copia local y comprobar que se ha importado correctamente tendríamos que hacer:

svn co file:///home/usuario/svn/holamundo copia_local

Lo que nos crearía en el directorio actual un subdirectorio ‘copia_local’ conteniendo el árbol (Subversionizado) de nuestro proyecto ‘HolaMundo’.

Sin embargo normalmente nos va a interesar crear más de un subdirectorio dentro de nuestro repositorio de ‘HolaMundo’ de forma que en uno de ellos contengamos el árbol de la versión en desarrollo o inestable, en otro las distintas ramas (veremos algo sobre ramas más adelante) y en otro las distintas versiones estables. Por ello nos conviene utilizar el subcomando mkdir para crear los distintos subdirectorios dentro del repositorio de nuestro proyecto ‘holamundo’:

mkdir /home/usuario/svn

svnadmin create /home/usuario/svn

svn mkdir file:///home/usuario/svn/holamundo -m “Directorio base para HolaMundo”

svn import file:///home/usuario/svn/holamundo /home/usuario/HolaMundo head -m “Rama en desarrollo”

svn mkdir file:///home/usuario/svn/holamundo/ramas -m “Directorio de ramas”

svn mkdir file:///home/usuario/svn/holamundo/finales -m “Directorio de versiones finales”

Tras esto nos quedaría un repositorio conteniendo a su vez tres directorios (que podríamos considerar ‘subrepositorios’) que serían ‘head’, con código ya añdido, y que contendrá las versiones en continuo desarrollo, “ramas” que podría contener en el futuro distintas ramas del desarrollo y “finales” que contendría imágenes de las versiones finales estables de nuestro programa.

Deshaciendo un cambio

Existen dos formas de deshacer un cambio, dependiendo de en que fase del desarrollo lo hayamos hecho. Si el cambio se ha producido sólo localmente, y queremos volver en determinado archivo a la versión del repositorio global, tan sólo tenemos que hacer svn revert fichero o svn revert a secas desde el directorio raíz si quisiéramos deshacer todos los cambios.

El segundo caso es que queramos deshacer uno o más cambios ya enviados al repositorio global en un commit anterior. En este caso tendremos que utilizar el subcomando ‘merge’ indicando en primer lugar la revisión desde la que queremos volver atrás y en segundo lugar la revisión a la que queremos volver. Por ejemplo, si en nuestro proyecto (revisión 5) un día que estábamos borrachos hicimos dos horrendos commits (revisión 6 y revisión 7) y al día siguiente comprobáramos con resacoso horror el estropicio realizado, podríamos volver tranquilamente a nuestra revisión pre-pedal con:

svn merge -r 7:5

Aquí podemos ver que hemos utilizado el subcomando merge con un parámetro ‘-r’ que nos permite indicar dos revisiones sobre las que efectuar el cambio, y hemos indicado en primer lugar la última revisión que hicimos tolingas seguido de dos puntos y la última revisión que hicimos sobrios. Como con casi todos los comandos, además, podemos especificar como parámetro uno o varios archivos o directorios para que los cambios se realicen sólamente sobre ellos.

‘merge’ tiene otros usos que veremos más adelante.

Históricos y registros

En muchas ocasiones nos resultará tremendamente útil comprobar que mensajes se adjuntaron a cada revisión, los cambios producidos en ellas, los cambios entre dos revisiones especificadas, etc. Todas estas operaciones se realizan mediante los comandos ‘svn log’ y ‘svn diff’.

‘svn log’ permite obtener los mensajes que el autor de cada revisión escribió. Si lo ejecutamos en el directorio raíz y sin parámetros nos mostrará todos los mensajes de todas las revisiones, pero también podemos ejecutarlo sobre un archivo o directorio en cuyo caso sólo nos mostrará los mensajes de las revisiones que modificaran ese archivo. También puede especificarse un conjunto de revisiones con el parámetro -r (como vimos anteriormente con svn merge) si sólo queremos ver las revisiones comprendidas en ese rango.

‘svn diff’ ejecutado sin parámetros nos permite, como vimos anteriormente, ver las diferencias entre nuestra copia de trabajo y el fichero original en el repositorio global, pero, como era de esperar, también admite el parámetro -r para especificar un rango de revisiones entre las que queremos que se nos muestren los cambios a los ficheros, por ejemplo svn diff -r 2:4 ejecutado desde el directorio raíz de la copia de trabajo mostraría todos los cambios realizados a los ficheros que fueran modificados entre la segunda y la cuarta revisión. ‘svn diff’ también admite ficheros o conjuntos de ficheros como parámetro para mostrar sólo los cambios producidos en ellos.

Ramas

El concepto de rama es uno de los más útiles a la hora de trabajar con sistemas de control de versiones. Se explica mejor con un ejemplo; imaginamos que nuestro afamado programa ‘HolaMundo’ ha llegado a un punto en el que tiene la estabilidad y características necesarias para poder considerarlo una versión ‘Beta’, pero tenemos otras características en mente que quisiéramos añdir (como colorear el HolaMundo, efectos de fuegos artificiales que forman las palabras, etc) pero a una versión posterior a esta beta. Una solución sería hacer un paquete con el código fuente de la versión actual, publicarlo como ‘HolaMundo 1.0-Beta’ y seguir trabajando en las nuevas características en nuestro repositorio Subversion. El problema obvio es que si, como es natural, a nuestra versión beta le salen fallos, ya no podemos incorporarlos al repositorio sin incorporar al mismo tiempo a esa versión las nuevas (e inestables) características que hemos desarrollado, con lo cual podríamos introducir nuevos fallos. Tendríamos que, o bien seguir desarrollando el código de esa beta por separado sin ningún repositorio, o bien crear un nuevo repositorio sólo para ella hasta que se convierta en ‘versión estable’. En cualquier caso si arregláramos un fallo en la versión beta, y quisiéramos incorporar ese arreglo también a la versión en desarrollo, tendríamos que hacerlo ‘a mano’.

Las ramas nos proporcionan una solución elegante a todo este embrollo. Las ramas (’branches’) nos permiten seguir desarrollando una versión paralela del proyecto, surgida a partir de una determinada última revisión común, y nos permitirán seguir intercambiando cambios entre ambas cuando queramos.

Para crear una rama a partir de una revisión existente se utiliza el subcomando ‘cp’. En este caso vamos a suponer que la revisión 173 de nuestro proyecto ‘HolaMundo’ es lo bastante estable como para poder considerarla una beta, por lo que decidimos crear una rama del proyecto llamada ‘holamundo-beta’. Suponiendo que hubiéramos utilizado la estructura explicada en el apartado de creación de un repositorio haríamos:

svn cp file:///home/usuario/svn/holamundo/head file:///home/usuario/svn/holamundo/ramas/holamundo-beta

Ya tenemos nuestra rama lista para ser modificada independientemente de la principal. Es importante destacar que la nueva rama no ocupará nada de espacio en disco mientras no modifiquemos nada, pues sus ficheros en realidad serán punteros a los mismos ficheros de la revisión en la que salga en la rama inestable pero según vayamos modificando ficheros se irán creando copias con las modificaciones en esta rama. Como vemos, ya podemos arreglar fallos tranquilamente en la rama holamundo-beta mientras seguimos añdiendo felizmente características inútiles y llenas de bugs a la rama head.

Aún nos queda el segundo problema que teníamos ¿cómo hacemos que las soluciones a los bugs de la versión beta se apliquen también a la versión inestable? Para ello se utiliza el comando svn merge, que ya conocíamos anteriormente aplicado a deshacer una revisión o parte de ella. En este caso, suponiendo que la solución al fallo se haya hecho en la revisión 177 de la rama holamundo-beta, el comando a utilizar sería (suponiendo que estuviéramos en el directorio raíz de la versión inestable):

svn merge -r 176:177 file:///home/usuario/svn/holamundo/ramas/holamundo-beta .

Con esto (si no hay conflictos) ya deberíamos tener también la solución al fallo incorporada en la versión inestable. Por supuesto para que este comando sólo incorpore la solución, esta debe de haber el único cambio incorporado entre la revisión 176 y la 177, es decir, no se deben de haber realizado otros cambios en ese mismo commit pues sino esos otros cambios también se aplicarán en nuestra versión inestable (salvo que especifiquemos ficheros pero, de nuevo, sólo suponiendo que la solución al fallo sea la única fuente de modificación de esos ficheros). Por ello (entre otros muchos motivos como por ejemplo la conveniencia de poder deshacer un cambio)es más que conveniente intentar que los commits sean pequeños y que nunca incorporen cambios que no estén relacionados.

¿Y qué son los tags? Los tags en terminología CVS no son más que etiquetas que le dan un nombre a una determinada revisión del árbol, por ejemplo llamar ‘1.0Final’ a la revisión 345. Subversion no tiene tags pero es fácil conseguir el mismo resultado simplemente copiando la revisión que interese con ‘svn cp’ al directorio ‘finales’ con el nombre de la versión real (que podríamos haber llamado igualmente ‘tags’) y ajustando la propiedad del directorio a sólo-lectura (veremos más adelante como ajustar las propiedades de un fichero o directorio):

svn cp -r 345 file:///home/usuario/svn/holamundo/ramas/holamundo-beta \\\\ file:///home/usuario/svn/holamundo/finales/1_0 svn propset

svn:read-only 1 file:///home/usuario/svn/holamundo/finales/1_0

Una vez que hemos terminado de trabajar con una rama, y creado una nueva versión (como hemos visto antes, con svn cp al directorio de tags) o incorporado sus cambios experimentales en nuestra rama principal, podemos eliminarla con ‘svm rm’.

Propiedades

Las propiedades son valores textuales que podemos asociar con cada fichero o directorio de un repositorio. Por ejemplo en el apartado anterior hemos puesto la propiedad ‘svn:read-only’ de un directorio del repositorio a uno. svn:read-only en realidad es una propiedad especial con un significado concreto, pero nosotros podemos poner propiedades con los nombre y los valores que queramos simplemente teniendo cuidado de que sus nombres no empiecen por ‘svn:’ pues este prefijo se ha reservado para las propiedades con un significado especial para Subversion.

Entre estas ‘propiedades especiales’, destacaremos:

svn;read-only

Como hemos visto, mientras exista esta propiedad no se nos permitirá modificar el fichero o directorio sobra el que la propiedad esté asignada.

svn:executable

Esta propiedad (que sólo es aplicable a ficheros) especifica que el fichero es ejecutable.

svn:mime-type

Esta propiedad se utiliza para intentar determinar el tipo mime del fichero. Si Subversion está intentando determinar el tipo de un fichero y no tiene esta propiedad puesta, intentará adivinar el tipo de forma ‘inteligente’ por lo que normalmente no vamos a tener que especificarle que ficheros son binarios y cuales no (como sucede con CVS).

svn:ignore

Hace que Subversion ignore todos los ficheros cuyos nombres coincidan con los patrones especificados por esta propiedad. Por defecto ignora automáticamente los ficheros con extensión .o, .lo, .la y alguno más, resultado de la compilación de programas C/C++. Los patrones deben ir uno en cada línea, más adelante veremos como poner propiedades con valores multilínea.

svn:keywords

Subversion, como CVS, tiene la habilidad para sustituir determinadas palabras clave dentro del texto de un archivo por valores, por ejemplo, puede sustituir $LastChangedDate$ automáticamente por $LastChangedDate: 2002-10-22 18:58:35 +100 (Thu 22 Oct 2002)$, pero para que se activen esas substituciones debe de existir el valor adecuado dentro de la propiedad keywords del archivo, por ejemplo en este caso debería contener (posiblemente entre otros) la cadena “Date”.

svn:eol-style

Esta propiedad especifica la forma en la que se hacen los saltos de línea en los archivos de texto; esto es útil porque distintos sistemas operativos tienen distintas formas de hacer los saltos de línea. Lo más aconsejable en un proyecto en el que los ficheros fuente vayan a ser utilizados desde distintos sistemas operativos es poner esta propiedad a “native” que especificará que en cada sistema operativo se utilicen los saltos de línea del mismo. Sin embargo, en otros casos puede interesar que determinado fichero tenga los saltos de línea de un determinado tipo, por lo que esta propiedad también puede tomar los valores “LF”, “CR”, o “CRLF”.

Pero ¿cómo cambiar y obtener las propiedades de un fichero o directorio? Muy sencillo, simplemente utilizamos ‘svn propget propiedad fichero’ para obtener las propiedades y ‘svn propset propiedad valor fichero’ para ponerlas. En el caso de que queramos editar una propiedad con nuestro editor de texto (algo interesante para propiedades que puedan tener valores de varias líneas como svn:ignore) utilizaremos ‘svn propedit propiedad fichero’.

Administración general de un repositorio

svnlook

Esta utilidad sirve para analizar los cambios que se han ido produciendo a un repositorio a lo largo del tiempo, sin cambiarlo. La forma más obvia de utilizarlo es con svnlook /home/usuario/svn (siendo por supuesto la ruta dependiente de donde esté nuestro repositorio). Esto nos mostrará por pantalla el árbol de directorios y ficheros correspondiente a ese repositorio en la revisión actual. Además podemos especificar una revisión concreta con svnlook /home/usuario/svn rev número lo que nos dará el árbol del repositorio para la revisión ’número’. svnlook [ruta] rev [numero] puede tener además subcomandos adicionales que especifican el tipo de información que queremos obtener para esa revisión determinada, que irán al final del comando:

  • log Mostrará el mensaje que el autor de la revisión escribió.
  • author Mostrará el autor de la revisión.
  • date Mostrará la fecha de la revisión
  • dirs-changed Mostrará los directorios que cambiaron en la revisión
  • changed Mostrará todos los ficheros y directorios que cambiaron en la revisión.
  • diff Mostrará diferencias en el formato utilizado por diff -u de los cambios realizados en la revisión.

svnadmin

Ya hemos visto anteriormente que podemos utilizar svnadmin para crear nuevo repositorios mediante su subcomando ‘create’. Pero svnadmin tiene otros subcomandos bastante interesantes, entre los que están:

  • lsrevs ruta_al_repositorio [revisión_menor] [revisión_mayor]: Muestra todo el árbol de todas las revisiones, incluyendo números de versión, mensajes de log y otros datos. Si se especifican revision_menor y revisión_mayor sólo listará las revisiones comprendidas entre esos dos parámetros.
  • lscr ruta_al_repositorio ruta: Mostrará todas las revisiones en las que se ha cambiado el fichero o directorio ‘ruta’ dentro del repositorio. setlog ruta_al_repositorio revisión fichero_con_mensaje: Cambiará el mensaje de log de la revisión especificada por el contenido del fichero ‘fichero con mensaje’. Hay que tener cuidado al hacer esto pues este cambio no se puede deshacer automáticamente.
  • shell ruta_al_repositorio: Este es uno de los (sub)comandos más útiles de svnadmin. Nos proporcionará una sencilla shell desde la que podemos navegar el repositorio especificado como si de un directorio local del sistema de archivos se tratase de forma que podamos cambiar entre los distintos directorios y listar sus contenidos. Esta simplísima shell sólo cuente (de momento) con los comandos ‘help’ (muestra la ayuda), ‘cd’ (cambia de directorio), ‘ls’ (lista un directorio), ‘cr’ (cambia la revisión sobre la que estamos navegando) y ‘exit’ (sale de la shell).
  • youngest ruta_al_repositorio:Muestra el número de la revisión más reciente del repositorio.
  • dump ruta_al_repositorio [revisión_menor] [revisión_mayor]: Otro comando extremádamente útil. Nos permite volcar el contenido de un repositorio, bien todas las revisiones, bien sólo una de ellas (si sólo se ha especificado revisión_menor) o bien un rango de ellas (si se han especificado tanto revisión_menor como revisión_mayor) a la salida estándar (aunque normalmente la vamos a redirigir a un fichero) en un formato de fichero portable. Este fichero normalmente lo vamos a utilizar como copia de seguridad del repositorio, o para trasladar el repositorio a otro sistema. También es necesario hacerlo cuando actualicemos Subversion y la nueva versión tenga un formato interno incompatible con la que veníamos utilizando.
  • load ruta_al_repositorio: Lee de la entrada estándar (a la que normalmente vamos a volcarle un fichero) un fichero como el creado mediante el comando dump, y recrea el repositorio en la ruta especificada. Esto es útil para restaurar copias de seguridad o crear una réplica de un repositorio que existía anteriormente en otro sistema.

Haciendo que un repositorio sea accesible a través de Internet

En algunos ejemplos anteriores hemos visto que cuando accedemos a un repositorio en Internet con Subversion especificamos una URL de protocolo HTTP (http://www.midominio,org/mirepositorio, por ejemplo). Esto es así porque para publicar repositorios por Internet Subversion utiliza Apache con el módulo WebDav, que es un protocolo que permite acceder y modificar ficheros de el servidor Apache. No nos vamos a extender en como instalar Apache (por cierto, necesita la versión 2.0) y el módulo WebDav, pero indicaré los pasos a seguir:

  • Instalar Apache 2.0, procurar que funcione ;)
  • Instalar el módulo mod_dav.
  • Instalar el plugin mod_dav_svn para el módulo mod_dav.
  • Configurar correctamente el fichero http.conf.
  • Los pasos uno a tres suelen poderse conseguir fácilmente si utilizamos una distribución moderna de Linux, pues casi todas incluyen ya entre sus paquetes Apache 2.0, el módulo WebDav para el mismo, y en algunas ocasiones hasta el plugin para el módulo webDav.

El último paso (configurar el fichero http.conf) consiste en añdir al final del fichero http.conf lo siguiente:

DAV svn SVNPath /home/usuario/svn

Cambiando ‘/home/usuario/svn’ por la ruta real de nuestro repositorio y ‘repos/mirepo’ por la parte final de la URL que queramos que represente nuestro repositorio a través de Internet, por ejemplo, si nuestro dominio es http://www.midominio.com y queremos que nuestro repositorio, situado en /home/usuario/repositorio se vea a través de internet como http://www.midominio.com/repositorio/HolaMundo tendríamos que añdir al http.conf:

DAV svn SVNPath /home/usuario/repositorio

Ya sólo nos queda restringir los permisos de acceso para que sólo puedan leer y hacer commits a nuestro repositorio las personas que nosotros consideremos oportuno. Para el caso más habitual de un acceso de lectura público y un acceso de escritura por usuario creamos un fichero que contenga nombres de usuarios y claves cifradas con el comando crypt con el siguiente formato:

usuario1:clave_cifrada1

usuario2:clave_cifrada2 … Después dentro del grupo ‘Location’ que acabamos de definir en el archivo http.conf añdimos las siguientes opciones:

AuthType Basic AuthName “Repositorio Subversion” AuthUserFile /ruta/al/fichero/de/usuarios

Require valid-user

Sustituyendo “Repositorio Subversion” por el texto que queramos que aparezca en la cadena de autenticación y “/ruta/al/fichero/de/usuarios” por la ruta real del fichero que hemos creado anteriormente con el listado de usuarios.

comments powered by Disqus