Fusionar (con squash) todos los cambios de otra rama como una sola confirmación

479

En Git, ¿hay alguna manera de fusionar todos los cambios de una rama a otra, pero aplastar a una sola confirmación al mismo tiempo?

A menudo trabajo en una nueva función en una rama separada y regularmente comprometo / empujo, principalmente para hacer copias de seguridad o transferir lo que estoy trabajando a otra máquina. La mayoría de los commits dicen "Feature xxx WIP" o algo redundante.

Una vez que el trabajo haya finalizado y quiera volver a fusionar la rama WIP en master, me gustaría descartar todas esas confirmaciones intermedias, y solo tener una única confirmación limpia.

¿Hay una forma fácil de hacer esto?

Alternativamente, ¿qué tal un comando que aplasta todos los commits en una rama desde el punto en que se bifurcó?

Brad Robinson
fuente

Respuestas:

601

Otra opción es git merge --squash <feature branch>finalmente hacer un git commit.

Desde Git fusionarse

--squash

--no-squash

Produzca el árbol de trabajo y el estado del índice como si ocurriera una fusión real (a excepción de la información de fusión), pero en realidad no realice una confirmación ni mueva HEAD, ni registre $GIT_DIR/MERGE_HEADpara que el siguiente git commitcomando cree una confirmación de fusión. Esto le permite crear una confirmación única en la parte superior de la rama actual cuyo efecto es el mismo que fusionar otra rama (o más en el caso de un pulpo).

fseto
fuente
1
Característica genial! Me encanta git Aunque definitivamente usaré esto en el futuro ahora, todavía recomendaría que conozcas tu manera de evitar rebase -i. Es una buena habilidad tenerla, en caso de que realmente quisieras hacerles más de un solo commit.
Will Buck
44
Una advertencia: esto funciona, pero el mensaje de confirmación predeterminado incluye el registro de la rama que se está fusionando. El problema es que se parece al formato que normalmente ve donde el texto completo que se muestra en realidad no forma parte del mensaje de confirmación, pero en este caso sí lo hace. Entonces, si no desea todo eso, debe eliminarlo manualmente de su mensaje de confirmación. Debería haber probado esto antes de usarlo ...
still_dreaming_1
23
Eso, y, ten en cuenta que la rama no se verá como fusionada. stackoverflow.com/questions/19308790/…
Ryan
3
En mi humilde opinión, esto debería haberse llamadorebase --squash
Andy
entonces (dado que realmente no combina la rama de la característica) esto sería apropiado si fuera a eliminar la rama de la característica después de la confirmación. ¿Es eso correcto? (No soy un experto en git)
Andrew Spencer
214

¡Lo encontré! El comando de fusión tiene una --squashopción

git checkout master
git merge --squash WIP

en este punto todo está fusionado, posiblemente en conflicto, pero no comprometido. Entonces ahora puedo:

git add .
git commit -m "Merged WIP"
Brad Robinson
fuente
2
lo que hace el git add .hacer?
Michael Potter
1
@MichaelPotter Agrega todos los archivos y cambios
Daksh Shah
2
git add .agrega todos los archivos no ignorados en el directorio actual, sería cuidadoso de recoger archivos no deseados de esta manera.
Jake Cobb el
77
Como alternativa git add ., puede usar git add -upara agregar solo archivos que ya se han agregado al árbol.
Brandon Ogle
19
Sugiriendo que un "git add". ser hecho también es confuso. Cuando hago el "git merge --squash WIP", ya tiene los cambios aplastados en el índice. Todo lo que se necesita es comprometerlos. Haciendo un "git add". agregará los cambios que están en el directorio de trabajo, pero que no formaban parte de la rama de características. La pregunta era cómo confirmar los cambios en la rama de características como una confirmación.
John Pankowicz
30

Pruebe git rebase -i masteren su rama de características. A continuación, puede cambiar todas las opciones de selección, excepto una, a squash para combinar las confirmaciones. Vea los compromisos de aplastamiento con rebase

Finalmente, puede fusionar desde la rama maestra.

fseto
fuente
8
Sí, eso funciona, pero no quiero la molestia de un rebase interactivo. Solo quiero todo desde que la rama se aplastó.
Brad Robinson el
2
+1 Esto lo convierte en un historial limpio. Es mucho más fácil identificar y administrar confirmaciones como parches individuales, tarjetas, historias, etc.
Ryan
2

El uso git merge --squash <feature branch>como sugiere la respuesta aceptada hace el truco, pero no mostrará la rama fusionada como realmente fusionada.

Por lo tanto, una solución aún mejor es:

  • Crea una nueva sucursal del último maestro
  • Fusionarse <feature branch>en lo anterior usandogit merge --squash
  • Fusiona la rama recién creada en master

Este wiki explica el procedimiento en detalle.

raratiru
fuente
0

He creado mi propio alias git para hacer exactamente esto. Lo estoy llamando git freebase! Tomará su rama de características desordenada e irreconocible existente y la recreará para que se convierta en una nueva rama con el mismo nombre con sus confirmaciones agrupadas en una confirmación y reforzada en la rama que especifique (maestra de forma predeterminada). Al final, le permitirá usar cualquier mensaje de confirmación que desee para su nueva rama "libre".

Instálelo colocando el siguiente alias en su .gitconfig:

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

Úselo desde su rama de características ejecutando: git freebase <new-base>

Solo he probado esto algunas veces, así que léalo primero y asegúrese de que desea ejecutarlo. Como una pequeña medida de seguridad, imprime el sha1 inicial, por lo que debería poder restaurar su antigua rama si algo sale mal.

Lo mantendré en mi repositorio de archivos de puntos en github: https://github.com/stevecrozz/dotfiles/blob/master/.gitconfig

Stephen Crosby
fuente
funcionó como una dicha! también podrías echar un vistazo a evernote.com/shard/s52/sh/7f8f4ff1-9a68-413f-9225-c49e3ee2fafd/…
Ilya Sheershoff
-1

git merge --squash <feature branch> es una buena opción. El "git commit" le dice a todos los mensajes de confirmación de ramificación de características con su elección para mantenerlo.

Por menos cometer fusión.

git merge do x times --git reset HEAD ^ --soft luego git commit.

Riesgo: los archivos eliminados pueden volver.

Arjun Mullick
fuente
-5

Puede hacer esto con el comando "rebase". Llamemos a las ramas "main" y "feature":

git checkout feature
git rebase main

El comando rebase reproducirá todas las confirmaciones en "característica" como una confirmación con un elemento primario igual a "principal".

Es posible que desee ejecutar git merge mainantes git rebase mainsi "main" ha cambiado desde que se creó "feature" (o desde la fusión más reciente). De esa manera, todavía tiene su historial completo en caso de que haya tenido un conflicto de fusión.

Después del rebase, puede fusionar su rama a main, lo que debería resultar en una fusión de avance rápido:

git checkout main
git merge feature

Vea la página de rebase de Understanding Git Conceptually para una buena visión general

NamshubWriter
fuente
Esto no funcionó para mí. Acabo de crear un repositorio de prueba simple, con una rama WIP e intenté lo anterior y obtuve conflictos de fusión (a pesar de que no había realizado ningún cambio en el maestro).
Brad Robinson el
Si la función fue creada a partir de principal (git checkout -b característica principal), y ha tenido una fusión reciente de la principal, no debe someterse a los conflictos desde el rebase
NamshubWriter
OK, lo intenté de nuevo. Esta vez no hubo conflictos, pero la historia no fue aplastada.
Brad Robinson el
Echando otro vistazo a la documentación de git-merge, tienes razón, algunos de los commits se mantendrán. Si ha realizado fusiones anteriores de "principal" a "función", la nueva versión eliminará algunas de ellas, pero no todas.
NamshubWriter
Solo recuerde que el rebase puede ser bastante peligroso si la rama de características se ha publicado previamente. Más información sobre esta pregunta SO .
Robert Rossmann