2009-09-28 16 views
25

que han comenzado a usar Git en el medio de mi proyecto, donde las dos primeras confirmaciones son sólo algunos ajustes iniciales (.gitignore y .gitattributes), y la tercera cometer M2 añade el contenido del tronco SVN:¿Cómo fusionar dos ramas sin un antecesor común?

I1 -- I2 -- M2 -- N -- .. -- Z 

he importado la historia sVN en una rama llamada sVN, donde M1 es el tronco sVN (con el mismo contenido que M2, excepto .gitignore y .gitattributes):

A -- B -- ... -- K -- L -- M1 

Q: ¿Cuál es el mejor enfoque para unir ambas sucursales?

pude combinar M1 M2 y en M3, y luego reajustar, pero no sé cómo eliminar los I1 I2 y compromete y si puedo quitar con seguridad la M3 commit (He encontrado algunos consejos para conservar los commit de fusión, pero en este caso M3 ya no es necesario).

A -- B -- ... -- K -- L -- M1 
          \ 
           M3 -- N' -- .. -- Z' 
          /
       I1 -- I2 -- M2 -- N -- .. -- Z 

Otra forma sería la de cereza recoger el N .. Z comete en SVN rama con la mano, pero me gustaría evitar este enfoque.

La solución más elegante sería la de reajustar los cambios introducidos por N .. Z se compromete en la parte superior de SVN rama, pero no lo encontró sin embargo, la sintaxis requerida por dos ramas sin un ancestro común .

Respuesta

22

Descargo de responsabilidad: Yo solo he usado "graft points" una vez en un repositorio de juguetes. Pero es una característica oscura de la que es posible que no haya oído hablar y que pueda ser útil en su situación.

Puede usar "puntos de injerto" para falsificar la información de ascendencia. Consulte, por ejemplo, What are .git/info/grafts for? o proceda inmediatamente al the git wiki entry on graft points.

En esencia, debe crear un archivo .git/info/grafts que engaña git en pensar que cometen M1 es un antepasado de cometer M2:

$ cat .git/info/grafts 
<your M2 commit hash> <your M1 commit hash> 

Posteriormente, se vería como M2 era una commit vacío que acaba de fusionar I2 y M1 en un árbol común.

La desventaja principal: el punto de injerto no está comprometida; por lo tanto, no está desprotegido, sino que debe agregarse manualmente a cada copia de trabajo local del repositorio.



Actualización:uso git replace --graft lugar.

Los puntos de injerto, como se describió anteriormente, han sido reemplazados. Ejecute

git replace --graft <your M2 commit hash> <your M1 commit hash> 

para crear el injerto. Esto se almacena en .git/refs/replace/. Aunque Git no recupera, o empujar, estas referencias por defecto, que se pueden sincronizar entre repositorios usando:

git push origin 'refs/replace/*' 
git fetch origin 'refs/replace/*:refs/replace/*' 

(StackOverflow: How to push 'refs/replace' without pushing any other refs in git?)

+0

+1 lo investigará – alexandrul

+4

Puede usar "' git filter-branch' "para ** reescribir el historial ** de acuerdo con los injertos, convirtiendo el parentesco injertado en un parentesco real. Pero eso reescribe la historia. –

+0

@Jakub: ¿daría un ejemplo de usar filter-branch con injertos (como respuesta para poder votar)? Estoy bien con la reescritura de la historia. – alexandrul

3

yo haría lo siguiente:

git checkout M1; git cherry-pick I1; git cherry-pick I2;

Eso agrega .gitignore y .gitattributes a su rama que contiene el mejor historial.

Y luego simplemente establecer la nueva compromete en la parte superior de aquél:

git filter-branch --parent-filter 'if $GIT_COMMIT = $hash_of_N; then printf -- '-p $hash_of_cherrypicked_I2\n'; else cat; fi'

La desventaja de esto es que reescribir la historia.

Así que un enfoque alternativo es crear una secuencia de comandos similar a the one for the Linux kernel y poner eso en su repositorio.

2

La solución más elegante sería volver a establecer los cambios introducidos por N .. Z commits en la parte superior de la rama svn, pero aún no encontré la sintaxis necesaria para dos ramas sin un ancestro común.

Trate de primera I1 cherry-picking y I2 en M1, y después de eso utilizar el comando git rebase --onto M1' M2 Z (donde M1' es la rama M1-I1-I2). No estoy seguro de si rebase --onto funciona cuando no hay antepasados ​​comunes, pero si no lo hace, existe la posibilidad de utilizar parches. Use el git format-patch para generar los parches de M2..Z y luego git am para aplicarlos encima de M1. Here are some experience reports para usarlo en la conversión de repositorios SVN y CVS antiguos.

Cuestiones relacionadas