Node:Fusionar repetidamente con la rama principal, Next:La Aproximación de la Cola de Milano -- Fusionar dentro y fuera de la rama principal, Previous:Algunos principios para trabajar con derivaciones, Up:Salir del limbo (Cómo trabajar con derivaciones y sobrevivir)
Supongamos que qsmith necesita hacer desarrollo en una derivación para
no desestabilizar la rama principal que comparte con jrandom. El primer
paso es crear una rama nueva. Observe como primero qsmith crea una
etiqueta normal (no-rama) en ese punto de la rama principal y después
crea la derivación:
paste$ pwd /home/qsmith/myproj paste$ cvs tag Root-of-Exotic_Greetings cvs tag: Tagging . T README.txt T foo.gif T hello.c cvs tag: Tagging a-subdir T a-subdir/whatever.c cvs tag: Tagging a-subdir/subsubdir T a-subdir/subsubdir/fish.c cvs tag: Tagging b-subdir T b-subdir/random.c paste$ cvs tag -b Exotic_Greetings-branch cvs tag: Tagging . T README.txt T foo.gif T hello.c cvs tag: Tagging a-subdir T a-subdir/whatever.c cvs tag: Tagging a-subdir/subsubdir T a-subdir/subsubdir/fish.c cvs tag: Tagging b-subdir T b-subdir/random.c paste$
Etiquetar primero la rama principal podría servir para obtener algún día la rama principal en el momento de que la derivación fue creada. Si tuviese que hacer eso debería haber un modo de referirse a esa instantánea de la rama principal sin referirse a la derivación. No puede usar la etiqueta de la derivación ya que lo que obtendría es esa derivación no las revisiones que forman la raiz del tronco. El único modo de hacer esto sería hacer una etiqueta de las revisiones de las que sale la derivación. (Alguna gente que esta regla tan fielmente que consideré listarla como "principio número 4 de ramificación: Crear siempre una etiqueta no-derivación en la posición de la derivación." Sin embargo en algunos sitios no se usa y parece que lo hacen bien por lo que es una cuestión de gusto.) De ahora en adelante me referiré a esta etiqueta no-derivación como etiqueta del punto de derivación.
Observe que me he adherido a una convención de nombres: La etiqueta
del punto de derivación empieza con Root-of-
(Raiz-de-), y
después el nombre, que usará subrayado en vez de guión para separar las
palabras. Cuando la derivación es creada su etiqueta acabará con el
sufijo -branch
(rama) que le indicará con sólo mirar el nombre
que es una derivación. (La etiqueta del punto de derivación
Root-of-Exotic_Greetings
no incluye el sufijo -branch
porque no
es una derivación.) No tiene que usar esta convención en particular pero
desde luego es aconsejable usar alguna.
Por supuesto, he sido extra pedante. En pequeños proyectos donde cada uno sabe quién está haciendo qué y se pueden arreglar fácilmente las confusiones estas convenciones no tienen que ser usadas. El que use la etiqueta del punto de derivación o una estricta convención de nombres para sus etiquetas dependerá de la complejidad del proyecto y su esquema de derivaciones. (No olvide que siempre puede volver atrás más tarde para actualizar viejas etiquetas y usar una nueva convención; obtenga la versión de la vieja etiqueta, añada la nueva etiqueta y borre después la antigua.)
Ahora qsmith puede empezar a trabajar con la derivación:
paste$ cvs update -r Exotic_Greetings-branch cvs update: Updating . cvs update: Updating a-subdir cvs update: Updating a-subdir/subsubdir cvs update: Updating b-subdir paste$
Hace algunos cambios a un par de ficheros y los entrega en la derivación:
paste$ emacs README.txt a-subdir/whatever.c b-subdir/random.c ... paste$ cvs ci -m "print greeting backwards, etc" cvs commit: Examining . cvs commit: Examining a-subdir cvs commit: Examining a-subdir/subsubdir cvs commit: Examining b-subdir Checking in README.txt; /usr/local/newrepos/myproj/README.txt,v <-- README.txt new revision: 1.14.2.1; previous revision: 1.14 done Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.3.2.1; previous revision: 1.3 done Checking in b-subdir/random.c; /usr/local/newrepos/myproj/b-subdir/random.c,v <-- random.c new revision: 1.1.1.1.2.1; previous revision: 1.1.1.1 done paste$
Mientras tanto jrandom sigue trabajando en el tronco. Ella modifica
dos o tres ficheros que qsmith tocó. Para ponerlo más dificil haremos
sus cambios creen conflictos con el trabajo de qsmith:
floss$ emacs README.txt whatever.c ... floss$ cvs ci -m "some very stable changes indeed" cvs commit: Examining . cvs commit: Examining a-subdir cvs commit: Examining a-subdir/subsubdir cvs commit: Examining b-subdir Checking in README.txt; /usr/local/newrepos/myproj/README.txt,v <-- README.txt new revision: 1.15; previous revision: 1.14 done Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.4; previous revision: 1.3 done floss$
El conflicto no es aparente todavía ya que ninguno de los desarrolladores
ha intentado hacer la fusión de la derivación con el tronco. Ahora
jrandom hace la fusión:
floss$ cvs update -j Exotic_Greetings-branch cvs update: Updating . RCS file: /usr/local/newrepos/myproj/README.txt,v retrieving revision 1.14 retrieving revision 1.14.2.1 Merging differences between 1.14 and 1.14.2.1 into README.txt rcsmerge: warning: conflicts during merge cvs update: Updating a-subdir RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v retrieving revision 1.3 retrieving revision 1.3.2.1 Merging differences between 1.3 and 1.3.2.1 into whatever.c rcsmerge: warning: conflicts during merge cvs update: Updating a-subdir/subsubdir cvs update: Updating b-subdir RCS file: /usr/local/newrepos/myproj/b-subdir/random.c,v retrieving revision 1.1.1.1 retrieving revision 1.1.1.1.2.1 Merging differences between 1.1.1.1 and 1.1.1.1.2.1 into random.c floss$ cvs update cvs update: Updating . C README.txt cvs update: Updating a-subdir C a-subdir/whatever.c cvs update: Updating a-subdir/subsubdir cvs update: Updating b-subdir M b-subdir/random.c floss$
Dos de los ficheros tienen conflictos. No importa, con su saber hacer
jarandom resuelve los conflictos, entrega y etiqueta el tronco
indicando una fusión con éxito.
floss$ emacs README.txt a-subdir/whatever.c ... floss$ cvs ci -m "merged from Exotic_Greetings-branch (conflicts resolved)" cvs commit: Examining . cvs commit: Examining a-subdir cvs commit: Examining a-subdir/subsubdir cvs commit: Examining b-subdir Checking in README.txt; /usr/local/newrepos/myproj/README.txt,v <-- README.txt new revision: 1.16; previous revision: 1.15 done Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.5; previous revision: 1.4 done Checking in b-subdir/random.c; /usr/local/newrepos/myproj/b-subdir/random.c,v <-- random.c new revision: 1.2; previous revision: 1.1 done floss$ cvs tag merged-Exotic_Greetings cvs tag: Tagging . T README.txt T foo.gif T hello.c cvs tag: Tagging a-subdir T a-subdir/whatever.c cvs tag: Tagging a-subdir/subsubdir T a-subdir/subsubdir/fish.c cvs tag: Tagging b-subdir T b-subdir/random.c floss$
Mientras, qsmith no necesita esperar que termine la fusión para
continuar el desarrollo si hace una etiqueta del conjunto de cambios
que jrandom fusionó (más tarde, jrandom necesitará saber el nombre
de esta etiqueta; en general las derivaciones dependen de una frecuente
y completa comunicación entre los desarrolladores):
paste$ cvs tag Exotic_Greetings-1 cvs tag: Tagging . T README.txt T foo.gif T hello.c cvs tag: Tagging a-subdir T a-subdir/whatever.c cvs tag: Tagging a-subdir/subsubdir T a-subdir/subsubdir/fish.c cvs tag: Tagging b-subdir T b-subdir/random.c paste$ emacs a-subdir/whatever.c ... paste$ cvs ci -m "print a randomly capitalized greeting" cvs commit: Examining . cvs commit: Examining a-subdir cvs commit: Examining a-subdir/subsubdir cvs commit: Examining b-subdir Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.3.2.2; previous revision: 1.3.2.1 done paste$
Y por supuesto cuando qsmith haya hecho sus cambios tendrá que etiquetar:
paste$ cvs -q tag Exotic_Greetings-2 T README.txt T foo.gif T hello.c T a-subdir/whatever.c T a-subdir/subsubdir/fish.c T b-subdir/random.c paste$
Mientras todo esto sucede jrandom hace un cambio en un fichero
distinto, uno que qsmith no ha tocado en sus ediciones:
floss$ emacs README.txt ... floss$ cvs ci -m "Mention new Exotic Greeting features" README.txt Checking in README.txt; /usr/local/newrepos/myproj/README.txt,v <-- README.txt new revision: 1.17; previous revision: 1.16 done floss$
En este momento qsmith ha entregado un nuevo cambio en su derivación
y jrandom ha entregado otro cambio no conflictivo en un fichero
distinto del tronco. Observe que sucede cuando jrandom trata de fusionar
desde la derivación de nuevo:
floss$ cvs -q update -j Exotic_Greetings-branch RCS file: /usr/local/newrepos/myproj/README.txt,v retrieving revision 1.14 retrieving revision 1.14.2.1 Merging differences between 1.14 and 1.14.2.1 into README.txt rcsmerge: warning: conflicts during merge RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v retrieving revision 1.3 retrieving revision 1.3.2.2 Merging differences between 1.3 and 1.3.2.2 into whatever.c rcsmerge: warning: conflicts during merge RCS file: /usr/local/newrepos/myproj/b-subdir/random.c,v retrieving revision 1.1 retrieving revision 1.1.1.1.2.1 Merging differences between 1.1 and 1.1.1.1.2.1 into random.c floss$ cvs -q update C README.txt C a-subdir/whatever.c floss$
¡Hay conflictos! ¿Esperaba esto?
El problema radica en el significado de fusionar. En Una introduccion a CVS expliqué que cuando usted ejecuta
floss$ cvs update -j BRANCH
en una copia de trabajo, CVS fusiona en la copia de trabajo las diferencias entre la raiz BRANCH y su estado actual. El problema con este comportamiento es que, en esta situación, la mayoría de esos cambios ya habían sido incorporados al tronco la primera vez que jrandom hizo una fusión. Cuando CVS intentó fusionarlos de nuevo (sobre ellos mismos que es como estaban) se produce naturalmente un conflicto.
Lo que jrandom realmente quería hacer era fusionar en su copia de trabajo
los cambios entre la más reciente fusión del tronco con su estado actual.
Usted puede hacer esto usando dos -j indicadores para actualizar, como
debería recordar en Una introduccion a CVS, siempre que sepa que
revisión corresponde con cada indicador. Afortunadamente qsmith hizó una
etiqueta exactamente en el último punto de fusión (¡hurra por planificar
con antelación!), por lo que esto no será problema. Primero veamos como
jrandom puede devolver su copia de trabajo un estado limpio, desde el
que puede rehacer la fusión:
floss$ rm README.txt a-subdir/whatever.c floss$ cvs -q update cvs update: warning: README.txt was lost U README.txt cvs update: warning: a-subdir/whatever.c was lost U a-subdir/whatever.c floss$
Ahora ella puede hacer la fusión, usando la etiqueta colocada
convenientemente por qsmith.
floss$ cvs -q update -j Exotic_Greetings-1 -j Exotic_Greetings-branch RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v retrieving revision 1.3.2.1 retrieving revision 1.3.2.2 Merging differences between 1.3.2.1 and 1.3.2.2 into whatever.c floss$ cvs -q update M a-subdir/whatever.c floss$
Mucho mejor. Los cambios de qsmith han sido incorporados a whatever.c;
jrandom puede hacer una entrega y etiquetado:
floss$ cvs -q ci -m "merged again from Exotic_Greetings (1)" Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.6; previous revision: 1.5 done floss$ cvs -q tag merged-Exotic_Greetings-1 T README.txt T foo.gif T hello.c T a-subdir/whatever.c T a-subdir/subsubdir/fish.c T b-subdir/random.c floss$
Incluso si qsmith hubiese olvidado etiquetar en el punto de fusión,
las esperanzas no estaría perdidas. Si jrandom supiese aproximadamente
cuando hizo qsmith su primera entrega ella podría tratar de filtrar
por la fecha:
floss$ cvs update -j Exotic_Greetings-branch:3pm -j Exotic_Greetings_branch
Aunque útil como último recurso, filtrar por fecha no es tan bueno porque selecciona los cambios basandose en los recuerdos de la gnete en vez de en designaciones que dependan del desarrollador. Si el primer conjunto de cambios fusionados de qsmith hubiera ocurrido en varias entregas en vez de sólo una jrandom pudiera equivocadamente elegir una fecha u hora que tomara algunos de los cambios, pero no todos.
No es necesario que cada punto etiquetado en los cambios de qsmith sea enviado al repositorio un una simple entrega. Ocurrió así casualmente en el ejemplo. En la vida real, qsmith pudo haber hecho varias entregas entre cada etiquetado. Él puede trabajar de forma aislada en su derivación tanto como quiera. La razón de las etiquetas es registar sucesivos puntos en la derivación donde considere que los cambios deban ser fusionados con la rama principal. Siempre que jrandom fusione usando dos indicadores -j y sea cuidadoso al usar las etiquetas de ramificación de qsmith en el orden apropiado y una sóla vez por cada un la rama principal padecer el problema de la doble fusión.
Podrían ocurrir conflictos, pero éstos serían de la inevitable clase que requiere resolución humana; situaciones en las que tanto el tronco como la derivación realizan cambios en la misma área de código.