Cómo dividir el último compromiso en dos en Git

Tengo dos twigs de trabajo, maestro y foro y acabo de hacer algunas modificaciones en la sucursal del foro , que me gustaría seleccionar como maestro . Pero desafortunadamente, el compromiso que quiero recoger también contiene algunas modificaciones que no quiero.

La solución probablemente sería eliminar de alguna manera la confirmación equivocada y replacela por dos confirmaciones separadas, una con los cambios que deseo elegir en el maestro y otras que no pertenezcan allí.

He intentado hacer

git reset --hard HEAD^ 

que eliminó todos los cambios, así que tuve que volver con

 git reset ORIG_HEAD 

Entonces mi pregunta es, ¿cuál es la mejor manera de dividir el último compromiso en dos commits separados?

Deberías usar el índice. Después de hacer un reinicio mixto (" git reset HEAD ^"), agregue el primer set de cambios en el índice, y luego confírmelos. Luego comete el rest.

Puede usar " git add " para poner todos los cambios realizados en un file en el índice. Si no desea representar todas las modificaciones realizadas en un file, solo algunas de ellas, puede usar "git add -p".

Veamos un ejemplo. Supongamos que tengo un file llamado myfile, que contiene el siguiente text:

 something something else something again 

Lo modifiqué en mi último commit para que ahora se vea así:

 1 something something else something again 2 

Ahora decido que quiero dividirlo en dos, y quiero que la inserción de la primera línea esté en la primera confirmación y la inserción de la última línea en la segunda confirmación.

Primero vuelvo a ser el padre de HEAD, pero quiero mantener las modificaciones en el sistema de files, así que utilizo "git reset" sin arguments (lo que hará un restablecimiento llamado "mixto"):

 $ git reset HEAD^ myfile: locally modified $ cat myfile 1 something something else something again 2 

Ahora uso "git add -p" para agregar los cambios que deseo comprometer con el índice (= los represento). "git add -p" es una herramienta interactiva que le pregunta qué cambios en el file debería agregar al índice.

 $ git add -p myfile diff --git a/myfile b/myfile index 93db4cb..2f113ce 100644 --- a/myfile +++ b/myfile @@ -1,3 +1,5 @@ +1 something something else something again +2 Stage this hunk [y,n,a,d,/,s,e,?]? s # split this section into two! Split into 2 hunks. @@ -1,3 +1,4 @@ +1 something something else something again Stage this hunk [y,n,a,d,/,j,J,g,e,?]? y # yes, I want to stage this @@ -1,3 +2,4 @@ something something else something again +2 Stage this hunk [y,n,a,d,/,K,g,e,?]? n # no, I don't want to stage this 

Entonces cometo este primer cambio:

 $ git commit -m "Added first line" [master cef3d4e] Added first line 1 files changed, 1 insertions(+), 0 deletions(-) 

Ahora puedo enviar todos los demás cambios (es decir, el número "2" puesto en la última línea):

 $ git commit -am "Added last line" [master 5e284e6] Added last line 1 files changed, 1 insertions(+), 0 deletions(-) 

Revisemos el logging para ver qué compromisos tenemos:

 $ git log -p -n2 | cat Commit 5e284e652f5e05a47ad8883d9f59ed9817be59d8 Author: ... Date: ... Added last line Diff --git a/myfile b/myfile Index f9e1a67..2f113ce 100644 --- a/myfile +++ b/myfile @@ -2,3 +2,4 @@ something something else something again +2 Commit cef3d4e0298dd5d279a911440bb72d39410e7898 Author: ... Date: ... Added first line Diff --git a/myfile b/myfile Index 93db4cb..f9e1a67 100644 --- a/myfile +++ b/myfile @@ -1,3 +1,4 @@ +1 something something else something again 

Metas:

  • Quiero dividir un commit pasado ( splitme ) en dos.
  • Quiero mantener el post de compromiso .

Plan:

  1. rebase interactivo de uno antes de splitme .
  2. editar splitme .
  3. Restablezca los files para dividirlos en una segunda confirmación.
  4. Enmendar la confirmación, mantener el post, modificar según sea necesario.
  5. Agregue los files divididos desde la primera confirmación.
  6. Comprométete con un nuevo post.
  7. Continuar rebase

Los pasos de rebase (1 y 7) se pueden omitir si el splitme es el compromiso más reciente.

 git rebase -i splitme^ # mark splitme commit with 'e' git reset HEAD^ -- $files git commit --amend git add $files git commit -m "commit with just some files" git rebase --continue 

Si quería que los files divididos se confirmaran primero, luego volvía a establecer la base -i y cambiaba el order

 git rebase -i splitme^ # swap order of splitme and 'just some files' 

Para cambiar la confirmación actual en dos confirmaciones, puede hacer algo como lo siguiente.

Ya sea:

 git reset --soft HEAD^ 

Esto deshace el último commit pero deja todo en etapas. A continuación, puede dejar de grabar ciertos files:

 git reset -- file.file 

Opcionalmente restagear partes de esos files:

 git add -p file.file 

Haz un nuevo primer commit:

 git commit 

El escenario y compromete el rest de los cambios en un segundo compromiso:

 git commit -a 

O:

Deshacer y borrar todos los cambios de la última confirmación:

 git reset HEAD^ 

Etapa selectiva de la primera ronda de cambios:

 git add -p 

Cometer:

 git commit 

Comprometerse con el rest de los cambios:

 git commit -a 

(En cualquiera de los pasos, si deshace una confirmación que agregó un nuevo file y desea agregar esto al segundo compromiso, deberá agregarlo manualmente como commit -a solo las etapas cambian a los files ya rastreados).

Ejecute git gui , select el button de opción "Modificar el último compromiso" y desmarque (Commit> Unstage From Commit, o CtrlU ) los cambios que no desee realizar en el primer commit. Creo que esa es la forma más fácil de hacerlo.

Otra cosa que podría hacer es seleccionar el cambio sin cometer ( git cherry-pick -n ) y luego manualmente o con git gui select los cambios deseados antes de comprometerse.

 git reset HEAD^ 

el "duro" es lo que está matando a tus cambios.

Me sorprende que nadie haya sugerido el git cherry-pick -n forum . Esto representará los cambios a partir de la última confirmación del forum pero no los comprometerá: puede reset los cambios que no necesita y comprometer lo que desea conservar.

El método double-revert-squash

  1. Realice otra confirmación que elimine los cambios no deseados. (Si es por file, esto es realmente fácil: git checkout HEAD~1 -- files with unwanted changes y git commit . De lo contrario, los files con cambios mixtos pueden ser parcialmente configurados git reset file y git add -p file como un paso intermedio . Llama a esto revertir .
  2. git revert HEAD – Realiza otra confirmación, que agrega los cambios no deseados. Esta es la doble reversión
  3. De los 2 commits que has hecho, aplasta el primero en el commit para dividir ( git rebase -i HEAD~3 ). Este compromiso ahora se libera de los cambios no deseados, ya que están en el segundo compromiso.

Beneficios

  • Conserva el post de confirmación
  • Funciona incluso si el compromiso de dividir no es el último. Solo requiere que los cambios no deseados no entren en conflicto con confirmaciones posteriores