Mueva el puntero de rama a una confirmación diferente sin finalizar la compra

760

Para mover el puntero de una rama desprotegida, se puede usar el git reset --hardcomando. Pero, ¿cómo mover el puntero de rama de una rama no extraída para apuntar a una confirmación diferente (manteniendo todas las demás cosas como una rama remota rastreada)?

Agudeza
fuente
11
Parece que todo lo que quería hacer es una rama de una confirmación diferente de la que se creó a partir de ahora. Si mi comprensión es correcta, ¿por qué no simplemente crea una nueva rama a partir del compromiso que desea crear usando git branch <branch-name> <SHA-1-of-the-commit>y volca la rama antigua?
Yasouser
66
@yasouser - No estoy seguro de que sea una buena idea descargar cualquier rama "maestra".
Bulwersator

Respuestas:

578

Puedes hacerlo por referencias arbitrarias. Así es como se mueve un puntero de rama:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

La forma general:

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

Puede elegir liendres sobre el mensaje de reflog si lo desea: creo que el mensaje branch -fes diferente del anterior reset --hard, y este no es exactamente ninguno de ellos.

Adam A
fuente
39
¿Para qué sirve el mensaje? ¿Dónde se almacena y cómo leerlo más tarde?
Mot
44
NOTA: Esto no funciona en repositorios desnudos. En repositorios desnudos, debe usar 'git branch -f master <commit>' para actualizar la rama (consulte la respuesta a continuación).
Junio ​​Rodas
37
Si, como yo, usas accidentalmente <branch> en lugar de refs / heads / <branch>, terminarás con un nuevo archivo en tu directorio .git en .git / <branch>, y recibirás mensajes como "refname 'master' es ambiguo" cuando intentas trabajar con él. Puede eliminar el archivo de su directorio .git para arreglarlo.
David Minor
34
No se ha explicado con satisfacción por qué esto es mejor que git branch -f. Para ser específicos, este método parece ser: (A) más difícil de usar (B) más difícil de recordar y (C) más peligroso
Steven Lu
10
"qué se entiende exactamente por referencias arbitrarias": las ramas no son el único tipo de referencia que apunta a un commit. Hay etiquetas, y también puede crear referencias arbitrarias / referencias de estilo myref usted mismo que no sean ramas ni etiquetas. Creo que eso también responde a la pregunta de Steven Lu sobre qué podría ser "mejor". Estoy de acuerdo en que la rama -f es más simple si está trabajando con ramas.
Adam A
966
git branch -f <branch-name> <new-tip-commit>
Chris Johnsen
fuente
24
O para árbitros arbitrarias, git update-ref -m "reset: Reset <branch> to <new commit>" <branch> <commit>. (Puede elegir liendres sobre el mensaje de reflog si lo desea, creo branch -fque es diferente del reset --hardotro, y este no es exactamente ninguno de los dos)
Cascabel
44
Jefromi, escribe una respuesta por separado para que puedas obtener votos. :)
Mot
16
Esta es una mejor respuesta ya que maneja el caso del 99% y en realidad se ajusta a la documentación. git help branchdice "-f, --force Restablecer <nombre de rama> a <punto de inicio> si ya existe <nombre de rama>. Sin -f git branch se niega a cambiar una rama existente".
AlexChaffee
12
Lo estoy haciendo git branch -f master <hash>y me dice fatal: Cannot force update the current branch.Ummmm, ¿tengo que hacer qué ahora, verifique alguna otra rama aleatoria antes de poder usar este comando?
Qwertie
20
Esto no funcionará si la rama que está tratando de mover es su rama actual (lo HEADseñala).
Vladimir Panteleev
135

También puede pasar git reset --harduna referencia de confirmación.

Por ejemplo:

git checkout branch-name
git reset --hard new-tip-commit

Me parece que hago algo como esto con frecuencia:

Asumiendo esta historia

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master
Amiel Martin
fuente
Esto tiene más sentido porque normalmente se usa HEAD o HEAD ^ para mover la punta de la rama hacia atrás en el tiempo. Por lo tanto, esto es consistente para especificar el compromiso por delante.
justingordon
11
Esto está bien si su árbol de trabajo está limpio. Si tiene muchos cambios por etapas o por etapas, probablemente sea mejor hacer git update-reflo mencionado anteriormente.
un nerd pagado el
16
¿Notó que su "respuesta" no agrega nada que no sea parte de la pregunta ya? - OP dijo: si está desprotegido ... puede usar ¡ git reset --hard ...No es necesario repetirlo aquí! :-(
Robert Siemer
66
@Robert: No estoy de acuerdo. La pregunta no decía cómo usarlo y esto lo hace. Fue agradable no tener que ir a buscar eso cómo.
Wilson F
77
@WilsonF, tal vez fue bueno para ti encontrar esto aquí, pero no responde a la pregunta en absoluto. Tal vez sea la respuesta de alguna otra pregunta, pero aquí está mal .
Robert Siemer
52

Solo para enriquecer la discusión, si desea mover la myBranchrama a su confirmación actual , simplemente omita el segundo argumento después-f

Ejemplo:

git branch -f myBranch


Generalmente hago esto cuando estoy rebaseen un estado HEAD separado :)

Matheus Felipe
fuente
13

En gitk --all:

  • haga clic derecho en la confirmación que desee
  • -> crear nueva sucursal
  • ingrese el nombre de una sucursal existente
  • presione regresar en el cuadro de diálogo que confirma el reemplazo de la rama anterior de ese nombre .

Tenga en cuenta que volver a crear en lugar de modificar la rama existente perderá la información de la rama de seguimiento . (Esto generalmente no es un problema para casos de uso simples donde solo hay un control remoto y su sucursal local tiene el mismo nombre que la sucursal correspondiente en el control remoto. Vea los comentarios para obtener más detalles, gracias @mbdevpl por señalar este inconveniente).

Sería genial si gitktuviera una función donde el cuadro de diálogo tuviera 3 opciones: sobrescribir, modificar existente o cancelar.


Incluso si normalmente eres un adicto a la línea de comandos como yo, git guiy gitkestás bastante bien diseñado para el subconjunto de uso de git que permiten. Recomiendo usarlos para lo que son buenos (es decir, organizar selectivamente los trozos dentro / fuera del índice en git gui, y también solo comprometerse. (Ctrl-s para agregar un cierre de sesión: línea, ctrl-enter para confirmar) .)

gitk es ideal para realizar un seguimiento de algunas ramas mientras clasifica sus cambios en una buena serie de parches para enviar en sentido ascendente, o cualquier otra cosa en la que necesite realizar un seguimiento de lo que está en medio de varias ramas.

Ni siquiera tengo abierto un navegador de archivos gráficos, pero me encanta gitk / git gui.

Peter Cordes
fuente
1
¡Tan fácil! Puede que me haya convertido de gitg a gitk.
Michael Cole
De esta manera, sin embargo, se pierde la información de la rama de seguimiento.
mbdevpl
@mbdevpl: No soy realmente un experto en git. Creo que entiendo lo que quieres decir, pero no las implicaciones. He usado esto con bastante frecuencia, y aún he podido empujar esas ramas a ramas del mismo nombre en un control remoto. ¿Qué hace por usted la asociación entre una rama y su rama de seguimiento remoto?
Peter Cordes
1
@ PeterCordes Ineed, cuando los nombres de las ramas no coinciden, es importante. También cuando hay más de un control remoto. Además, cuando usa git prompt para mostrar el estado de la sucursal, mostrará la distancia de confirmación a su rama de seguimiento (si está configurada). Además, la git statussalida se ve afectada. Además, en algunos casos git fetchy git pushno funcionará sin especificar explícitamente el control remoto si no configura la rama de seguimiento. No conozco todos los casos, pero para mí la regla general es que, por conveniencia y rapidez de trabajo, es mejor tener ramas de seguimiento en orden.
mbdevpl
7

La solución recomendadagit branch -f branch-pointer-to-move new-pointer en TortoiseGit :

  • "Git Mostrar registro"
  • Marque "Todas las ramas"
  • En la línea a la que desea que se mueva el puntero de rama (puntero nuevo):
    • Haga clic derecho, "Crear rama en esta versión"
    • Al lado de "Rama", ingrese el nombre de la rama a mover (branch-pointer-to-move)
    • En "Base On", verifique que el nuevo puntero sea correcto
    • Marque "Fuerza"
    • Okay

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

hacha.
fuente
4

Honestamente, me sorprende cómo nadie pensó en el git pushcomando:

git push -f . <destination>:<branch>

El punto (.) Se refiere al repositorio local, y es posible que necesite la opción -f porque el destino podría estar "detrás de su contraparte remota" .

Aunque este comando se usa para guardar los cambios en su servidor, el resultado es exactamente el mismo que si se moviera la rama remota ( <branch>) a la misma confirmación que la rama local ( <destination>)

Adrian
fuente
También puede hacer esto sin -fevitar golpear nada local; por ejemplo, git fetch origin && git push . origin/develop:developes una versión de prueba rápida sin fallas de git checkout develop && git pull --ff-only
btown
1

Abra el archivo .git/refs/heads/<your_branch_name>y cambie el hash almacenado allí al que desea mover el encabezado de su rama. Simplemente edite y guarde el archivo con cualquier editor de texto. Solo asegúrese de que la rama a modificar no sea la actual activa.

Descargo de responsabilidad: Probablemente no sea una forma recomendable de hacerlo, pero hace el trabajo.

Guillermo Gutiérrez
fuente
1
No estoy seguro si esta es la forma caótica o malvada de hacerlo. 🤔 😉
Keith Russell
@KeithRussell puede ser ambos: P
Guillermo Gutiérrez
0

En el caso de que la confirmación a la que desea apuntar esté por delante de la rama actual (que debería ser el caso, a menos que desee deshacer las últimas confirmaciones de la rama actual), simplemente puede hacer:

git merge <commit>
Juan Pablo
fuente
Pregunta sobre qué hacer si la sucursal no está desprotegida.
Keith Russell
Vaya, me perdí ese punto. En ese caso, podría hacer lo git push . <commit>:<branch>que ya se sugirió.
Jean Paul