Node:Conceptos Básicos, Next:, Up:Una introduccion a CVS



Conceptos Básicos

Si nunca ha usado antes CVS (o ningún otro sistema de control de versiones), es fácil desconcertarse con algunas de las suposiciones que éste hace. Lo que parece causar más confusión inicialmente sobre CVS, es que se usa para dos cosas que aparentemente no guardan relación alguna: guardar registros, y al mismo tiempo hacer posible la colaboración. Sin embargo, se da el caso de que estas dos funciones están estrechamente relacionadas.

Se hizo necesario guardar registros porque las personas querían comparar el estado actual de un programa con el estado en el que encontraba en un momento dado en el pasado. Por ejemplo, en el transcurso normal de la implantación de una nueva función, un desarrollador puede llevar el programa a un estado en el que resulta inutilizable, estado que posiblemente perdurará hasta que la implantación de la nueva función esté casi hecha. Por desgracia, se da la casualidad de que éste suele ser precisamente el momento en el que alguien informa de un fallo en la última versión distribuida al público; para solucionar el problema (que podría estar también presente en la versión actual de las fuentes), el programa ha de volver de nuevo a un estado utilizable.

Restaurar un estado determinado es tarea fácil si el historial del código fuente se mantiene bajo CVS. El desarrollador puede simplemente decir: "Dame el programa tal como estaba hace tres semanas", o quizás, "Dame el programa en el estado en el que se encontraba en el momento de hacer nuestra última distribución pública". Si nunca ha disfrutado de este cómodo acceso a "fotografías" históricas, posiblemente se sorprenda de la rapidez con la que llegará a depender de él. En mi caso, personalmente ahora siempre uso control de revisiones en mis proyectos de programación, puesto que es algo que me ha salvado en multitud de ocasiones.

Para comprender cómo está ésto relacionado con la colaboración, deberemos observar con más detalle el mecanismo ofrecido por CVS para ayudar a muchas personas a trabajar en un mismo proyecto. Pero, antes de que lleguemos ahí, echemos un vistazo al mecanismo que CVS *no* proporciona (o que, por lo menos, no fomenta): el bloqueo de ficheros. Si ha usado algún otro sistema de control de versiones, quizás esté familiarizado con el modelo de desarrollo bloquear-modificar-desbloquear, en el que un desarrollador obtiene primero un acceso exclusivo de escritura (un bloqueo) sobre el fichero que va a editar, hace los cambios, y a continuación elimina el bloqueo para permitir que otros desarrolladores puedan acceder al fichero. Si alguien tiene un bloqueo establecido sobre un fichero, esa persona deberá "liberarlo" para que usted pueda bloquear el fichero y comenzar a hacer sus cambios (en algunas implantaciones usted podría "robarle" el bloqueo, pero con frecuencia esto viene a ser una desagradable sorpresa para la otra persona, ¡y en ningún caso una práctica aconsejable!).

Este sistema es factible cuando los desarrolladores se conocen, saben quién se propone hacer qué en un momento dado, y pueden comunicarse con los demás rápidamente en caso de que alguien no pueda trabajar por tener limitado su acceso. Sin embargo, si el grupo de desarrolladores se hace demasiado grande o no es posible una comunicación fluida entre ellos, gestionar cuestiones de bloqueo de ficheros comenzará a restar tiempo al desarrollo del código, para convertirse en un problema constante que puede ser contraproducente para el normal discurrir del proyecto.

CVS propone una solución intermedia: en lugar de obligar a los desarrolladores a coordinarse entre sí para evitar conflictos, CVS les permite editar el código de forma simultánea, asume la tarea de integrar todos los cambios, y guarda un registro de todos los conflictos que vayan surgiendo. El proceso utiliza el modelo copiar-modificar-fusionar, que viene a funcionar de la forma siguiente:

  1. El desarrollador A solicita a CVS una copia de trabajo, esto es, un árbol de directorios que contiene los ficheros que conforman el proyecto. Esta operación es también conocida como "obtener una copia" (comando "checkout"), y es como tomar un libro prestado de una biblioteca.
  2. El desarrollador A edita libremente su copia de trabajo. Al mismo tiempo, otros desarrolladores pueden estar atareados con sus propias copias de trabajo. Puesto que todas son copias separadas, no hay interferencias: es como si todos los desarrolladores tuvieran su propia copia del mismo libro, y todos estuvieran trabajando anotando comentarios en los márgenes o reescribiendo determinadas páginas de forma independiente.
  3. El desarrollador A termina sus cambios y los envía (comando "commit") a CVS junto con un informe de cambios, que es un comentario que explica la naturaleza y propósito de los cambios que ha realizado. Esto es el equivalente a informar a la biblioteca de los cambios que ha hecho al libro y el porqué de los mismos. Entonces, la biblioteca incorpora estos cambios a la "copia maestra", donde se guardan de forma permanente.
  4. Mientras tanto, y también por medio de CVS, otros desarrolladores pueden consultar a la biblioteca para ver si la copia maestra ha cambiado recientemente, en cuyo caso CVS actualizará automáticamente sus copias de trabajo personales. (Esta parte es mágica y maravillosa, y espero que sepa apreciarla. ¡Imagine lo diferente que sería el mundo si los libros de verdad funcionasen de esta forma!)

Por lo que concierne a CVS, todos los desarrolladores de un proyecto son iguales. La decisión de cuándo actualizar o cuándo enviar al almacén es un tema de preferencias personales o de política establecida entre los miembros que participan en el proyecto. Una de las estrategias más comunes para proyectos de programación es la de siempre actualizar antes de empezar a trabajar en un cambio importante, y enviar los cambios sólo cuando éstos hayan sido finalizados y probados, a fin de que la copia principal se mantenga en todo momento en un estado "ejecutable".

Quizás se esté preguntando lo que ocurre cuando los desarrolladores A y B, cada uno trabajando en su copia de trabajo personal, hacen distintos cambios al mismo trozo de texto y después ambos envían sus cambios. Esto se conoce como conflicto, y CVS se percata del mismo en cuanto el desarrollador B intenta enviar sus cambios: en lugar de permitir que el desarrollador B proceda, CVS anuncia que ha descubierto un conflicto y coloca marcadores de conflicto (marcas de texto fácilmente reconocibles) en el lugar de su copia local donde se ha descubierto el conflicto. En ese lugar se mostrarán ambos paquetes de cambios, convenientemente ordenados para hacer fácil su comparación. El desarrollador B deberá entonces solucionar el problema y enviar una nueva revisión con el conflicto resuelto. Quizás los dos desarrolladores deban hablar entre ellos para solucionar el problema; CVS sólo avisa a los desarrolladores de que hay un conflicto, dejando bajo su responsabilidad la tarea de resolverlo.

¿Y qué hay de la copia maestra? En terminología oficial de CVS, se la conoce como "repositorio" del proyecto, y es simplemente un árbol de ficheros guardado en un servidor central. Sin entrar en mucho detalle sobre su estructura (pero lea Administracion del Repositorio), veamos lo que el repositorio debe hacer para cumplir con los requisitos del ciclo copiar-enviar-actualizar. Considere el siguiente caso:

  1. Dos desarrolladores, A y B, obtienen una copia de trabajo de un proyecto al mismo tiempo. El proyecto se encuentra en su punto de partida: nadie ha hecho todavía cambio alguno, así que todos los ficheros están todavía en su estado original e impoluto.
  2. El desarrollador A empieza de inmediato a trabajar, y pronto envía su primer paquete de cambios.
  3. Mientras tanto, el desarrollador B está viendo la televisión.
  4. El desarrollador A, trabajando como si el mundo se acabase al día siguiente, envía su segundo paquete de cambios. En este momento, el historial del repositorio contiene los ficheros originales, seguidos por el primer paquete de cambios introducidos por A, que a su vez han ido seguidos por estos últimos cambios.
  5. Mientras tanto, el desarrollador B está jugando a su videojuego favorito.
  6. De pronto, el desarrollador C se une al proyecto y obtiene su copia de trabajo del repositorio. La copia del desarrollador C refleja los dos primeros paquetes de cambios de A, puesto que ya estaban en el repositorio cuando C obtuvo su copia.
  7. El desarrollador A, que ha estado programando como un poseso, completa y envía su tercer paquete de cambios.
  8. Por último, e ignorando la actividad frenética habida recientemente, B decide que es hora de empezar a trabajar. No se molesta en actualizar su copia; simplemente comienza a editar ficheros, algunos de los cuales pueden ser ficheros en los que A ha estado trabajando. Un poco más tarde, el desarrollador B envía sus primeros cambios.

Llegados a este punto, pueden suceder dos cosas. Si ninguno de los ficheros editados por B han sido editados por A, el envío tiene éxito. Sin embargo, si CVS percibe que algunos de los ficheros de B están pasados de fecha con respecto a las últimas copias disponibles en el repositorio, y todos esos ficheros han sido también cambiados por B en su copia de trabajo, CVS informa a B de que debe hacer una actualización antes de enviar estos ficheros.

Cuando el desarrollador B efectúa la actualización, CVS reune todos los cambios realizados por A en la copia local de los ficheros de B. Parte del trabajo de A puede entrar en conflicto con los cambios no enviados por B, mientras que otros pueden no hacerlo. Aquellas partes que no lo hacen son simplemente aplicadas en las copias de B, sin más, pero los cambios que supongan un conflicto deberán ser resueltos por B para poder ser enviados.

Si el desarrollador C efectúa ahora una actualización, recibirá del repositorio algunos cambios nuevos, que serán aquéllos pertenecientes al tercer envío de A, y los pertenecientes al primero con éxito de B (que en realidad podrían proceder del segundo intento de B de enviar, asumiendo que el primer intento de B tuviese como resultado el que B se viera obligado a resolver algún conflicto).

Para que CVS pueda servir los cambios en la secuencia correcta a los desarrolladores cuyas copias de trabajo puedan no estar sincronizadas en mayor o menor grado, el repositorio necesita guardar todos los envíos recibidos desde el comienzo del proyecto. En la práctica, el repositorio de CVS los guarda todos en ficheros de diferencias (también llamados "diffs") sucesivos. Así pues, incluso para una copia de trabajo muy antigua, CVS es capaz de establecer las diferencias entre la copia de trabajo y el estado actual del repositorio, y es por tanto capaz de actualizar la copia de trabajo de una forma eficiente. Esto hace que los desarrolladores puedan en cualquier momento revisar fácilmente el historial del proyecto, y conseguir copias de trabajo tan antiguas como sea necesario.

A pesar de que, estrictamente hablando, el repositorio podría conseguir los mismos resultados por otros medios, en la práctica guardar ficheros de diferencias es una forma simple e intuitiva de implantar la funcionalidad necesaria. Además, este método tiene la ventaja añadida de que, usando apropiadamente el programa "patch", CVS puede reconstruir cualquier estado previo del árbol de ficheros y, por tanto, llevar una copia de trabajo de un estado a otro. Esto permite que cualquiera pueda obtener una copia del proyecto tal y como era en un momento determinado, a la vez que permite mostrar las diferencias, en formato diff, entre dos estados del árbol sin afectar a la copia de trabajo de nadie.

Por lo tanto, las mismas funcionalidades que son necesarias para dar un útil acceso al historial del proyecto también resultan útiles para proporcionar a un grupo de desarrolladores descentralizado y descoordinado la posibilidad de colaborar en el proyecto.

Por ahora, puede ignorar todos los detalles de cómo configurar un repositorio, administrar el acceso a los usuarios, y navegar por formatos de fichero específicos de CVS (los cuales se cubrirán en Administracion del Repositorio); de momento, nos centraremos en cómo hacer cambios en una copia de trabajo.

Pero antes, aquí va una rápida explicación de los términos: