Pregunta

Me gustaría pasar los últimos comete he comprometido principal a una nueva rama y tomar maestro antes de los commits realizados.Por desgracia, mi Git-fu no es lo bastante fuerte todavía, alguna ayuda?

I. e.¿Cómo puedo ir de este

master A - B - C - D - E

a este?

newbranch     C - D - E
             /
master A - B 
¿Fue útil?

Solución

Mudarse a una nueva sucursal

ADVERTENCIA: este método funciona porque está creando una nueva rama con el primer comando: git branch newbranch. Si desea mover las confirmaciones a una rama existente , debe fusionar sus cambios en la rama existente antes de ejecutar git reset --hard HEAD~3 (consulte Mover a una rama existente abajo). Si no combina sus cambios primero, se perderán.

A menos que haya otras circunstancias involucradas, esto se puede hacer fácilmente ramificando y retrocediendo.

# Note: Any changes not committed will be lost.
git branch newbranch      # Create a new branch, saving the desired commits
git reset --hard HEAD~3   # Move master back by 3 commits (Make sure you know how many commits you need to go back)
git checkout newbranch    # Go to the new branch that still has the desired commits

Pero asegúrate de cuántos commits volver. Alternativamente, puede en lugar de HEAD~3, simplemente proporcionar el hash de la confirmación (o la referencia como origin / master ) que desea & Quot; volver a & Quot; en la rama maestra (/ actual), por ejemplo:

git reset --hard a1b2c3d4

* 1 solo estarás " perdiendo " confirmaciones de la rama maestra, pero no se preocupe, ¡tendrá esas confirmaciones en newbranch!

ADVERTENCIA: con Git versión 2.0 y posterior, si luego git rebase la nueva rama sobre la rama original (master), es posible que necesite una opción explícita --no-fork-point durante el cambio de base para evitar perder los compromisos prorrogados. Tener branch.autosetuprebase always establecido hace que esto sea más probable. Consulte la respuesta de John Mellor para obtener más detalles.

Mudarse a una sucursal existente

Si desea mover sus confirmaciones a una rama existente , se verá así:

git checkout existingbranch
git merge master
git checkout master
git reset --hard HEAD~3 # Go back 3 commits. You *will* lose uncommitted work.
git checkout existingbranch

Otros consejos

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:

A-B-C-D-E (HEAD)
        ↑
      master

Después de git branch newBranch:

    newBranch
        ↓
A-B-C-D-E (HEAD)
        ↑
      master

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

    newBranch
        ↓
A-B-C-D-E (HEAD)
    ↑
  master

Dado que una rama es solo un puntero, master señaló la última confirmación. Cuando creó newBranch , simplemente creó un nuevo puntero a la última confirmación. Luego, usando 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.

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

git checkout master
git log

Tenga en cuenta los hashes de (digamos 3) confirmaciones que desee en 9aa1233. Aquí usaré:
C commit: 453ac3d
D commit: 612ecb3
E commit: <=>

  

Nota: puede usar los primeros siete caracteres o   todo el hash de confirmación

Paso 2: colóquelos en el <=>

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

O (en Git 1.7.2+, use rangos)

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

git cherry-pick aplica esas tres confirmaciones a newbranch.

Otra forma de hacer esto, usando solo 2 comandos. También mantiene intacto su árbol de trabajo actual.

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

Versión anterior : antes de conocer git branch -f

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

Poder push a . es un buen truco para saber.

La mayoría de las respuestas anteriores son peligrosamente equivocado!

NO hacer esto:

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

Como la próxima vez que ejecute git rebase (o git pull --rebase) los 3 compromete sería descartan de newbranch!(ver explicación más abajo)

En lugar de hacer esto:

git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
  • Primero descarta los 3 más recientes (--keep es como --hard, pero más segura, como falla, en lugar de tirar los cambios no confirmados).
  • A continuación, se divide newbranch.
  • Entonces cherry-picks de los 3 compromete de nuevo en newbranch.Puesto que ya no hace referencia a una rama, lo hace mediante el uso de git reflog: HEAD@{2} es la confirmación de que HEAD se utiliza para referirse a 2 operaciones de atrás, es decir,antes de 1.desprotegido newbranch y 2.usa git reset para descartar el 3 compromete.

Advertencia:el reflog está habilitado por defecto, pero si has desactivado manualmente (por ejemplo,mediante el uso de un "desnudo" repositorio git), usted no será capaz de obtener el 3 compromete de nuevo después de correr git reset --keep HEAD~3.

Una alternativa que no dependen de la reflog es:

# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3

(si lo prefiere, puede escribir @{-1} - el previamente se comprueba la sucursal - en lugar de oldbranch).


Explicación técnica

¿Por qué git rebase deseche el 3 cometa después de que el primer ejemplo?Es porque git rebase sin argumentos permite la --fork-point la opción por defecto, que utiliza el local reflog para tratar de ser robusto frente a la rama de aguas arriba está la fuerza empujó.

Supongamos que usted se separaron origin/master que contiene comete M1, M2, M3, y luego hizo tres compromete a ti mismo:

M1--M2--M3  <-- origin/master
         \
          T1--T2--T3  <-- topic

pero entonces alguien vuelve a escribir la historia por la fuerza empujando origin/master para quitar M2:

M1--M3'  <-- origin/master
 \
  M2--M3--T1--T2--T3  <-- topic

El uso de su local reflog, git rebase puede ver que se bifurca a partir de una anterior encarnación de el origen o la rama principal, y de ahí que el M2 y M3 comete no son realmente parte de su rama.De ahí que razonablemente se supone que ya M2 fue retirado de la rama de aguas arriba, que ya no quiere que en el tema de la sucursal de una vez el tema de la sucursal es rebasada:

M1--M3'  <-- origin/master
     \
      T1'--T2'--T3'  <-- topic (rebased)

Este comportamiento tiene sentido, y es generalmente la cosa correcta a hacer, cuando de reajuste.

Así que la razón por la que los comandos siguientes errores:

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

es porque dejan el reflog en mal estado.Git ve newbranch como tener bifurcada fuera de la rama de aguas arriba en una revisión que incluye los 3 compromete, a continuación, el reset --hard vuelve a escribir la parte de arriba de la historia de quitar la comete, y así que la próxima vez que se ejecute git rebase descarta como cualquier otro commit que ha sido retirado de la parte de arriba.

Pero en este caso en particular queremos que esos 3 se compromete a ser considerado como parte de la rama.Para lograr eso, necesitamos bifurque la parte de arriba en la revisión anterior, que no incluyen los 3 compromete.Eso es lo que a mi las soluciones que se proponen hacer, por lo que ambos dejan el reflog en el estado correcto.

Para más detalles, véase la definición de --fork-point en el git rebase y git merge-base docs.

Solución mucho más sencilla de usar git stash

Aquí está una mucho más simple enfoque se compromete a que el mal de la rama.Comenzando en la rama master que tiene tres equivocado compromete a:

git reset HEAD~3
git stash
git checkout newbranch
git stash pop

Para la utilización de este?

  • Si su propósito principal es revertir master
  • Desea mantener los cambios en el archivo
  • No se preocupan acerca de los mensajes en la errónea compromete
  • Usted no ha empujado aún
  • Queremos que esto sea fácil de memorizar
  • Usted no quiere complicaciones como temporal/nuevas sucursales, la búsqueda y copia de cometer hashes, y otros dolores de cabeza

Lo que esto hace, por número de línea

  1. Deshace el último de los tres comete (y sus mensajes) master, sin embargo, deja todos los archivos de trabajo intacto
  2. Caletas de distancia todos los cambios de los archivos, haciendo que el master árbol de trabajo exactamente igual a la de la CABEZA~3 estado
  3. Cambia a una rama existente newbranch
  4. Se aplica el escondido cambios en su directorio de trabajo y borra el alijo

Ahora puede utilizar git add y git commit como lo haría normalmente.Todos los nuevos commits será añadido a newbranch.

Lo que este no

  • No dejar al azar las ramas temporales abarrotar el árbol
  • No conservar el error que comete y los mensajes de confirmación, así que usted necesitará agregar un nuevo mensaje de confirmación a este nuevo commit

Objetivos

El OP dijo que el objetivo era "tomar el amo de nuevo antes de que los comete fueron hechas" sin perder los cambios y esta solución hace que.

Puedo hacer esto al menos una vez a la semana cuando accidentalmente se compromete a hacer de nuevo master en lugar de develop.Generalmente solo tengo una comprometerse a la reversión en cuyo caso el uso de git reset HEAD^ en la línea 1 es una manera más simple de reversión sólo un commit.

No haga esto si usted empuja el maestro de los cambios arriba

Alguien se ha tirado a esos cambios.Si sólo la reescritura de su maestro local no hay ningún efecto cuando es empujado arriba, pero empujando un reescribe la historia a los colaboradores pueden causar dolores de cabeza.

Esto no " mover " en el 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)

Para hacer esto sin reescribir el historial (es decir, si ya presionó las confirmaciones):

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

¡Ambas ramas se pueden empujar sin fuerza!

Tenía esta situación:

Branch one: A B C D E F     J   L M  
                       \ (Merge)
Branch two:             G I   K     N

Realicé:

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

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

git branch newbranch 
git reset --hard #########
git checkout newbranch

1) Cree una nueva rama, que mueve todos sus cambios a new_branch.

git checkout -b new_branch

2) Luego regrese a la rama anterior.

git checkout master

3) Hacer git rebase

git rebase -i <short-hash-of-B-commit>

4) Luego, el editor abierto contiene los últimos 3 datos de confirmación.

...
pick <C's hash> C
pick <D's hash> D
pick <E's hash> E
...

5) Cambie pick a drop en todas esas 3 confirmaciones. Luego guarde y cierre el editor.

...
drop <C's hash> C
drop <D's hash> D
drop <E's hash> E
...

6) Ahora se eliminan los últimos 3 commits de la rama actual (master). Ahora empuje la rama con fuerza, con el signo + antes del nombre de la rama.

git push origin +master

¿Cómo puedo pasar de esto?

A - B - C - D - E 
                |
                master

a esto?

A - B - C - D - E 
    |           |
    master      newbranch

Con dos comandos

  • git branch -m master newbranch

dar

A - B - C - D - E 
                |
                newbranch

y

  • git branch master B

dar

A - B - C - D - E
    |           |
    master      newbranch

Puede 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) Encuentra 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 está hecho. Si eligió la identificación correcta y la rama correcta, entonces tendrá éxito. Así que antes de hacer esto ten cuidado. De lo contrario, puede ocurrir otro problema.

Ahora puedes insertar tu código

git push

Si solo necesita mover todas sus confirmaciones sin empujar a una nueva sucursal , entonces solo necesitas,

  1. crear una nueva sucursal de la actual: git branch new-branch-name

  2. empuje su nueva sucursal : git push origin new-branch-name

  3. revierte su rama (actual) anterior al último estado estable / empujado: git reset --hard origin/old-branch-name

Algunas personas también tienen otras upstreams en lugar de origin, deberían usar los upstream

apropiados
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top