Cómo aplastar confirmaciones en sucursales

Estoy importando un viejo svn repo en git. En un punto, se cambió el nombre de una carpeta en todas las twigs. Esto se hizo en svn creando un duplicado con historial, seguido de una eliminación del original en un segundo commit. Así que tengo un repository que se ve así:

A -> B -> C -> D* -> E* -> F -> G -> H \-> 1 -> 2* -> 3* - > 4 -/ 

Donde D / E y 2/3 son los compromisos que quiero aplastar. La razón para aplastar es que mientras svn sabe de "duplicar con historial", git no ve esto como un cambio de nombre ya que los files originales no se eliminaron hasta la próxima confirmación, y pierdo el historial de culpabilidad en este punto.

He experimentado con algunos scripts de rebase que funcionan, pero también aplanan todas mis twigs. Lo anterior es una versión seriamente simplificada de lo que tengo que hacer, y es por eso que realmente necesito los scripts ya que no puedo hacerlo manualmente. Hay más de 1,000 sucursales a lo largo de la historia del repository de SVN y probablemente una docena de sucursales paralelas donde se realizó este cambio (todas al mismo time).

El repository de git aún no se ha publicado, por lo que mantener hashes es irrelevante. Supongo que tendré que usar algún script de twig de filter, pero todavía estoy tratando de encontrar la forma de administrarlo, con lo que esperaba conseguir ayuda aquí. Puedo proporcionar el sha1 de cada commit que necesita aplastado y su padre.

Desea usar una git filter-branch usando --parent-filter para replace cualquier apariencia de SHA de D con SHA de C También puede ver en .git/info/grafts o git replace , que podría ser más simple que escribir un --parent-filter y puede hacerse permanente con una filter-branch .

Actualización: Como dice @torek, definitivamente deberías usar git replace . Para usar un ejemplo de la vida real, aquí hay un cambio de nombre de readme.md a README.md se ejecutó con un cambio de nombre intermedio a README1.md : https://github.com/dahlbyk/posh-git/compare/dahlbyk:2b9342c. ..dahlbyk: 57394c5 . Llamemos a 2b9342c su C y 57394c5 su E :

 $ git tag E 57394c5 $ git tag C 2b9342c $ git tag G 450d8f1 $ git log --oneline --graph --decorate C~..G * 450d8f1 (tag: G) Merge pull request #320 ... |\ | * 941935c Fix a few kbd / missing markdown issues/ | * f13dcf9 Upcase readme and have more prompt examples. | * 57394c5 (tag: E) Now rename to README.md. | * eb79ef2 Prepare to upcase README.md filename. * | 536c57f Merge pull request #319 ... |\ \ | |/ |/| | * 7fafb7b Speed up Get-GitStatus |/ * 2b9342c (tag: C) Merge pull request #313 ... 

Para pretender que el movimiento intermedio nunca sucedió, puedo replace el padre de E~ ( E~ ) con su abuelo ( E~2 = C ):

 $ git log --stat --oneline C..E 57394c5 Now rename to README.md. README1.md => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) eb79ef2 Prepare to upcase README.md filename. readme.md => README1.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) $ git replace E~ C $ git log --stat --oneline C..E 57394c5 Now rename to README.md. readme.md => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) eb79ef2 Merge pull request ... 

Finalmente, una filter-branch hará que los cambios sean permanentes:

 $ git filter-branch -- ^CGE # For demo, only rewrite G & E afer C $ git log --graph --oneline --decorate C~..G * fcfd345 (tag: G) Merge pull request #320 ... |\ | * fa76267 Fix a few kbd / missing markdown issues/ | * 4900687 Upcase readme and have more prompt examples. | * b25aa5a (tag: E) Now rename to README.md. * | 536c57f Merge pull request #319 ... |\ \ | |/ |/| | * 7fafb7b Speed up Get-GitStatus |/ * 2b9342c (tag: C) Merge pull request #313 ... 

Para tus propósitos, harás algo como:

 $ git replace E~ E~2 $ git replace 3~ 3~2 $ git filter-branch -- ^A --all 

Actualización 2 :

El post de compromiso que obtengo está fuera de E, lo que no me importa. Prefiero tener el post de confirmación de D's (o un post de script proporcionado).

Para mantener los metadatos de confirmación de D , sugeriría empezar de nuevo y usar un --commit-filter para especificar el tree E ( git cat-file -p E ) para D (y que E debería omitirse), por ejemplo

 git filter-branch --commit-filter ' if [ "$GIT_COMMIT" = "SHA of D" ]; then git commit-tree "TREE of E" -p "SHA of C"; elif [ "$GIT_COMMIT" = "SHA of E" ]; then skip_commit "$@"; else git commit-tree "$@"; fi; ' -- ^AEG