Soy nuevo en las complejidades de ramificación de Git. Siempre trabajo en una sola rama y confirmo cambios y luego me desplazo periódicamente a mi origen remoto.
Recientemente, en algún lugar, restablecí algunos archivos para sacarlos de la puesta en escena de la confirmación, y luego hice una rebase -i
para deshacerme de un par de confirmaciones locales recientes. Ahora estoy en un estado que no entiendo del todo.
En mi área de trabajo, git log
muestra exactamente lo que esperaría: estoy en el tren correcto con los compromisos que no quería que se fueran, y los nuevos allí, etc.
Pero simplemente ingresé al repositorio remoto, y lo que hay allí es diferente: un par de los compromisos que maté en el rebase fueron empujados, y los nuevos cometidos localmente no están allí.
Creo que "maestro / origen" está separado de HEAD, pero no estoy 100% claro sobre lo que eso significa, cómo visualizarlo con las herramientas de línea de comandos y cómo solucionarlo.
I did a reset of some files to get them out of commit staging
parte? lo siento por las preguntas :)Respuestas:
Primero, aclaremos qué es HEAD y qué significa cuando se separa.
HEAD es el nombre simbólico para el commit actualmente desprotegido. Cuando HEAD no está separado (la situación "normal" 1 : tiene una rama desprotegida), HEAD señala la "referencia" de una rama y la rama apunta a la confirmación. HEAD está "unido" a una rama. Cuando realiza una nueva confirmación, la rama a la que apunta HEAD se actualiza para que apunte a la nueva confirmación. HEAD sigue automáticamente ya que solo apunta a la rama.
git symbolic-ref HEAD
rendimientosrefs/heads/master
La rama llamada "maestro" está desprotegida.
git rev-parse refs/heads/master
ceder17a02998078923f2d62811326d130de991d1a95a
Ese compromiso es la punta actual o "cabeza" de la rama maestra.
git rev-parse HEAD
también rinde17a02998078923f2d62811326d130de991d1a95a
Esto es lo que significa ser una "referencia simbólica". Apunta a un objeto a través de alguna otra referencia.
(Las referencias simbólicas se implementaron originalmente como enlaces simbólicos, pero luego se cambiaron a archivos simples con interpretación adicional para que pudieran usarse en plataformas que no tienen enlaces simbólicos).
Tenemos
HEAD
→refs/heads/master
→17a02998078923f2d62811326d130de991d1a95a
Cuando HEAD está separado, apunta directamente a un commit, en lugar de señalar indirectamente a uno a través de una rama. Puedes pensar en un HEAD separado como si estuviera en una rama sin nombre.
git symbolic-ref HEAD
falla confatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
cede17a02998078923f2d62811326d130de991d1a95a
Dado que no es una referencia simbólica, debe apuntar directamente al compromiso en sí.
Tenemos
HEAD
→17a02998078923f2d62811326d130de991d1a95a
Lo importante para recordar con un HEAD separado es que si el commit al que apunta no tiene referencia (ninguna otra referencia puede alcanzarlo), entonces se convertirá en "colgante" cuando compruebe algún otro commit. Eventualmente, tales confirmaciones pendientes se podarán a través del proceso de recolección de basura (de forma predeterminada, se conservan durante al menos 2 semanas y pueden mantenerse más tiempo al hacer referencia al reflog de HEAD).
1 Está perfectamente bien hacer un trabajo "normal" con una CABEZA separada, solo tiene que hacer un seguimiento de lo que está haciendo para evitar tener que sacar el historial eliminado del registro.
Los pasos intermedios de un rebase interactivo se realizan con un HEAD separado (parcialmente para evitar contaminar el reflog de la rama activa). Si finaliza la operación de rebase completa, actualizará su rama original con el resultado acumulativo de la operación de rebase y volverá a conectar HEAD a la rama original. Supongo que nunca completó completamente el proceso de rebase; esto lo dejará con un HEAD separado que apunte al commit que fue procesado más recientemente por la operación de rebase.
Para recuperarse de su situación, debe crear una rama que apunte al compromiso al que apunta su HEAD separado:
(estos dos comandos se pueden abreviar como
git checkout -b temp
)Esto volverá a conectar su CABEZA a la nueva
temp
rama.A continuación, debe comparar la confirmación actual (y su historial) con la rama normal en la que esperaba trabajar:
(Probablemente quiera experimentar con las opciones de registro: agregar
-p
, dejar de--pretty=…
ver todo el mensaje de registro, etc.)Si su nueva
temp
sucursal se ve bien, es posible que desee actualizar (por ejemplo)master
para señalarla:(estos dos comandos se pueden abreviar como
git checkout -B master temp
)Luego puede eliminar la rama temporal:
Finalmente, probablemente querrás impulsar la historia restablecida:
Es posible que deba agregar
--force
al final de este comando para presionar si la rama remota no se puede "reenviar rápidamente" a la nueva confirmación (es decir, eliminó o reescribió alguna confirmación existente, o de lo contrario reescribió un poco de historial).Si estaba en medio de una operación de rebase, probablemente debería limpiarlo. Puede verificar si se estaba procesando un cambio de base buscando el directorio
.git/rebase-merge/
. Puede limpiar manualmente el rebase en progreso simplemente borrando ese directorio (por ejemplo, si ya no recuerda el propósito y el contexto de la operación de rebase activa). Por lo general, lo usaríagit rebase --abort
, pero eso hace un restablecimiento adicional que probablemente desee evitar (mueve HEAD de nuevo a la rama original y lo restablece a la confirmación original, lo que deshacerá parte del trabajo que hicimos anteriormente).fuente
man git-symbolic-ref
: "En el pasado,.git/HEAD
un enlace simbólico apuntabarefs/heads/master
. Cuando queríamos cambiar a otra rama, lo hicimosln -sf refs/heads/newbranch .git/HEAD
, y cuando queríamos saber en qué rama estamos, lo hicimosreadlink .git/HEAD
. Pero los enlaces simbólicos no son completamente portátiles , por lo que ahora están en desuso y las referencias simbólicas (como se describió anteriormente) se usan de forma predeterminada ".git branch -f master HEAD && git checkout master
es suficiente: asumir que su objetivo es mantener la cabeza actual pero designarla comomaster
. Otros objetivos también tienen sentido y requieren otras recetas.Solo haz esto:
O, si tiene cambios que desea conservar, haga lo siguiente:
fuente
git reset
debería venir con una advertencia "Si no tiene idea de lo que está haciendo, deténgalo". Acabo de recuperarme de una hora de terror pensando que había perdido la última semana de trabajo. ¡Gracias!Me encontré con este problema y cuando leí en la respuesta más votada:
Pensé: ¡Ah, ja! Si
HEAD
es el nombre simbólico para el commit de pago actual, puedo reconciliarlomaster
al cambiarlo amaster
:Este comando:
master
HEAD
regreso al puntoHEAD
divergido demaster
master
El resultado final es que todos los commits que estaban en
HEAD
pero nomaster
están entonces también enmaster
.master
permanece desprotegido.Con respecto al control remoto:
El historial remoto ya no puede reenviarse rápidamente utilizando su historial local. Deberá forzar-presionar (
git push -f
) para sobrescribir el historial remoto. Si tiene colaboradores, generalmente tiene sentido coordinar esto con ellos para que todos estén en la misma página.Después de presionar
master
al control remotoorigin
, su rama de seguimiento remotoorigin/master
se actualizará para que apunte al mismo compromiso quemaster
.fuente
git reflog
luego restablezca su rama a ese compromiso congit rest —hard $commit
Mire aquí para obtener una explicación básica de la cabeza separada:
http://git-scm.com/docs/git-checkout
Línea de comando para visualizarlo:
o
Obtendrá salida como a continuación:
Los
* (no branch)
espectáculos que estás en la cabeza separada.Podría haber llegado a este estado haciendo un
git checkout somecommit
etc. y le habría advertido lo siguiente:Ahora, para llevarlos al maestro:
Haz un
git reflog
o incluso sologit log
y anota tus compromisos. Ahoragit checkout master
ygit merge
los commits.Editar:
Para agregar, use
git rebase -i
no solo para eliminar / eliminar confirmaciones que no necesita, sino también para editarlas. Solo mencione "editar" en la lista de confirmación y podrá modificar su confirmación y luego emitir ungit rebase --continue
para continuar. Esto habría asegurado que nunca llegaras a un HEAD separado.fuente
Obtenga su compromiso separado en su propia rama
Simplemente corre
git checkout -b mynewbranch
.Luego ejecute
git log
, y verá que commit está ahoraHEAD
en esta nueva rama.fuente
mynewbranch
adjunta a algo?si solo tiene una rama maestra y quiere volver a "desarrollar" o una característica, simplemente haga esto:
Nota: verificando origen / desarrollo .
Estás en estado HEAD separado . Puede mirar a su alrededor, hacer cambios experimentales y confirmarlos, y puede descartar cualquier confirmación que realice en este estado sin afectar ninguna rama al realizar otro pago ...
entonces
Funciona :)
fuente
Si desea empujar su CABEZA separada actual (verifique
git log
antes), intente:para enviar su CABEZA separada a la rama maestra en origen. Si su empuje es rechazado, intente
git pull origin master
primero obtener los cambios desde el origen. Si no le importan los cambios desde el origen y se rechaza, porque realizó un cambio de base intencional y desea reemplazar el origen / maestro con su rama actualmente separada, entonces puede forzarla (-f
). En caso de que haya perdido el acceso a confirmaciones anteriores, siempre puede ejecutargit reflog
para ver el historial de todas las ramas.Para volver a una rama maestra, mientras mantiene los cambios, pruebe los siguientes comandos:
Ver: Git: "Actualmente no en ninguna rama". ¿Hay una manera fácil de volver a una sucursal, manteniendo los cambios?
fuente
Encontré esta pregunta al buscar
You are in 'detached HEAD' state.
Después de analizar lo que había hecho para llegar aquí, en comparación con lo que había hecho en el pasado, descubrí que había cometido un error.
Mi flujo normal es:
Esta vez hice:
El problema es que accidentalmente lo hice:
Más bien que:
La solución (en mi situación) era simplemente ejecutar el comando anterior y luego continuar el flujo:
fuente
Lo siguiente funcionó para mí (usando solo el maestro de rama):
El primero empuja la CABEZA separada al origen remoto.
El segundo se mueve a la rama maestra.
El tercero recupera la CABEZA que se une al maestro de rama.
Pueden surgir problemas con el primer comando si se rechaza la inserción. Pero esto ya no sería un problema de cabeza separada, sino que se trata del hecho de que la CABEZA separada no es consciente de algunos cambios remotos.
fuente
Hoy me encontré con este problema y estoy bastante seguro de que lo resolví haciendo:
Estaba en mi computadora de trabajo cuando descubrí cómo hacer esto, y ahora me encuentro con el mismo problema en mi computadora personal. Entonces tendré que esperar hasta el lunes cuando vuelva a la computadora del trabajo para ver exactamente cómo lo hice.
fuente
Si está completamente seguro de que HEAD es el buen estado:
Probablemente no puedas empujar al origen, ya que tu maestro ha divergido del origen. Si está seguro de que nadie más está utilizando el repositorio, puede forzar:
Más útil si está en una rama de características que nadie más está usando.
fuente
Todo lo que tiene que hacer es 'git checkout [nombre-sucursal]' donde [nombre-sucursal] es el nombre de la sucursal original de la que ingresó en un estado de cabeza separada. El (separado de asdfasdf) desaparecerá.
Entonces, por ejemplo, en la rama 'dev' revisa el commit asdfasd14314 ->
ahora estás en un estado de cabeza separada
'git branch' enumerará algo como ->
pero para salir del estado de la cabeza separada y volver a dev ->
y luego 'git branch' listará ->
pero eso es, por supuesto, si no tiene la intención de mantener ningún cambio desde el estado de la cabeza separada, pero me encuentro haciendo esto mucho sin tener la intención de hacer ningún cambio, sino solo mirar una confirmación anterior
fuente
Como señaló Chris, tuve la siguiente situación
git symbolic-ref HEAD
falla confatal: ref HEAD is not a symbolic ref
Sin embargo,
git rev-parse refs/heads/master
estaba apuntando a una buena confirmación desde donde podría recuperarme (en mi caso, la última confirmación y puedes ver esa confirmación usandogit show [SHA]
Hice muchas cosas desordenadas después de eso, pero lo que parece haber solucionado es simplemente,
git symbolic-ref HEAD refs/heads/master
Y la cabeza se vuelve a unir!
fuente
En lugar de hacer
git checkout origin/master
solo haz
git checkout master
luego
git branch
confirmará su sucursal.fuente
Tuve este problema hoy, donde había actualizado un submódulo, pero no estaba en ninguna rama. Ya me había comprometido, por lo que esconder, pagar, desapilar no funcionaría. Terminé escogiendo el compromiso de la cabeza separada. Entonces, inmediatamente después de cometer (cuando el empuje falló), hice:
Mi pensamiento fue: estoy en una cabeza separada, pero quiero estar en el maestro. Suponiendo que mi estado separado no sea muy diferente del maestro, si pudiera aplicar mi confirmación al maestro, estaría configurado. Esto es exactamente lo que hace Cherry-Pick.
fuente
Si hiciste algunos commits encima del master y solo quieres "fusionar hacia atrás"
master
allí (es decir, quieresmaster
señalarHEAD
), la línea sería:master
, incluso si ya existe (que es como moversemaster
y eso es lo que queremos).HEAD
, que es donde se encuentra.master
después.Encontré esto especialmente útil en el caso de los repositorios secundarios, que también se encuentran en un estado separado con bastante frecuencia.
fuente
Tuve el mismo problema y lo resolví siguiendo los siguientes pasos.
Si necesita conservar sus cambios
git checkout master
comando para volver a la rama maestra.git checkout -b changes
ygit checkout -B master changes
Si no necesitas tus cambios
Para eliminar todos los archivos no rastreados de su rama ejecute
git clean -df
.Luego debe borrar todos los cambios no organizados dentro de su repositorio. Para hacer eso tienes que correr
git checkout --
Finalmente, debe volver a colocar su rama en la rama maestra mediante el
git checkout master
comando.fuente
Para mí fue tan fácil como eliminar la sucursal local nuevamente, ya que no tenía ningún compromiso local que quisiera impulsar:
Así que lo hice:
Y luego revisando la rama nuevamente:
fuente
Cuando personalmente me encuentro en una situación en la que resulta que hice algunos cambios mientras no estoy
master
(HEAD
es decir, está separado justo encimamaster
y no hay compromisos en el medio), el escondite podría ayudar:fuente
En palabras simples, el estado HEAD separado significa que no está desprotegido en HEAD (o punta) de ninguna rama .
Comprender con un ejemplo
Una rama en la mayoría de los casos es una secuencia de confirmaciones múltiples como:
Commit 1: master -> branch_HEAD (123be6a76168aca712aea16076e971c23835f8ca)
Commit 2: master -> 123be6a76168aca712aea16076e971c23835f8ca -> branch_HEAD (100644a76168aca712aea16076e971c23835f8ca)
Como puede ver arriba en caso de secuencia de confirmaciones, su rama apunta a su última confirmación. Entonces, en ese caso, si realiza el pago para comprometerse 123be6a76168aca712aea16076e971c23835f8ca, entonces estaría en estado de cabeza separada ya que HEAD de su sucursal apunta a 100644a76168aca712aea16076e971c23835f8ca y técnicamente está desprotegido en HEAD of no branch. Por lo tanto, estás en el estado HEAD separado.
Explicación teórica
En este Blog , está indicando claramente que un repositorio de Git es un árbol de compromisos, con cada confirmación que apunta a su antepasado con cada puntero de confirmación actualizado y estos punteros a cada rama se almacenan en los subdirectorios .git / refs. Las etiquetas se almacenan en .git / refs / tags y las ramas se almacenan en .git / refs / heads. Si observa cualquiera de los archivos, encontrará que cada etiqueta corresponde a un solo archivo, con un hash de confirmación de 40 caracteres y, según lo explicado anteriormente por @Chris Johnsen y @Yaroslav Nikitenko, puede consultar estas referencias.
fuente
Llegué a un estado realmente tonto, dudo que alguien más lo encuentre útil ... pero por si acaso
que eventualmente arreglé con
fuente
Esto me funcionó perfectamente:
1.
git stash
para guardar sus modificaciones localesSi desea descartar los cambios,
git clean -df
git checkout -- .
git clean elimina todos los archivos no rastreados (advertencia: aunque no eliminará los archivos ignorados mencionados directamente en .gitignore, puede eliminar los archivos ignorados que residen en carpetas) y git checkout borra todos los cambios no organizados.
2.
git checkout master
para cambiar a la rama principal (suponiendo que quiera usar master)3.
git pull
para extraer el último commit de la rama master4.
git status
para verificar que todo se vea genialfuente
En mi caso, corrí
git status
y vi que tenía algunos archivos sin seguimiento en mi directorio de trabajo.Para que el rebase funcione, solo tuve que limpiarlos (ya que no los necesitaba).
fuente
Si está utilizando EGit en Eclipse: suponga que su maestro es su rama de desarrollo principal
Después de esto, debería poder volver a conectar al origen-maestro.
fuente
Yo tuve el mismo problema. Guardo mis cambios
git stash
y restablezco la rama en local a un commit anterior (pensé que eso causó), luego hice ungit pull
y no estoy despegando esa cabeza ahora. No olvidegit stash apply
tener sus cambios nuevamente.fuente
fuente