Dividir una confirmación anterior en múltiples confirmaciones
Sin crear una rama y hacer un montón de trabajo extraño en una nueva rama, ¿es posible dividir una única confirmación en algunas confirmaciones diferentes después de que se haya confirmado en el repositorio local?
git rebase -i
lo haré.
Primero, comience con un directorio de trabajo limpio: git status
no debería mostrar modificaciones, eliminaciones o adiciones pendientes.
Ahora tienes que decidir qué confirmaciones quieres dividir.
A) Dividir el compromiso más reciente
Para dividir su confirmación más reciente, primero:
$ git reset HEAD~
Ahora confirme las piezas individualmente de la forma habitual, produciendo tantas confirmaciones como necesite.
B) Dividir un compromiso más atrás
Esto requiere rebasar , es decir, reescribir la historia. Para especificar la confirmación correcta, tiene varias opciones:
Si son tres confirmaciones, entonces
$ git rebase -i HEAD~3
¿ Dónde
3
está cuántas confirmaciones hay?Si está más atrás en el árbol de lo que desea contar, entonces
$ git rebase -i 123abcd~
¿Dónde
123abcd
está el SHA1 del compromiso que desea dividir?Si está en una rama diferente (por ejemplo, una rama de funciones) en la que desea fusionarse
master
:$ git rebase -i master
Cuando aparezca la pantalla de edición de rebase, busque la confirmación que desea dividir. Al principio de esa línea, reemplácela pick
con edit
( e
para abreviar). Guarde el búfer y salga. Rebase ahora se detendrá justo después de la confirmación que desea editar. Entonces:
$ git reset HEAD~
Confirme las piezas individualmente de la forma habitual, produciendo tantas confirmaciones como necesite.
Finalmente
$ git rebase --continue
Del manual de git-rebase (sección DIVISIÓN DE COMPROMISOS)
En modo interactivo, puedes marcar confirmaciones con la acción "editar". Sin embargo, esto no significa necesariamente que git rebase espere que el resultado de esta edición sea exactamente una confirmación. De hecho, puede deshacer la confirmación o agregar otras confirmaciones. Esto se puede utilizar para dividir una confirmación en dos:
Inicie una rebase interactiva con
git rebase -i <commit>^
, ¿dónde<commit>
está el compromiso que desea dividir? De hecho, cualquier rango de confirmación servirá, siempre que contenga esa confirmación.Marque el compromiso que desea dividir con la acción "editar".
Cuando se trata de editar ese compromiso, ejecute
git reset HEAD^
. El efecto es que el HEAD se rebobina uno y el índice hace lo mismo. Sin embargo, el árbol de trabajo sigue siendo el mismo.Ahora agregue los cambios al índice que desea tener en la primera confirmación. Puede utilizar
git add
(posiblemente de forma interactiva) ogit gui
(o ambos) para hacerlo.Confirme el índice actual con cualquier mensaje de confirmación apropiado en este momento.
Repita los dos últimos pasos hasta que su árbol de trabajo esté limpio.
Continúe el rebase con
git rebase --continue
.
Las respuestas anteriores han cubierto el uso de git rebase -i
para editar la confirmación que desea dividir y su confirmación en partes.
Esto funciona bien al dividir los archivos en diferentes confirmaciones, pero si desea dividir los cambios en los archivos individuales, necesita saber más.
Una vez que haya llegado al compromiso que desea dividir, usándolo rebase -i
y marcándolo edit
, tiene dos opciones.
Después de usarlo
git reset HEAD~
, revise los parches individualmente usandogit add -p
para seleccionar los que desee en cada confirmación.Edite la copia de trabajo para eliminar los cambios que no desee; comprometer ese estado provisional; y luego retirar el compromiso completo para la siguiente ronda.
La opción 2 es útil si está dividiendo una confirmación grande, ya que le permite comprobar que las versiones provisionales se compilan y ejecutan correctamente como parte de la combinación. Esto procede de la siguiente manera.
Después de usar rebase -i
y edit
realizar el compromiso, use
git reset --soft HEAD~
para deshacer la confirmación, pero deje los archivos comprometidos en el índice. También puedes hacer un reinicio mixto omitiendo --soft, dependiendo de qué tan cerca del resultado final estará tu confirmación inicial. La única diferencia es si comienza con todos los cambios en etapas o con todos ellos sin etapas.
Ahora entra y edita el código. Puedes eliminar cambios, eliminar archivos agregados y hacer lo que quieras para construir la primera confirmación de la serie que estás buscando. También puede compilarlo, ejecutarlo y confirmar que tiene un conjunto de fuentes coherente.
Una vez que esté satisfecho, prepare o retire los archivos según sea necesario (me gusta usarlos git gui
para esto) y confirme los cambios a través de la interfaz de usuario o la línea de comando.
git commit
Esa es la primera confirmación realizada. Ahora desea restaurar su copia de trabajo al estado que tenía después de la confirmación que está dividiendo, para que pueda realizar más cambios para su próxima confirmación. Para encontrar el sha1 de la confirmación que estás editando, usa git status
. En las primeras líneas del estado verás el comando rebase que se está ejecutando actualmente, en el que puedes encontrar el sha1 de tu confirmación original:
$ git status
interactive rebase in progress; onto be83b41
Last commands done (3 commands done):
pick 4847406 US135756: add debugging to the file download code
e 65dfb6a US135756: write data and download from remote
(see more in file .git/rebase-merge/done)
...
En este caso, el compromiso que estoy editando tiene sha1 65dfb6a
. Sabiendo eso, puedo verificar el contenido de esa confirmación en mi directorio de trabajo usando el formulario que git checkout
toma tanto una confirmación como una ubicación de archivo. Aquí utilizo .
como ubicación del archivo para reemplazar toda la copia de trabajo:
git checkout 65dfb6a .
¡No te pierdas el punto al final!
Esto verificará y organizará los archivos tal como estaban después de la confirmación que está editando, pero en relación con la confirmación anterior que realizó, por lo que cualquier cambio que ya haya confirmado no será parte de la confirmación.
Puede continuar ahora y confirmarlo tal como está para finalizar la división, o volver a hacerlo y eliminar algunas partes de la confirmación antes de realizar otra confirmación provisional.
Si desea reutilizar el mensaje de confirmación original para una o más confirmaciones, puede usarlo directamente desde los archivos de trabajo de la rebase:
git commit --file .git/rebase-merge/message
Finalmente, una vez que hayas realizado todos los cambios,
git rebase --continue
continuará y completará la operación de rebase.
Úselo git rebase --interactive
para editar esa confirmación anterior, ejecute git reset HEAD~
y luego git add -p
agregue algo, luego haga una confirmación, luego agregue algo más y haga otra confirmación, tantas veces como desee. Cuando haya terminado, ejecute git rebase --continue
y tendrá todas las confirmaciones divididas anteriormente en su pila.
Importante : tenga en cuenta que puede jugar y realizar todos los cambios que desee, y no tener que preocuparse por perder cambios antiguos, porque siempre puede ejecutar git reflog
para encontrar el punto en su proyecto que contiene los cambios que desea (llamémoslo a8c4ab
) , y luego git reset a8c4ab
.
Aquí hay una serie de comandos para mostrar cómo funciona:
mkdir git-test; cd git-test; git init
ahora agrega un archivoA
vi A
agregue esta línea:
one
git commit -am one
luego agregue esta línea a A:
two
git commit -am two
luego agregue esta línea a A:
three
git commit -am three
ahora el archivo A se ve así:
one
two
three
y nuestro git log
aspecto es el siguiente (bueno, yo usogit log --pretty=oneline --pretty="%h %cn %cr ---- %s"
bfb8e46 Rose Perrone 4 seconds ago ---- three
2b613bc Rose Perrone 14 seconds ago ---- two
9aac58f Rose Perrone 24 seconds ago ---- one
Digamos que queremos dividir el segundo compromiso two
.
git rebase --interactive HEAD~2
Esto muestra un mensaje similar a este:
pick 2b613bc two
pick bfb8e46 three
Cambie el primero pick
a an e
para editar esa confirmación.
git reset HEAD~
git diff
nos muestra que acabamos de cancelar la confirmación que hicimos para la segunda confirmación:
diff --git a/A b/A
index 5626abf..814f4a4 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
one
+two
Preparemos ese cambio y agreguemos "y un tercero" a esa línea en el archivo A
.
git add .
Este suele ser el punto durante una rebase interactiva donde ejecutaríamos git rebase --continue
, porque normalmente solo queremos volver a nuestra pila de confirmaciones para editar una confirmación anterior. Pero esta vez queremos crear una nueva confirmación. Así que correremos git commit -am 'two and a third'
. Ahora editamos el archivo A
y agregamos la línea two and two thirds
.
git add .
git commit -am 'two and two thirds'
git rebase --continue
Tenemos un conflicto con nuestro compromiso, three
así que resolvámoslo:
cambiaremos
one
<<<<<<< HEAD
two and a third
two and two thirds
=======
two
three
>>>>>>> bfb8e46... three
a
one
two and a third
two and two thirds
three
git add .; git rebase --continue
Ahora nuestro git log -p
se ve así:
commit e59ca35bae8360439823d66d459238779e5b4892
Author: Rose Perrone <[email protected]>
Date: Sun Jul 7 13:57:00 2013 -0700
three
diff --git a/A b/A
index 5aef867..dd8fb63 100644
--- a/A
+++ b/A
@@ -1,3 +1,4 @@
one
two and a third
two and two thirds
+three
commit 4a283ba9bf83ef664541b467acdd0bb4d770ab8e
Author: Rose Perrone <[email protected]>
Date: Sun Jul 7 14:07:07 2013 -0700
two and two thirds
diff --git a/A b/A
index 575010a..5aef867 100644
--- a/A
+++ b/A
@@ -1,2 +1,3 @@
one
two and a third
+two and two thirds
commit 704d323ca1bc7c45ed8b1714d924adcdc83dfa44
Author: Rose Perrone <[email protected]>
Date: Sun Jul 7 14:06:40 2013 -0700
two and a third
diff --git a/A b/A
index 5626abf..575010a 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
one
+two and a third
commit 9aac58f3893488ec643fecab3c85f5a2f481586f
Author: Rose Perrone <[email protected]>
Date: Sun Jul 7 13:56:40 2013 -0700
one
diff --git a/A b/A
new file mode 100644
index 0000000..5626abf
--- /dev/null
+++ b/A
@@ -0,0 +1 @@
+one