2010-11-12 10 views
22

Usé git-svn para crear un espejo git de un repositorio SVN. La estructura dentro del SVN estaba un poco fuera de estándar, por lo que git creó una rama que no tiene una confirmación común con la rama master.git - configuración de un padre de commit sin rebase

 A---B---C topic 

D---E---F---G master 

Sé que cometen A se basa de cometer E y estoy bastante seguro de que lo he arreglado los problemas que causan git no reconocer ese hecho (usando filter-branch). Lo que quiero hacer es volver a conectar topic a la rama master, el establecimiento de E como padre de A:

 A---B---C topic 
    /
D---E---F---G master 

git-rebase no parece funcionar para mí porque el diff para cometer A listas de la creación de una una gran cantidad de archivos que ya existen en master, lo que resulta en una gran cantidad de conflictos.
Desde mi comprensión de git acaba de establecer E como el padre de A debería ser suficiente para resolver todos los problemas.
¿Esto es posible? Si es así, ¿cómo puedo hacerlo?

+0

¿Alguna posibilidad de volver a iniciar el espejo git del svn apuntando "ramas" al directorio correcto? ¿O arreglando la estructura svn primero? – stefanw

+0

en realidad el repositorio usó el diseño estándar de troncales/etiquetas/ramas. Sin embargo, la rama que estaba tratando de corregir se creó al copiar solo un subcampo del tronco, supongo que eso fue demasiado para git-svn. –

+0

rebase tiene una opción 'root'. Úselo con 'onto' y' preserve-merges' si lo necesita. –

Respuesta

28

Eche un vistazo a los injertos (el archivo de injerto se puede encontrar en .git/info/grafts). El formato es bastante simple:

<commit sha1> <parent1 sha1> <parent2 sha1> … <parentN sha1> 

Esto hace que git crea que un compromiso tiene padres diferentes de lo que realmente tiene. Usar filtro de rama para hacer injertos permanente (por lo que el archivo de injertos se puede quitar):

git filter-branch --tag-name-filter cat -- --all 

Tenga en cuenta que esta historia reescrituras del repositorio, por lo que no debe ser utilizado en repositorios compartidos!


Si sólo desea volver a escribir la historia de las confirmaciones que se están injerta en la rama principal, por ejemplo, utilizar este comando:

git filter-branch --tag-name-filter cat -- master.. 
+0

No utilice injertos o ramas de filtros si no es necesario. –

+3

Los injertos son increíblemente útiles si los necesita, pero al igual que algunas otras características en git, deben usarse antes de compartir el repositorio (o tendrá que hacer que todos los demás se clonen nuevamente). Como dice la respuesta, simplemente crea el archivo de injertos (hash-of-A, espacio, hash-of-E, newline) y usa "git filter-branch --tag-name-filter cat --all" para reescribir historial sin cambiar otros datos de confirmación – JodaStephen

+0

@JodaStephen debe agregar eso a la respuesta. ¿Sabes si está bien hacer eso si el repositorio está publicado, pero los injertos con los que estás jugando solo están tocando confirmaciones nuevas e inéditas? – naught101

8

Con base en sus diagramas (aunque estoy preocupado por lo que quiere decir con "Estoy bastante seguro de haber solucionado los problemas que hacían que Git no reconociera ese hecho (usando filter-branch)."), debería poder hacer algo como lo siguiente.

# checkout A 
git checkout A 

# Reset the branch pointer to E so that E is the parent of the next commit 
# --soft ensures that the index stays the same 
git reset --soft E 

# Remake the commit with the E as the parent, re-using the old commit metadata 
git commit -C [email protected]{1} 

# Rebase the topic branch onto the modified A commit (current HEAD) 
git rebase --onto HEAD A topic 
+0

Funciona casi bien, pero el tema termina no rastreando el origen/tema remoto después de esa operación! –

5

Todo lo que necesita es la siguiente:

git rebase --root --onto master^^ topic^^ topic 

la opción de raíz permite incluir A.

ACTUALIZACIÓN:

Añadir la opción --preserve-merges si desea conservar la ramificación y fusión de la parte que está redefiniendo.

+1

¡Este comando funcionó perfectamente para mí! – jarvisschultz

+0

Esto funciona muy bien si tienes un historial lineal, si tiene commit de fusión, tienes que usar '--preserve-merges', y tienes que volver a resolver los conflictos de combinación manualmente. – Flimm

+0

Sí. Actualizaré la respuesta. Otra vez que respondí la misma pregunta, incluí esa opción. –

Cuestiones relacionadas