El control de versiones es quizá una de las tareas de integración continua más importantes para un proyecto. Mediante esta, podemos versionar los distitnos archivos o artefactos que componen al proyecto o producto, a fín de garantizar la gestión en el tiempo de los cambios y los autores de los mismos.
En este POST revisaremos los principales fundamentos del control de versiones, los distintos sabores de ellos que han sido desarrollados y en especial trabajaremos con un pequeño ejemplo de SubVersion, haciendo uso de googleCode como servidor y el IDE NetBeans como cliente a través de uno de sus plugins.
1. DEFINICIÓN
Se llama control de versiones a la gestión de los diversos cambios que se realizan sobre los elementos de algún producto o una configuración del mismo. Los sistemas de control de versiones facilitan la administración de las distintas versiones de cada producto desarrollado, así como las posibles especializaciones realizadas (por ejemplo, para algún cliente específico).[1]
2. CARACTERÍSTICAS
Un sistema de control de versiones debe proporcionar:
- Mecanismo de almacenaje de los elementos que deba gestionar (ej. archivos de texto, imágenes, documentación…)
- Posibilidad de realizar cambios sobre los elementos almacenados (ej. modificaciones parciales, añadir, borrar, renombrar o mover elementos)
- Registro histórico de las acciones realizadas con cada elemento o conjunto de elementos (normalmente pudiendo volver o extraer un estado anterior del producto)
Aunque no es estrictamente necesario, suele ser muy útil la generación de informes con los cambios introducidos entre dos versiones, informes de estado, marcado con nombre identificativo de la versión de un conjunto de ficheros.[2]
3. CLASIFICACIÓN
La principal clasificación que se puede establecer está basada en el almacenamiento del código:
- Centralizados: existe un repositorio centralizado de todo el código, del cual es responsable un único usuario (o conjunto de ellos). Se facilitan las tareas administrativas a cambio de reducir flexibilidad, pues todas las decisiones fuertes (como crear una nueva rama) necesitan la aprobación del responsable. Algunos ejemplos son CVS y Subversion
- Distribuidos: cada usuario tiene su propio repositorio. No es necesario tomar decisiones centralizadamente. Los distintos repositorios pueden intercambiar y mezclar revisiones entre ellos. Ejemplos: Git y Mercurial[1]
4. TIPOS
Todos los sistemas de control de versiones se basan en disponer de un repositorio, que es el conjunto de información gestionada por el sistema. Este repositorio contiene el historial de versiones de todos los elementos gestionados.
Cada uno de los usuarios puede crearse una copia local duplicando el contenido del repositorio para permitir su uso. Es posible duplicar la última versión o cualquier versión almacenada en el historial. Este proceso se suele conocer como check out o desproteger. Para modificar la copia local existen dos semánticas básicas:
- Exclusivos: para poder realizar un cambio es necesario marcar en el repositorio el elemento que se desea modificar y el sistema se encargará de impedir que otro usuario pueda modificar dicho elemento.
- Colaborativos: en el que cada usuario se descarga la copia la modifica y el sistema automáticamente mezcla las diversas modificaciones. El principal problema es la posible aparición de conflictos que deban ser solucionados manualmente o las posibles inconsistencias que surjan al modificar el mismo fichero por varias personas no coordinadas. Además, esta semántica no es apropiada para ficheros binarios.
Tras realizar la modificación es necesario actualizar el repositorio con los cambios realizados. Habitualmente este proceso se denomina publicar, commit, check in o proteger.[2]
5. VENTAJAS DE USAR CONTROL DE VERSIONES
- Tener un control exacto sobre cual es la última versión del código, y quién y cuando la ha cargado.
- Poder comparar versiones, viendo cuales han sido los cambios realizados.
- Regresar atrás (a una vesión anterior) cuando lo que hemos desarrollado no nos ha dado los resultados esperados.
- Crear distintas ramas del proyecto. Si llegado a un punto se hace necesario hacer dos aplicaciones con distintas funcionalidades, pero con cosas en común, se pueden separar en dos ramas.
6. SISTEMAS DE CONTROL DE VERSIONES
- CSV (Concurrent Version System): Desarrollado por GNU se distribuye bajo licencia GPL. Fue muy popular hasta la aparición de Subversion.
- SVN (Subversion): Hoy es el más popular, fue creado para mejorar CVS, mejorando sobre todo el manejo de archivos binarios.
- Git: Diseñado por Linus Torvalds, es usado por el desarrollo del kernel de Linux, aunque no alcanza la popularidad de los otros dos.
- Mercurial: Un gestor de vesiones para entornos distribuidos sin necesidad de usar un servidor.
- Monotone: Al igual que Mercurial no usa servidor, cada cliente hace al mismo tiempo de cliente y servidor.[1]
7. SUBVERSION
Para nuestro caso de estudio de este POST, estudiaremos a fondo Subversion.
7.1 Definición
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 utilizada en la línea de órdenes; por ej.:
$ svn export nombre-de-repositorio
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 un instante determinado.
Subversion puede acceder al repositorio a través de redes, lo que le permite ser usado por personas que se encuentran en distintos ordenadores. A cierto nivel, la posibilidad de que varias personas puedan modificar y administrar el mismo conjunto de datos desde sus respectivas ubicaciones fomenta la colaboración. Se puede progresar más rápidamente sin un único conducto por el cual deban pasar todas las modificaciones. Y puesto que el trabajo se encuentra bajo el control de versiones, no hay razón para temer por que la calidad del mismo vaya a verse afectada —si se ha hecho un cambio incorrecto a los datos, simplemente se deshace ese cambio.[3]
7.2 Estructura de directorios
La estructura o arbol de directorios por defecto en svn esta compuesta de la siguiente manera:
- /trunk: Se utiliza para alojar el proyecto de desarrollo (co?digo fuente)
- /branch: En este caso, el branch es empleado para poder generar bifurcaciones en el proyecto, de forma tal de poder mantener dos o ma?s versiones que pudieran ser desarrolladas de forma independiente.
- /tag: Este directorio es utilizado cuando desea generarse una versio?n “estable” producto del desarrollo. En este caso, cada versio?n generada en el tag es una versio?n “congelada” del proyecto. Por lo general se utiliza este directorio para generar versiones estables que son instaladas en el cliente.
7.3 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.).[4]
7.4 Desventajas
- El manejo de cambio de nombres de archivos no es completo. Lo maneja como la suma de una operación de copia y una de borrado.
- No resuelve el problema de aplicar repetidamente parches entre ramas, no facilita llevar la cuenta de qué cambios se han realizado. Esto se resuelve siendo cuidadoso con los mensajes de commit. Esta carencia será corregida en la próxima versión (1.5).[4]
7.5 Algunos 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.
8. EJEMPLO PRÁTICO
Para este ejemplo práctico se utilizará el cliente de SVN en el IDE NetBeans y el repositorio alojado en googleCode.
8.1 Registro en googleCode
El primer paso para ejecutar nuestro ejemplo práctico es ir a la dirección Web de googleCode y hacer clic en «Project Hosting». Allí se nos llevará a la página principal de los hostings. Es de acotar que, parece un patrón de la gente de google, que oculten las opciones en las interfaces de usuario, por lo que la primera vez que se desea crear un nuevo proyecto es toda una proesa encontrar la opción. Por suerte ya he pasado por esto y puedo decirles como. Hacemos entonces clic en la opción «Search Open Source Projects» y en la siguiente página donde se nos redirige, abajo se encuentra el link «Create a New Project». Una vez realizado esto, los pasos siguientes son realitvamente sencillos, llenamos el formulario con los datos del proyecto y generamos el espacio.
Una vez generado el espacio, tal como se puede observar en la imagen de arriba, contamos con una serie de herramientas aparte del hosting y el subversion que complementan el manejo del proyecto en su parte colaborativa. Dichas herramientas son el Download, para gestionar documentos de relevancia para el proyecto(Historias de Usuario, documentos de arquitectura y otros artefactos), el wiki para colocar contenido dinámico, el Manejo de Incidencias (Issues) y la parte del código como tal, donde podemos observar las últimas versiones de los archivos que forman parte del código.
Continuando con nuestro ejemplo, el siguiente paso es ir a la pestaña Project Home->People y agregar los correos electrónicos de nuestro equipo de trabajo en tres distintos niveles de permosología(Dueño del producto, Equipo y Cliente). Una vez realizado esto, ya podemos empezar a aprovechar todas las ventajas que nos ofrece googleCode.
8.2 Importando el repositorio con NetBeans
8.3 Verificando repositorio con NetBeans
8.4 Operaciones de Commit y Update
Para utilizar las herramientas que provee el plugin de Netbeans de cara a Subversion, tenemos que hacer clic derecho en nuestro proyecto y marcar la opción: Subversion->mostrar cambios. Al realizar esto, se mostrará en la parte de abajo de la pantalla un recuadro como el que se encuentra en la imagen de abajo, desde donde se colocan los archivos que se van modificando o creando mostrados en verde o azul respectivamente. A la derecha y arriba se encuentran dos dibujos de repositorios con elementos, uno en verde y otro en amarillo. El verde es para las operaciones de commit y el amarillo para las operaciones de Update.
Cuando realizamos commit, se suben los cambios desde nuestra máquina al servidor de googleCode y cuando hacemos Update el proceso es inverso, se actualiza nuestra máquina con la última versión existente en los servidores de googleCode. Estas opciones se pueden realizar a nivel general para todo el proyecto o archivo por archivo. Es una buena práctica que tras cada operación de commit que se realize se deje un mensaje indicando los cambios de versión, a fin de que se lleve un registro de los cambios realizados en cada operación, para cuando se presenten posibles conflictos.
8.5 Los conflictos
8.5.1 Definición
Al actualizar nuestra copia local del repositorio cabe la posibilidad de que existan diferencias incompatibles entre el contenido de algún archivo local y su versión almacenada en el repositorio. Esto es lo que se denomina conflicto. A partir de la versión 1.5 de Subversion se informa inmediatamente al usuario de la existencia de un conflicto, proponiéndole diversas acciones a realizar en ese momento. Las herramientas gráficas para acceder al repositorio se suelen ejecutar en modo no interactivo, por lo que no se le propone al usuario ninguna acción inmediata.
8.5.2 Solución a los Conflictos
Tras actualizar nuestra copia local hemos obtenido un conflicto. Llegados a este punto, disponemos de tres posibilidades para resolverlo:
- Descartar nuestros cambios locales: Esta es la solución más fácil, aunque con ella perderemos el trabajo que hemos realizado en nuestra copia local, por lo que no se recomienda. Para llevarla a cabo desharemos nuestros cambios y luego actualizaremos de nuevo nuestra copia local.
- Descartar los cambios existentes en el repositorio:Esta solución tampoco se recomienda, ya que borraremos los cambios introducidos en la revisión existente en el repositorio. De todos modos, para llevarla a cabo tenemos que copiar nuestra versión sobre el original, e indicarle a Subversion que ya hemos resuelto el conflicto.
- Mezclar ambas versiones en una nueva: Esta es la única forma que se recomienda para resolver los conflictos generados al actualizar nuestra copia local del repositorio.Si intentamos abrir el archivo «xx.class» en Lokalize obtendremos un mensaje de error. Si queremos ver en qué consisten exactamente los conflictos que se han producido en dicho archivo, tendremos que echar mano de un editor de texto plano, como KWrite. El archivo «xx.class» contiene marcas que identifican dónde se ha producido un conflicto.
Por ejemplo:
#: rc.cpp:15 rc.cpp:30 <<<<<<< .mine #| msgid "Definition" ======= >>>>>>> .r1116691 msgid "Description:" msgstr "Descripción"
El principio del conflicto se marca con siete signos < seguidos. Lo que contiene nuestra copia de trabajo local se encuentra entre esta marca (a la que se añade la etiqueta .mine) y la de siete signos =, mientras que lo que contiene la copia del repositorio se encuentra entre estos signos = y la marca de siete signos > (a la que se añade el número de la revisión existente en el repositorio, .r1116691 en este caso).Como se puede observar en el ejemplo, este conflicto se ha producido porque la revisión con la que hemos estado trabajando localmente contenía un comentario antiguo (#| msgid «Definition») que ha sido eliminado en la revisión 1116691 que contiene el repositorio.
Resolver el conflicto significa decidir cuál de las dos posibilidades es la correcta. Para ello, en el editor de texto borramos las líneas que marcan el principio y el final delconflicto, así como la línea se signos = y el texto de la versión que no queramos que figure finalmente en el archivo.Procederemos del mismo modo para localizar y solucionar el resto de conflictos que pudieran existir en el archivo antes de guardarlo en nuestra copia local del repositorio.Finalmente, le indicaremos a Subversion que hemos terminado de resolver el conflicto:
8.5.3 Buenas prácticas para evitar conflictos
El método de trabajo más recomendable para evitar la aparición de conflictos en nuestra copia local pasa por actualizarla siempre justo antes de ponerse a trabajar en ella y justo después de terminar de trabajar. Tampoco conviene esperar mucho antes de enviar nuestro trabajo al repositorio: es preferible hacer poco trabajo y subirlo cuanto antes, a esperar varias semanas a tener todo traducido para enviarlo.
9. ALGUNOS COMANDOS POR CONSOLA
En lugar de trabajar con clientes, también se pudiese elegir trabajar directamente desde comandos de la consolo de Unix. Algunos de los comandos son los siguientes:
- Crear un repositorio nuevo:
svnadmin create nombre_repositorio
- Añadir un árbol de directorios al repositorio
svn import path_al_directorio nombre_repositorio
- Obtener una copia de trabajo
svn checkout file:///nombre_repositorio/dir directorio_de_trabajo
- Obtener una copia sin control de versiones
svn export file:///nombre_repositorio/dir directorio_destino
- Hacer una copia de seguridad de todo el repositorio
svnadmin dump nombre_repositorio > ficheroBackup
- Restaurar una copia de seguridad en un nuevo repositorio
svnadmin create nombre_nuevo_repositorio svnadmin load nombre_nuevo_repositorio < ficheroBackup
- Ver el estado actual de la copia de trabajo
svn status
- Añadir nuevos ficheros o directorios
svn add nombre_fichero
- Eliminar ficheros
svn del nombre_fichero --force
- Actualizar la copia de trabajo con los últimos cambios en el repositorio
svn update
- Actualizar el repositorio con los cambios de tu copia de trabajo
svn commit -m "Mensaje para etiquetar los cambios"
10. ENLACES DE INTERÉS
11. REFERENCIAS
[1] Collins-Sussman, Ben; Fitzpatrick, B.W. and Pilato, C.M. (2004). Version Control with Subversion. O’Reilly. ISBN 0-596-00448-6.
[2] Wingerd, Laura (2005). Practical Perforce. O’Reilly. ISBN 0-596-10185-6.
[3] Practical Subversion(2008), Second Edition, Daniel Berlin and Garrett Rooney, Appress
[4] http://es.wikipedia.org/wiki/Control_de_versiones
Excelente articulo!!! Felicitaciones y muchas gracias!!
Saludos.
muchas gracias Gustavo. Saludos!
I really like your writing style, superb info, thank you for posting :D. «God save me from my friends. I can protect myself from my enemies.» by Claude Louis Hector de Villars.