Mueve los últimos compromisos a una nueva rama con Git

Me gustaría mover los últimos compromisos que hice para tomar posesión de la nueva rama y recuperar al maestro antes de que se realizaran estos compromisos. Desafortunadamente, mi git -fu todavía no es lo suficientemente fuerte, ¿alguna ayuda?

es decir, Como puedo ir de esto

 master A - B - C - D - E 

a esto?

 newbranch C - D - E / master A - B 
3467
27 окт. Establecido por Mark A. Nicolosi 27 de octubre 2009-10-27 06:07 '09 a las 6:07 am 2009-10-27 06:07
@ 8 respuestas

Ir a la nueva sucursal

Si no hay otras circunstancias, esto se puede hacer fácilmente mediante bifurcación y retrotracción.

 git reset --hard a1b2c3d4 

* 1 solo "perderá" la confirmación de la rama principal, pero no se preocupe, ¡tendrá estas confirmaciones en newbranch!

ADVERTENCIA: Al usar Git versión 2.0 y posteriores, si más adelante una git rebase nueva rama de la rama original ( master ), es posible que necesite una opción explícita --no-fork-point durante la rebase para evitar perder compromisos portátiles. La presencia del conjunto branch.autosetuprebase always hace más probable. Para más detalles, ver John Mellor .

Ir a la sucursal existente

ADVERTENCIA: el método anterior funciona porque está creando una nueva rama con el primer comando: git branch newbranch . Si desea usar una rama existente , antes de realizar el git reset --hard HEAD~3 , debe combinar los cambios en una rama existente . Si no fusiona primero sus cambios, se perderán. Por lo tanto, si está trabajando con una rama existente, se verá así:

4382
27 окт. respuesta dada sykora 27 oct. 2009-10-27 06:15 '09 a las 6:15 am 2009-10-27 06:15

Para aquellos que se preguntan por qué funciona (como era al principio):

Desea volver a C y mover D y E a una nueva rama. Así es como se ve al principio:

 ABCDE (HEAD) ↑ master 

Después de git branch newBranch :

border=0
  newBranch ↓ ABCDE (HEAD) ↑ master 

Después de git reset --hard HEAD~2 :

  newBranch ↓ ABCDE (HEAD) ↑ master 

Como la rama es solo un puntero, el maestro apuntó a la última confirmación. Cuando creó newBranch, simplemente hizo un nuevo puntero a la última confirmación. Luego, usando git reset , moviste el puntero principal a dos confirmaciones. Pero como no moviste newBranch, aún apunta al compromiso que hizo originalmente.

801
23 июля '11 в 1:37 2011-07-23 01:37 la respuesta la da Ryan Lundy el 23 de julio de 2011 a la 1:37 2011-07-23 01:37

En general ...

En este caso, la mejor opción es el método abierto de sykora. Pero a veces este no es el método más fácil y general. Para el método general, use git cherry-pick:

Para lograr el OP deseado, este es un proceso de dos pasos:

Paso 1: una nota que corrige el maestro requerido en el newbranch

Correr

 git checkout master git log 

Tenga en cuenta que los hashes (por ejemplo, 3) lo comprometen a newbranch . Aquí voy a utilizar:
C commit: 9aa1233
D commit: 453ac3d
E commit: 612ecb3

Nota . Puede utilizar los primeros siete caracteres o todo el hash de la confirmación.

Paso 2 - newbranch en newbranch

 git checkout newbranch git cherry-pick 612ecb3 git cherry-pick 453ac3d git cherry-pick 9aa1233 

O (en git 1.7.2+, usar rangos)

 git checkout newbranch git cherry-pick 612ecb3~1..9aa1233 

git cherry-pick aplica estos tres compromisos al newbranch.

315
07 февр. Responder Ivan 07 Feb. 2012-02-07 19:58 '12 a las 19:58 2012-02-07 19:58

Otra forma de hacerlo es usando solo 2 comandos. También mantiene su árbol de trabajo actual entero.

 git checkout -b newbranch # switch to a new branch git push . +HEAD~3:master # make master point to some older commit 

La capacidad de push a . - Este es un buen truco.

Edición posterior: ahora que sé sobre git branch -f , la forma correcta de hacerlo es:

 git checkout -b newbranch # switch to a new branch git branch -f master HEAD~3 # make master point to some older commit 

Lo mismo, pero menos "mágico".

235
26 марта '14 в 11:13 2014-03-26 11:13 la respuesta se da aragaer 26 de marzo de 2014 a las 11:13 2014-03-26 11:13

¡La mayoría de las respuestas anteriores están peligrosamente equivocadas!

NO hagas esto:

 git reset --keep HEAD~3 git checkout -t -b newbranch git cherry-pick ..HEAD@{2} 
  • En primer lugar, descarta los 3 últimos confirmaciones ( --keep es similar a --hard , pero es más seguro, ya que falla, en lugar de lanzar cambios no confirmados).
  • Entonces él desactiva el newbranch .
  • Luego escoge los tres que lleva a la newbranch . Ya que ya no hacen referencia a la rama, lo hace con git reflog : HEAD@{2} es una solución que HEAD usa para hacer referencia a 2 operaciones atrás, es decir, antes de que 1. comprobáramos newbranch y 2. usamos git reset para descartar 3 confirmaciones.

Advertencia: reflog está habilitado de forma predeterminada, pero si lo deshabilitó manualmente (por ejemplo, usando el repositorio git simple), no podrá obtener 3 git reset --keep HEAD~3 después de ejecutar git reset --keep HEAD~3 .

Una alternativa que no se basa en reflog es:

 git branch -t newbranch git reset --hard HEAD~3 git checkout newbranch 

Es que dejan el reflog en el estado equivocado. git ve a newbranch como una ramificación ramificada de la revisión, que incluye 3 confirmaciones, luego reset --hard sobrescribe el historial de subida para eliminar confirmaciones, y la próxima vez que inicie git rebase como cualquier otra. eliminado de aguas arriba.

Pero en este caso particular, queremos que estas 3 fijaciones se consideren como parte del hilo del tema. Para lograr esto, debemos colocarlo en una versión anterior que no incluya 3 confirmaciones. Esto es lo que están haciendo mis soluciones propuestas, por lo que ambos dejan el reflog en el estado correcto.

Para obtener más información, consulte la definición de --fork-point en git rebase y git merge base .

179
07 апр. Respuesta dada por John Mellor 07 de abril. 2016-04-07 01:38 '16 a la 1:38 pm 2016-04-07 01:38

Esto no los "mueve" en un sentido técnico, pero tiene el mismo efecto:

 A--B--C (branch-foo) \ ^-- I wanted them here! \ D--E--F--G (branch-bar) ^--^--^-- Opps wrong branch! While on branch-bar: $ git reset --hard D # remember the SHAs for E, F, G (or E and G for a range) A--B--C (branch-foo) \ \ D-(E--F--G) detached ^-- (branch-bar) Switch to branch-foo $ git cherry-pick E..G A--B--C--E'--F'--G' (branch-foo) \ E--F--G detached (This can be ignored) \ / D--H--I (branch-bar) Now you won't need to worry about the detached branch because it is basically like they are in the trash can waiting for the day it gets garbage collected. Eventually some time in the far future it will look like: A--B--C--E'--F'--G'--L--M--N--... (branch-foo) \ \ D--H--I--J--K--.... (branch-bar) 
26
19 окт. La respuesta la da Sukima el 19 de octubre. 2013-10-19 17:12 '13 a las 17:12 2013-10-19 17:12

Para hacer esto sin volver a escribir el historial (es decir, si ya ha hecho clic en confirmar):

 git checkout master git revert <commitID(s)> git checkout -b new-branch git cherry-pick <commitID(s)> 

Ambas ramas se pueden presionar sin esfuerzo!

17
21 янв. respuesta dada teh_senaus 21 de enero 2016-01-21 19:10 '16 a las 19:10 2016-01-21 19:10

Si tal situación:

 Branch one: ABCDEFJLM \ (Merge) Branch two: GIKN 

Yo completé

 git branch newbranch git reset --hard HEAD~8 git checkout newbranch 

Esperaba que la solución fuera HEAD, pero commit L es ahora ...

Para aterrizar en el lugar correcto de la historia, es más fácil trabajar con el hash de confirmación.

 git branch newbranch git reset --hard ######### git checkout newbranch 
11
20 сент. La respuesta la da Darkglow el 20 de septiembre. 2013-09-20 13:17 '13 a las 13:17 2013-09-20 13:17