git checkout –our cuando la especificación del file incluye el file eliminado

Cuando nos fusionamos guardamos la versión local de nuestros files Maven pom.xml:

git merge origin/remote_branch git checkout --ours **/pom.xml pom.xml git add **/pom.xml pom.xml git commit -m "Merge" 

Esto funciona muy bien, excepto si se ha eliminado un file pom.xml en la sucursal local. Después de ejecutar el command n. ° 2 anterior, obtenemos un error:

 d:\code>git checkout --ours **/pom.xml pom.xml error: path 'blah/pom.xml' does not have our version 

… y después de este error, el siguiente command # 3 git add **/pom.xml pom.xml agrega efectivamente los files remotos pom.xml, exactamente lo que no queremos.

¿Cómo podemos actualizar nuestro script para manejar esto?

Primero:

 git merge origin/remote_branch 

probablemente debería leer git merge --no-commit para asegurarse de que Git no cometa estos cambios si no hay conflictos de fusión, de lo contrario, sus próximos pasos no tienen mucho sentido. Tenga en count que no habrá conflictos de fusión en absoluto si el --theirs commit ha cambiado algunos files pom.xml y no los ha modificado, o si Git piensa que fusionó con éxito sus cambios y los suyos. (Si quiere usar los suyos en uno de estos casos, eso también es un poco complicado, pero parece que quiere usar las versiones --ours siempre.)

Siguiente:

 git checkout --ours **/pom.xml pom.xml 

Esto depende de tu caparazón (presumiblemente bash o similar) para expandirse ** la manera que quieras; es posible que desee citar los asteriscos y hacer que Git realice la expansión global. Sin embargo, esto podría afectar tu caso particular, y no estoy seguro de cómo lo maneja Git durante un conflicto de fusión, así que antes de hacer algo como eso, querrás experimentar con cuidado.

Esto funciona muy bien, excepto si se ha eliminado un file pom.xml en la sucursal local. Después de ejecutar el command n. ° 2 anterior, obtenemos un error:

 d:\code>git checkout --ours **/pom.xml pom.xml error: path 'blah/pom.xml' does not have our version 

Derecha: en este caso, si desea mantener eliminado el file eliminado, debe anular la acción pnetworkingeterminada de Git de elegir mantener su versión en el índice y en el tree de trabajo.

Pasemos a la parte específica de Git de todo esto, el índice . Restring, el índice de Git es donde construyes el siguiente compromiso que harás. Durante una fusión, es también donde se resuelven los conflictos.

Entradas en el índice durante una fusión

En los casos normales (sin fusiones), el índice tiene una input por cada file rastreado. Si el file F está en la confirmación actual (HEAD) y en el tree de trabajo, el índice tiene una input para F. Inicialmente, esta versión de input de índice coincide con la versión HEAD. Usted modifica el file en el tree de trabajo, luego git add la versión del tree de trabajo para copyrlo en el índice en su lugar o en la versión HEAD; y luego el próximo git commit saveá la versión del índice.

Durante una fusión en conflicto, donde el file F tiene un conflicto, el índice tiene hasta tres inputs para F en lugar de la habitual. Estas inputs van en los slots número 1, 2 y 3. (Slot zero está reservado para la input normal, no conflictiva). Slot 1 es para la versión base de combinación . El slot 2 es para --ours , y el slot 3 es para --theirs , y puedes usar estos nombres para 2 y 3, pero no hay un nombre para el slot 1.

Un conflicto de fusión ocurre cuando:

  • la misma (s) línea (s) se modificaron en la nuestra y la suya, con respecto a la versión base (esto es un conflicto de modificación / modificación), o
  • no hay una versión base, solo la nuestra y la de ellos (esto es un conflicto de crear / crear), o
  • eliminamos el file y ellos cambiaron algo, incluso solo el nombre (esto es un conflicto de eliminación / modificación o eliminación / cambio de nombre), o
  • eliminaron el file y cambiamos algo: esto también es un conflicto de modificación / eliminación o cambio de nombre / eliminación, con los socios intercambiados.

Para el conflicto modificar / modificar, las tres ranuras están ocupadas. Para los otros tres types de conflicto, una ranura está vacía: la ranura de la base de combinación está vacía (crear / crear), o --ours está vacía (eliminar / X), o --theirs está vacía (X / borrar).

El process de git checkout --ours paso falla cuando el --ours slot está vacío. Tiene éxito cuando el --ours slot no está vacío: extrae la versión --ours en el tree de trabajo.

La acción pnetworkingeterminada de Git en cualquier conflicto de eliminación / X o X / eliminar es dejar, en el tree de trabajo, la versión que haya sobrevivido. Es decir, si la ranura 3 (suyos) está vacía, el file del tree de trabajo coincide con la input de la ranura 2, pero si la ranura 2 (nuestra) está vacía, el file del tree de trabajo coincide con la input de la ranura 3.

Puede optar por manejar esto escaneando en busca de "ranura 2" vacías y git rm el file para este caso:

 git ls-files --stage | fancy-script-or-program 

Si escribe esto como, por ejemplo, un progtwig de Python, use git ls-files -z --stage para que sea fácilmente analizable por máquina. Incluso podría dejar de usar git checkout --ours en absoluto, y dejar de depender de shell o Git globbing, y codificar las reglas para resolver files pom.xml completo en el script.

Esencialmente, puede leer todo el índice, buscando files cuyo nombre base (todo después del final / ) coincida con pom.xml :

  • Si hay una input de etapa cero, Git cree que resolvió el file correctamente. Compare la ID de hash con la de la confirmación HEAD , porque es posible que Git no haya resuelto el file correctamente después de todo; en este caso, reemplace el hash de blobs de índice con el del commit de HEAD . Consulte la documentation de git update-index para más detalles. Debería poder usar --cacheinfo , aunque no he probado esto con inputs de índice no fusionadas.

  • De lo contrario, hay inputs de etapa 1, 2 y / o 3. Si hay una input en la etapa 2, utilícela como resolución, es decir, proporciónela a git update-index como se git update-index anteriormente. Si no hay input en la etapa 2, use git update-index para eliminar las inputs (usando 0 para el modo, y cualquier cosa, incluido el hash all-ceros, para el hash, el hash es irrelevante si el modo es 0).

Una vez que haya hecho esto con todas las routes de acceso pom.xml , cualquier input de índice de etapa que no sea cero restante indica un conflicto de fusión que debe pasar de nuevo a su usuario. De lo contrario, puede estar listo para comprometerse.

(Un análisis rápido de http://gitpython.readthedocs.io/en/stable/reference.html#module-git.index.base sugiere que esto podría hacerse con bastante facilidad en GitPython, pero no tengo experiencia en su uso. )

Advertencia final: no tengo ninguna experiencia con Maven, pero entiendo que los files pom.xml son files XML que controlan varias cosas y que Git se funde mal (el último es cierto para casi todos los files XML). Sin embargo, no tengo claro que el solo uso de la versión "nuestra" sea correcto.