Subversion es un software de sistema de control de versiones diseñado específicamente para reemplazar al popular CVS, el cual posee varias deficiencias. Es software libre bajo una licencia de tipo Apache/BSD y se le conoce también como svn por ser ese el nombre de la herramienta de línea de comandos. Una característica importante de Subversion es que, a diferencia de CVS, los archivos versionados no tienen cada uno un número de revisión independiente. En cambio, todo el repositorio tiene un único número de versión que identifica un estado común de todos los archivos del repositorio en cierto punto del tiempo.
Ventajas
- Se sigue la historia de los archivos y directorios a través de copias y renombrados.
- Las modificaciones (incluyendo cambios a varios archivos) son atómicas.
- La creación de ramas y etiquetas es una operación más eficiente; Tiene costo de complejidad constante (O(1)) y no lineal (O(n)) como en CVS.
- Se envían sólo las diferencias en ambas direcciones (en CVS siempre se envían al servidor archivos completos).
- Puede ser servido mediante Apache, sobre WebDAV/DeltaV. Esto permite que clientes WebDAV utilicen Subversion en forma transparente.
- Maneja eficientemente archivos binarios (a diferencia de CVS que los trata internamente como si fueran de texto).
- Permite selectivamente el bloqueo de archivos. Se usa en archivos binarios que, al no poder fusionarse fácilmente, conviene que no sean editados por más de una persona a la vez.
- Cuando se usa integrado a Apache permite utilizar todas las opciones que este servidor provee a la hora de autentificar archivos (SQL, LDAP, PAM, etc.).
Clientes
Existen varias interfaces a Subversion, ya sea programas individuales como interfaces que lo integran en entornos de desarrollo.
- TortoiseSVN. Provee integración con el explorador de Windows. Es la interfaz más popular en este sistema operativo.
- Subclipse. "Plugin" que integra Subversion al entorno Eclipse.
- Subversive. "Plugin" alternativo para Eclipse.
- Cervisia Programa para interacción para linux, combinada con Quanta Plus puede llegar a ser muy eficaz.
- ViewVC. Interfaz web, que también trabaja delante de CVS.
- Para mac, pueden emplearse los interfaces SvnX, RapidSVN y Zigversion
- RapidSVN también corre en Linux.
- NautilusSVN Para el administrador de archivos Nautilus.
- KDESvn. Provee integración con el escritorio KDE, muy parecido en aparencia/funcionamiento/caracteristicas a TortoiseSVN
- Easyeclipse, EasyEclipse es un paquete basado en eclipse es una plataforma de desarrollo, con algunos plugins de código abierto.
- sventon Interfaz web
- Versions Interfaz de escritorio para Mac OS X
- AnkhSVN "Plugin" para Visual Studio para versiones 2002, 2003, 2005, 2008 y 2010, esta última en modo experimental.
Uso y reconocimiento
La subversión es muy conocido en la comunidad de software libre y se utiliza en muchos proyectos, incluyendo la fundación del software de Apache, KDE, GNOME, Free Pascal, FreeBSD, GCC, Python, Django, Ruby, Mono, SourceForge.net, ExtJS y Tigris.org. El servicio Google Code también proporciona almacenamiento Subversion para sus proyectos de software libre. Los sistemas de BountySource lo utilizan exclusivamente. Codeplex ofrece acceso tanto para Subversión como para otros tipos de clientes. Subversión también está siendo adoptado en el mundo corporativo. En un informe 2007 de Forrester Research, reconocía a Subversion como el único líder en la categoría de sistema de control de versiones.
Instalación y configuración de Subversion
Instalamos Subversion
Pueden descargar e instalar Subversion desde la página oficial de Subversion. O si están usando una distro como Debian, instalarlo desde los repositorios, como en mi caso:
apt-get install subversion
Creamos un repositorio
Creamos un directorio en donde queramos, puede ser en /home o en /var o donde se les antoje. En este caso vamos a crearlo en la raíz del sistema (/) y lo vamos a llamar svn, pero puede llamarse como quieran.
mkdir /svn
Bien, ahora vamos a indicarle a Subversion de que cree un nuevo repositorio en ese directorio, utilizando la herramienta svnadmin:
svnadmin create /svn
Creamos usuarios y otorgamos permisos
Para decidir quienes van a entrar en nuestro repositorio y quienes no, necesitamos crear usuarios con contraseña, y otorgarles los permisos correspondientes en los diferentes repositorios que queremos que tengan acceso.
Para no complicarnos la existencia, vamos a hacer algo bien simple: vamos a crear un grupo llamado con el mismo nombre del repositorio, en este caso svn. Vamos a crear todos los usuarios que necesitemos dentro de ese grupo. Y por último vamos a otorgarle permisos a este grupo en el repositorio.
Creamos el grupo con el mismo nombre que el repositorio
groupadd svn
Ahora creamos todos los usuarios que hagan falta, y los metemos dentro del grupo. En este caso voy a crear dos usuarios.
useradd pepe -m -G svn passwd pepe useradd homero -m -G svn passwd homero
Le damos permisos en el repositorio al grupo:
chown -R root:svn /svn chmod 770 /svn
Y no olvidemos asignar el umask, para que los usuarios al crear revisiones, las creen con determinados permisos de manera que todos los usuarios puedan acceder. Sino lo hacemos, los usuarios no van a obtener errores de permiso denegado, como este:
No se pudo abrir el archivo '/svn/db/current': Permiso denegado
Así que para que esto no pase, asignamos el umask para cada usuario que creemos, desde el archivo .profile de su home, veamos el ejemplo con el usuario pepe:
vi /home/pepe/.profile
Cambiamos la línea: view source print? 1. #umask 022
Descomentándola y cambiando el umask a 007 view source print? 1. umask 007
Perfecto, ya tenemos instalado un servidor Subversion. Veamos como utilizarlo. Uso de Subversion
Ahora nos vamos a poner del lado del cliente. Nos vamos a conectar al servidor por medio de nuestro usuario (cualquiera de los creados anteriormente) y vamos a hacer algunas “operaciones básicas”, como añadir ficheros al repositorio, descargar una copia local del repositorio, etc.
Cliente Subversion
El paquete subversion, que instalamos antes, incluye además del servidor, el cliente. Así que nosotros en nuestro caso ya debemos tenerlo instalado. Pero en el caso de los clientes, van a tener que instalarlo para poder conectarse a nuestro servidor:
apt-get install subversion
De ahora en adelante, para usar el cliente, usamos el comando svn. *
Nos conectamos al servidor
Para conectarnos al servidor, Subversion nos ofrece varios métodos:
o SSH o WebDAV o Localmente o SVN
En este caso vamos a utilizar SSH. Así que para realizar alguna acción en el servidor, nos conectaríamos así:
svn [acción] svn+ssh://usuario@host/repositorio
Es decir, si por ejemplo quisiéramos obtener una copia local, con el usuario pepe del repositorio creado anteriormente, y la IP del servidor Subversion fuera 72.14.207.104, sería algo así:
svn checkout svn+ssh://pepe@72.14.207.104/svn
o svn+ssh://: es el protocolo que estamos utilizando, en este caso SSH. Si fuera WebDAV sería http://, pero eso ya es otra historia. o pepe: es el usuario, en este caso pepe (que es uno de los que habíamos creado anteriormente). o 72.14.207.104: nuestro host o /svn: es la ruta del repositorio, ¿se acuerdan que lo habíamos creado en la raíz del sistema? si lo hubiéramos creado en /home/svn sería svn+ssh://pepe@72.14.207.104/home/svn *
Importación inicial
Hay dos formas de añadir ficheros al repositorio. Usando import y usando add. Cuando se comienza a crear un proyecto, la primera vez suele hacerse un import para importar todo lo que “ya se tiene” del proyecto al servidor.
Vamos a hacer de cuenta que tenemos este directorio con la siguiente estructura:
o /home/HelloWorld/ o /home/HelloWorld/trunk o /home/HelloWorld/branches o /home/HelloWorld/tags
Entonces para importar este proyecto al servidor, haríamos algo así:
svn import /home/HelloWorld svn+ssh://pepe@72.14.207.104/svn
NOTA: ¿por qué esa estructura de directorios? en Subversion, los proyectos suelen tener esa estructura, a continuación una breve descripción de lo que contiene cada directorio:
o trunk: contiene lo que se llama el tronco del proyecto, es la estructura principal, donde se va creando los directorios/ficheros y se van modificando. o branches: es donde se crean las ramas. Una rama vendría a ser una copia del tronco principal, en la que se pueden hacer cambios, sin modificar el tronco principal. Es decir, sirve para cuando se quiere hacer algo “experimental” y no se quiere hacer sobre el proyecto original. Se hace sobre una copia, una rama. o tags: sirve para guardar estados de nuestro proyecto (versiones mejor dicho). Es decir, serían las releases, las versiones de nuestro proyecto. * Obtener copia local del repositorio
Imaginemos que somos uno de los usuarios creados anteriormente, somos pepe. Y somos un desarrollador, nos acaban de contratar en un proyecto, nos dieron nuestro usuario y contraseña para conectarnos al servidor Subversion, así que ya podemos empezar a trabajar. ¿Qué es lo primero que vamos a hacer? bueno, crear una copia local del proyecto, es decir, descargarnos una copia del proyecto sobre la cual poder empezar a trabajar. Así:
cd /home/pepe svn checkout svn+ssh://pepe@72.14.207.104/svn
De esa manera estaríamos obteniendo una copia del repositorio entero en /home/pepe. Nos quedaría algo así:
o /home/pepe/svn/HelloWorld/ o /home/pepe/svn/HelloWorld/trunk o /home/pepe/svn/HelloWorld/branches o /home/pepe/svn/HelloWorld/tags
Si solo quisiéramos obtener una copia de un determinado directorio, sería algo así:
svn checkout svn+ssh://pepe@72.14.207.104/svn/trunk
Algunos servidores Subversion utilizan un repositorio por proyecto. Otros almacenan en un solo repositorio varios proyectos. En nuestro caso, tenemos un repositorio por proyecto, así que obtener el repositorio completo está bien. *
Añadir y eliminar ficheros en el repositorio
En el paso anterior creamos una copia local del proyecto con el usuario pepe. Ahora vamos a agregar ficheros al proyecto. Simplemente los agregamos en la copia, y después los agregamos al repositorio haciendo uso de los comandos add y commit, así:
Creamos un fichero
cd /home/pepe/svn/HelloWorld echo "Hello World" > helloworld
Lo añadimos al repositorio:
svn add helloworld svn commit -m "añado helloworld"
Con el comando add añadimos el fichero. Y con el comando commit aceptamos los cambios realizados (en este caso el añadir el fichero). A commit le pasamos como parámetro -m para agregarle un comentario (sobre porque hice el cambio, etc… puede decir lo que quieran). Si no usan el parámetro -m, entonces se les va a abrir su editor predeterminado para que agreguen el comentario.
Para eliminar es lo mismo, pero se usa el comando delete:
svn delete hellworld svn commit -m "elimino el fichero helloworld"
Actualizando copia local con el repositorio
Ahora imaginemos que el otro usuario (homero) que ya tiene su copia local del repositorio, quiere actualizar su copia con el servidor. Es decir, agregar a su copia los cambios hechos por pepe (o sea, el fichero helloworld).
Para esto, homero hace lo siguiente:
cd /home/homero/svn svn update
Con el comando update, homero actualizó su copia, agregándose el fichero añadido por pepe. Quedándole su estructura de directorios así:
o /home/homero/svn/HelloWorld/ o /home/homero/svn/HelloWorld/trunk o /home/homero/svn/HelloWorld/trunk/helloworld o /home/homero/svn/HelloWorld/branches o /home/homero/svn/HelloWorld/tags * Modificando ficheros
Ahora, ¿qué pasa si homero modifica el fichero helloworld? ¿cómo lo vuelve a subir al servidor?
Bueno, muy simple, lo hace con commit. Así:
echo "Bye Cruel World" > helloworld svn commit -m "modifico fichero helloworld"
Cada vez que utilizamos commit, estamos subiendo un cambio al servidor. Por lo que se crea una nueva revisión. Lo bueno de esto, es que cada cambio nunca sobreescribe al anterior, sino que se crea una nueva revisión. Si después se quiere volver a una revisión anterior, se puede hacer sin problemas. *
Conflicto
Veamos el siguiente caso:
Los usuarios pepe y homero actualizan sus copias con el servidor. Los dos tienen una copia del fichero helloworld con un contenido A. El usuario pepe por su parte modifica su copia del fichero, cambiando el contenido a un contenido B. Por otra parte, el usuario homero, actualiza su copia a un contenido C. pepe sube su copia con el contenido B. Después, homero sube su copia, con el contenido C. ¿Qué pasa con la copia de pepe? ¿se borra el contenido B?
¡NO! claro que no, ¿para qué estamos usando un sistema de control de versiones? ¡para que controle estas situaciones por ejemplo! pero entonces… ¿qué pasaría?
Bueno, homero obtendría un lindo mensajito del servidor, dicéndole que necesita actualizar su copia:
Transmitiendo contenido de archivos .svn: Falló el commit (detalles a continuación): svn: Desactualizado: 'helloworld' en transacción '7-1' svn: Su mensaje de commit fue dejado en un archivo temporario: svn: '/svn/svn-commit.tmp'
Lo que homero debe hacer en un caso así, es lo siguiente:
Ejecutar el comando update
svn update
Al hacer eso, se van a generar en la copia de homero, tres ficheros: helloworld.r2, helloworld.r3 y helloworld.mime (donde r2 y r3 es el número de revisión).
El fichero helloworld.r2 contiene el fichero anterior (sin los cambios de pepe ni de homero). En el fichero helloworld.r3 están los cambios realizados por pepe (los que actualmente están en el servidor). Y el fichero helloworld.mine contiene los cambios de homero (que NO están en el servidor). Por otra parte, el fichero helloworld, contiene algunas marcas para mostrar así la diferencia entre los dos ficheros.
Con esta información, homero, debería poder solucionar el conflicto, es decir, unir los cambios suyos con los de pepe en el fichero helloworld.
Una vez resuelto eso, homero debe ejecutar el comando resolved para resolver el conflicto en el servidor:
svn resolved helloworld
Algunos comandos útiles
Información sobre el repositorio:
svn info
Información sobre la última revisión:
svn status --show-updates --verbose
Obtener una revisión en concreto:
svn checkout --revision [número de revisión]
Actualizar copia local con una revisión en concreto:
svn update --revision [número de revisión]
Diferencias entre la copia local y el repositorio:
svn diff