2009-11-12 25 views
49

Quería tener una solución simple para aplastar dos commit de fusión juntos durante una rebase interactiva.git rebase interactive: squash merge commits together

Mi repositorio parece:

X --- Y --------- M1 -------- M2 (my-feature) 
/    /  /
/    /  /
a --- b --- c --- d --- e --- f (stable) 

Es decir, que tienen una rama my-feature que se ha fusionado dos veces recientemente, sin verdadera compromete en el medio. Yo no sólo quiero rebase la rama my-feature ya que es una rama publicada en sí mismo, sólo quiero aplastar juntos los dos última combinación se compromete en una (no se han publicado todavía esas confirmaciones)

X --- Y ---- M (my-feature) 
/  /
/  /
a --- ... -- f (stable) 

probé:

git rebase -p -i M1^ 

Pero tengo:

Refusing to squash a merge: M2 

Lo que finalmente hice es:

git checkout my-feature 
git reset --soft HEAD^ # remove the last commit (M2) but keep the changes in the index 
git commit -m toto  # redo the commit M2, this time it is not a merge commit 
git rebase -p -i M1^ # do the rebase and squash the last commit 
git diff M2 HEAD  # test the commits are the same 

Ahora, la nueva confirmación de fusión ya no se considera una obligación de fusión (solo mantuvo el primer padre). Entonces:

git reset --soft HEAD^    # get ready to modify the commit 
git stash       # put away the index 
git merge -s ours --no-commit stable # regenerate merge information (the second parent) 
git stash apply      # get the index back with the real merge in it 
git commit -a      # commit your merge 
git diff M2 HEAD      # test that you have the same commit again 

Pero esto puede ser complicado si tengo muchos compromisos, ¿tiene una mejor solución? Gracias.

Mildred

+0

Bueno, cuando haz tu segunda fusión, siempre puedes usar '--squash' para evitar crear una confirmación, y luego usar' git commit --amend' para modificar la combinación anterior. – Mildred

+0

Esto no funcionará, no guardará la nueva versión de la rama de la que se fusionó en la confirmación – Mildred

Respuesta

8

si no se ha publicado la última combinación de dos compromete, se puede hacer un reset y una combinación sencilla.

git reset --hard Y 
git merge stable 
+2

Sí, pero la fusión fue difícil, prefiero fusionar el menor número posible de cambios. No quiero resolver conflictos que ya he resuelto. – Mildred

+9

si no quieres volver a resolver conflictos, necesitas "usar" git-rerere (y al "usar" realmente quiero decir "activarlo" porque git maneja la re-fijación de conflictos idénticos automáticamente una vez que esto es habilitado). –

47

Este es un tema antiguo, pero acabo de encontrarlo mientras busco información similar.

Un truco similar a la descrita en Subtree octopus merge es una muy buena solución a este tipo de problema:

git checkout my-feature 
git reset --soft Y 
git rev-parse f > .git/MERGE_HEAD 
git commit 

que tomará el índice, tal como existe en la punta de mi-estelar, y utilizarlo para crear un nuevo compromiso fuera de Y, con 'f' como segundo padre. El resultado es el mismo que si nunca hubieras ejecutado M1, pero pasaste directamente a realizar M2.

+0

Tenga en cuenta que este tipo de combinación no tiene nada que ver con un subárbol o fusión de pulpos. El blog que enlazas solo usa la técnica para * combinar * una combinación de subárbol y una combinación de pulpo en una única combinación (porque git no puede hacer ambas combinaciones de una sola vez). – sleske

+0

El inconveniente de esto es que git no podrá generar mensajes de confirmación adecuados. Copié los mensajes de las antiguas asignaciones de fusión. De lo contrario, una solución agradable y fácil. –

+0

tanto votaciones! acabamos de hacer una fusión muy difícil y el enfoque de mis colegas fue fusionar cada compromiso de su árbol al mío, uno a la vez. luego vino el aplastamiento y nosotros encontramos esta solución. es una pena que necesites escribir tu propio mensaje de compromiso. – Sam

0

Ninguno de los métodos mencionados funciona para mí con una versión reciente de git. En mi caso lo siguiente hizo el truco:

git reset --soft Y 
git reset --hard $(git commit-tree $(git write-tree) -p HEAD -p stable < commit_msg) 

Vas a tener que escribir el mensaje de confirmación en el fichero de commit_msg en primer lugar, sin embargo.

5

Vine a este tema queriendo aplastar una sola combinación de fusión; entonces mi respuesta no es tan útil para la pregunta original.

   X 
       \ 
       \ 
a --- b --- c --- M1 (subtree merge) 

Lo que quería era rebase la fusión M1 y calabaza todo como una única confirmación en la parte superior de b.

a --- b --- S (include the changes from c, X and M1) 

he intentado todo tipo de combinaciones diferentes, pero esto es lo que ha funcionado:

git checkout -b rebase b (checkout a working branch at point b) 
git merge --squash M1 

Esto permite aplicar los cambios en el índice en el que se pueden cometer git commit

+1

Para este caso, puede hacer 'git diff b> diff.patch', luego' git checkout b', 'cat diff.patch | patch -p1' y luego 'git commit'. Esto funciona si el * merge * incluye resoluciones. La pregunta original es diferente; pero creo que viniste aquí buscando lo mismo que yo. Puede obtener los mensajes de check-in con 'git log' antes de la mano. –

+0

pasos adicionales necesarios si desea tener la situación en su maestro: 'git checkout master && git reset --hard b && git rebase rebase'. Esto es solo para recrearme a mí mismo. Podrías haber elegido otro nombre para la rama que "rebase" :) – eis