Git: cómo forzar el conflicto de combinación y la combinación manual en el archivo seleccionado

82

Mantenemos una aplicación web que tiene una rama maestra común y muchas ramas paralelas, una para cada instalación, cada una tiene algunos cambios específicos. El código fuente se administra en git y es una herramienta excelente cuando necesitamos transferir funciones y corregir errores de la rama maestra a las paralelas. Pero son pocos los archivos que son sensibles y la fusión automática suele dar malos resultados. Por lo tanto, la combinación sería mucho más fácil si se pueden marcar de alguna manera y cada combinación resultaría en un conflicto que requeriría una combinación manual.

Busqué una respuesta:

  1. Estoy usando las opciones de combinación --no-commit y --no-ff , pero no es lo mismo.
  2. Aquí y aquí alguien hace la misma pregunta pero sin solución.
  3. Un caso similar parece ser cómo evitar que el archivo se fusione usando .gitattributes que contienen: somefile.php merge = our . Intenté encontrar alguna opción de fusión que generara un conflicto o forzaría la fusión manual, pero no encontré ninguna hasta ahora.
  4. .gitattributes que contienen: somefile.php -merge nunca se fusiona automáticamente y por lo tanto obliga a la fusión manual. Es una solución al 90%, pero lo que busco es probar la fusión automática y marcarlo como conflicto sin importar si es exitoso o no. Pero esto es lo más cercano a la solución. (... gracias Charles Bailey por la aclaración ...)
  5. Alguien sugirió escribir un controlador de combinación personalizado ( 1 , 2 ), pero no tengo claro cómo hacerlo.

editar: variante 4. descripción

Stepan
fuente
6
Esta no sería la respuesta exacta que está buscando, pero por la misma razón que hago git fetchprimero, luego uso git difftool <file> FETCH_HEAD, para poder aplicar manualmente el cambio en la rama remota a la local.
MHC
MHC: este es un buen truco (especialmente si se guarda en un script para cada rama paralela + combinado con la prevención de la fusión automática de archivos). La principal desventaja es que, en el flujo de trabajo en equipo, es probable que alguien olvide este paso y, en su lugar, realice una fusión normal.
Stepan
2
La configuración -mergeno le impide fusionar los archivos, solo le obliga a hacerlo manualmente, por ejemplo, con una herramienta de fusión. ¿No es esto lo que necesitas?
CB Bailey
Es el 90% de lo que quiero. Me gustaría que la combinación se realizara automáticamente, pero para este archivo sensible, la combinación se considera un conflicto incluso cuando no hay ninguno, por lo que la verificación manual se fuerza cada vez.
Stepan
@Stepan Estoy en una situación similar así que quiero aclarar algo. ¿Qué estás diciendo que con -mergein .gitatttributes git mergeno hace nada y que todo el trabajo debe realizarse con la herramienta de combinación? Entonces, no hay <<<<< ===== >>>> para usar la herramienta de combinación, ¿verdad? ¿Y la solución de Dan proporciona esto?
Nero gris

Respuestas:

59

La opción 5, un controlador de combinación personalizado, es probablemente la forma de acercarse más a lo que desea. Es sorprendentemente fácil de hacer. A continuación se muestra un ejemplo de uno que creo que debería acercarlo bastante al comportamiento que desea.

Primero, cree un script de controlador de combinación llamado merge-and-verify-driver. Hágalo ejecutable y colóquelo en una ubicación adecuada (es posible que desee considerar verificar este script en el repositorio, incluso, ya que el archivo de configuración del repositorio dependerá de él). Git ejecutará este script de shell para realizar la fusión de los archivos sensibles:

#!/bin/bash
git merge-file "${1}" "${2}" "${3}"
exit 1

Esto solo hace el comportamiento de fusión predeterminado que normalmente hace Git. La diferencia clave es que el script siempre devuelve un valor distinto de cero (para indicar que hubo un conflicto, incluso si la fusión se resolvió sin conflictos).

A continuación, debe informar a Git sobre la existencia de su controlador de combinación personalizado. Haz esto en el archivo de configuración del repositorio ( .git/config):

[merge "verify"]
        name = merge and verify driver
        driver = ./merge-and-verify-driver %A %O %B

En este ejemplo, puse merge-and-verify-driverel directorio de nivel superior del repositorio ( ./). Deberá especificar la ruta al script en consecuencia.

Ahora, solo necesita dar a los archivos confidenciales los atributos adecuados para que se use el controlador de combinación personalizado al combinar esos archivos. Agregue esto a su .gitattributesarchivo:

*.sensitive merge=verify

Aquí, le dije a Git que cualquier archivo con un nombre que coincida con el patrón *.sensitivedebería usar el controlador de combinación personalizado. Obviamente, necesita usar un patrón que sea apropiado para su archivo (s).

Moldeo Dan
fuente
¡Muchas gracias por esta guía detallada!
Stepan
13
Parece que el controlador de combinación no se llama en soluciones "obvias". Por ejemplo, si el archivo solo se cambió en una rama y realiza una combinación, el archivo "sensible" se sobrescribirá y no se llamará al controlador de combinación. ¿Hay alguna forma de solucionarlo?
VitalyB
¿Realmente se comportaría esto como sugiere @VitalyB? ¡Gracias!
filippo
1
Esto funciona, pero ¿hay alguna forma de convertirla en una opción global en todos los repositorios de una máquina? Además, ¿alguna forma de invocarlo por línea de comando? Ojalá hubiera una forma de hacer esto en algo tan simple como cambiar la estrategia de fusión en la línea de comandos.
user1748155
4
agregando al comentario de @VitalyB. La combinación tampoco aparece si ambas ramas realizaron el mismo cambio en un archivo. Por ejemplo, ambas ramas aumentaron la versión en 1, y le gustaría aumentar en 2 al intentar fusionar ... Problema muy práctico, aún sin resolver. :(
VasiliNovikov
1

Estos dos comandos parecen tener el mismo efecto que usar el controlador de combinación personalizado:

git merge --no-commit your_target_branch
git checkout --conflict merge .   (do not forget the . and run it in the top dir of the repository)

El primer comando detiene la fusión antes de la creación de la confirmación de fusión, y el segundo marca todos los archivos modificados en las dos ramas como un conflicto para resolver incluso si no había ningún conflicto originalmente.

Louisiuol
fuente
Me gusta la idea de una solución "única" (acabo de encontrarme con un caso así), sin embargo, esto no funcionó para mí. Git hizo un FF que resultó en una fusión incorrecta (esencialmente y la nuestra se fusionó).
Nero gris
@Nerogris De hecho, no funcionará para fusiones de avance rápido. Siempre puede agregar la opción --no-ff, pero el segundo comando no producirá ningún conflicto ya que no hay cambios del ancestro común en una de las dos ramas de la combinación.
louisiuol
He establecido ff en falso en mi configuración global. Cuando dije que era una fusión de FF, quiero decir que si no le hubiera dicho a Git que no hiciera eso, lo habría hecho.
Nero gris
0

Nota: este artículo " Escribir un controlador de combinación de git para archivos PO " ilustra el tipo de manipulación que puede realizar al combinar manualmente un archivo: puede preprocesarlo para que su combinación manual tenga ciertos datos listos.

git merge-filese puede utilizar, por ejemplo, para DESCRIPTAR (y volver a cifrar) archivos antes de fusionarlos (!)

En su caso, al salir de su controlador de combinación con un estado distinto de 0, asegúrese de que la combinación sea manual.

VonC
fuente
2
¿Podría dar más detalles sobre el enlace "fusionar controlador para archivos PO" porque parece que me niega el acceso? Espero que brinde respuesta a la pregunta stackoverflow.com/questions/16214067/…
Mikko Rantalainen
@MikkoRantalainen bloqueado en el trabajo, así que intentaré esta noche desde casa.
VonC
1
El "controlador de combinación para archivos PO" tampoco me funciona :(
sampablokuper
1
@sampablokuper Estoy de acuerdo: el artículo está bloqueado para lectores "no autorizados". No sabría por qué.
VonC
1
@sampablokuper No tengo acceso a este blog en este momento. Seguiré buscando su contenido.
VonC