Mostrando entradas con la etiqueta ramas. Mostrar todas las entradas
Mostrando entradas con la etiqueta ramas. Mostrar todas las entradas

sábado, agosto 16, 2014

PlasticSCM: ¿Qué es nivelar un rama?

Por: Fernando D. Bozzo

En un SCM o en un DVCS trabajar con ramas es algo de todos los días.

Se suelen hacer ramas por tarea para poder trabajar en cada tarea de forma independiente, también se hacen ramas por release, de las que cuelgan las ramas de las sub-tareas que la conforman, también podemos tener a uno o más desarrolladores en cada tarea, donde cada uno tiene su propia rama de trabajo, y finalmente está la rama principal (main o trunk) de donde cuelga todo lo anterior.



Nivelación de ramas


La nivelación de ramas es el mecanismo que se usa para actualizar una rama que tiene un ritmo de actualización menor o distinto a otras ramas, y que se hace mediante la operación de merge o de cherry pick.


Un ejemplo:
Si dos o más personas trabajan en una misma petición o tarea, cada uno haciendo una parte específica de la misma (por ej, uno hace la parte visual y otro el acceso a datos y la lógica de negocio), uno no ve lo que hacen los otros y ninguno tiene todo lo de todos, entonces lo que se hace es que todos combinan sus cambios en la rama de la tarea mediante el merge y luego cada uno nivela su rama con el trabajo de los demás desde la propia tarea.


En la siguiente imagen, se puede observar una tarea TESTS en la que trabajan 2 desarrolladores, DEV_1 y DEV_2, trabajando cada uno en su rama, como se detalló antes, y ocurre la siguiente secuencia de eventos, irando de izquierda a derecha:

1. DEV_1 hace un merge desde su rama de trabajo /main/DEV_1 hacia la rama de la tarea TESTS (flecha verde ascendente), que será automático por ser el primero

2. DEV_2 hace un merge desde su rama de trabajo /main/DEV_2 hacia la rama de la tarea TESTS (flecha verde descendente)

3. En este punto, la rama de la tarea TESTS tiene la suma de los cambios de DEV_1 y DEV_2, por lo que DEV_2 ahora hace una nivelación en su propia rama (flecha verde ascendente) teniendo así los cambios de DEV_1

4. DEV_1 hace lo mismo, y nivela su rama con los cambios de TESTS (flecha verde descendente) mediante un merge, por lo que al terminar tendrá todo lo que hizo el compañero DEV_2

5. DEV_1 termina sus cambios y hace merge en TESTS (flecha verde ascendente)

6. DEV_2 termina sus cambios y hace merge también en TESTS (flecha verde descendente)

7. Finalmente, la tarea TESTS se integra en /main (flecha verde ascendente)





Técnicas de nivelación de ramas


Cuando se hacen merges o nivelaciones, siempre se debe buscar actualizar lo más nuevo sobre lo antiguo y nunca al revés, ya que es más fácil pensar integrar "lo que se agregó nuevo" que hacer el razonamiento y la operación opuesta.

El siguiente es un ejemplo típico de una Release, donde la v1.0 está en Producción (o en el cliente), se está trabajando en la próxima Release v2.0 y en medio hay que sacar un parche v1.1 urgentemente.

La secuencia de eventos es la siguiente:

1. Partiendo de la v1.0 de la primera etiqueta circular verde, salen tanto la rama de la próxima release_2 como la rama del parche v1.1

2. El parche se desarrolla y se integra con un merge sobre la v1.0, lo que crea un nuevo changeset que se etiqueta como v1.1 en segunda etiqueta verde

3. Luego, en vez de integrar este mismo parche sobre la rama de la release_2, se crea una subrama de nivelación desde la v1.1 de arriba (1), se le hace un merge desde la rama de la release_2 (2) para agregar todo lo nuevo, y finalmente se hace la nivelación de la rama release_2 desde la rama_de_nivelación que ya contiene el parche aplicado (3)


De esta forma se maximiza la posibilidad de que los merges que se hacen sean automáticos, ya que de la otra forma (aplicando el parche sobre la release_2) es más probable que haya que hacer merge manual.



Aunque a primera vista pueda parecer un poco complejo, realmente no lo es una vez que se comienza a practicar.


Hasta la próxima!

martes, marzo 25, 2014

Control de Código Fuente: Terminología común que hay que conocer

Por: Fernando D. Bozzo

Esta entrada fue motivada por las inquietudes de algunos de ustedes durante las pruebas que hicimos en marzo 2014, y que me recordaron que en este tema hay términos de uso común que el que recién comienza no domina (obviamente), y por eso quiero hacer una breve reseña de los términos más usados y de lo que significan, y que iré completando a medida que me hagan nuevas preguntas sobre "¿qué significa tal término?".

Para facilitar las cosas, pondré alguna imagen cuando sea necesario y relacionaré los términos con los de FoxPro cuando pueda aplicarse.



Workspace


El workspace, que se traduce como "espacio de trabajo", es un alias que se le asigna a un directorio. Así como en FoxPro podemos usar un alias para usar una tabla bajo otro nombre, donde el alias "clientes" apunta a "c:\un-directorio\clientes.dbf", el workspace es eso mismo, pero aplicado a un directorio, de modo que si creamos un workspace llamado "dvcs_vfp9" para referirnos al directorio "c:\desa\tests\dvcs_vfp9", realmente estamos creando ese alias para que sea más fácil de manejar en Plastic, ya que es más cómodo mostrar un alias significativo en una de las solapas superiores que todo el nombre de un directorio, lo que dejaría poco lugar para las solapas de otros workspaces. De modo que hablar de "workspace" y de "directorio de trabajo" es lo mismo.

Vista del workspace "vfp_test_grupo" y el directorio que representa en Plastic





Checkin y Checkout



Check-in significa algo así como "verificar o realizar entrada", que es lo opuesto a Check-out, que es "verificar o realizar salida". Tanto la entrada como la salida se refiere a archivos, entrada o salida de archivos, o lo que es lo mismo, enviar/subir (checkin) o recuperar/bajar (checkout) archivos al servidor del Control de Código fuente.

El paralelismo con FoxPro sería el buffering de tablas, donde uno agrega, elimina o modifica registros en vez de archivos, en cualquier momento se pueden comprobar qué registros han cambiado con GetFldState (en Plastic se revisa la vista de Cambios Pendientes que actúa sobre los archivos del workspace) y luego se confirma la grabación de los mismos con TableUpdate (equivale al Check-in) o bien se pueden deshacer todos los cambios usando TableRevert (en Plastic equivale a "Deshacer Cambios"). El Checkout en Plastic solo es un estado que indica si un archivo está marcado para modificar o no. En otros SCM el checkout es la operación que se baja la última versión de un archivo al workspace, pero en Plastic esto se hace seleccionando un workspace por su solapa, o eligiendo "Actualizar workspace" en la vista de Items, o con el comando cm getfile en una ventana de comandos DOS.



Hacer un "Diff"


Versión corta: Hacer un Diff es buscar y mostrar las "Diferencias" (Differences en Inglés) entre dos archivos. Se usa para saber qué líneas o bloques de código se han cambiado entre dos versiones de un programa, por ejemplo trabajamos un rato en un programa, donde vamos guardando los cambios cada tanto (con checkin) y luego queremos ver los últimos cambios visualmente (a diferencia de tener que recordarlos)
Para la versión larga aplicada a Plastic, leer este artículo.



Hacer un "Merge"


Versión corta: Hacer un Merge es realizar la mezcla de las modificaciones hechas por separado a un mismo programa, para volver a tener un solo programa que tenga todos los cambios. Si yo tengo un programa copiado en dos directorios, a una copia le agrego un método "A" y a la otra copia le agrego un método "B", el merge sería tomar el programa original y agregarle los métodos "A" y "B".
Para la versión larga aplicada a Plastic, leer este artículo.



Cherry Pick


Versión corta: Es un tipo de Merge que permite seleccionar changesets o ramas específicas, sin incluir el resto de archivos heredados.
Para la versión larga aplicada a Plastic, leer este artículo.



Rama


Una rama es una línea paralela de trabajo, una copia completa del workspace (o directorio del proyecto) en la cuál poder trabajar sabiendo que a la copia original no la afectamos en lo más mínimo.
Una rama está compuesta por uno o más changesets.
En la práctica es como hacerse una copia del sistema en otro directorio y trabajar en él para, al terminar, pasar los cambios al directorio original.

Para la versión larga aplicada a Plastic, leer este artículo.

Imagen de la rama v1.19.17 de FoxBin2Prg con 4 changesets y una etiqueta de versión




Repositorio


En Plastic un repositorio es una base de datos (archivos de SQL Server, MySQL, etc) que contienen un grupo de tablas y esquemas que contendrán los archivos y relaciones que se hagan entre ellos.

Los archivos contenidos serán los que nosotros "subamos" al control de código, mediante las opciones "Agregar al control de código" o mediante los "checkin", y que también se pueden marcar opcionalmente como modificables con un checkout.

Normalmente se usa un repositorio por cada proyecto.



Changeset


"Changeset" significa "juego de cambios" o "conjunto de cambios", y se usa para identificar las operaciones de agregado, borrado o modificación hechos a uno o varios archivos que luego se guardan con checkin.
En Plastic se puede ver el contenido de las operaciones de un changeset haciendo doble click sobre uno de ellos.

Ejemplo de las operaciones contenidas en un changeset (archivos Movidos, Borrados y Añadidos):




Lista de archivos ignorados (ignore.conf)


Los archivos ignorados son aquellos archivos Privados que no nos interesa ver en la vista de Items de Plastic para mantenerla más despejada y poder enfocarnos en los archivos que sí nos interesa controlar. Es un filtro, un archivo de texto que contiene una lista de archivos o especificaciones de archivo donde generalmente se suelen anotar los .tmp (temporales), .fxp (compilados), .bak (backups), y demás archivos que no queramos ver.

Ejemplo de parte de un ignore.conf:

*.FXP
*.LNK
!/_iniciar aqui.lnk
*.SCC
*.TMP
*.BAK
*.ZIP
*.7Z

foxuser.dbf
*/FXUResults.*




Detalle de la especificación: 


En el ejemplo anterior tenemos los 4 tipos de ignore soportados, que se interpretan como un filtro con la función LIKE() en FoxPro:
  • La extensión sola (ej: *.FXP): Se ignoran todos los .fxp dentro del workspace, incluyendo subdirectorios
  • Un nombre de archivo (ej: foxuser.dbf): Se ignora el archivo indicado dentro del workspace, incluyendo subdirectorios
  • Un directorio con especificación de archivo (ej: */FXUResults.*): Se ignora el archivo dentro del directorio indicado. La raíz del workspace siempre es "/", que como se ve no es la contrabarra de Windows, sino el signo dividido que se usa en Linux y Mac para los directorios, ya que Plastic es multiplataforma
  • Una excepción a la regla (ej: !/_iniciar aqui.lnk): Este tipo realmente actúa como "anti-filtro" y es muy útil en los casos en los que tenemos definido un filtro, pero no queremos que se aplique en un directorio en particular. En el ejemplo dado se ignoran todos los accesos directos (*.lnk), pero se exceptúa de esta regla a un archivo en particular que está en la raíz y que se usa para abrir una sesión de FoxPro


Lista de archivos cloaked (cloaked.conf):


Los archivos cloaked son aquellos archivos controlados por Plastic, donde no nos interesa que se vuelvan a descargar o actualizar desde la base de datos.
Su uso habitual es para evitar que algunos archivos pesados (como un DBF con datos o un binario) se descarguen cada vez que actualizamos el workspace o nos cambiamos de changeset.
Se usa mucho en la industria del videojuego, donde ciertos mapas de textura pueden tener cientos de MB que tardarían un buen rato en descargarse y que al programador no le aporta nada para sus pruebas.

En FoxPro, un buen caso de uso podría ser el archivo "/_iniciar aqui.lnk" del ejemplo anterior, donde por un lado nos interesa controlarlo con Plastic para que todos los programadores se lo puedan descargar y que luego cada uno lo pueda personalizar según dónde tenga instalado FoxPro, poniéndolo en el cloaked.conf para que no se le vuelva a descargar y se pierda su configuración particular.

La especificación de archivos es la misma que para los ignorados.



Lista de cambios ocultos (hidden_changes.conf):


Los "cambios ocultos", como podría llegar a deducirse, son los archivos controlados por Plastic que no queremos ver en la vista de Cambios Pendientes aunque hayan sido modificados.
Un ejemplo podría un archivo LOG que se protegió inicialmente vacío, pero que suele cambiar frecuentemente y cuyo contenido no nos interesa que se guarde en la base de datos.

La especificación de archivos es la misma que para los ignorados.




Nivelar una rama


Nivelar una rama significa actualizarla con el contenido más actualizado de otra rama, y se hace tomando el contenido de otra rama (origen) y haciendo un merge sobre la rama a nivelar (destino).

Para nivelar una rama se debe estar ubicado sobre ella, en el último changeset más actualizado (en Plastic es donde se debe ubicar la casa)

Para la versión larga aplicada a Plastic, leer este artículo.



Si creen que faltan términos, me comentan y los voy agregando.


Saludos!



domingo, marzo 16, 2014

PlasticSCM: Cómo trabajar en FoxPro 9 con ramas por tarea

Por: Fernando D. Bozzo

En esta ocasión vamos ver una forma de trabajar con ramas, que sirve tanto para uno como para varios desarrolladores. Si no sabes lo que es una rama, antes de seguir te convendría leer el artículo anterior sobre este tema: PlasticSCM: Cómo crear una rama para comenzar a trabajar


La norma básica a seguir es muy simple: Jamás hacer cambios en la rama principal!. Nunca!


(Bueno, las únicas excepciones son el primer add/checkin con un archivo README.txt, que recomiendo absolutamente, y la subida del proyecto FoxPro 9, que será el segundo add/checkin)

A partir de quí, lo único que se debe hacer en la rama Principal es el merge final de las demás ramas para etiquetar la versión. Todo el trabajo se debe hacer en ramas derivadas de la principal.

Antes de continuar un aviso: Para todo lo que sigue voy a asumir que la estructura de directorios de tu proyecto está encapsulada de forma que en la raíz está el proyecto (pjx) y el programa principal, y en los subdirectorios están los componentes, y que no se referencian componentes externos a esta estructura de directorios, por ejemplo apuntando a otra aplicación o ubicación de librerías como las FFC de FoxPro. Si esto no se cumple entonces no podrás obtener todas las ventajas de trabajar con control de código por las dependencias externas que tengas y tal vez de convendría leer antes: Crear un proyecto FoxPro: ¿por dónde comenzar?


Pasos a seguir para comenzar a trabajar con un proyecto nuevo


En este caso tenemos un proyecto FoxPro 9 que se crea desde cero y que desde el mismo inicio se pone bajo control de código.






Cómo agregar un proyecto existente al control de código para trabajar


Este es el caso típico para muchos desarrolladores que tienen proyectos hechos, y que ahora deciden meterlos en control de código para continuar trabajando de esta forma.
Los pasos para agregar un proyecto FoxPro existente al control de código está explicado en este artículo.
Para comenzar a trabajar con este proyecto FoxPro ya controlado, ver el siguiente punto.


Pasos a seguir para comenzar a trabajar con un proyecto existente


En este caso tenemos un proyecto FoxPro 9 que ya estaba bajo control de código fuente previamente, por lo que los nuevos desarrolladores solo deben unirse para tener lo último, crearse sus ramas y comenzar a trabajar en ellas, por lo que deben:
  • Crear el directorio en el disco donde se alojará el proyecto FoxPro 9 (ojo, el directorio vacío!)
  • Crear el repositorio Plastic para el proyecto
  • Crear el workspace asociado al directorio para poder actualizar el repositorio
  • Sincronizar el repositorio Plastic local con el repositorio remoto (esto se bajará el proyecto con archivos y directorios)
  • Crear una rama personal de desarrollo desde el último changeset de la rama Principal
  • Ya se puede comenzar a trabajar en la rama de desarrollo

Ejemplo de la rama de desarrollo v1.19.17 de FoxBin2Prg, que se creo a partir de la última versión v1.19.16 (círculo verde) de la rama Principal /main. Al finalizar se hará merge de la v1.19.17 de desarrollo en la rama principal nuevamente y se etiquetará la nueva versión como v1.19.17



Trabajo en ramas cuando se trabaja en solitario


Este caso es el que uso para trabajar en FoxBin2Prg, y es el modo de trabajo mínimo recomendado.

Se basa en tener:
  • La rama principal (/main) donde solo se hará merge y se etiquetarán las versiones
  • La rama secundaria para desarrollar
  • Alguna rama puntual para solucionar incidencias solamente

Pantallazo de un momento del historial de FoxBin2Prg
(click en la imagen para agrandarlo):


Como puede verse en la captura anterior, en la versión v1.15 de la rama principal hice una rama secundaria de desarrollo para trabajar en el soporte de los menús (MNX) que llamé "Soporte_MNX" (la tarea a realizar) y que luego se convertiría en la versión v1.16.

Mientras estaba trabajando en esta tarea descubrí un error en el soporte OLE de los forms y clases, lo que debía arreglar y promocionar cuanto antes, pero sin incluir nada del nuevo desarrollo. Y es en ese momento que abro una nueva rama desde la v1.15 para hacer el parche v1.15p1
Se puede ver gráficamente que con el arreglo hecho en ese parche (un solo changeset) luego hice un merge en la rama principal, que hizo la versión v1.15p1 pública y también hice un merge en la rama de desarrollo del Soporte_MNX, ya que de otra forma si no lo hiciera así, en la siguiente versión estaría incorporando nuevamente el error que había solucionado.

Al finalizar el trabajo en esta tarea, hice el merge final en la rama principal, que etiqueté como v1.16 pública e hice una nueva rama para comenzar a trabajar en el soporte para Proceso en modo Batch. En este punto Fidel Charny me reportó una incidencia sobre el posicionamiento del menú, pero esta vez en vez de crear una rama aparte para el parche, lo mezclé en la tarea actual, en el segundo changeset de "ProcesoEnModoBatch" y liberé todo junto al día siguiente como versión v1.17. Esto lo hice así porque tanto el desarrollo de la tarea como el parche los hice en un corto período de tiempo (1 día) y no valía la pena separarlos en versiones distintas.

Sobre la conveniencia de crear un parche y versionarla por separado solo con los arreglos o hacer los arreglos dentro de la rama de desarrollo para sacar todo junto en la siguiente versión, todo depende del tipo de desarrollo que se esté haciendo y de los tiempos que se manejen.

Para un programa como FoxBin2Prg, cualquiera de las dos formas de trabajo es válida porque es un conversor y no un aplicativo comercial, y en este caso el baremo que usé es de fechas: Si el desarrollo que estaba haciendo iba para largo y surgía algún reporte de bugs en medio, no podía dejar colgados a todos con el error hasta que termine el desarrolo actual, por lo que lo conveniente era sacar y versionar un parche por separado para luego poder seguir con el desarrollo actual. Pero si el desarrollo iba a ser rápido y surgía algún reporte de fallo, entonces sí hacía el arreglo en la rama de desarrollo actual y versionaba todo junto.

Como ahora el desarrollo de FoxBin2Prg esta terminado, está en etapa de mantenimiento, por lo que las ramas que se hacen son para corregir fallos e incorporar optimizaciones.


Trabajo en ramas cuando se trabaja en equipo


Cuando se trabaja en equipo, el desarrollo es similiar a trabajar en solitario, con la diferencia de que habrá una rama por cada desarrollador, y que en general los desarrolladores harán el merge en una rama de Integración, que en el ejemplo de la imagen de abajo es /main/TESTS, y en esa rama es donde irán integrando funcionalidades terminadas.

En esta rama de Integración no se deben subir cambios incompletos nunca, ya que esta rama debería ser lo bastante estable como para que el resto de desarrolladores puedan actualizar sus propias ramas desde la misma, con bastante seguridad en que no comenzarán a tener errores provocados por una subida inconclusa o errónea.

Convendría que se defina la figura del Integrador Principal, que sería la persona a cargo de hacer la revisión final del código que se integrará y los merge de las ramas de Integración en la rama principal una vez concluida la revisión. Esta figura es muy importante en el ciclo de desarrollo, ya que tiene la responsabilidad de integrar todos los desarrollos en la rama principal.

Durante esta revisión, el Integrador inspecciona las diferencias en el código de la rama de Integración (no en la rama de cada desarrollador!) usando la herramienta de Diff, para buscar posibles problemas o cosas mejorables y detectarlas antes de que se suban a la release definitiva en la rama Principal.


Pantallazo de un proyecto con su rama principal, su rama de Integración y dos desarrolladores Dev_1 y Dev_2:


Sobre esta forma de trabajar, ya había publicado un video.

Como puede verse en la imagen de arriba, cada desarrollador va trabajando en su rama y cuando tiene una funcionalidad terminada puede hacer una de dos opciones:

  • La integra con un merge en la rama de Integración, y acto seguido se actualiza su propia rama desde la de Integración para tener el trabajo de los demás. (Se puede ver que Dev_1 hizo esto en los dos primeros changesets)
  • O se baja primero lo de la rama de Integración en la rama propia con un merge y luego, con todo ya intgrado en su rama, hace otro merge en la rama de Integración desde la propia. (se puede ver que Dev_2 hizo esto en su segundo y tercer changeset)
Como recomendación personal, yo creo que la segunda forma de integrar es la mejor y más segura, ya que cada uno se está Integrando en la rama propia lo que hay en la rama de Integración, con lo cual si surgieran conflictos, se resolverían en la propia rama y no se afectaría a nadie si esto se hiciera mal. Además de que esto permite que una vez realizada esta actualización local se puedan probar los cambios integrados y corregir posibles errores antes de hacer el merge nuevamente en la rama de Integración, y así se tiene cierta seguridad sobre lo que se sube, ya que en el peor caso, si surgen errores en las pruebas locales (rama propia), nadie más estará afectado aunque se actualice desde la rama de Integración.

Si se hiciera al revés (merge a Integración y posterior merge a rama propia), se corre el riesgo de que se haga algo mal durante la Integración dejando esta rama inestable, y el problema es que, aunque se detecte en las pruebas posteriores, como esta rama es pública para el resto de desarrolladores, un error puede provocar que los demás que se actualicen se les propague a sus propias ramas antes de que se pueda corregir el error, lo que puede tomar un buen rato.



Trabajo en ramas con sistemas complejos y varios desarrolladores


Este escenario es similar al anterior, pero en este caso pueden haber varias ramas intermedias para distintas funcionalidades simultáneas, lo que crea un diagrama más complejo, y en el que la figura del Integrador Principal es imprescindible, ya que es quien debe conocer qué desarrollos deben integrarse en la versión actual o cuáles son para la próxima versión.

La siguiente imagen es una simulación de lo que puede ser un sistema complejo, formado por dos proyectos cortos, cada uno con dos desarrolladores, en los que se harán dos funcionalidades distintas que confluirán en la rama de Integración y de ahí a la rama principal en la versión etiquetada como v2.0, y de un proyecto a medio plazo, también con dos desarrolladores, que se va actualizando con la release principal, pero que todavía debe continuar desarrollando y por eso no hace merge en la principal.

(Click en la imagen para agrandar)


Cuando ese proyecto de mediano plazo se deba integrar, se deberá crear primero una nueva rama de Integración que salga de la última release disponible (por ej: de la v4.0), y deberá integrar sus cambios allí para poder realizar pruebas y certificar el funcionamiento, antes de que se integre en la rama Principal.



Recomendaciones finales


Como se ve, dependiendo del tipo de proyecto a realizar, el trabajo en ramas ayuda mucho si se usa adecuadamente. Dejo algunas recomendaciones para tener en cuenta, que están basadas en las buenas prácticas y en la experiencia de varios proyectos durante bastante tiempo:

  • En los componentes usar rutas relativas, nunca rutas absolutas. Esto permitirá que el proyecto sea portable e independiente de la ruta que se use para trabajar
  • Para un proyecto compartido conviene predefinir y usar el mismo directorio entre desarrolladores para evitar diferencias en el pjx, que si no a cada desarrollador le detectará un directorio distinto, el cuál aceptará y esto generará una nueva diferencia innecesaria
  • Hacer uso extensivo de las buenas prácticas de programación (encapsulación, refactorización, etc).
  • Como mínimo se debería respetar una nomenclatura de objetos, como la sugerida por la ayuda de FoxPro. Esto no solo permite que el código se auto-documente, sino que facilita los merge manuales y maximiza los automáticos que no requieren intervención
  • Usar FoxPro desde el directorio raiz del proyecto (workspace) y no cambiar la sesión a otros directorios (set default to <dir> o cd <dir>) ya que esto puede provocar problemas y bloqueos en el SCM cuando se quiera hacer un checkin o cambiar a otro changeset
  • Cerrar siempre los forms, proyectos, clases y programas abiertos, y hacer CLEAR ALL antes de ir al SCM a realizar alguna tarea.
  • Un bloqueo en algún archivo controlado por el SCM puede provocar un error en el checkin o que impida poder regenerar las versiones texto o binario con FoxBin2Prg y que en consecuencia se suban archivos des-sincronizados entre sí, como un binario sin su tx2 o viceversa

Hasta la próxima!


viernes, marzo 07, 2014

PlasticSCM: Hice un checkin erróneo de un archivo nuevo ¿cómo lo arreglo?

Por: Fernando D. Bozzo

A todos nos puede pasar que estamos trabajando en algo, y en un momento dado queremos proteger los cambios, entonces vamos al SCM, elegimos los archivos y hacemos checkin.... pero luego nos damos cuenta de que cometimos un error, ¿cómo lo arreglamos?

   Si el error detectado es de capitalización de un archivo recién agregado, pero al cual todavía no hicimos checkin, es muy fácil: Ir a la ventana de Cambios Pendientes y seleccionar el botón "Deshacer cambios". Problema resuelto, se soluciona el problema de capitalización haciendo la conversión texto/binario que ya comenté en el punto 3 y 4 de la otra nota, y se repite el proceso de agregar el archivo.

   Si el error detectado es de capitalización de un archivo agregado y que además se le hizo checkin, entonces habrá que hacer una copia del mismo (en un zip por ejemplo) y eliminar el último changeset creado, así:


1) Seleccionamos el changeset anterior con click-derecho:


2) Elegimos la opción "Apuntar workspace a este changeset":



2.b) ¿Muestra un error?: Si les muestra un error como el de la imagen, pueden elegir entre las opciones que ven en la imagen, y que ahí mismo están explicadas:




3) Hacemos click-derecho en el changeset a borrar (siempre es el último) y elegimos "Borrar changeset":


4) Y listo, el changeset fue borrado y el nuevo changeset actual es el anterior:


5) Finalmente, como se ha borrado un changeset que en este caso consistía en archivos agregados al SCM, esto implica que Plastic los borrará del directorio de trabajo, y por eso hicimos el ZIP en un paso anterior. Simplemente se vuelven a descomprimir los archivos, se procesan con FoxBin2Prg (solo si son binarios Fox) pasándolos a texto y binario nuevamente, se comprueba la capitalización y se vuelven a agregar al control de código.


Esto también se puede hacer cuando se protege un cambio que no se quiere guardar, pero lo ideal es solo hacer el checkin cuando se tiene certeza de que lo que se sube es correcto.


Video de ejemplo:

FoxPro 9: Deshacer Merge de 2 ramas en PlasticSCM




Importante:
Para evitar estos inconvenientes, es mejor verificar visualmente la capitalización de los archivos justo antes de que se vayan a proteger, y no olvidar que cualquier form, clase, etc, que se haya modificado, se debe pasar primero a texto y luego del texto se debe pasar a binario otra vez, ya que en estos pasos también se hace el ajuste de la capitalización.

Otra cosa a estar atento es no subir cualquier archivo, es decir, el control de código fuente (SCM) es justamente para eso, para controlar los archivos de programa que hacemos, y no para proteger los archivos temporales (tmp) o los backup (bkp) u otro tipo de archivos que no tienen nada que ver con nuestro desarrollo.

Incluso es conveniente guardar la versión texto de las tablas (archivos DB2) y bases de datos (archivos DC2) generados con FoxBin2Prg, pero no guardar las tablas con datos, porque si no el espacio destinado para el código se agotaría bastante rápido. Recordar que todo esto se guarda en una base de datos de Plastic que se puede elegir entre la que viene por defecto  y que sirve para pequeños desarrollos o desarrollos personales (SQL Server CE - 4 GB por repositorio/proyecto), u otras bases de datos más potentes como SQL Server full, MySQL, Oracle u otras.


Nota Relacionada:
FoxPro 9 y PlasticSCM: Como deshacer un changeset sin borrarlo




jueves, marzo 06, 2014

PlasticSCM: Cómo crear una rama para comenzar a trabajar

Por: Fernando D. Bozzo

En esta nota vamos a ver cómo crear una rama en PlasticSCM, pero antes de hacerlo es necesario saber qué es un rama.
Antiguamente se usaban directorios para crear copias del sistema o de ciertos componentes con determinados cambios. Por ejemplo, si se tiene un form con una pageframe y una página, se agrega otra página y se quería guardar ambas versiones por las dudas, entonces se creaba un directorio para la versión de 1 página y otro directorio para la versión de 2 páginas, y en cada uno se copiaban los forms correspondientes.

Esto tiene el inconveniente de que no es práctico, la cantidad de directorios y copias va creciendo y es fácil perderse entre tantas copias. Además que no hay forma de mezclar los cambios de un directorio con los de otro.


Las ramas

Una rama se usa para lo mismo que se usaban los directorios con distintas versiones, mantener una serie de modificaciones relacionadas a uno o varios componentes. Qué parámetro se use para establecer esa relación puede variar para cada uno, pero lo ideal es tener una rama por usuario y por tarea, ya que la idea es no trabajar nunca sobre la rama principal directamente, hacerlo siempre sobre ramas independientes.


El changeset (o "juego de cambios")


En Plastic el icono de la casa indica un punto en la historia de modificaciones que fueron guardadas con check-in y es el equivalente a lo que antes era el directorio con una copia con cierta modificación particular, por eso es importante hacer un check-in cada vez que se  complete alguna funcionalidad, y antes de pasar a la siguiente.

Para seleccionar un "changeset" se hace click-derecho en el changeset al que se quiere ir, y se elige la opción "Apuntar workspace a este changeset", o sea, se cambia el área de trabajo a ese punto de la historia del proyecto.

Pero, ¿qué ocurre cuando se cambia de changeset realmente? Lo voy a explicar con directorios.
Imaginen que tienen un directorio llamado "c:\mi_sistema_actual" que contiene 3 archivos:

c:\mi_sistema_actual => a.txt, b.txt y c.txt

Ahora se cambian a una copia más vieja que llamaron "c:\mi_sistema_feb_2012" donde solo había 2 archivos:

c:\mi_sistema_feb_2012 => a.txt y b.txt

El archivo c.txt no existe aquí porque fue agregado más recientemente en "c:\mi_sistema_actual", entonces al cambiarse a este directorio es lógico no ver ese archivo, pero si nos volvemos a cambiar al otro, entonces sí que lo vemos.

Pues en Plastic es parecido, pero ocurre todo esto en el directorio que se ha elegido como "workspace", y recalco lo de "espacio de trabajo" porque durante toda la vida del proyecto, todos los cambios se harán en este directorio o workspace. Lo que hace Plastic es "reemplazar" los archivos "controlados" por los archivos del changeset que elijamos, borrando del workspace (directorio) los archivos "controlados" del changeset actual y descargando del servidor los archivos "controlados" del changeset elegido.

No hay que asustarse cuando hablo de "borrar", ya que esto solo lo hace con los archivos que sabe que luego puede recuperar, y por eso los archivos "no controlados" se llaman "privados" y no se tocan. Los archivos privados para Plastic es como si no existieran, aunque los muestra en la ventana de items para que podamos agregarlos al control de código si queremos, y que desde ese momento cambien al estado de "controlados".


Creando una rama


Vamos a crear una rama para que cada uno pueda realizar sus pruebas o su trabajo, y no entre en conflicto con lo que hagan los demás desarrolladores.
Como origen de esta rama se debe seleccionar el changeset desde el cuál se quiere partir, que en general es el último, pero también puede ser otro anterior.


1) Abrimos la vista del Explorador de Ramas (panel izquierdo), hacemos click-derecho en el changeset elegido para bifurcar y seleccionamos "Crear rama desde este changeset"


Figura 1


2) Luego le damos un nombre a la rama. Normalmente este nombre debería ser el de la tarea que se comenzará, algo como "nuevo-form-articulos", "petición-02332" o "tarea-nnn", pero para el caso de las prácticas que estamos haciendo lo voy a nombrar como "usuario" donde cada uno debe reemplazar "usuario" por su usuario:


Figura 2


3) Finalmente podemos ver la nueva rama con la casita, ya que en la pantalla anterior estaba marcado por defecto la opción "Apuntar workspace a esta rama":

Figura 3


Y ahora sí, teniendo cada uno su propia rama, se puede comenzar a trabajar en la tarea, lo que normalmente es abrir una sesión de FoxPro en el directorio del workspace y comenzar a trabajar.



Comprobación de la ruta de nuestra rama


Cuando se crea una rama, queda una flecha gris señalando el origen de datos de la misma, que en este caso coincide con el changeset de origen, y el panel derecho muestra su ruta completa:

Figura 4


Cuando se crea una rama de otra que todavía no tiene nada nuevo, la flecha gris sigue señalando el origen de datos de la misma, pero en este caso el origen de datos no coincide visualmente con el changeset del ejemplo anterior elegido para hacer la rama, lo que puede confundir inicialmente, pero si observamos en el panel derecho, la ruta es correcta a pesar de lo que marca la flecha gris:

Figura 5


Una vista útil para esto es la llamada "Ramas" (panel izquierdo), donde se muestra la relación entre las ramas en forma de texto, y se resalta en negrita la actual (que en la vista anterior muestra el icono de la casa).

Desde esta vista también se pueden crear sub-ramas, y en algunos casos en los que en el Explorador de Ramas no se puede clickear o seleccionar la rama buscada, por ejemplo, por estar tapada por otra, esta es la única forma de poder hacerlo sin equivocarse.

Figura 6


Bueno, ya es hora de practicar un poco!


En este punto les puede interesar:
FoxPro 9: Creando un componente y añadiéndolo al control de código PlasticSCM
FoxPro 9 y PlasticSCM: Como deshacer un changeset sin borrarlo

(Sigue en: "PlasticSCM: Hice un checkin erróneo de un archivo nuevo, ¿cómo lo arreglo?")