2009-12-15 11 views
10

Tengo una cantidad de repositorios remotos que quiero fusionar. Algunos de los subárboles en esos repositorios son exclusivos del control remoto (contienen datos que son específicos del host), otros subárboles contienen datos que (se supone que son) comunes en todos los controles remotos."git merge -s theirs" necesario, pero sé que no existe

Lo que quiero hacer, esencialmente, es ejecutar "git pull" para cada control remoto. Esto adelantará rápidamente la rama maestra local a lo largo de la rama de seguimiento para el maestro remoto para los archivos específicos del host que han cambiado en el control remoto, y no hará nada por los archivos comunes porque no habrán cambiado.

Un cambio en un archivo común (llámalo F, con el cambio siendo F ') no debería ser un problema, incluso si solo ocurre en un control remoto al principio. git-merge hará lo correcto y me dará una copia de F 'en mi espacio de trabajo compuesto, que es lo que quiero. El problema viene si el mismo archivo común cambia de una manera diferente en otro control remoto (llámalo F "). Git-merge me dará un compuesto de F 'y F", que no es lo que quiero. Todo lo que quiero es F "

Cuando trabajé con ClearCase llamamos a esto una fusión de copias. El resultado de la fusión siempre fue una copia exacta del colaborador. Esto suena muy parecido a" git merge -s theirs " sería, excepto que no existe.

Me pregunto si puedo cocinar algo con "git-read-tree -m --trivial" para obtener las fusiones rápidas fuera del camino, luego lo hago algo de magia con git-merge y una herramienta de combinación personalizada que simplemente copia el archivo $ REMOTE en $ MERGED. Pero incluso con eso no veo cómo puedo evitar que git-merge componga F 'y F "si es que la fusión es trivial.

He leído el enlace Is there a "theirs" version of "git merge -s ours"? en este sitio, y la publicación de Junio ​​Hamano hace referencia explicando por qué "git merge -s theirs" es una mala idea, pero este no es el caso para mí. Valoro la historia anterior, pero necesito abandonar el barco y seguir el cambio en el sitio remoto cuando ocurra. No se realiza ningún trabajo nuevo en el sitio local. Simplemente necesita formar un conjunto de todos los sitios remotos, tomando el último archivo "común" desde el último control remoto cuando uno cambia.

Gracias de antemano por cualquier ayuda que pueda darme.

+0

Desde la página gitattributes hombre: la hora de decidir qué atributos son asignados a un path, git consulta el archivo $ GIT_DIR/info/attributes (que tiene la prioridad más alta), el archivo .gitattributes en el mismo directorio que la ruta en cuestión, y sus directorios principales hasta el nivel superior del árbol de trabajo (más el directorio que contiene .gitattributes es de la ruta en cuestión, menor es su precedencia) ... así que pon tu .gitattribute en la parte superior del árbol correspondiente. el controlador de combinación personalizado solo se aplicará a ese árbol. – VonC

+0

'echo * merge = keepTheir> dirWithCopyMerge \ .gitattributes' debe hacerlo para todos los archivos en' dirWithCopyMerge', no para todos los archivos de todo el repositorio. Eso debería ser lo que estás buscando. – VonC

+0

Acabo de completar mi respuesta para reflejar mis comentarios anteriores. – VonC

Respuesta

1

(actualización de 2011:
La respuesta "git command for making one branch like another" enumera todas las las posibles maneras de simular un git fusionar -s theirs`)


Para los archivos/árboles específicos que desea copiar y fusionar, puede configurar un gitattributes value como el que menciono en este SO question, que define un controlador de combinación personalizado.
La secuencia de comandos asociada con el atributo de fusión garantizaría siempre mantener el archivo remoto como el resultado de la fusión (vea este SO answer para una ilustración, aunque para el escenario opuesto, manteniendo la versión local).

echo * merge=keepTheir > dirWithCopyMerge\.gitattributes 
git config merge.keepTheir.name "always keep theirduring merge" 
git config merge.keepTheir.driver "keepTheir.sh %O %A %B" 

Al establecer un .gitattribute en la parte superior del subárbol que desea ser copia-fusionado, con '* merge=keepTheir' como su contenido, se atribuye de manera efectiva una costumbre fusionar conductor para todos los archivos de ese subárbol (nota el uso del comodín '*' aquí).

Con keepTheir.sh como:

mv -f $3 $2 
exit 0 

usted no tiene que modificar ninguna "default" fusionar conductor, y aplicar su propio sólo de los archivos que desea.

+0

La solución funcionará pero, como quiero que suceda para cada archivo, hacerlo con atributos es un poco desgarbado. Sin embargo, la sección de la página de manual de gitattributes (5) en "merge" menciona la variable de configuración "merge.default". Esto define el controlador de combinación para llamar a los archivos donde el atributo de fusión no está especificado, que será mi repositorio completo si no lo especifico. Parece que puedo hacer "git config merge.default.driver" mv -f% B% A && exit 0 '"y no me preocupo por establecer atributos. ¿Tiene sentido para usted? Usé mv en lugar de cp porque es más rápido. – kbro

+0

@kbro: "como quiero que suceda para cada archivo, hacerlo con atributos es un poco desgarbado". Yo diría: bastante "beneficioso" en realidad; un '*' sería suficiente. Ver mi respuesta completa. – VonC

+0

¿El símbolo comodín '*' se mostrará globalmente en los sistemas U * IX, o debería haber un atributo adicional para '. *' Suponiendo que quiero copiar-combinar esos archivos también? ¿O hay una manera de englobar tanto dot-files como no dot-files? ¡Triste que no sé! – kbro

7

Muchas gracias a @VonC para sugerir el uso de la combinación de = medida controlador atributo en las .gitattributes archivo. Aunque esto funcionará, soy reacio a contaminar mi espacio de trabajo con archivos .git, y si bien podría usar $ GIT_DIR/info/attributes para evitar la contaminación, me molesta la necesidad de 2 reglas para atrapar dot-files y archivos no dot.

Después de un poco de experimentación I logró obtener una solución con la variable de configuraciónmerge.default (mencionado en los gitattributes (5) página del manual) de trabajo. El truco que perdí fue que merge.default toma el nombre de un controlador personalizado que ha definido previamente; no le da el comando personalizado directamente. Esto es lo que funciona para mí ...

Primero defina su controlador personalizado copy-merge. Puede usar comandos de shell directamente; no hay necesidad de un script externo (sólo asegúrese de obtener su cáscara meta-carácter citando a derecha):

git config merge.copy-merge.name 'Copy Merge' 
git config merge.copy-merge.driver 'mv %B %A' 

Tenga en cuenta que los rendimientos mv 0 en caso de éxito, 1 en caso de fallo, que satisfacen los criterios de combinación de informes "éxito" de vuelta a git.

Ahora dicen que TODOS git fusiones son fusiones de copia-:

git config merge.default copy-merge 

¡listo! Trabajo hecho. git merge <branch> ahora copian y fusionan todo, por lo que la rama en la que se encuentra contiene copias exactas de todos los archivos en <branch>. QED.

Si usted quiere hacer una copia no-merge luego simplemente reiniciar el controlador de combinación por defecto:

git config --unset merge.default 

Si quieres ser más selectivos luego dejar merge.default desarmar y usar atributos como @VonC dice:.

cd path/to/copy-merge/in 
echo '* merge=copy-merge' > .gitattributes 
echo '.* merge=copy-merge' >> .gitattributes 

hacer esto en la parte superior de cada sub-árbol que desea copiar-fundirse en Si hay un sub-sub-árbol que nO desea copiar-fusionar, puede apagarlo nuevamente:

cd path/to/copy-merge/in/path/to/normal-merge/in 
echo '* merge' > .gitattributes 
echo '.* merge' >> .gitattributes 

ADVERTENCIA: ensuciar su árbol de trabajo con muchos archivos .gitattributes puede confundir, especialmente si también utiliza cosas como "* .bin -merge" en otros directorios para forzar todas las fusiones de archivos .bin fallar con conflictos Puede ser mejor usar $ GIT_DIR/info/attributes para este tipo de cosas, ya que tiene la mayor prioridad.

+0

Tiene tantos subárboles que no desea los archivos .gitattributes? Y no entiendo que "está destinado a generar confusión, especialmente si también utilizas cosas como la parte '* .bin -merge'. De todos modos, comentarios interesantes. +1 – VonC

+0

Para mis propósitos, solo tengo un subárbol: todo el repositorio. ! Pero estoy en contra de los archivos .gitattributes en principio, ya que contaminan el espacio de trabajo - Trabajé demasiado tiempo con CVS y Subversion para querer poner cr * p específico de herramienta entre mis archivos :-) – kbro

+0

La confusión de la que hablo podría Si ya ha utilizado .gitattributes para configurar acciones de combinación personalizadas para otros tipos de archivos, y luego desea configurar las cosas para una fusión de copia. Dadas las reglas de precedencia para los archivos .gitattributes, poner uno en su directorio de nivel superior no anulará la configuración en ningún archivo .gitattributes de nivel inferior. Por lo tanto, obtendrá una fusión de copia para archivos previamente fusionados previamente, pero obtendrá la acción de anulación anterior para los que ya ha definido. Definitivamente confuso. – kbro

3

En la versión 1.7.1 de Git, puede pasar una estrategia de "ellos" para fusionarse y el argumento "-Xtheirs".

git merge -Xtheirs otherBranch

No estoy seguro si eso se aplica a lo que está tratando de hacer, pero es probablemente vale la pena un tiro.

(Ver también this related question)

+2

Creo que debería ser git merge -s recursivo -X sus otrasBranco – kbro

+0

'--strategy' y' - estrategia-opción' son cosas muy diferentes. Tiene que downvote:/ – lkraav

3

encontré con este problema, el otro día:

http://seanius.net/blog/2011/02/git-merge-s-theirs/

git merge -s ours ref-to-be-merged 
git diff --binary ref-to-be-merged | git apply -R --index 
git commit -F .git/COMMIT_EDITMSG --amend 
+0

acaba de probar esto, funciona bastante bien, excepto que no puede limitar la fusión a rutas específicas. pero aparte de eso, es genial –

0

Después de una tonelada de investigación, pasando por todo el ruido SO, y aprender más sobre git otra vez (¿alguna vez termina?), creo que esta respuesta es la forma más libre de ruido y óptima para lograr un --strategy theirs sim personalizado controlador de combinación de ulación. Utilizable a pedido, no se necesita gitattributes arena higiénica.

En realidad todavía estoy un poco mareado sobre si se trata de una simulación --strategy theirs, o el método de resolución de conflictos checkout --theirs . más suave utilizable. Tal vez sean equivalentes, pero tendría que diagnosticar algunos gráficos de resultados para comprender completamente, que no hay tiempo para ahora.

Apoyos a @kbro hacer lo correcto persiguiendo a los detalles finos, y conseguir bastante cerca en https://stackoverflow.com/a/1911370/35946

[git:master] es pantalla intérprete de comandos.

CONFIGURACIÓN

$ [git:master] git config merge.theirs.name 'simulate `-s theirs`' 
$ [git:master] git config merge.theirs.driver 'cat %B > %A' # same as `mv` or `cp`, matter of taste 

USO

$ [git:master] GIT_CONFIG_PARAMETERS="'merge.default=theirs'" git merge develop 

PRIMA: ALIAS

$ [git:master] git config alias.merge-theirs \!GIT_CONFIG_PARAMETERS=\""'"merge.default=theirs"'"\"\ git\ merge 

USO: ALIAS

$ [git:master] git merge-theirs develop 

Aviso la estructura de las frases GIT_CONFIG_PARAMETERS, porque tiene que ser capaz de tomar múltiples valores complejos. Obtener esa línea de comandos BONUS tomó un esfuerzo para averiguarlo.

PS GIT_CONFIG_PARAMETERS debe ser el secreto mejor guardado en el SO, estamos casi hecho con el 2016, tiene https://stackoverflow.com/search?q=git_config_parameters 1 (uno) resultado (1)

Cuestiones relacionadas