VS 2013 C # y Git: files .csproj no se combinan al tirar

Yo y un amigo estamos trabajando en un proyecto escrito en C # utilizando VS 2013 Express con Git ( no el complemento VS Git, fíjate), y nos encontramos con un problema. Nuestro flujo de trabajo se configura de esta manera: tenemos un repository central y cada uno de nosotros tiene nuestro propio tenedor del repository en el que trabajamos por separado. Cuando termina nuestro trabajo individual, pasamos al repository central. Cuando queremos sincronizar con el repository central, lo hacemos.

El problema es que cuando tiramos, los files csproj se actualizan aleatoriamente. A veces se actualizan correctamente y los files que se han agregado desde la última extracción se muestran correctamente en VS, y otras veces el file csproj no se ve afectado por completo.

Es extraño porque el csproj se actualiza correctamente en cualquier otro lugar, incluido el repository central, a veces no se actualiza correctamente cuando lo extraemos.

En nuestro file .gitattributes tenemos .csproj configurado para merge=union .

El command que realizamos al tirar es git pull upstream donde upstream es solo un control remoto que apunta a nuestro repository central.

¿Algunas ideas?

Voy a poner esto como una respuesta, basada en el comentario de Edward Thomson , que contiene este enlace para fusionar conflictos en files csproj (haacked.com/archive/2014/04/16/csproj-merge-conflicts) . Tenga en count que no sé nada acerca de Visual Studios, C # o Windows, pero sí sé sobre git. 🙂

El problema es que cuando tiramos, los files csproj se actualizan aleatoriamente. A veces se actualizan correctamente y los files que se han agregado desde la última extracción se muestran correctamente en VS, y otras veces el file csproj no se ve afectado por completo.

Primero, hagamos algunas breves notas de revisión:

  1. git pull es solo git fetch seguido de git merge . Puedes decirle a Git que haga una rebase en rebase lugar. Esta puede ser una buena idea dependiendo de su flujo de desarrollo, pero no cambiará este problema en particular, porque …
  2. Nada más en Git hace fusionar commits , pero …
  3. Varios otros commands, incluyendo git rebase , usan la maquinaria de fusión.
  4. Empujar ( git push ) nunca se fusiona, por lo que solo verás el problema en el caso "tráeme cosas nuevas después de que yo y alguien más hagamos algo". Incluso entonces, si ves el problema depende bastante de lo que hiciste tú y el otro. Esto se debe a que la maquinaria de fusión, utilizada tanto por git merge como git rebase , simplemente no es tan inteligente.

Ahora echemos un vistazo al problema subyacente, que (basado en el enlace) es que estos files *.csproj contienen XML : datos estructurados que las operaciones integradas de fusión de text de git no se pueden combinar correctamente.

Los cambios entran en conflicto cuando, en la salida de git diff , dos líneas de desarrollo diferentes (las twigs o confirmaciones que se fusionan) realizan cambios diferentes en la misma región de un único file. Un ejemplo clásico ocurre en los files cuando dos editores no pueden estar de acuerdo con la ortografía. Por ejemplo, hice este cambio hace algún time:

 diff --git a/plates.tex b/plates.tex index 09939ca..3dfc610 100644 --- a/plates.tex +++ b/plates.tex @@ -15,7 +15,7 @@ that I took on a trip to parts of Australia in February of 2010 \end{plate*} The kangaroo is probably the most widely known marsupial. There are actually four species of large kangaroo: -the networking, the eastern and western gray, and the antilopine. +the networking, the eastern and western grey, and the antilopine. There are also smaller tree-kangaroos and rat-kangaroos. \begin{plate*}[h] 

Si fuera a fusionar esto con alguien que hiciera un cambio diferente a cualquiera de las líneas mostradas en el diff, pero dejara el "gris" deletreado con la letra a , obtendría un conflicto. Por ejemplo, si mi editor insistiera en que la palabra se deletreara "kangaru", los cambios entrarían en conflicto:

 Auto-merging plates.tex CONFLICT (content): Merge conflict in plates.tex Automatic merge failed; fix conflicts and then commit the result. 

Cuando git encuentra cambios conflictivos, su reacción habitual es simplemente declarar que hay un conflicto y detenerse. Te deja con una versión de tree de trabajo del file que contiene marcadores de conflicto <<<<<<< ======= >>>>>>> rodea ambos lados del conflicto (junto con

| sobre la versión base si y solo si establece merge.conflictstyle en diff3 ):

 \end{plate*} <<<<<<< HEAD The kangaru is probably the most widely known marsupial. There are actually four species of large kangaru: the networking, the eastern and western gray, and the antilopine. There are also smaller tree-kangarus and rat-kangarus. 

| merged common ancestors The kangaroo is probably the most widely known marsupial. There are actually four species of large kangaroo: the networking, the eastern and western gray, and the antilopine. There are also smaller tree-kangaroos and rat-kangaroos. ======= The kangaroo is probably the most widely known marsupial. There are actually four species of large kangaroo: the networking, the eastern and western grey, and the antilopine. There are also smaller tree-kangaroos and rat-kangaroos. >>>>>>> master \begin{plate*}[h]

De nuevo, sin embargo, este es el comportamiento pnetworkingeterminado . Puede, a través de los modificadores de línea de command o un file .gitattributes , cambiar el valor pnetworkingeterminado.

Seleccionó la combinación union y la documentation de git se mejoró un poco :

union

Ejecute la fusión de files de tres vías para files de text, pero tome líneas de ambas versiones, en lugar de dejar marcadores de conflicto. Esto tiende a dejar las líneas agregadas en el file resultante en order aleatorio y el usuario debe verificar el resultado. No use esto si no entiende las implicaciones.

(en negrita mía). La versión corta aquí, sin embargo, es que git creerá que la fusión tuvo éxito (bueno, tuvo éxito) pero lo hará al producir un file XML no válido. Hay ejemplos en la página enlazada de haacked.com de cómo funciona esto incorrectamente para los files *.csproj , pero esto es generalmente cierto para cualquier combinación de unión: no es lo suficientemente inteligente para get el resultado correcto y hay pocos lugares donde un conductor razonable. Tendría sentido invocarlo manualmente en algunos casos, luego revisar el file y realizar correcciones a mano, pero dado que solo tiene éxito y permite continuar la fusión, debe tener mucho cuidado al colocarlo en .gitattributes .

Idealmente, nos gustaría tener un controller de fusión que entendiera el formatting XML y la intención de un file .csproj (el formatting XML solo no es suficiente ya que la semántica del marcado no está vinculada a la syntax). Como no uso VS en Windows, solo puedo citar el artículo de haacked.com nuevamente:

Otra forma sería escribir un controller de combinación de XML adecuado para Git, pero eso es todo un desafío, como puede atestiguar mi compañero de trabajo Markus Olsson. Si fuera fácil, o incluso moderadamente difícil, ya se habría hecho. Aunque me pregunto si lo limitamos a problemas comunes de .csproj, ¿podríamos escribir uno que no sea perfecto pero lo suficientemente bueno como para manejar conflictos de combinación comunes? Quizás.

Si los contenidos son tan simples como el XML de ejemplo, creo que un controller de este tipo no sería demasiado difícil, así que sospecho que se vuelven más complicados.