Pregunta ¿Cómo puedo fusionar dos commits en uno si ya comencé la rebase?


Estoy intentando fusionar 2 commits en 1, así que seguí "Squashing commits with rebase" de git ready.

corrí

git rebase --interactive HEAD~2

En el editor resultante, cambio pick a squash y luego guardar-salir, pero la rebase falla con el error

No se puede 'aplastar' sin una confirmación previa

Ahora que mi árbol de trabajo ha alcanzado este estado, tengo problemas para recuperarme. El comando git rebase --interactive HEAD~2 falla con

La base de datos interactiva ya comenzó

y git rebase --continue falla con

No se puede 'aplastar' sin una confirmación previa


989
2018-04-01 20:56


origen


Respuestas:


Resumen

El mensaje de error

No se puede 'aplastar' sin una confirmación previa

significa que probablemente intentó "aplastar hacia abajo". Git siempre aplasta un compromiso más nuevo en un compromiso más antiguo o "hacia arriba" como se ve en la lista de tareas de rebase interactiva, es decir, en una confirmación en una línea anterior. Cambiar el comando en la primera línea de la lista de tareas pendientes a squash siempre producirá este error ya que no hay nada para que el primer compromiso se aplaste.

La solución

Primero regrese a donde comenzó con

$ git rebase --abort

Digamos que tu historia es

$ git log --pretty=oneline
a931ac7c808e2471b22b5bd20f0cad046b1c5d0d c
b76d157d507e819d7511132bdb5a80dd421d854f b
df239176e1a2ffac927d8b496ea00d5488481db5 a

Es decir, a fue el primer compromiso, luego b y finalmente c. Después de cometer c decidimos aplastar b y c juntos:

(Nota: corriendo git log canaliza su salida a un buscapersonas, less por defecto en la mayoría de las plataformas. Para salir del buscapersonas y regresar al símbolo del sistema, presione q llave.)

Corriendo git rebase --interactive HEAD~2 te da un editor con

pick b76d157 b
pick a931ac7 c

# Rebase df23917..a931ac7 onto df23917
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

(Tenga en cuenta que esta lista de tareas está en el orden inverso en comparación con la salida de git log.)

Cambiando b pick a squash dará como resultado el error que vio, pero si en su lugar aplasta c en b (el compromiso más nuevo en el anterior o "aplastamiento hacia arriba") al cambiar la lista de tareas a

pick   b76d157 b
squash a931ac7 c

y guardado de su editor, obtendrá otro editor cuyos contenidos son

# This is a combination of 2 commits.
# The first commit's message is:

b

# This is the 2nd commit message:

c

Cuando guarda y sale, el contenido del archivo editado se convierte en mensaje de confirmación de la nueva confirmación combinada:

$ git log --pretty=oneline
18fd73d3ce748f2a58d1b566c03dd9dafe0b6b4f b and c
df239176e1a2ffac927d8b496ea00d5488481db5 a

Nota acerca de reescribir el historial

Rebase interactivo reescribe el historial. Intentar presionar a un control remoto que contiene el historial anterior fracasará porque no es un avance rápido.

Si la rama que ha cambiado de base es un tema o rama de características en el que trabajas solo, no es gran cosa. Empujar a otro repositorio requerirá --force opción, o alternativamente puede, dependiendo de los permisos del repositorio remoto, eliminar primero la rama anterior y luego presionar la versión rebasada. Los ejemplos de esos comandos que potencialmente destruirán el trabajo están fuera del alcance de esta respuesta.

Reescribiendo el historial ya publicado en una rama en la que está trabajando con otras personas sin muy una buena razón, como la filtración de una contraseña u otros detalles confidenciales, obliga a trabajar a sus colaboradores y es antisocial y molestará a otros desarrolladores. los Sección "Recuperación desde una base de datos reversa" en el git rebase documentación explica, con énfasis adicional.

Reasignar (o cualquier otra forma de reescritura) una rama sobre la que otros han basado su trabajo es una mala idea: cualquiera que esté más abajo se ve obligado a corregir su historial manualmente. Esta sección explica cómo hacer la solución desde el punto de vista de la corriente descendente. La solución real, sin embargo, sería evitar volver a basar el flujo ascendente en primer lugar. ...


1533
2018-04-02 19:04



Si hay varias confirmaciones, puede usar git rebase -i para aplastar dos compromisos en uno.

Si solo hay dos confirmaciones que desea combinar, y son las "dos más recientes", los siguientes comandos se pueden usar para combinar las dos confirmaciones en una sola:

git reset --soft "HEAD^"
git commit --amend

335
2017-07-11 05:31



Primero debes verificar cuántos commit tienes:

git log

Hay dos estados:

Una es que hay solamente dos compromisos:

Por ejemplo:

commit A
commit B

(En este caso, no puede usar git rebase para hacerlo) debe hacer lo siguiente.

$ git reset --soft HEAD^1

$ git commit --amend

Otra es que hay más de dos commits; desea fusionar cometer C y D.

Por ejemplo:

commit A
commit B
commit C
commit D

(Bajo esta condición, puedes usar git rebase)

git rebase -i B

Y que usar "squash" para hacer. El resto adelgaza es muy fácil. Si aún no sabes, lee http://zerodie.github.io/blog/2012/01/19/git-rebase-i/ 


50
2018-05-27 19:01



Rebase: No vas a necesitarlo:

Una forma más simple para el escenario más frecuente.

En la mayoría de los casos:

En realidad, si todo lo que quieres es solo simplemente combine varios commits recientes en uno  pero no es necesario drop, reword y otro trabajo de rebase

puedes simplemente hacer:

git reset --soft "HEAD~n"
  • Asumiendo ~n es el número de confirmaciones para desunir suavemente (es decir ~1, ~2, ...)

Luego, use el siguiente comando para modificar el mensaje de confirmación.

git commit --amend

que es bastante similar a una larga gama de squash y uno pick.

Y funciona para n commits pero no solo para dos confirmaciones como se indicó anteriormente.


49
2018-04-26 09:15



Asumiendo que estabas en tu propia rama de tema. Si desea fusionar los 2 últimos commits en uno y parecer un héroe, bifurque el commit justo antes de realizar los dos últimos commits.

git checkout -b temp_branch HEAD^2

Luego squash compromete a la otra rama en esta nueva rama:

git merge branch_with_two_commits --squash

Eso traerá los cambios pero no los comprometerá. Así que simplemente compromételos y listo.

git commit -m "my message"

Ahora puede fusionar esta nueva rama temática en su rama principal.


26
2017-10-23 23:44



puedes cancelar la rebase con

git rebase --abort

y cuando ejecuta de nuevo el comando rebase interactivo, 'squash; commit debe estar debajo del pick commit en la lista


22
2018-04-01 20:59



A menudo uso git reset --mixed para revertir una versión base antes de múltiples commits que desee fusionar, entonces realizo un nuevo commit, de esa manera podría permitir que su commit sea lo más nuevo, asegúrese de que su versión sea HEAD después de enviar al servidor.

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

Si quiero unir dos commits principales en uno, primero uso:

git reset --mixed 249cf9392da197573a17c8426c282

"249cf9392da197573a17c8426c282" fue la tercera versión, también es su versión base antes de fusionarse, después de eso, realizo una nueva confirmación:

git add .
git commit -m 'some commit message'

Es todo, la esperanza es otra forma para todos.

FYI, de git reset --help:

 --mixed
     Resets the index but not the working tree (i.e., the changed files are
     preserved but not marked for commit) and reports what has not been
     updated. This is the default action.

13
2017-09-09 02:48



$ git rebase --abort

Ejecuta este código en cualquier momento si quieres deshacer la git rebase

$ git rebase -i HEAD~2

Para volver a aplicar los últimos dos commits. El comando anterior abrirá un editor de código

  • [ El último compromiso estará en la parte inferior ] Cambiar el último comprometerse con squash (s). Dado que squash se fusionará con commit anterior.
  • A continuación, presione la tecla Esc y escriba: wq para guardar y cerrar

Después: wq estarás en modo rebase activo

Nota: Obtendrá otro editor si no hay mensajes de advertencia / error. Si hay un error o advertencia que no se mostrará en otro editor, puede cancelar mediante la ejecución. $ git rebase --abort si ve un error o advertencia, simplemente continúe ejecutando $ git rebase --continue

Verás tu mensaje de 2 commits. Elija uno o escriba su propio mensaje de confirmación, guarde y salga [: wq]

Nota 2: Es posible que necesites forzar tus cambios al repositorio remoto si ejecutas el comando rebase

$ git push -f

$ git push -f origin master


10
2018-02-20 21:49



Si su rama principal git log se parece a lo siguiente:

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

y desea fusionar los dos primeros commits, solo siga los sencillos pasos:

  1. Primero estar en el lado seguro de la compra el segundo último compromiso en una rama separada. Puedes nombrar cualquier rama. git checkout 77df2a40e53136c7a2d58fd847372 -b merged-commits
  2. Ahora, simplemente seleccione sus cambios desde el último compromiso en esta nueva rama como: git cherry-pick -n -x ac72a4308ba70cc42aace47509a5e. (Resolver conflictos si surgen)
  3. Entonces, sus cambios en el último commit están ahí en su segundo último commit. Pero aún tienes que comprometerte, así que primero agrega los cambios que acabas de seleccionar y luego ejecuta git commit --amend.

Eso es. Puede insertar esta versión fusionada en la rama "fusionados-commits" si lo desea.

Además, puedes descartar los dos commits consecutivos en tu rama principal ahora. Simplemente actualice su rama principal como:

git checkout master
git reset --hard origin/master (CAUTION: This command will remove any local changes to your master branch)
git pull

1
2018-06-16 15:57



Como yo uso git cherry-pick para casi todo, para mí es natural hacerlo incluso aquí.

Dado que tengo branchX desprotegido y hay dos confirmaciones en la punta, de las cuales quiero crear una confirmación que combine su contenido, hago esto:

git checkout HEAD^ // Checkout the privious commit
git cherry-pick --no-commit branchX // Cherry pick the content of the second commit
git commit --amend // Create a new commit with their combined content

Si quiero actualizar branchX también (y supongo que este es el lado negativo de este método) también tengo que:

git checkout branchX
git reset --hard <the_new_commit>

1
2017-11-26 10:52



Si desea combinar las dos confirmaciones más recientes y simplemente usa el mensaje de la confirmación anterior, puede automatizar el proceso utilizando expect.

Asumo:

  • Estás usando vi como editor
  • Tus compromisos son de una sola línea

Probé con git version 2.14.3 (Apple Git-98).


#!/usr/bin/env expect
spawn git rebase -i HEAD~2

# down, delete word, insert 's' (for squash), Escape, save and quit
send "jdwis \033:wq\r"

expect "# This is a"

# down 4, delete 3 lines, save and quit
send "4j3d\r:wq\r"

interact

0
2018-02-06 04:45