¿Cómo aplastar los commits en git después de que hayan sido presionados?

551

Esto da una buena explicación de aplastar múltiples confirmaciones:

http://git-scm.com/book/en/Git-Branching-Rebasing

pero no funciona para confirmaciones que ya se han enviado. ¿Cómo elimino las últimas confirmaciones tanto en mis repositorios locales como remotos?

EDITAR: cuando lo haga git rebase -i origin/master~4 master, mantenga el primero como pick, configure los otros tres como squashy luego salga (a través de cx cc en emacs), obtengo:

$ git rebase -i origin/master~4 master
# Not currently on any branch.
nothing to commit (working directory clean)

Could not apply 2f40e2c... Revert "issue 4427: bpf device permission change option added"
$ git rebase -i origin/master~4 master
Interactive rebase already started

donde 2f40 es el pickcommit. Y ahora no aparece ninguno de los 4 commits git log. Esperaba que mi editor se reiniciara para poder ingresar un mensaje de confirmación. ¿Qué estoy haciendo mal?

Loren
fuente

Respuestas:

781

Squash se compromete localmente con

git rebase -i origin/master~4 master

y luego forzar el empuje con

git push origin +master

Diferencia entre --forcey+

De la documentación de git push:

Tenga en cuenta que se --forceaplica a todas las referencias que se envían, por lo tanto, usarlo con push.defaultset to matchingo con múltiples destinos de inserción configurados con remote.*.pushpuede sobrescribir referencias que no sean la rama actual (incluidas las referencias locales que están estrictamente detrás de su contraparte remota). Para forzar un empuje a una sola rama, use un + frente de la especificación de referencia para empujar (por ejemplo, git push origin +masterpara forzar un empuje a la masterrama).

Alan Haggai Alavi
fuente
30
también puedesgit push --force origin master
Daenyth
77
Daenyth : Sí, pero siempre prefiero esta sintaxis ya que es más corta.
Alan Haggai Alavi
86
Y, por supuesto, tenga en cuenta que si alguien más podría haberse retirado del repositorio remoto, probablemente no quiera hacer esto; la respuesta en ese caso es "no".
Cascabel
10
Además, creo que el OP está copiando exactamente el comando git rebase -i origin/master, y en realidad quiere saber cómo volver a crear los commits más atrás que eso, por ejemplo git rebase -i origin/master~20 master.
Cascabel
66
gstackoverflow :+fuerza solo la refspec que tiene el prefijo. --forceobligará a todas las especificaciones a ser empujadas. Por favor vea la respuesta actualizada.
Alan Haggai Alavi
120

En una sucursal pude hacerlo así (durante los últimos 4 commits)

git checkout my_branch
git reset --soft HEAD~4
git commit
git push --force origin my_branch
jakob-r
fuente
1
Hacer esto con el comando suave en una rama ya presionada terminó presionando a un montón de otras personas comprometidas por mí.
cchamberlain
3
Una tonelada? ¿Cómo puede ser más de 4? ¿Puedes elaborar?
jakob-r
De eso no estoy seguro, pero tenía algo que ver con tratar de aplastar un commit ya empujado. Parece que otros experimentaron algo similar aquí - stackoverflow.com/questions/5189560/…
cchamberlain
44
Hubiera aceptado esto como respuesta esperada. Más limpio que aceptó la respuesta.
vikramvi
44
Esta es la respuesta más clara y aceptada en solo 4 pasos
Ameya Salagre
45

Diferencia menor a la respuesta aceptada, pero estaba teniendo muchas dificultades para aplastar y finalmente lo obtuve.

$ git rebase -i HEAD~4
  • En la pantalla interactiva que se abre, reemplace pick con squash en la parte superior para todas las confirmaciones que desea aplastar.
  • Guarde y cierre el editor a través de esc --> :wq

Empuje al control remoto usando:

$ git push origin branch-name --force
BLRBoy
fuente
2
breve y eficaz, elaborado:
terwxqian
22

Se pueden evitar muchos problemas creando solo una branchpara trabajar y no trabajando master:

git checkout -b mybranch

Lo siguiente funciona para remoteconfirmaciones ya enviadas y una mezcla de remoteconfirmaciones enviadas / localsolo confirmaciones:

# example merging 4 commits

git checkout mybranch
git rebase -i mybranch~4 mybranch

# at the interactive screen
# choose fixup for commit: 2 / 3 / 4

git push -u origin +mybranch

También tengo algunas notas de solicitud de extracción que pueden ser útiles.

Stuart Cardall
fuente
17

git rebase -i master

obtendrá el editor vm abierto y msgs algo como esto

Pick 2994283490 commit msg1
f 7994283490 commit msg2
f 4654283490 commit msg3
f 5694283490 commit msg4
#Some message 
#
#some more

Aquí he cambiado la selección de todos los otros commits a "f" (significa reparación).

git push -f origin feature/feature-branch-name-xyz

esto arreglará todas las confirmaciones en una confirmación y eliminará todas las demás confirmaciones. Hice esto y me ayudó.

Nupur
fuente
3

Cuando trabajas con un Gitlab o Github, puedes tener problemas de esta manera. Aplasta tus commits con uno de los métodos anteriores. Mi preferido es:

git rebase -i HEAD~4
or
git rebase -i origin/master

seleccione squash o arreglo para su compromiso. En este punto, debería verificar el estado de git. Y el mensaje podría ser:

    On branch ABC-1916-remote
    Your branch and 'origin/ABC-1916' have diverged,
    and have 1 and 7 different commits each, respectively.
      (use "git pull" to merge the remote branch into yours)

Y puedes tener la tentación de tirar de él. NO HAGAS ESO o estarás en la misma situación que antes.

En su lugar, empuje a su origen con:

git push origin +ABC-1916-remote:ABC-1916

El + permite forzar el empuje solo a una rama.

Alex
fuente
no hay nada de malo en tirar, especialmente si tienes conflictos, se pueden resolver más fácilmente que si fuerzas el empuje
Ray_Poly
2

Para aplastar dos commits, uno de los cuales ya fue empujado, en una sola rama funcionó lo siguiente:

git rebase -i HEAD~2
    [ pick     older-commit  ]
    [ squash   newest-commit ]
git push --force

Por defecto, esto incluirá el mensaje de confirmación de la confirmación más reciente como un comentario sobre la confirmación más antigua.

langosta
fuente
2

1) git rebase -i HEAD~4

Para elaborar: Funciona en la rama actual; HEAD ~ 4 significa aplastar los últimos cuatro commits; modo interactivo (-i)

2) En este punto, el editor abrió, con la lista de confirmaciones, para cambiar las segundas y siguientes confirmaciones, reemplazando pick con squash y luego guárdelo.

salida: referencias y cabezas / nombre de sucursal actualizadas y actualizadas correctamente.

3) git push origin refs/heads/branch-name --force

salida:

remote:
remote: To create a merge request for branch-name, visit:
remote: http://xxx/sc/server/merge_requests/new?merge_request%5Bsource_branch%5D=sss
remote:To ip:sc/server.git
 + 84b4b60...5045693 branch-name -> branch-name (forced update)
terwxqian
fuente