Resolviendo conflictos

De vez en cuando, obtendrá un conflicto cuando actualice/fusione sus archivos desde el repositorio o cuando cambie su copia de trabajo a una URL diferente. Hay dos tipos de conflictos:

conflictos de archivo

Un conflicto de archivo ocurre si dos (o más) desarrolladores han cambiado las mismas líneas de un archivo.

conflictos de árboles

Un conflicto de árbol ocurre cuando un desarrollador mueve/renombra/elimina un archivo o una carpeta, que otro desarrollador también ha movido/renombrado/borrado, o quizás lo haya modificado.

Conflictos de archivos

A file conflict occurs when two or more developers have changed the same few lines of a file. As Subversion knows nothing of your project, it leaves resolving the conflicts to the developers. The conflicting area in a text file is marked like this:

<<<<<<< filename
    your changes
=======
    code merged from repository
>>>>>>> revision

Also, for every conflicted file Subversion places three additional files in your directory:

nombre-del-archivo.ext.mine

Este es su archivo tal y como estaba en su copia de trabajo antes que actualizara su copia de trabajo - esto es, sin marcadores de conflicto. Este archivo tiene sus últimos cambios en él y nada más.

nombre-del-archivo.ext.rREV-ANTIGUA

Este es el archivo que era la revisión BASE antes que actualizara su copia de trabajo. Esto es, el archivo que obtuvo antes de empezar a hacer sus últimos cambios.

nombre-del-archivo.ext.rREV-NUEVA

Este es el archivo que su cliente de Subversion acaba de recibir desde el servidor del que actualizó su copia de trabajo. Este archivo corresponde a la revisión HEAD del repositorio.

Puede lanzar una herramienta de fusión / editor de conflictos externo con TortoiseSVNEditar Conflictos o puede usar cualquier editor de texto para resolver el conflicto manualmente. Debe decidir cómo debe quedar finalmente el código, hacer los cambios necesarios y guardar el fichero. Usando una herramienta de fusión como TortoiseMerge o cualquier otra herramienta popular es normalmente la mejor opción ya que generalmente presentan los ficheros en una vista de 3 paneles y no tiene que preocuparse de las marcas de conflicto. Si usa un editor de texto entonces debe buscar las líneas que comiencen con el literal <<<<<<<.

Después, ejecute el comando TortoiseSVNResolver y confirme sus modificaciones al repositorio. Tome nota que el comando Resolver realmente no resuelve el conflicto. Simplemente elimina los archivos filename.ext.mine y filename.ext.r*, dejándole confirmar sus cambios.

Si tiene conflictos con archivos binarios, Subversion no intentará mezclar dichos archivos por si mismo. El archivo local se mantendrá sin cambios (exactamente tal y como lo había cambiado usted) y obtendrá unos archivos nombrefichero.ext.r*. Si desea descartar sus cambios y quedarse con la versión del repositorio, utilice el comando Revertir. Si desea mantener su versión y sobreescribir la versión del repositorio, utilice el comando Resuelto y luego confirme su versión.

Puede utilizar el comando Resuelto para múltiples archivos si pulsa con el botón derecho en la carpeta padre y selecciona TortoiseSVNResuelto... Esto mostrará un diálogo con todos los archivos en conflicto dentro de esa carpeta, y le permitirá seleccionar cuáles marcar como resueltos.

Conflictos de propiedad

Un conflicto de propiedades ocurre si dos (o más) desarrolladores han cambiado la misma propiedad. Como con los conflictos de archivos, resolver el conflicto solo puede ser hecho por los desarrolladores.

Si uno de los cambios debe sobreescribir al otro entonces seleccione la opción Resolver usando la propiedad local o Resolver usando la propiedad remota. Si los cambios deben ser fusionados entonces seleccione Editar propiedad manualmente, resuelva cuál debiera ser el valor de la propiedad y marque como resuelto.

Conflictos de árbol

Un conflicto de árbol ocurre cuando un desarrollador mueve/renombra/elimina un archivo o una carpeta, que otro desarrollador también ha movido/renombrado/borrado, o quizás lo haya modificado. Hay diferentes situaciones que puede resultar en un conflicto de árbol, y todas ellas requiere pasos diferentes para resolver el conflicto.

Cuando se elimina un archivo de forma local en Subversion, el archivo también se elimina del sistema local de archivos, por lo que incluso si es parte de un conflicto de árbol no se puede mostrar un ícono superpuesto de conflicto y no puede hacer clic con el botón derecho sobre él para resolver el conflicto. En este caso, utilice el diálogo Comprobar modificaciones para acceder a la opción Editar conflictos.

TortoiseSVN puede ayudarle a encontrar el lugar correcto para fusionar los cambios, pero puede que necesite realizar un trabajo adicional para arreglar los conflictos. Recuerde que tras una actualización la BASE de trabajo siempre contendrá la revisión de cada ítem tal y como estaba en el repositorio en el momento de la actualización. Si revierte un cambio tras la actualización, se revierte a su estado del repositorio, no a como estaba cuando empezó a hacer sus propios cambios locales.

Borrado local, llega un cambio en la actualización

  1. El desarrollador A modifica Foo.c y lo confirma en el repositorio.

  2. El desarrollador B al mismo tiempo ha movido Foo.c a Bar.c en su propia copia de trabajo, o simplemente ha borrado Foo.c o su carpeta padre.

Una actualización de la copia de trabajo del desarrollador B acaba con un conflicto de árbol:

  • Foo.c ha sido borrado de la copia de trabajo, pero está marcado como un conflicto de árbol.

  • Si el conflicto aparece después de un renombrado en vez de un borrado, entonces Bar.c está marcado como añadido, pero no contiene las modificaciones del desarrollador A.

El desarrollador B ahora tiene que elegir si mantiene los cambios realizados por el desarrollador A. En el caso de un renombrado, puede fusionar los cambios de Foo.c dentro del archivo renombrado Bar.c. Para simples borrados de archivos o directorios puede elegir quedarse con los cambios del ítem del desarrollador A y descartar el borrado. O, si marca el conflicto como resuelto sin hacer nada más, estará descartando los cambios del desarrollador A.

El diálogo de editar conflictos ofrece la posibilidad de fusionar cambios si puede encontrar el archivo original del renombrado Bar.c. Dependiendo de dónde se haya realizado la actualización, puede que no sea posible encontrar el archivo de origen.

Edición local, entra un borrado en la actualización

  1. El desarrollador A mueve Foo.c a Bar.c y lo confirma en el repositorio.

  2. El desarrollador B modifica Foo.c en su copia de trabajo.

O en el caso de mover una carpeta...

  1. El desarrollador A mueve la carpeta padre FooFolder a BarFolder y lo confirma en el repositorio.

  2. El desarrollador B modifica Foo.c en su copia de trabajo.

Una actualización de la copia de trabajo de B acaba con un conflicto de árbol. Para un conflicto simple de archivo:

  • Bar.c se añade a la copia de trabajo como un archivo normal.

  • Foo.c se marca como añadido (con historia) y tiene un conflicto de árbol.

Para un conflicto de carpeta:

  • BarFolder se añade a la copia de trabajo como una carpeta normal.

  • FooFolder se marca como añadida (con historia) y tiene un conflicto de árbol.

    Foo.c se marca como modificado.

El desarrollador B tiene ahora que decidir si desea continuar con la reorganización del desarrollador A y fusionar sus cambios en los archivos correspondientes de la nueva estructura, o simplemente revertir los cambios de A y mantener el archivo local.

Para fusionar sus cambios locales con la reorganización, el desarrollador B tiene que encontrar primero qué nombre de archivo tiene ahora el archivo en conflicto Foo.c que fue renombrado/movido en el repositorio. Esto puede hacerse utilizando el diálogo de registro. Luego debe fusionar los cambios a mano ya que no hay actualmente forma de automatizar o simplificar este proceso. Una vez que se hayan portado los cambios, la ruta en conflicto es redundante y puede borrarse. En este ccaso utilice el botón Eliminar en el diálogo de editar conflictos para limpiar y marcar el conflicto como resuelto.

Si el desarrollador B decide que los cambios de A eran erróneos deberá elegir el botón Mantener en el diálogo de editar conflictos. Esto marca el archivo o carpeta en conflicto como resuelto, pero los cambios del desarrollador A tendrán que eliminarse a mano. De nuevo el diálogo de registro ayuda a controlar lo que se ha movido.

Eliminación local, entra una eliminación en la actualización

  1. El desarrollador A mueve Foo.c a Bar.c y lo confirma en el repositorio.

  2. El desarrollador B mueve Foo.c a Bix.c.

Una actualización de la copia de trabajo del desarrollador B acaba con un conflicto de árbol:

  • Bix.c se marca como añadido con historia.

  • Bar.c se añade a la copia de trabajo con el estado 'normal'.

  • Foo.c se marca como borrado y tiene un conflicto de árbol.

Para resolver este conflicto, el desarrollador B tiene que averiguar qué nombre de archivo tiene ahora el archivo en conflicto Foo.c que fue renombrado/movido en el repositorio. Esto puede hacerse utilizando el diálogo de registro.

Luego el desarrollador B tiene que decidir qué nuevo nombre de archivo de Foo.c mantiene - el del desarrollador A o el renombrado que hizo él mismo.

Después que el desarrollador B haya resuelto manualmente el conflicto, el conflicto de árbol debe marcarse como resuelto mediante el botón del diálogo de editar conflictos.

Falta en local, entra un cambio en la fusión

  1. El desarrollador A, que está trabajando en el tronco, modifica Foo.c y lo confirma en el repositorio

  2. El desarrollador B, que está trabajando en una rama, mueve Foo.c a Bar.c y lo confirma en el repositorio

Una fusión de los cambios en el tronco del desarrollador A con los cambios de la copia de trabajo de la rama del desarrollador B acaba con un conflicto de árbol:

  • Bar.c ya está en la copia de trabajo con estado 'normal'.

  • Foo.c se marca como faltante con un conflicto de árbol.

Para resolver este conflicto, el desarrollador B tiene que marcar el archivo como resuelto en el diálogo de edición de conflictos, lo que lo eliminará de la lista de conflictos. Luego tendrá que decidir si copia el archivo faltante Foo.c desde el repositorio a la copia de trabajo, si fusiona los cambios del desarrollador A hechos a Foo.c en el archivo renombrado Bar.c, o si desea ignorar los cambios marcando el conflicto como resuelto y no haciendo nada más.

Tenga en cuenta que si copia el archivo faltante desde el repositorio y luego marca como resuelto, su copia de eliminará de nuevo. Tiene que resolver el conflicto antes.

Edición local, entra un borrado en la fusión

  1. El desarrollador A, que está trabajando en el tronco, mueve Foo.c a Bar.c y lo confirma en el repositorio.

  2. El desarrollador B, que está trabajando en una rama, modifica el archivo Foo.c y lo confirma en el repositorio.

Hay un caso equivalente cuando se mueven carpetas, pero todavía no se detecta en Subversion 1.6...

  1. El desarrollador A, que está trabajando en el tronco, mueve la carpeta padre FooFolder a BarFolder y lo confirma en el repositorio.

  2. El desarrollador B, que está trabajando en un rama, modifica Foo.c en su copia de trabajo.

Una fusión de los cambios en el tronco del desarrollador A con los cambios de la copia de trabajo de la rama del desarrollador B acaba con un conflicto de árbol:

  • Bar.c se marca como añadido.

  • Foo.c se marca como modificado con un conflicto de árbol.

El desarrollador B tiene ahora que decidir si desea continuar con la reorganización del desarrollador A y fusionar sus cambios en los archivos correspondientes de la nueva estructura, o simplemente revertir los cambios de A y mantener el archivo local.

Para fusionar sus cambios locales con la reorganización, el desarrollador B debe primero averiguar qué nombre de archivo tiene ahora el archivo en conflicto Foo.c que fue renombrado/movido en el repositorio. Esto se puede hacer utilizando el diálogo mostrar registro sobre el origen de la fusión. El editor de conflictos sólo muestra el registro para la copia de trabajo ya que no sabe qué ruta fue utilizada en la fusión, así que lo tendrá que averiguar por su cuenta. Luego se deben fusionar los cambios a mano ya que no hay actualmente forma de automatizar o simplificar este proceso. Una vez que los cambios se hayan portado, la ruta en conflicto es redundante y puede eliminarse. En este caso utilice el botón Eliminar en el diálogo de edición de conflictos para limpiar y marcar el conflicto como resuelto.

Si el desarrollador B decide que los cambios de A eran erróneos, deberá elegir el botón Mantener en el diálogo de editar conflictos. Esto marca el archivo o carpeta en conflicto como resuelto, pero los cambios del desarrollador A deberán eliminarse a mano. De nuevo el diálogo de registro sobre el origen de la fusión ayuda a averiguar qué se movió.

Eliminación local, entra un borrado en la fusión

  1. El desarrollador A, que está trabajando en el tronco, mueve Foo.c a Bar.c y lo confirma en el repositorio.

  2. El desarrollador B, que está trabajando en una rama, mueve Foo.c a Bix.c y lo confirma en el repositorio.

Una fusión de los cambios en el tronco del desarrollador A con los cambios de la copia de trabajo de la rama del desarrollador B acaba con un conflicto de árbol:

  • Bix.c se marca con el estado normal (no modificado).

  • Bar.c se marca como añadido con historia.

  • Foo.c se marca como faltante con un conflicto de árbol.

Para resolver este conflicto, el desarrollador B tiene que averiguar qué nombre de archivo tiene ahora el archivo en conflicto Foo.c que fue renombrado/movido en el repositorio. Esto puede hacerse utilizando el diálogo de registro sobre el origen de la fusión. El editor de conflictos sólo muestra el registro de la copia de trabajo, dado que no conoce qué ruta se utilizó para la fusión, por lo que tendrá que averiguarlo por si mismo.

Luego el desarrollador B tiene que decidir qué nuevo nombre de archivo de Foo.c mantiene - el del desarrollador A o el renombrado que hizo él mismo.

Después que el desarrollador B haya resuelto manualmente el conflicto, el conflicto de árbol debe marcarse como resuelto mediante el botón del diálogo de editar conflictos.

Otros conflictos de árboles

Hay otros casos etiquetados como conflictos de árboles simplemente porque el conflicto implica un directorio en vez de un archivo. Por ejemplo, si añade un directorio con el mismo nombre tanto al tronco como a la rama y trata de fusionarlos obtendrá un conflicto de árbol. Si quiere mantener el directorio del objetivo de la fusión, marque el conflicto como resuelto. Si quiere usar el de la fuente de fusión, entonces necesita primero hacer un SVN delete para borrar el directorio del objetivo y volver a lanzar la fusión. Si necesita algo más complejo deberá hacerlo manualmente.