¿Cómo mover ciertas confirmaciones para basarse en otra rama en git?

381

La situación:

  • el maestro está en X
  • quickfix1 está en X + 2 confirmaciones

Tal que:

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)

Luego comencé a trabajar en quickfix2, pero por accidente tomé quickfix1 como la rama de origen para copiar, no el maestro. Ahora quickfix2 está en X + 2 commits + 2 commits relevantes.

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

Ahora quiero tener una rama con quickfix2, pero sin los 2 commits que pertenecen a quickfix1.

      q2a'--q2b' (quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Intenté crear un parche a partir de una determinada revisión en quickfix2, pero el parche no conserva el historial de confirmación. ¿Hay alguna manera de guardar mi historial de confirmación, pero tener una rama sin cambios en quickfix1?

Alex Yarmula
fuente
8
@Kevin Esa pregunta solo se refiere a mover confirmaciones de una rama a otra, esta tiene el requisito adicional de no incluir las confirmaciones quickfix1. (Tenga en cuenta también la diferencia en las respuestas.)
Scott Weldon

Respuestas:

372

Este es un caso clásico de rebase --onto:

 # let's go to current master (X, where quickfix2 should begin)
 git checkout master

 # replay every commit *after* quickfix1 up to quickfix2 HEAD.
 git rebase --onto master quickfix1 quickfix2 

Entonces deberías ir de

o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

a:

      q2a'--q2b' (new quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Esto se hace mejor en un árbol de trabajo limpio.
Vergit config --global rebase.autostash true , especialmente después de Git 2.10 .

VonC
fuente
24
Tenga en cuenta que estos pasos modificarán el historial de quickfix2, por lo que si ya compartió la rama, use la selección de cereza (consulte las siguientes respuestas).
Max Chernyak
Sólo para los registros: registro con solo arrastrar de SmartGit q2aOnto Xy seleccione Rebase 2 confirmaciones de las opciones del cuadro de diálogo que se produzcan.
Thomas S.
1
@ThomasS. Interesante. Esa es una buena implementación GUI de a git rebase --onto.
VonC
1
Tengo que admitir que hago cosas tontas como comprometerme con la rama equivocada con más frecuencia de lo que realmente debería, la GUI de la vista de registro de SmartGit me ha salvado tantas veces con la misma situación.
WORMSS
1
@Cosine De acuerdo. He editado mi respuesta para agregar la referencia a la rebase.autostashconfiguración: eso evitará cualquier pérdida de trabajo en progreso en el árbol de trabajo al hacer un rebase.
VonC
155

Puede usar git cherry-pickpara elegir la confirmación que desea copiar.

Probablemente la mejor manera es crear la rama de master, luego en esa rama use git cherry-picklos 2 commits de quickfix2 que desee.

DJ.
fuente
Esta también es la mejor opción si desea mover solo una confirmación. Gracias.
Alex
142

Lo más simple que puedes hacer es elegir un rango. Hace lo mismo que el rebase --ontopero es más fácil para los ojos :)

git cherry-pick quickfix1..quickfix2
Christoph
fuente
66
además, no pierde los commits originales, IIUC, por lo que parece preferible para "jugar-es-seguro" como yo;) o rebase --ontotambién preserva los cambios originales?
akavel
66
ambos rebasey cherry-pickdarle nuevas llaves SHA. Esto se debe a que cada confirmación es una instantánea única del repositorio.
Christoph
66
Lo que @akavel quiso decir es que cherry-pick mantendrá los commits originales en su rama, lo cual es cierto
Mr_and_Mrs_D el
44
Por lo que sea que valga, intenté cherry-pickun rango como en esta respuesta y confundió mi repositorio. Tuve que hacer cherry-picks individuales para cada commit. (Y tal vez no sea necesario decirlo, pero en caso de que alguien tenga dificultades, debe hacerlo cherry-picken el orden cronológico en que se aplicaron sus compromisos).
carmenismo
3
git checkoutEs crucial aquí. ¿Cuál es tu cabeza :)?
Sławomir Lenart
28

Yo creo que es:

git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2
Matthew Flaschen
fuente
3
cherry-pickfunciona con hash de confirmación, así que si solo quieres obtener una confirmación de algún lugar y colocarla en otro lugar, este es el camino a seguir. Solo asegúrese de hacer checkout <branch>primero la rama correcta.
John Leidegren
-1
// on your branch that holds the commit you want to pass
$ git log
// copy the commit hash found
$ git checkout [branch that will copy the commit]
$ git reset --hard [hash of the commit you want to copy from the other branch]
// remove the [brackets]

Otros comandos más útiles aquí con explicación: Guía Git

Ardilla de tierra
fuente