Supongamos que tengo el siguiente historial de confirmación en mi sucursal solo local:
A -- B -- C
¿Cómo inserto una nueva confirmación entre Ay B?
Supongamos que tengo el siguiente historial de confirmación en mi sucursal solo local:
A -- B -- C
¿Cómo inserto una nueva confirmación entre Ay B?
Respuestas:
Es incluso más fácil que en la respuesta de OP.
git rebase -i <any earlier commit>. Esto muestra una lista de confirmaciones en su editor de texto configurado.a1b2c3d). En su editor, para esa línea, cambie picka edit.a1b2c3d) como si acabara de confirmarse .git commit( NO enmiendas, a diferencia de la mayoría de los edits). Esto crea una nueva confirmación después de la que eligió.git rebase --continue. Esto reproduce las confirmaciones sucesivas, dejando su nueva confirmación insertada en el lugar correcto.Tenga en cuenta que esto reescribirá la historia y destruirá a cualquier otra persona que intente tirar.
A -- B -- C -- Dlugar de lo deseado A -- D -- B -- C.
Dpodría ser un compromiso en cualquier lugar. Supongamos que tenemos A - B - Cy tenemos alguna confirmación Dque ni siquiera está en esta rama. Sin embargo, sabemos que es SHA. Podemos hacerlo git rebase -i HEAD~3. Ahora entre las líneas Ay B pick, insertamos una nueva pick línea que dice pick SHA, dando el hash de lo deseado D. No tiene por qué ser el hash completo, solo el acortado. git rebase -isolo cherry selecciona las confirmaciones que se enumeran por picklíneas en el búfer; no tienen que ser los originales que enumeró para usted.
breakpalabra clave en el editor en su propia línea entre dos confirmaciones (o en la primera línea, para insertar una confirmación antes de la confirmación especificada).
Resulta ser bastante simple, la respuesta se encuentra aquí . Supongamos que estás en una rama branch. Realice estos pasos:
cree una rama temporal desde el commit después de que desee insertar el nuevo commit (en este caso, commit A):
git checkout -b temp A
realiza los cambios y los confirma, creando un commit, llamémoslo N:
git commit -a -m "Message"
(o git addseguido de git commit)
vuelva a redactar las confirmaciones que desea tener después de la nueva confirmación (en este caso, confirmaciones By C) en la nueva confirmación:
git rebase temp branch
(posiblemente deba usar -ppara preservar las fusiones, si hubiera alguna, gracias a un comentario ya no existente de ciekawy )
eliminar la rama temporal:
git branch -d temp
Después de esto, la historia se ve de la siguiente manera:
A -- N -- B -- C
Por supuesto, es posible que aparezcan algunos conflictos durante el rebase.
En caso de que su sucursal no sea solo local, esto introducirá el historial de reescritura, por lo que podría causar serios problemas.
git push --forceque cambiar el repositorio remoto.
git rebase temp branch -Xtheirs. ¡Respuesta útil para inyectar en un guión!
git rebase temp branch, pero antes git branch -d temp, todo lo que tiene que hacer es arreglar y organizar la fusión de conflictos y problemas git rebase --continue, es decir, no es necesario cometer nada, etc.
Solución aún más fácil:
Crea tu nueva confirmación al final, D. Ahora tienes:
A -- B -- C -- D
Entonces corre:
$ git rebase -i hash-of-A
Git abrirá su editor y se verá así:
pick 8668d21 B
pick 650f1fc C
pick 74096b9 D
Simplemente mueva D a la parte superior de esta manera, luego guarde y salga
pick 74096b9 D
pick 8668d21 B
pick 650f1fc C
Ahora tendrás:
A -- D -- B -- C
Suponiendo que el historial de confirmación es preA -- A -- B -- C, si desea insertar una confirmación entre Ay B, los pasos son los siguientes:
git rebase -i hash-of-preA
Git abrirá tu editor. El contenido puede gustar esto:
pick 8668d21 A
pick 650f1fc B
pick 74096b9 C
Cambia el primero picka edit:
edit 8668d21 A
pick 650f1fc B
pick 74096b9 C
Guardar y Salir.
Modifica tu código y luego git add . && git commit -m "I"
git rebase --continue
Ahora tu historial de commit de Git es preA -- A -- I -- B -- C
Si encuentra un conflicto, Git se detendrá en esta confirmación. Puede utilizar git diffpara localizar marcadores de conflicto y resolverlos. Después de resolver todos los conflictos, debe usar git add <filename>para decirle a Git que el conflicto se ha resuelto y luego volver a ejecutarlo git rebase --continue.
Si desea deshacer el rebase, use git rebase --abort.
Aquí hay una estrategia que evita hacer un "hack de edición" durante el rebase visto en las otras respuestas que he leído.
Al usar git rebase -i, obtienes una lista de confirmaciones desde esa confirmación. Simplemente agregue un "salto" en la parte superior del archivo, esto hará que el rebase se rompa en ese punto.
break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>
Una vez lanzado, git rebaseahora se detendrá en el punto del "descanso". Ahora puede editar sus archivos y crear su confirmación normalmente. Luego puede continuar el rebase con git rebase --continue. Esto puede causar conflictos que tendrá que solucionar. Si te pierdes, no olvides que siempre puedes abortar el uso git rebase --abort.
Esta estrategia se puede generalizar para insertar un compromiso en cualquier lugar, simplemente coloque el "salto" en el lugar donde desea insertar un compromiso.
Después de reescribir el historial, no te olvides git push -f. Se aplican las advertencias habituales sobre otras personas que buscan su rama.
rebaseaquí. No hay mucha diferencia si creará el commit durante el rebase o de antemano.
Muchas buenas respuestas aquí ya. Solo quería agregar una solución "sin rebase", en 4 sencillos pasos.
Resumen
git checkout A
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD
Explicación
(Nota: una ventaja de esta solución es que no toca su rama hasta el paso final, cuando está 100% seguro de que está de acuerdo con el resultado final, por lo que tiene un paso muy útil de "confirmación previa" permitiendo pruebas AB ).
Estado inicial (asumí masterel nombre de su sucursal)
A -- B -- C <<< master <<< HEAD
1) Comience señalando HEAD en el lugar correcto
git checkout A
B -- C <<< master
/
A <<< detached HEAD
(Opcionalmente aquí, en lugar de separar HEAD, podríamos haber creado una rama temporal con la git checkout -b temp Aque tendríamos que eliminar al final del proceso. Ambas variantes funcionan, haga lo que prefiera ya que todo lo demás sigue igual)
2) Cree el nuevo commit D para insertar
# at this point, make the changes you wanted to insert between A and B, then
git commit -am "Message for commit D"
B -- C <<< master
/
A -- D <<< detached HEAD (or <<< temp <<< HEAD)
3) Luego traiga copias de los últimos commits faltantes B y C (sería la misma línea si hubiera más commits)
git cherry-pick A..C
# (if any, resolve any potential conflicts between D and these last commits)
B -- C <<< master
/
A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)
(Prueba AB cómoda aquí si es necesario)
Ahora es el momento de inspeccionar su código, probar cualquier cosa que necesite ser probada, y también puede diferenciar / comparar / inspeccionar lo que tenía y lo que obtendría después de las operaciones.
4) Dependiendo de sus pruebas entre Cy C', está bien o es KO.
(CUALQUIERA) 4-OK) Finalmente, mueva la referencia demaster
git branch -f master HEAD
B -- C <<< (B and C are candidates for garbage collection)
/
A -- D -- B' -- C' <<< master
(O) 4-KO) Solo déjelo mastersin cambios
Si creó una bifurcación temporal, simplemente elimínela con git branch -d <name>, pero si optó por la ruta HEAD separada, no es necesaria ninguna acción en este momento, las nuevas confirmaciones serán elegibles para la recolección de basura justo después de volver HEADa unir con ungit checkout master
En ambos casos (OK o KO), en este punto simplemente mastervuelva a pagar para volver a adjuntar HEAD.