Me gustaría mover los últimos commits que he comprometido a master a una nueva rama y volver a master antes de que se realicen esos commits. Desafortunadamente, mi Git-fu no es lo suficientemente fuerte todavía, ¿alguna ayuda?
Es decir, ¿cómo puedo ir de esto?
master A - B - C - D - E
¿a esto?
newbranch C - D - E
/
master A - B
git
git-branch
branching-and-merging
Mark A. Nicolosi
fuente
fuente
Respuestas:
Mudarse a una sucursal existente
Si desea mover sus confirmaciones a una rama existente , se verá así:
La
--keep
opción conserva los cambios no confirmados que pueda tener en archivos no relacionados, o aborta si esos cambios tendrían que sobrescribirse, de manera similar a lo quegit checkout
hace. Si aborta,git stash
cambia y vuelve a intentarlo, o usa--hard
para perder los cambios (¡incluso de archivos que no cambiaron entre las confirmaciones!)Mudarse a una nueva sucursal
Este método funciona creando una nueva rama con el primer comando (
git branch newbranch
) pero sin cambiar a él. Luego, retrocedemos la rama actual (maestra) y cambiamos a la nueva rama para continuar trabajando.Pero asegúrese de cuántas confirmaciones para volver. Alternativamente, en lugar de
HEAD~3
, simplemente puede proporcionar el hash de la confirmación (o la referencia comoorigin/master
) a la que desea volver, por ejemplo:ADVERTENCIA: con Git versión 2.0 y posteriores, si luego se agrega
git rebase
la nueva rama a la rama original (master
), es posible que necesite una--no-fork-point
opción explícita durante el rebase para evitar perder las confirmaciones que movió de la rama maestra. Tenerlo lobranch.autosetuprebase always
hace más probable. Ver la respuesta de John Mellor para más detalles.fuente
Para aquellos que se preguntan por qué funciona (como estaba al principio):
Desea volver a C y mover D y E a la nueva rama. Esto es lo que parece al principio:
Después
git branch newBranch
:Después
git reset --hard HEAD~2
:Como una rama es solo un puntero, el maestro señaló la última confirmación. Cuando creó newBranch , simplemente creó un nuevo puntero a la última confirmación. Luego, utilizando
git reset
, movió el puntero maestro hacia atrás dos confirmaciones. Pero como no movió newBranch , todavía señala la confirmación que hizo originalmente.fuente
git push origin master --force
cambio para que aparezca en el repositorio principal.git rebase
, los 3 commits se descartarán silenciosamentenewbranch
. Vea mi respuesta para más detalles y alternativas más seguras.origin/master
no aparece en el diagrama anterior. Si presionóorigin/master
y luego realizó los cambios anteriores, seguro, las cosas serían divertidas. Pero ese es un problema del tipo "Doctor, me duele cuando hago esto". Y está fuera del alcance de lo que hizo la pregunta original. Le sugiero que escriba su propia pregunta para explorar su escenario en lugar de secuestrarlo.git branch -t newbranch
". Regrese y lea las respuestas nuevamente. Nadie sugirió hacer eso.newbranch
basarse en sumaster
rama local existente . Después de realizar la respuesta aceptada, cuando el usuario consigue alrededor de ejecutargit rebase
ennewbranch
, git les recordará que se olvidaron de establecer la rama aguas arriba, por lo que van a ejecutargit branch --set-upstream-to=master
a continuación,git rebase
y tienen el mismo problema. También pueden usargit branch -t newbranch
en primer lugar.En general...
El método expuesto por sykora es la mejor opción en este caso. Pero a veces no es lo más fácil y no es un método general. Para un método general, use git cherry-pick :
Para lograr lo que OP quiere, es un proceso de 2 pasos:
Paso 1: tenga en cuenta qué confirmaciones del maestro desea en un
newbranch
Ejecutar
Tenga en cuenta los hashes de (digamos 3) confirmaciones que desea
newbranch
. Aquí usaré:C commit:
9aa1233
D commit:
453ac3d
E commit:
612ecb3
Paso 2 - Póngalos en el
newbranch
O (en Git 1.7.2+, use rangos)
git cherry-pick aplica esos tres commits a newbranch.
fuente
Otra forma de hacer esto, usando solo 2 comandos. También mantiene intacto su árbol de trabajo actual.
Versión anterior - antes de aprender sobre
git branch -f
Poder
push
hacerlo.
es un buen truco para saber.fuente
git branch -f
aquí?.
es el director actual. git puede empujar a REMOTOS o URL de GIT.path to local directory
es compatible con la sintaxis de URL de Git. Consulte la sección URL de GIT engit help clone
.¡La mayoría de las respuestas anteriores son peligrosamente incorrectas!
No hagas esto:
¡Como la próxima vez que ejecute
git rebase
(ogit pull --rebase
) esos 3 commits serían descartados en silencionewbranch
! (ver explicación a continuación)En cambio, haz esto:
--keep
es como--hard
, pero más seguro, ya que falla en lugar de descartar los cambios no confirmados).newbranch
.newbranch
. Dado que una rama ya no hace referencia a ellos, lo hace mediante el uso de refit de git :HEAD@{2}
es el compromiso queHEAD
solía referirse a 2 operaciones hace, es decir, antes de 1. desprotegidonewbranch
y 2. utilizadogit reset
para descartar los 3 compromisos.Advertencia: el reflog está habilitado de forma predeterminada, pero si lo ha deshabilitado manualmente (por ejemplo, utilizando un repositorio git "desnudo"), no podrá recuperar los 3 commits después de ejecutarlo
git reset --keep HEAD~3
.Una alternativa que no depende del reflog es:
(si lo prefiere, puede escribir
@{-1}
, la rama previamente extraída, en lugar deoldbranch
).Explicación técnica
¿Por qué
git rebase
descartar los 3 commits después del primer ejemplo? Es porquegit rebase
sin argumentos habilita la--fork-point
opción por defecto, que usa el registro local para tratar de ser robusto contra la rama ascendente que se empuja a la fuerza.Supongamos que ramificó origen / maestro cuando contenía confirmaciones M1, M2, M3, y luego realizó tres confirmaciones usted mismo:
pero luego alguien reescribe el historial presionando forzar origin / master para eliminar M2:
Usando su reflog local,
git rebase
puede ver que se bifurcó de una encarnación anterior de la rama de origen / maestra, y por lo tanto, las confirmaciones de M2 y M3 no son realmente parte de su rama de tema. Por lo tanto, se supone razonablemente que, dado que M2 se eliminó de la rama ascendente, ya no lo desea en su rama temática una vez que la rama temática se haya modificado:Este comportamiento tiene sentido y, por lo general, es lo que se debe hacer al rebasar.
Entonces, la razón por la que fallan los siguientes comandos:
es porque dejan el reflog en el estado incorrecto. Git ve
newbranch
que se ha bifurcado de la rama ascendente en una revisión que incluye los 3 commits, luegoreset --hard
reescribe el historial del upstream para eliminar los commits, por lo que la próxima vez quegit rebase
lo ejecutes los descarta como cualquier otro commit que se haya eliminado del upstream.Pero en este caso particular, queremos que esas 3 confirmaciones se consideren como parte de la rama del tema. Para lograr eso, necesitamos bifurcar el flujo ascendente en la revisión anterior que no incluye las 3 confirmaciones. Eso es lo que hacen mis soluciones sugeridas, por lo tanto, ambos dejan el registro en el estado correcto.
Para obtener más detalles, consulte la definición de
--fork-point
en los documentos git rebase y git merge-base .fuente
master
. Entonces no, no están peligrosamente equivocados.-t
te refieresgit branch
sucede implícitamente si lo hasgit config --global branch.autosetuprebase always
configurado. Incluso si no lo hace, ya le expliqué que el mismo problema ocurre si configura el seguimiento después de ejecutar estos comandos, como el OP probablemente intenta hacer dada su pregunta.Solución mucho más simple usando git stash
Aquí hay una solución mucho más simple para los compromisos con la rama incorrecta. Comenzando en la rama
master
que tiene tres confirmaciones erróneas:¿Cuándo usar esto?
master
Qué hace esto, por número de línea
master
, pero deja intactos todos los archivos de trabajomaster
árbol de trabajo sea exactamente igual al estado HEAD ~ 3newbranch
Ahora puede usar
git add
ygit commit
como lo haría normalmente. Se agregarán todos los nuevos commitsnewbranch
.Lo que esto no hace
Metas
El OP declaró que el objetivo era "recuperar el master antes de que se realizaran esas confirmaciones" sin perder los cambios y esta solución lo hace.
Hago esto al menos una vez a la semana cuando accidentalmente hago nuevos commits en
master
lugar dedevelop
. Por lo general, solo tengo un commit para revertir, en cuyo caso usargit reset HEAD^
en la línea 1 es una forma más simple de revertir solo un commit.No hagas esto si empujaste los cambios del maestro hacia arriba
Alguien más puede haber sacado esos cambios. Si solo está reescribiendo a su maestro local, no hay ningún impacto cuando se empuja hacia arriba, pero enviar un historial reescrito a los colaboradores puede causar dolores de cabeza.
fuente
git add
ygit commit
que usé, así que todo lo que tenía que hacer era presionar la flecha hacia arriba e ingresar algunas veces y ¡boom! Todo había vuelto, pero ahora en la rama correcta.Esto no los "mueve" en el sentido técnico, pero tiene el mismo efecto:
fuente
rebase
para lo mismo?rebase
en la rama separada en el escenario anterior.Para hacer esto sin reescribir el historial (es decir, si ya ha empujado los commits):
¡Ambas ramas pueden ser empujadas sin fuerza!
fuente
Acabo de esta situación:
Yo actué:
Esperaba que commit fuera el HEAD, pero commit L es ahora ...
Para asegurarse de aterrizar en el lugar correcto de la historia, es más fácil trabajar con el hash del commit
fuente
¿Cómo puedo ir de esto?
¿a esto?
Con dos comandos
dando
y
dando
fuente
Si solo necesita mover todas sus confirmaciones no apresuradas a una nueva sucursal , entonces solo necesita,
crear una nueva rama de la actual:
git branch new-branch-name
empuja tu nueva sucursal :
git push origin new-branch-name
revierta su rama anterior (actual) al último estado de inserción / estable:
git reset --hard origin/old-branch-name
Algunas personas también tienen otros en
upstreams
lugar deorigin
, deberían usarupstream
fuente
1) Crea una nueva rama, que mueve todos tus cambios a new_branch.
2) Luego regresa a la rama anterior.
3) Hacer git rebase
4) Luego, el editor abierto contiene los últimos 3 datos de confirmación.
5) Cambie
pick
adrop
en todos esos 3 commits. Luego guarde y cierre el editor.6) Ahora se eliminan los últimos 3 commits de la rama actual (
master
). Ahora empuje la rama con fuerza, con un+
signo antes del nombre de la rama.fuente
Puedes hacer esto, solo 3 pasos simples que utilicé.
1) crea una nueva sucursal donde quieras confirmar tu actualización reciente.
git branch <branch name>
2) Encuentre el ID de confirmación reciente para confirmar en una nueva sucursal.
git log
3) Copie esa nota de identificación de confirmación de que la lista de confirmación más reciente tiene lugar en la parte superior. para que pueda encontrar su compromiso. también lo encuentras por mensaje.
git cherry-pick d34bcef232f6c...
También puede proporcionar algún tipo de ID de confirmación.
git cherry-pick d34bcef...86d2aec
Ahora tu trabajo hecho. Si eligió la identificación correcta y la rama correcta, entonces tendrá éxito. Entonces, antes de hacer esto, ten cuidado. De lo contrario, puede ocurrir otro problema.
Ahora puedes empujar tu código
git push
fuente
Otra forma de hacer esto:
[1] Cambie el nombre de la
master
rama a sunewbranch
(suponiendo que esté en lamaster
rama):[2] Crea una
master
rama desde el commit que desees:fuente