Git: Cómo aplastar todos los commits en la rama

315

Hago una nueva sucursal mastercon:

git checkout -b testbranch

Hago 20 compromisos en él.

Ahora quiero aplastar esos 20 commits. Lo hago con:

git rebase -i HEAD~20

¿Qué pasa si no sé cuántos commits? ¿Hay alguna manera de hacer algo como:

git rebase -i all on this branch
usuario3803850
fuente
66
Puede hacer lo git rebase -i 58333012713fc168bd70ad00d191b3bdc601fa2dque hará un rebase interactivo donde el número de confirmación es la última confirmación que permanece sin cambios
denns
@denns Usando este método con el último se comprometen en la rama que se rebase de trabajado fantástico. ¡Muchas gracias!
Joshua Pinter

Respuestas:

395

Otra forma de aplastar todas sus confirmaciones es restablecer el índice a maestro:

 git checkout yourBranch
 git reset $(git merge-base master yourBranch)
 git add -A
 git commit -m "one commit on yourBranch"

Esto no es perfecto ya que implica que sabes de qué rama proviene "yourBranch".
Nota: encontrar esa rama de origen no es fácil / posible con Git (la forma visual es a menudo la más fácil , como se ve aquí ).


EDITAR: deberá usar git push --force


Karlotcha Hoa agrega en los comentarios :

Para el reinicio, puedes hacer

git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD)) 

[Eso] usa automáticamente la rama en la que estás actualmente.
Y si usa eso, también puede usar un alias, ya que el comando no depende del nombre de la rama .

VonC
fuente
2
Es mejor pagar para confirmar dónde YourBranchestá actualmente. Esto se mantendrá YourBranchintacto cuando lo hagasreset
Eugen Konkov
1
@Abdurrahim O abra un git bash, ¡y podrá copiar y pegar estos comandos!
VonC
3
Para el restablecimiento, puede hacer git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD))para usar automáticamente la rama en la que se encuentra actualmente. Y si usa eso, también puede usar un alias, ya que el comando no depende del nombre de la rama.
Karlotcha Hoa
1
@Druska Para casos de ramificación simlpe, no, debería funcionar bien.
VonC
1
@Shimmy sí, siempre y cuando fuerces la presión después del reinicio: git push --force(y advierte a tus colegas si son varias personas que trabajan en esa rama)
VonC
112

Verifique la rama para la que desea agrupar todas las confirmaciones en una confirmación. Digamos que su llamado, feature_branch.

git checkout feature_branch

Paso 1:

Realice un restablecimiento parcial de su origin/feature_branchcon su mastersucursal local (dependiendo de sus necesidades, también puede restablecer con origen / maestro). Esto restablecerá todas las confirmaciones adicionales en su feature_branch, pero sin cambiar ninguno de sus cambios de archivo localmente.

git reset --soft master

Paso 2:

Agregue todos los cambios en su directorio git repo, al nuevo commit que se va a crear. Y cometer lo mismo con un mensaje.

git add -A && git commit -m "commit message goes here"

inestable
fuente
66
Esta fue la solución más confiable para mí, sin causar errores de rebase ni conflictos de fusión.
ANTARA
1
Advertencia: el git agrega -A agrega TODO lo que tienes en la carpeta local - a la rama.
David H
Me encanta esta solución! ¡Esto es exactamente lo que quería!
jacoballenwood
1
La mejor solución para un novato - no destructiva y sólo Vaya momento se puede comprobar en exceso como los secretos de aplicaciones, etc, que no debería importar si usted tiene un archivo adecuado gitignore
kkarakk
@NSduToit Respuesta corta: No, no tienes que hacerlo. Después de hacer los pasos mencionados anteriormente en mi respuesta, terminará con una confirmación con algunos cambios en el código. Puede considerarlo como cualquier otra confirmación con algunos cambios de código. Puede empujar eso a su rama remota sin la -fbandera.
shanky
110

Lo que estás haciendo es bastante propenso a errores. Solo haz:

git rebase -i master

que automáticamente cambiará las confirmaciones de su sucursal al último maestro actual.

Eevee
fuente
55
gracias, lo
entendí
10
¿Probablemente porque es fácil equivocarse el número?
Daniel Scott
13
De acuerdo, esta es su mejor solución. pero siga este enlace, ya que explica mejor lo que debe hacer.
Christo
3
En lugar de aplastar los commits, puede fusionar la rama para masterizar y hacer un restablecimiento de git a origin / master para desestabilizar todos los commits. Eso dejará enviar el código existente con unstagedcommit -am "the whole thing!"
nurettin
2
@nurettin Creo que el reset origin/mastermétodo es realmente malo, ya que es lo mismo que hacer confirmaciones directamente en el maestro: no hay historial de 'fusión de rama', no hay opción de solicitud de extracción. La respuesta de @WaZaA es mucho más acorde con el flujo de trabajo normal de git, creo
Drenai
79

Otra forma simple de hacer esto: ir a la rama de origen y hacer a merge --squash. Este comando no realiza la confirmación "aplastada". cuando lo haga, se recopilarán todos los mensajes de confirmación de su Rama.

$ git checkout master
$ git merge --squash yourBranch
$ git commit # all commit messages of yourBranch in one, really useful
 > [status 5007e77] Squashed commit of the following: ...
WaZaA
fuente
1
Cierto. Mencioné la diferencia entre fusionar --squash y rebase -i en stackoverflow.com/a/2427520/6309
VonC
1
Esto funciona si no quieres hacer squash en la rama principal, solo crea y cambia a una nueva rama basada en la rama principal y haz que la calabaza se fusione con eso.
Charlotte
Saludos amigo, gran consejo!
Nestor Milyaev
¡bonito! creo una rama "temp" de "master" primero para aplastar "yourBranch" y luego fusionar "temp" en "master".
lazieburd
34

Suponiendo que se estaba bifurcando desde el maestro, no necesita ingresar yourBranchal paso de reinicio todo el tiempo:

git checkout yourBranch
git reset --soft HEAD~$(git rev-list --count HEAD ^master)
git add -A
git commit -m "one commit on yourBranch"

Explicacion :

  • git rev-list --count HEAD ^mastercuenta las confirmaciones desde que realizó su ramificación de características desde el maestro, f.ex. 20)
  • git reset --soft HEAD~20realizará un restablecimiento parcial de las últimas 20 confirmaciones. Esto deja sus cambios en los archivos, pero elimina las confirmaciones.

Uso :

En mi .bash_profile he agregado un alias para gisquashhacer esto con un comando:

# squash all commits into one
alias gisquash='git reset --soft HEAD~$(git rev-list --count HEAD ^master)'

Después de resetear y comprometerse, debe hacer a git push --force.

Pista :

Si está utilizando Gitlab> = 11.0 ya no necesita hacerlo, ya que tiene una opción de aplastamiento al fusionar ramas. Opción de aplastamiento de Gitlab

mles
fuente
15

Basado en la lectura de varias preguntas y respuestas de Stackoverflow sobre el aplastamiento, creo que este es un buen revestimiento para aplastar todos los commits en una rama:

git reset --soft $(git merge-base master YOUR_BRANCH) && git commit -am "YOUR COMMIT MESSAGE" && git rebase -i master

Esto supone que el maestro es la rama base.

Travis Reeder
fuente
1
Muchas gracias, la compañía tiene muchas restricciones y no pudo cambiar la forma habitual con un editor, ya que no estaba en voz alta para guardar. Tampoco se pudo usar la función de fusión y fusión en git, ya que esta rama va al desarrollador principal para la fusión y no le gusta. Este liner funcionó y ahorró dolores de cabeza. Trabajo asombroso.
L1ghtk3ira
10

Solución para personas que prefieren hacer clic:

  1. Instalar sourcetree (es gratis)

  2. Comprueba cómo se ven tus commits. Lo más probable es que tengas algo similar a esto ingrese la descripción de la imagen aquí

  3. Haga clic derecho en confirmación de padres . En nuestro caso es la rama maestra.

ingrese la descripción de la imagen aquí

  1. Puede aplastar el compromiso con el anterior haciendo clic en un botón. En nuestro caso tenemos que hacer clic 2 veces. También puedes cambiar el mensaje de confirmación ingrese la descripción de la imagen aquí

  2. ¡Los resultados son impresionantes y estamos listos para impulsar! ingrese la descripción de la imagen aquí

Nota al margen: si estaba empujando sus confirmaciones parciales al control remoto, debe usar el empuje forzado después del squash

Marcin Szymczak
fuente
¡Gracias por esto!
Cristal
0

Otra solución sería guardar todos los registros de confirmación en un archivo

git log> branch.log

Ahora branch.log tendrá todos los identificadores de confirmación desde el comienzo ... desplácese hacia abajo y tome la primera confirmación (esto será difícil en la terminal) usando la primera confirmación

git reset --soft

todos los commits serán aplastados

pranav
fuente
0

Git reset, como se mencionó en muchas respuestas anteriores, es, con mucho, la mejor y más simple forma de lograr lo que desea. Lo uso en el siguiente flujo de trabajo:

(en la rama de desarrollo)

git fetch
git merge origin/master  #so development branch has all current changes from master
git reset origin/master  #will show all changes from development branch to master as unstaged
git gui # do a final review, stage all changes you really want
git commit # all changes in a single commit
git branch -f master #update local master branch
git push origin master #push it
Marcus
fuente
0

Todo este git reset, hard, soft, y todo lo demás mencionado aquí probablemente esté funcionando (no lo hizo para mí) si sigues los pasos correctamente y algún tipo de genio.
Si eres el Joe Smo promedio, prueba esto:
¿Cómo usar git merge --squash?


Me salvó la vida, y será mi lugar para el squash, he estado usando esto 4 veces desde que me enteré. Simple, limpio y básicamente 1 comando. En resumen:


si está en una sucursal, llamémosla "my_new_feature" fuera del desarrollo y su solicitud de extracción tiene 35 confirmaciones (o la cantidad que sea) y desea que sea 1.

A. Asegúrese de que su sucursal esté actualizada, continúe desarrollar, obtener lo último y fusionar y resolver cualquier conflicto con "my_new_feature"
(este paso realmente debería tomarlo tan pronto como sea posible de todos modos)

B. Obtener lo último de desarrollo y ramificarse a una nueva sucursal llámelo "my_new_feature_squashed"

C. la magia está aquí.
Desea llevar su trabajo de "my_new_feature" a "my_new_feature_squashed"
Así que solo haga (mientras que en su nueva sucursal creamos fuera del desarrollo):
git merge --squash my_new_feature

Todos sus cambios ahora estarán en su nueva rama, siéntase libre de probarlo, luego solo haga su única confirmación, empuje, nuevo PR de esa rama y espere a que se repita al día siguiente.
¿No te encanta la codificación? :)

ItaiRoded
fuente